JuliangAccountReportChargeService.php 16 KB

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