GdtCostHourLogic.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <?php
  2. namespace app\v1\logic\tool\advert;
  3. use app\v1\logic\advert\AgentSiteLogic;
  4. use GuzzleHttp\Client;
  5. use support\think\Db;
  6. class GdtCostHourLogic
  7. {
  8. protected string $dateTable = "media_cost";
  9. protected string $hourTable = "media_cost_hour";
  10. protected string $date;
  11. protected array $advertiserIds=[];
  12. protected array $siteMap=[];
  13. private int $apiId=0;
  14. public function run($params=[])
  15. {
  16. // 重跑用,传数组
  17. if(!empty($params['date'])){
  18. $sDate = is_array($params['date']) ? $params['date'][0] : $params['date'];
  19. $eDate = !empty($params['date'][1]) ? $params['date'][1] : $params['date'][0];
  20. // 检查日期格式是否正确
  21. if(!isValidDate($sDate) || !isValidDate($eDate)){
  22. return json_encode(["status"=>"error", "msg"=>"日期格式不正确"], 256);
  23. }
  24. }else{
  25. $sDate = date('Y-m-d');
  26. $eDate = date('Y-m-d');
  27. }
  28. // 重跑用,传数组
  29. if(!empty($params['advertiser_ids'])){
  30. $this->advertiserIds = $params['advertiser_ids'];
  31. }
  32. // 重跑用,传int
  33. if(!empty($params['api_id'])){
  34. $this->apiId = $params['api_id'];
  35. }
  36. for ($date = $sDate; $date <= $eDate; $date = date('Y-m-d', strtotime($date . '+1 day'))){
  37. $this->date = $date;
  38. try {
  39. $this->initStart();
  40. }catch (\Exception $e){
  41. return json_encode(["status"=>"error", "msg"=>$e->getMessage()], 256);
  42. }
  43. }
  44. $this->reRun();
  45. return json_encode(["status"=>"success", "msg"=>""], 256);
  46. }
  47. // 重跑
  48. protected function reRun(): void
  49. {
  50. if (date('H') == 8 && date('i') < 20) {
  51. $this->date = date('Y-m-d', strtotime("-1 days"));
  52. $this->initStart();
  53. }
  54. }
  55. protected function initStart(): void
  56. {
  57. $tokenMap = $this->getTokenMap();
  58. $accountList = $this->getAccountList();
  59. $this->siteMap = (new AgentSiteLogic())->getSiteAuth();
  60. // 循环执行
  61. foreach ($accountList as $account)
  62. {
  63. $accessToken = $tokenMap[$account['pmid']] ?? "";
  64. if(!$accessToken) continue;
  65. // 获取消耗
  66. $dataList = $this->getGdtCost($account['advertiser_id'], $accessToken);
  67. // 整理数据入库
  68. $this->organizeDataList($account, $dataList);
  69. }
  70. }
  71. // 获取媒体消耗
  72. protected function getGdtCost($advertiser_id, $access_token): array
  73. {
  74. $page = 1;
  75. $data = [];
  76. do {
  77. $nonce = md5(time().rand(00000, 99999));
  78. $url = 'https://api.e.qq.com/v3.0/hourly_reports/get?access_token='.$access_token.'&timestamp='.time().'&nonce='.$nonce;
  79. $request_data = [
  80. 'account_id' => $advertiser_id,
  81. 'level' => 'REPORT_LEVEL_ADGROUP',
  82. 'date_range' => json_encode(['start_date' => $this->date, 'end_date' => $this->date]),
  83. 'group_by' => json_encode(['hour', 'adgroup_id']),
  84. 'fields' => json_encode(['hour', 'adgroup_id', 'adgroup_name', 'view_count', 'valid_click_count', 'cost', 'activated_count']),
  85. 'page' => $page,
  86. 'page_size' => 100,
  87. ];
  88. $url = $url."&".http_build_query($request_data);
  89. $httpClient = new Client(['timeout' => 10]);
  90. $res = $httpClient->request('GET', $url);
  91. $result = json_decode($res->getBody(), true);
  92. if (empty($result['data']['list'])) {
  93. break;
  94. }
  95. $data = array_merge($data, $result['data']['list']);
  96. $totalPage = $result['data']['page_info']['total_page'] ?? 1;
  97. $page++;
  98. } while ($page <= $totalPage);
  99. return $data;
  100. }
  101. // 整理入库数据列表
  102. protected function organizeDataList($account, $dataList): void
  103. {
  104. if(!$dataList) return;
  105. $db = Db::connect('db_advert');
  106. // 返点率
  107. $fandianRate = ($account['son_fandian']>1) ? (1/$account['son_fandian']) : $account['son_fandian'];
  108. $adData = [];
  109. foreach ($dataList as $val) {
  110. $ad_id = $val['adgroup_id'];
  111. $ad_name = $val['adgroup_name'];
  112. $cost = $val['cost']/100;
  113. $show = $val['view_count'];
  114. $click = $val['valid_click_count'];
  115. $convert = $val['activated_count'];
  116. // Todo 从广告名称中拆分归因数据
  117. preg_match("/([\d]*)_([\d]*)_([\d]*)/", $ad_name, $matchs);
  118. $game_id = $matchs[1] ?? 0;
  119. $agent_id = $matchs[2] ?? 0;
  120. $site_id = $matchs[3] ?? 0;
  121. if(!$game_id || empty($this->siteMap[$site_id])) continue;
  122. $where = [
  123. 'ad_id' => $ad_id,
  124. 'game_id' => $game_id,
  125. 'agent_id'=> $agent_id,
  126. 'site_id' => $site_id,
  127. 'tdate' => $this->date,
  128. 'thour' => $val['hour'],
  129. ];
  130. $data = [
  131. 'advertiser_id' => $account['advertiser_id'],
  132. 'ad_show' => $show,
  133. 'ad_click' => $click,
  134. 'ad_convert' => $convert,
  135. 'ori_money' => $cost,
  136. 'money' => $cost * $fandianRate,
  137. 'media_id' => $this->siteMap[$site_id]['media_id'],
  138. 'auth_id' => $this->siteMap[$site_id]['auth_id'],
  139. ];
  140. $hourId= $db->table($this->hourTable)->where($where)->value("id");
  141. if($hourId) {
  142. $data['id'] = $hourId;
  143. }
  144. // 保存小时数据
  145. $db->table($this->hourTable)->save(array_merge($data, $where));
  146. // 计算天的数据
  147. $adKey = $game_id . "_" . $site_id . "_" . $ad_id;
  148. $adData[$adKey]['game_id'] = $game_id;
  149. $adData[$adKey]['agent_id'] = $agent_id;
  150. $adData[$adKey]['site_id'] = $site_id;
  151. $adData[$adKey]['ad_id'] = $ad_id;
  152. $adData[$adKey]['ad_show'] = !empty($adData[$adKey]['ad_show']) ? $adData[$adKey]['ad_show']+$show : $show;
  153. $adData[$adKey]['ad_click'] = !empty($adData[$adKey]['ad_click']) ? $adData[$adKey]['ad_click']+$click : $click;
  154. $adData[$adKey]['ad_convert'] = !empty($adData[$adKey]['ad_convert']) ? $adData[$adKey]['ad_convert']+$convert : $convert;
  155. $adData[$adKey]['cost'] = !empty($adData[$adKey]['cost']) ? $adData[$adKey]['cost']+$cost : $cost;
  156. }
  157. foreach($adData as $value){
  158. $where = [
  159. 'ad_id' => $value['ad_id'],
  160. 'game_id' => $value['game_id'],
  161. 'agent_id'=> $value['agent_id'],
  162. 'site_id' => $value['site_id'],
  163. 'tdate' => $this->date,
  164. ];
  165. $data = [
  166. 'advertiser_id' => $account['advertiser_id'],
  167. 'ad_show' => $value['ad_show'],
  168. 'ad_click' => $value['ad_click'],
  169. 'ad_convert'=> $value['ad_convert'],
  170. 'ori_money' => $value['cost'],
  171. 'money' => $value['cost']*$fandianRate,
  172. 'media_id' => $this->siteMap[$site_id]['media_id'],
  173. 'auth_id' => $this->siteMap[$site_id]['auth_id'],
  174. ];
  175. $dateId= $db->table($this->dateTable)->where($where)->value("id");
  176. if($dateId) {
  177. $data['id'] = $dateId;
  178. }
  179. // 保存日数据
  180. $db->table($this->dateTable)->save(array_merge($data, $where));
  181. }
  182. }
  183. // 获取需要拉取消耗的媒体账户
  184. protected function getAccountList(): array
  185. {
  186. $table = "ad_gdt_account_list";
  187. $where = [
  188. "status" => 1
  189. ];
  190. if($this->advertiserIds){
  191. $where['advertiser_id'] = $this->advertiserIds;
  192. }
  193. return Db::connect('db_advert')
  194. ->table($table)
  195. ->where($where)
  196. ->column("pmid, advertiser_id, advertiser_name, son_fandian");
  197. }
  198. protected function getTokenMap(): array
  199. {
  200. $table = "ad_gdt_account";
  201. $where = [
  202. "status" => 1
  203. ];
  204. if($this->apiId){
  205. $where['id'] = $this->apiId;
  206. }
  207. return Db::connect('db_advert')->table($table)->where($where)->column("access_token", "id");
  208. }
  209. }