JLEventReportChargeService.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. <?php
  2. namespace App\Service\Callback;
  3. use App\Service\Callback\Tiktok\TiktokEventReportService;
  4. use App\Service\Util\Support\Trace\TraceContext;
  5. use Illuminate\Support\Facades\DB;
  6. /**
  7. * 巨量2.0事件
  8. */
  9. class JLEventReportChargeService
  10. {
  11. private $uid;
  12. /**
  13. * @var TraceContext
  14. */
  15. private $traceContext;
  16. private $order;
  17. private $result;
  18. private $trackRecord;
  19. private $callbackConfig;
  20. private $promotion;
  21. private $rateConfig;
  22. private $configLog;
  23. public function __construct($uid, $order, $traceInfo)
  24. {
  25. $this->order = $order;
  26. $this->uid = $uid;
  27. $this->traceContext = TraceContext::newFromParent($traceInfo);
  28. $this->result = [
  29. 'need_report' => true,
  30. 'config_rate' => 0,
  31. 'current_rate' => 0,
  32. 'report_success' => false,
  33. 'info_type' => 'ok',
  34. 'continue_judge' => true,
  35. ];
  36. }
  37. public function report() {
  38. $this->fillRanseInfo();
  39. $this->fillTrackInfo();
  40. $this->judgeOrderAlreadyDeal();
  41. $this->judgeIsRoi();
  42. $this->judgeChargeType();
  43. $this->judgeChargeMoney();
  44. $this->reportJuliang();
  45. $this->saveRecord();
  46. }
  47. /**
  48. * 判断是否roi全量回传
  49. */
  50. private function judgeIsRoi() {
  51. if(!$this->result['need_report']) {
  52. return;
  53. }
  54. if(1 == $this->callbackConfig->is_roi) {
  55. $this->result['continue_judge'] = false;
  56. $this->result['info_type'] = 'roi_report_all';
  57. $this->result['info_str'] = 'roi全量上报';
  58. }
  59. }
  60. private function saveRecord() {
  61. if($this->result['save_record'] ?? true) {
  62. $now = date('Y-m-d H:i:s');
  63. $chargeRecord = DB::table('callback_report_charge_record')->where([
  64. 'order_no' => $this->order->trade_no
  65. ])->first();
  66. if(!$chargeRecord) {
  67. DB::table('callback_report_charge_record')
  68. ->insert([
  69. 'uid' => $this->uid,
  70. 'order_id' => $this->order->id,
  71. 'order_no' => $this->order->trade_no,
  72. 'optimizer_uid' => $this->promotion->uid,
  73. 'filter_type' => $this->result['info_type'] ?? 'ok',
  74. 'filter_reason' => $this->result['info_str'] ?? '允许回传',
  75. 'report_success' => intval($this->result['report_success'] ?? false),
  76. 'report_result' => \json_encode($this->result['report_result'] ?? []),
  77. 'report_param' => \json_encode($this->result['report_param'] ?? []),
  78. 'created_at' => $now,
  79. 'updated_at' => $now,
  80. 'advertiser_id' => $this->trackRecord->advertiser_id ?? '',
  81. 'adv_promotion_id' => $this->trackRecord->adv_promotion_id ?? '',
  82. 'config_rate' => $this->result['config_rate'],
  83. 'current_rate' => $this->result['current_rate'],
  84. 'user_ranse_start_at' => $this->trackRecord->ranse_start_at ?? null,
  85. 'order_price' => $this->order->price,
  86. 'order_created_at' => $this->order->created_at,
  87. 'user_ranse_ip' => $this->trackRecord->ranse_ip ?? '',
  88. 'miniprogram_id' => $this->promotion->miniprogram_id,
  89. 'user_ranse_id' => $this->promotion->id,
  90. 'callback_type' => $this->promotion->callback_type,
  91. 'callback_config_id' => $this->promotion->callback_config_id,
  92. 'ext_a' => $this->configLog->callback_param ?? '',
  93. ]);
  94. } else {
  95. DB::table('callback_report_charge_record')
  96. ->where(['id' => $chargeRecord->id])
  97. ->update([
  98. 'uid' => $this->uid,
  99. 'order_id' => $this->order->id,
  100. 'order_no' => $this->order->trade_no,
  101. 'optimizer_uid' => $this->promotion->uid,
  102. 'filter_type' => $this->result['info_type'] ?? 'ok',
  103. 'filter_reason' => $this->result['info_str'] ?? '允许回传',
  104. 'report_success' => intval($this->result['report_success'] ?? false),
  105. 'report_result' => \json_encode($this->result['report_result'] ?? []),
  106. 'report_param' => \json_encode($this->result['report_param'] ?? []),
  107. 'updated_at' => $now,
  108. 'advertiser_id' => $this->trackRecord->advertiser_id ?? '',
  109. 'adv_promotion_id' => $this->trackRecord->adv_promotion_id ?? '',
  110. 'config_rate' => $this->result['config_rate'],
  111. 'current_rate' => $this->result['current_rate'],
  112. 'user_ranse_start_at' => $this->trackRecord->ranse_start_at ?? null,
  113. 'order_price' => $this->order->price,
  114. 'order_created_at' => $this->order->created_at,
  115. 'user_ranse_ip' => $this->trackRecord->ranse_ip ?? '',
  116. 'miniprogram_id' => $this->promotion->miniprogram_id,
  117. 'user_ranse_id' => $this->promotion->id,
  118. 'callback_type' => $this->promotion->callback_type,
  119. 'callback_config_id' => $this->promotion->callback_config_id,
  120. 'ext_a' => $this->configLog->callback_param ?? '',
  121. ]);
  122. }
  123. if($this->configLog) {
  124. if('ok' == $this->result['info_type'] && $this->result['report_success']) {
  125. DB::table('jl_event_rate_config_log')
  126. ->where(['id' => $this->configLog->id])
  127. ->update([
  128. 'report_count' => $this->configLog->report_count + 1,
  129. 'updated_at' => $now,
  130. ]);
  131. if(3 == $this->configLog->callback_type) {
  132. DB::table('jl_event_rate_config_log')
  133. ->where(['id' => $this->configLog->id])
  134. ->update([
  135. 'flag' => $this->configLog->flag,
  136. 'flag_report' => $this->configLog->flag_report,
  137. 'flag_unreport' => $this->configLog->flag_unreport,
  138. 'updated_at' => $now,
  139. ]);
  140. }
  141. } elseif ('rate_filter' == $this->result['info_type']) {
  142. DB::table('jl_event_rate_config_log')
  143. ->where(['id' => $this->configLog->id])
  144. ->update([
  145. 'unreport_count' => $this->configLog->unreport_count + 1,
  146. 'updated_at' => $now,
  147. ]);
  148. if(3 == $this->configLog->callback_type) {
  149. DB::table('jl_event_rate_config_log')
  150. ->where(['id' => $this->configLog->id])
  151. ->update([
  152. 'flag' => $this->configLog->flag,
  153. 'flag_report' => $this->configLog->flag_report,
  154. 'flag_unreport' => $this->configLog->flag_unreport,
  155. 'updated_at' => $now,
  156. ]);
  157. }
  158. }
  159. }
  160. }
  161. }
  162. /**
  163. * 判断回传比例
  164. */
  165. private function judgeCallbackRate(){
  166. if(!$this->result['need_report']) {
  167. return;
  168. }
  169. if(!$this->result['continue_judge']) {
  170. return;
  171. }
  172. $this->rateConfig = DB::table('juliang_account_rate_config_log')
  173. ->where(['company_uid' => $this->promotion->uid,
  174. 'account_id' => $this->trackRecord->advertiser_id, 'is_enabled' => 1])
  175. ->first();
  176. if(!$this->rateConfig) {
  177. $this->result['need_report'] = false;
  178. $this->result['info_type'] = 'no_rate_config';
  179. $this->result['info_str'] = '没有可用的回传比率设置';
  180. return;
  181. }
  182. $configRate = $this->rateConfig->config_per;
  183. if(0 == $configRate) {
  184. $this->result['need_report'] = false;
  185. $this->result['info_type'] = 'rate_eq_0';
  186. $this->result['info_str'] = '设定比例为0不执行回传';
  187. return;
  188. }
  189. $currentTotalCount = $this->rateConfig->total_count;
  190. $currentReportCount = $this->rateConfig->report_count;
  191. if(0 == $currentTotalCount) {
  192. $currentRate = 0;
  193. } else {
  194. $currentRate = min(1, round($currentReportCount / $currentTotalCount, 4)) * 100;
  195. }
  196. if($currentRate <= $configRate) {
  197. $this->result['need_report'] = true;
  198. $this->result['config_rate'] = $configRate;
  199. $this->result['current_rate'] = $currentRate;
  200. } else {
  201. $this->result['need_report'] = false;
  202. $this->result['info_type'] = 'rate_filter';
  203. $this->result['info_str'] = '比率过滤';
  204. $this->result['config_rate'] = $configRate;
  205. $this->result['current_rate'] = $currentRate;
  206. }
  207. }
  208. /**
  209. * 判断订单是不是已经处理过了.如果处理过了,就不入库
  210. */
  211. private function judgeOrderAlreadyDeal() {
  212. if(!$this->result['need_report']) {
  213. return;
  214. }
  215. if(DB::table('callback_report_charge_record')
  216. ->where(['order_id' => $this->order->id])
  217. ->exists()) {
  218. $this->result['need_report'] = false;
  219. $this->result['save_record'] = false;
  220. $this->result['info_type'] = 'order_exists';
  221. $this->result['info_str'] = '订单已经处理';
  222. }
  223. }
  224. /**
  225. * 判断充值的金额区间
  226. */
  227. private function judgeChargeMoney() {
  228. if(!$this->result['need_report'] || !$this->result['continue_judge']) {
  229. return;
  230. }
  231. $this->configLog = DB::table('jl_event_rate_config_log')
  232. ->where([
  233. 'user_id' => $this->promotion->uid,
  234. 'config_id' => $this->callbackConfig->id,
  235. 'is_enabled' => 1,
  236. ])->where('min_money', '<=', $this->order->price)
  237. ->where('max_money', '>', $this->order->price)
  238. ->orderBy('id', 'desc')
  239. ->first();
  240. if(!$this->configLog) {
  241. $this->result['need_report'] = false;
  242. $this->result['continue_judge'] = false;
  243. $this->result['info_type'] = 'money_filter';
  244. $this->result['info_str'] = '订单金额不在所有金额项区间内';
  245. return;
  246. } else {
  247. if(1 == $this->configLog->callback_type) {
  248. $this->result['continue_judge'] = false;
  249. }elseif(2 == $this->configLog->callback_type) {
  250. $this->result['continue_judge'] = false;
  251. $this->result['need_report'] = false;
  252. $this->result['info_type'] = 'money_filter';
  253. $this->result['info_str'] = sprintf('订单金额在区间:[%s元-%s元]全部不回传',
  254. $this->configLog->min_money, $this->configLog->max_money);
  255. return;
  256. } elseif (3 == $this->configLog->callback_type) {
  257. // ToDo,检测传几卡几
  258. $sm = explode(':', $this->configLog->callback_param);
  259. $this->chuanNkaM($this->configLog, $sm[0], $sm[1]);
  260. if($this->configLog->flag) {
  261. $this->configLog->flag_report++;
  262. } else {
  263. $this->configLog->flag_unport++;
  264. $this->result['continue_judge'] = false;
  265. $this->result['need_report'] = false;
  266. $this->result['info_type'] = 'rate_filter';
  267. $this->result['info_str'] = sprintf('当前配置传%s卡%s,本轮已传:%s,已卡%s', $sm[0], $sm[1],
  268. $this->configLog->flag_report, $this->configLog->flag_unport);
  269. }
  270. }
  271. }
  272. }
  273. private function chuanNkaM($obj, $s, $m)
  274. {
  275. if($obj->flag) {
  276. if(($obj->flag_report) < $s){
  277. $obj->flag = 1;
  278. } else {
  279. $obj->flag_report = 0;
  280. $obj->flag = 0;
  281. }
  282. } else {
  283. if(($obj->unreport) < $m) {
  284. $obj->flag = 0;
  285. } else {
  286. $obj->flag_unreport = 0;
  287. $obj->flag = 1;
  288. }
  289. }
  290. }
  291. /**
  292. * 判断充值行为
  293. */
  294. private function judgeChargeType() {
  295. if(!$this->result['need_report'] || !$this->result['continue_judge']) {
  296. return;
  297. }
  298. if(1 == $this->callbackConfig->charge_type) {
  299. $isFirstCharge = DB::table('orders')
  300. ->where([
  301. 'uid' => $this->uid,
  302. 'status' => 'paid',
  303. 'promotion_id' => $this->trackRecord->ranse_id,
  304. ])->where('created_at', '>=', $this->trackRecord->ranse_start_at)
  305. ->where('created_at', '<=', $this->trackRecord->ranse_end_at)
  306. ->where('id', '<', $this->order->id)
  307. ->count() == 0;
  308. if(!$isFirstCharge) {
  309. $this->result['need_report'] = false;
  310. $this->result['continue_judge'] = false;
  311. $this->result['info_type'] = 'neq_first_charge';
  312. $this->result['info_str'] = '非首充';
  313. }
  314. }
  315. }
  316. /**
  317. * 获取订单的染色信息,回传配置信息, 推广被禁用,就按照没有回传配置处理
  318. */
  319. private function fillRanseInfo() {
  320. $ranseId = $this->order->promotion_id;
  321. $this->promotion = DB::table('promotions')->where('id', $ranseId)->first();
  322. if(0 == $this->promotion->status || $this->promotion->callback_config_id < 1) {
  323. $this->result['need_report'] = false;
  324. $this->result['info_type'] = 'no_callback_config';
  325. $this->result['info_str'] = '没有回传配置';
  326. return;
  327. }
  328. $this->callbackConfig = DB::table('jl_event_callback_config')
  329. ->where(['id' => $this->promotion->callback_config_id])
  330. ->first();
  331. if(!$this->callbackConfig) {
  332. $this->result['need_report'] = false;
  333. $this->result['info_type'] = 'no_callback_config';
  334. $this->result['info_str'] = '没有回传配置';
  335. return;
  336. }
  337. }
  338. private function reportJuliang() {
  339. if(!$this->result['need_report']) {
  340. return;
  341. }
  342. $service = new TiktokEventReportService;
  343. $reportResult = $service->reportCharge((object)[
  344. 'callback' => $this->trackRecord->callback
  345. ]);
  346. $reportContent = \json_decode($reportResult['content'], true);
  347. if($reportResult['result'] && 0 == $reportContent['code']) {
  348. $this->result['report_success'] = true;
  349. } else {
  350. $this->result['report_success'] = false;
  351. }
  352. $this->result['report_result'] = $reportResult;
  353. $this->result['need_report'] = false;
  354. }
  355. /**
  356. * 获取匹配的广告用户信息,主要是获取回传 callback
  357. */
  358. private function fillTrackInfo() {
  359. if(!$this->result['need_report']) {
  360. return;
  361. }
  362. $this->trackRecord = DB::table('callback_report_ranse_record')
  363. ->where(['uid' => $this->uid, 'ranse_id' => $this->order->promotion_id])
  364. ->where('ranse_start_at', '<=', $this->order->created_at)
  365. ->where('ranse_end_at', '>=', $this->order->created_at)
  366. ->orderBy('id', 'desc')
  367. ->first();
  368. if(!$this->trackRecord) {
  369. $this->result['need_report'] = false;
  370. $this->result['info_type'] = 'no_track_info';
  371. $this->result['info_str'] = '无匹配用户';
  372. return;
  373. }
  374. $this->result['report_param'] = [
  375. 'callback' => $this->trackRecord->callback,
  376. ];
  377. }
  378. }