StatisticsAgentAttrsRepository.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. <?php
  2. /**
  3. * 统计用户属性相关.
  4. *
  5. * @author nj
  6. * @date 2021-08-15 16:25
  7. */
  8. namespace App\Repositories\Statistics;
  9. use App\Constants\PayConstant;
  10. use App\Models\Mongo\AgentAttrsLogsModel;
  11. use App\Models\Mongo\AgentAttrsTodayModel;
  12. use App\Models\Mongo\AttrsIncLogsModel;
  13. use App\Repositories\AgentRepository;
  14. use App\Repositories\ChannelRepository;
  15. use Carbon\Carbon;
  16. use Illuminate\Support\Str;
  17. use DB;
  18. class StatisticsAgentAttrsRepository
  19. {
  20. /**
  21. * 定义支付仓库.
  22. * @var null|StatisticsPayRepository
  23. */
  24. protected $payRepo = null;
  25. /**
  26. * 定义新用户仓库
  27. * @var null|StatisticsNewUserRepository
  28. */
  29. protected $userRepo = null;
  30. /**
  31. * 余额变化日志仓库
  32. * @var null|BalanceLogsRepository
  33. */
  34. protected $balanceLogsRepo = null;
  35. /**
  36. * 日活仓库.
  37. * @var null|StatisticsActiveRepository
  38. */
  39. protected $activeRepo = null;
  40. /**
  41. * 代理仓库.
  42. * @var null|AgentRepository
  43. */
  44. protected $agentRepo = null;
  45. /**
  46. * 渠道仓库.
  47. * @var null|ChannelRepository
  48. */
  49. protected $channelRepo = null;
  50. /**
  51. * 从数据源根计算
  52. * @param $date
  53. * @param string $channelUid
  54. * @return false
  55. */
  56. public function rootJob($date, $channelUid = '')
  57. {
  58. $originChannelUid = $channelUid; // 保存入参原始渠道UID.
  59. $date = Carbon::parse($date)->toDateString();
  60. $dateIsoObj = Carbon::parse($date)->startOfDay();
  61. $channelObj = null; // 预定定义渠道对象.
  62. // 当前渠道所属代理.
  63. $currAgent = null;
  64. $currAgentUid = '';
  65. $conditionChannelUid = ''; // 定义条件查询渠道UID
  66. if (!empty($channelUid)) {
  67. $channelObj = $this->getChannelRepo()->makeModel()->query()->where(['uid' => $channelUid])->first();
  68. if (!empty($channelObj->id)) {
  69. $currAgent = $this->getAgentRepo()->makeModel()->query()->where(['uid' => $channelObj->agent_uid])->first();
  70. if (empty($currAgent->id)) {
  71. // 没有代理不执行
  72. return false;
  73. }
  74. $currAgentUid = $channelObj->agent_uid;
  75. $conditionChannelUid = $channelUid;
  76. } else {
  77. // 没有这个渠道不统计
  78. return false;
  79. }
  80. }
  81. // 日活
  82. $dauTotal = $this->getActiveRepo()->countOneDayActive($date, $conditionChannelUid);
  83. $dauAndroid = $this->getActiveRepo()->countOneDayActive($date, $conditionChannelUid, 'A');
  84. $dauIos = $this->getActiveRepo()->countOneDayActive($date, $conditionChannelUid, 'I');
  85. $dauH5 = $this->getActiveRepo()->countOneDayActive($date, $conditionChannelUid, 'H');
  86. // 用户
  87. $userTotal = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid]);
  88. $userAndroid = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A']);
  89. $userIos = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I']);
  90. $userH5 = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H']);
  91. // 用户单独扣量的
  92. $userDeductionTotal = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 1]);
  93. $userDeductionAndroid = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A', 'is_deduction' => 1]);
  94. $userDeductionIos = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I', 'is_deduction' => 1]);
  95. $userDeductionH5 = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H', 'is_deduction' => 1]);
  96. // 订单支付
  97. $orderTotal = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid]);
  98. $orderSuccess = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'pay_status' => PayConstant::SUCCESS]);
  99. $orderFailed = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'pay_status' => PayConstant::FAIL]);
  100. $orderMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid]);
  101. $orderSuccessMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'pay_status' => PayConstant::SUCCESS]);
  102. $androidTotal = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A']);
  103. $androidSuccess = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A', 'pay_status' => PayConstant::SUCCESS]);
  104. $androidFailed = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A', 'pay_status' => PayConstant::FAIL]);
  105. $androidMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A']);
  106. $androidSuccessMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A', 'pay_status' => PayConstant::SUCCESS]);
  107. $iosTotal = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I']);
  108. $iosSuccess = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I', 'pay_status' => PayConstant::SUCCESS]);
  109. $iosFailed = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I', 'pay_status' => PayConstant::FAIL]);
  110. $iosMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I']);
  111. $iosSuccessMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I', 'pay_status' => PayConstant::SUCCESS]);
  112. $h5Total = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H']);
  113. $h5Success = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H', 'pay_status' => PayConstant::SUCCESS]);
  114. $h5Failed = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H', 'pay_status' => PayConstant::FAIL]);
  115. $h5Money = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H']);
  116. $h5SuccessMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H', 'pay_status' => PayConstant::SUCCESS]);
  117. $deductionTotal = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 0]);
  118. $deductionSuccess = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 0, 'pay_status' => PayConstant::SUCCESS]);
  119. $deductionFailed = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 0, 'pay_status' => PayConstant::FAIL]);
  120. $deductionMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 0]);
  121. $deductionSuccessMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 0, 'pay_status' => PayConstant::SUCCESS]);
  122. // 当日累计.
  123. $incItem = $baseInfo = [
  124. 'date' => $dateIsoObj,
  125. 'created_at' => Carbon::now(),
  126. 'updated_at' => Carbon::now(),
  127. 'agent_uid' => $currAgentUid, // 代理UID,空字符串,代表没有.
  128. 'order_total' => $orderTotal, // 累计订单数
  129. 'order_success' => $orderSuccess, // 累计成功订单数.
  130. 'order_failed' => $orderFailed, // 累计失败订单数
  131. 'order_money' => $orderMoney, // 关累计订单金额
  132. 'order_success_money' => $orderSuccessMoney, // 累计成功金额
  133. 'dau_total' => $dauTotal, // 累计日活
  134. 'dau_android' => $dauAndroid, // 累计Android日活
  135. 'dau_ios' => $dauIos, // 累计iOS日活
  136. 'dau_h5' => $dauH5, // 累计h5日活
  137. 'android_total' => $androidTotal, // 累计android订单数
  138. 'android_success' => $androidSuccess, // 累计android成功订单数
  139. 'android_failed' => $androidFailed, // 累计android失败订单数
  140. 'android_money' => $androidMoney, // 累计android总金额
  141. 'android_success_money' => $androidSuccessMoney, // 累计android成功订单金额.
  142. 'ios_total' => $iosTotal, // 累计ios订单数
  143. 'ios_success' => $iosSuccess, // 累计ios成功订单数
  144. 'ios_failed' => $iosFailed, // 累计ios失败订单数
  145. 'ios_money' => $iosMoney, // 累计ios总金额
  146. 'ios_success_money' => $iosSuccessMoney, // 累计ios成功订单金额
  147. 'h5_total' => $iosTotal, // 累计h5订单数
  148. 'h5_success' => $iosSuccess, // 累计h5成功订单数
  149. 'h5_failed' => $iosFailed, // 累计h5失败订单数
  150. 'h5_money' => $iosMoney, // 累计h5总金额
  151. 'h5_success_money' => $iosSuccessMoney, // 累计h5成功订单金额
  152. 'deduction_total' => $deductionTotal, //累计渠道扣量后的总订单数
  153. 'deduction_success' => $deductionSuccess, // 计渠道扣量后的成功订单数
  154. 'deduction_failed' => $deductionFailed, // 累计渠道扣量后的失败单数
  155. 'deduction_money' => $deductionMoney, // 累计渠道扣量后的总金额
  156. 'deduction_success_money' => $deductionSuccessMoney,
  157. 'commission_money' => 0, // 累计代理提成金额
  158. 'withdraw_money' => isset($currUserAttrs->withdraw_money) ? floatval(number_format($currUserAttrs->withdraw_money, 2)) : 0, // Todo 累计提现金额, 依赖xiaomum
  159. 'users_total' => $userTotal, // 累计用户数量
  160. 'users_android_total' => $userAndroid, // 累计android用户数量
  161. 'users_ios_total' => $userIos, // 累计ios用户数量
  162. 'users_h5_total' => $userH5, // 累计h5用户数量
  163. 'users_deduction' => $userDeductionTotal, // 累计扣量用户数量
  164. 'users_android_deduction' => $userDeductionAndroid, // 累计android扣量用户数量
  165. 'users_ios_deduction' => $userDeductionIos, // 累计ios扣量用户数量
  166. 'users_h5_deduction' => $userDeductionH5, // 累计h5扣量用户数量
  167. 'commission_ratio' => isset($currAgent->commission_ratio) ? intval($currAgent->commission_ratio) : 0, // 本人提成比例, 没代理就是0
  168. 'commission_diff_ratio' => isset($currAgent->commission_diff_ratio) ? intval($currAgent->commission_diff_ratio) : 0, // 没代理就是0
  169. ];
  170. // 处理当前用户.
  171. if (!empty($channelUid)) {
  172. // 非顶级.
  173. $incItem['commission_money'] = floatval(number_format($baseInfo['deduction_success_money'] * ($currAgent->commission_ratio / 100), 2)); // 当前渠道的当前用户用commission_ratio计算
  174. }
  175. if (empty($channelUid)) {
  176. $incItem['commission_ratio'] = $incItem['commission_diff_ratio'] = 100; // 官方,提成100%.
  177. $incItem['commission_money'] = $baseInfo['deduction_success_money'] * 1; // 官方,提成100%.
  178. }
  179. $startOfDate = Carbon::parse($date)->startOfDay();
  180. $recordObj = AttrsIncLogsModel::where(['date' => $startOfDate, 'root_agent_uid' => $currAgentUid])->first();
  181. if (empty($recordObj)) {
  182. // 没有就先写进去, 风险:如果这个任务中途失败,就再也无法继续冲头跑今天的这个root user.
  183. $recordData = [
  184. 'created_at' => Carbon::now(),
  185. 'date' => $startOfDate,
  186. 'root_agent_uid' => $currAgentUid,
  187. ];
  188. AttrsIncLogsModel::create($recordData);
  189. } else {
  190. // 有记录了,不能跑了,防止重复叠加.
  191. return false;
  192. }
  193. $info = AgentAttrsLogsModel::where('date', '=', $startOfDate)->where('agent_uid', '=', $currAgentUid)->first();
  194. if (empty($info)) {
  195. $result = AgentAttrsLogsModel::create($incItem);
  196. } else {
  197. // 有当前的日志,则追加下级的增量.
  198. foreach ($incItem as $k => $v) {
  199. if (!in_array($k, self::getIncExceptFields()) && !Str::startsWith($k, 'td_')) {
  200. $info->{$k} += $v;
  201. }
  202. $info->updated_at = Carbon::now();
  203. }
  204. $result = $info->save();
  205. }
  206. // 递归累加
  207. self::loopParent($date, $baseInfo, $currAgent);
  208. }
  209. private function loopParent($date, $baseInfo, $currAgent = null)
  210. {
  211. $startOfDateObj = Carbon::parse($date)->startOfDay();
  212. $dateUtcObj = $startOfDateObj;
  213. if (!empty($currAgent->parent_uid)) {
  214. $parentAgent = $this->getAgentRepo()->makeModel()->query()->where(['uid' => $currAgent->parent_uid])->first();
  215. if (!empty($parentAgent->id)) {
  216. $incItem = $baseInfo;
  217. $info = AgentAttrsLogsModel::where('date', '=', $dateUtcObj)->where('agent_uid', '=', $currAgent->parent_uid)->first();
  218. $parentDiffRatio = !empty($currAgent->commission_diff_ratio) ? $currAgent->commission_diff_ratio : 0;
  219. $incItem['agent_uid'] = $parentAgent->uid;
  220. $incItem['order_total'] = $baseInfo['order_total'];
  221. $incItem['order_success'] = $baseInfo['order_success'];
  222. $incItem['order_failed'] = $baseInfo['order_failed'];
  223. $incItem['order_money'] = $baseInfo['order_money'];
  224. $incItem['order_success_money'] = $baseInfo['order_success_money'];
  225. $incItem['dau_total'] = $baseInfo['dau_total'];
  226. $incItem['dau_android'] = $baseInfo['dau_android'];
  227. $incItem['dau_ios'] = $baseInfo['dau_ios'];
  228. $incItem['dau_h5'] = $baseInfo['dau_h5'];
  229. $incItem['android_total'] = $baseInfo['android_total'];
  230. $incItem['android_failed'] = $baseInfo['android_failed'];
  231. $incItem['android_money'] = $baseInfo['android_money'];
  232. $incItem['android_success_money'] = $baseInfo['android_success_money'];
  233. $incItem['ios_total'] = $baseInfo['ios_total'];
  234. $incItem['ios_success'] = $baseInfo['ios_success'];
  235. $incItem['ios_failed'] = $baseInfo['ios_failed'];
  236. $incItem['ios_money'] = $baseInfo['ios_money'];
  237. $incItem['ios_success_money'] = $baseInfo['ios_success_money'];
  238. $incItem['h5_total'] = $baseInfo['h5_total'];
  239. $incItem['h5_success'] = $baseInfo['h5_success'];
  240. $incItem['h5_failed'] = $baseInfo['h5_failed'];
  241. $incItem['h5_money'] = $baseInfo['h5_money'];
  242. $incItem['h5_success_money'] = $baseInfo['h5_success_money'];
  243. $incItem['deduction_total'] = $baseInfo['deduction_total'];
  244. $incItem['deduction_success'] = $baseInfo['ios_money'];
  245. $incItem['deduction_failed'] = $baseInfo['deduction_failed'];
  246. $incItem['deduction_money'] = $baseInfo['deduction_money'];
  247. $incItem['deduction_success_money'] = $baseInfo['deduction_success_money'];
  248. $incItem['commission_money'] = floatval(number_format($baseInfo['deduction_success_money'] * ($parentDiffRatio / 100), 2)); // 提成差
  249. $incItem['withdraw_money'] = isset($parentAgentAttrs->withdraw_money) ? floatval(number_format($parentAgentAttrs->withdraw_money, 2)) : 0;
  250. $incItem['users_total'] = $baseInfo['users_total'];
  251. $incItem['users_android_total'] = $baseInfo['users_android_total'];
  252. $incItem['users_ios_total'] = $baseInfo['users_ios_total'];
  253. $incItem['users_h5_total'] = $baseInfo['users_h5_total'];
  254. $incItem['users_deduction'] = $baseInfo['users_deduction'];
  255. $incItem['users_android_deduction'] = $baseInfo['users_android_deduction'];
  256. $incItem['users_ios_deduction'] = $baseInfo['users_ios_deduction'];
  257. $incItem['users_h5_deduction'] = $baseInfo['users_h5_deduction'];
  258. $incItem['commission_ratio'] = isset($parentAgentAttrs->commission_ratio) ? intval($parentAgentAttrs->commission_ratio) : 0;
  259. $incItem['commission_diff_ratio'] = isset($parentAgentAttrs->commission_diff_ratio) ? intval($parentAgentAttrs->commission_diff_ratio) : 0;
  260. if (empty($info)) {
  261. $result = AgentAttrsLogsModel::create($incItem);
  262. } else {
  263. // 有当前的日志,则追加下级的增量.
  264. foreach ($incItem as $k => $v) {
  265. if (!in_array($k, self::getIncExceptFields()) && !Str::startsWith($k, 'td_')) {
  266. $info->{$k} += $v;
  267. }
  268. $info->updated_at = Carbon::now();
  269. }
  270. $result = $info->save();
  271. }
  272. // 递归累加
  273. self::loopParent($date, $baseInfo, $parentAgent);
  274. }
  275. }
  276. }
  277. /**
  278. * 今天单次任务.
  279. * @param $date
  280. * @param string $channelUid
  281. * @return false
  282. */
  283. public function todayJob($date, $channelUid = '')
  284. {
  285. $originChannelUid = $channelUid; // 保存入参原始渠道UID.
  286. $conditionChannelUid = $originChannelUid; // 统计条件参数.
  287. $date = Carbon::parse($date)->toDateString();
  288. $dateIsoObj = Carbon::parse($date)->startOfDay();
  289. $channelObj = null; // 预定定义渠道对象.
  290. // 当前渠道所属代理.
  291. $currAgent = null;
  292. $currAgentUid = '';
  293. if (!empty($channelUid)) {
  294. $channelObj = $this->getChannelRepo()->makeModel()->query()->where(['uid' => $channelUid])->first();
  295. if (empty($channelObj)) {
  296. // 数据库没有这个渠道,则不执行计算.
  297. return false;
  298. }
  299. }
  300. if (!empty($channelObj->id)) {
  301. $conditionChannelUid = $channelUid;
  302. $currAgent = $this->getAgentRepo()->makeModel()->query()->where(['uid' => $channelObj->agent_uid])->first();
  303. if (empty($currAgent->id)) {
  304. // 没有代理,就不执行.
  305. return false;
  306. }
  307. $currAgentUid = $currAgent->uid;
  308. }
  309. // 日活
  310. $dauTotal = $this->getActiveRepo()->countOneDayActive($date, $conditionChannelUid);
  311. $dauAndroid = $this->getActiveRepo()->countOneDayActive($date, $conditionChannelUid, 'A');
  312. $dauIos = $this->getActiveRepo()->countOneDayActive($date, $conditionChannelUid, 'I');
  313. $dauH5 = $this->getActiveRepo()->countOneDayActive($date, $conditionChannelUid, 'H');
  314. // 用户
  315. $userTotal = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid]);
  316. $userAndroid = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A']);
  317. $userIos = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I']);
  318. $userH5 = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H']);
  319. // 用户单独扣量的
  320. $userDeductionTotal = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 1]);
  321. $userDeductionAndroid = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A', 'is_deduction' => 1]);
  322. $userDeductionIos = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I', 'is_deduction' => 1]);
  323. $userDeductionH5 = $this->getUserRepo()->computeOneDay($date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H', 'is_deduction' => 1]);
  324. // 订单支付
  325. $orderTotal = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid]);
  326. $orderSuccess = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'pay_status' => PayConstant::SUCCESS]);
  327. $orderFailed = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'pay_status' => PayConstant::FAIL]);
  328. $orderMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid]);
  329. $orderSuccessMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'pay_status' => PayConstant::SUCCESS]);
  330. $androidTotal = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A']);
  331. $androidSuccess = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A', 'pay_status' => PayConstant::SUCCESS]);
  332. $androidFailed = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A', 'pay_status' => PayConstant::FAIL]);
  333. $androidMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A']);
  334. $androidSuccessMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'A', 'pay_status' => PayConstant::SUCCESS]);
  335. $iosTotal = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I']);
  336. $iosSuccess = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I', 'pay_status' => PayConstant::SUCCESS]);
  337. $iosFailed = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I', 'pay_status' => PayConstant::FAIL]);
  338. $iosMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I']);
  339. $iosSuccessMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'I', 'pay_status' => PayConstant::SUCCESS]);
  340. $h5Total = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H']);
  341. $h5Success = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H', 'pay_status' => PayConstant::SUCCESS]);
  342. $h5Failed = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H', 'pay_status' => PayConstant::FAIL]);
  343. $h5Money = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H']);
  344. $h5SuccessMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'device_type' => 'H', 'pay_status' => PayConstant::SUCCESS]);
  345. $deductionTotal = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 0]);
  346. $deductionSuccess = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 0, 'pay_status' => PayConstant::SUCCESS]);
  347. $deductionFailed = $this->getPayRepo()->computeOneDay('count', $date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 0, 'pay_status' => PayConstant::FAIL]);
  348. $deductionMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 0]);
  349. $deductionSuccessMoney = $this->getPayRepo()->computeOneDay('money', $date, ['channel_uid' => $conditionChannelUid, 'is_deduction' => 0, 'pay_status' => PayConstant::SUCCESS]);
  350. // 当日累计.
  351. $incItem = $baseInfo = [
  352. 'date' => $dateIsoObj,
  353. 'created_at' => Carbon::now(),
  354. 'updated_at' => Carbon::now(),
  355. 'agent_uid' => $currAgentUid, // 代理用户uid,非自增, 如果是空代表总后台
  356. 'td_order_total' => $orderTotal, // 累计订单数
  357. 'td_order_success' => $orderSuccess, // 累计成功订单数.
  358. 'td_order_failed' => $orderFailed, // 累计失败订单数
  359. 'td_order_money' => $orderMoney, // 关累计订单金额
  360. 'td_order_success_money' => $orderSuccessMoney, // 累计成功金额
  361. 'td_dau_total' => $dauTotal, // 累计日活
  362. 'td_dau_android' => $dauAndroid, // 累计Android日活
  363. 'td_dau_ios' => $dauIos, // 累计iOS日活
  364. 'td_dau_h5' => $dauH5, // 累计H5日活
  365. 'td_android_total' => $androidTotal, // 累计android订单数
  366. 'td_android_success' => $androidSuccess, // 累计android成功订单数
  367. 'td_android_failed' => $androidFailed, // 累计android失败订单数
  368. 'td_android_money' => $androidMoney, // 累计android总金额
  369. 'td_android_success_money' => $androidSuccessMoney, // 累计android成功订单金额.
  370. 'td_ios_total' => $iosTotal, // 累计ios订单数
  371. 'td_ios_success' => $iosSuccess, // 累计ios成功订单数
  372. 'td_ios_failed' => $iosFailed, // 累计ios失败订单数
  373. 'td_ios_money' => $iosMoney, // 累计ios总金额
  374. 'td_ios_success_money' => $iosSuccessMoney, // 累计ios成功订单金额
  375. 'td_h5_total' => $h5Total, // 累计h5订单数
  376. 'td_h5_success' => $h5Success, // 累计h5成功订单数
  377. 'td_h5_failed' => $h5Failed, // 累计h5失败订单数
  378. 'td_h5_money' => $h5Money, // 累计h5总金额
  379. 'td_h5_success_money' => $h5SuccessMoney, // 累计ios成功订单金额
  380. 'td_deduction_total' => $deductionTotal, //累计渠道扣量后的总订单数
  381. 'td_deduction_success' => $deductionSuccess, // 计渠道扣量后的成功订单数
  382. 'td_deduction_failed' => $deductionFailed, // 累计渠道扣量后的失败单数
  383. 'td_deduction_money' => $deductionMoney, // 累计渠道扣量后的总金额
  384. 'td_deduction_success_money' => $deductionSuccessMoney,
  385. 'td_commission_money' => 0, // 累计代理提成金额
  386. 'td_users_total' => $userTotal, // 累计用户数量
  387. 'td_users_android_total' => $userAndroid, // 累计android用户数量
  388. 'td_users_ios_total' => $userIos, // 累计ios用户数量
  389. 'td_users_h5_total' => $userH5, // 累计h5用户数量
  390. 'td_users_deduction' => $userDeductionTotal, // 累计扣量用户数量
  391. 'td_users_android_deduction' => $userDeductionAndroid, // 累计扣量android用户数量
  392. 'td_users_ios_deduction' => $userDeductionIos, // 累计扣量ios用户数量
  393. 'td_users_h5_deduction' => $userDeductionH5, // 累计扣量h5用户数量
  394. 'commission_ratio' => isset($currAgent->commission_ratio) ? intval($currAgent->commission_ratio) : 0,
  395. 'commission_diff_ratio' => isset($currAgent->commission_diff_ratio) ? intval($currAgent->commission_diff_ratio) : 0,
  396. ];
  397. // 处理当前用户.
  398. if (!empty($currAgentUid)) {
  399. // 非顶级.
  400. $incItem['td_commission_money'] = floatval(number_format($baseInfo['td_deduction_success_money'] * ($currAgent->commission_ratio / 100), 2)); // 当前渠道的当前用户用commission_ratio计算
  401. }
  402. if (empty($channelUid)) {
  403. $incItem['commission_ratio'] = $incItem['commission_diff_ratio'] = 100; // 官方,提成100%.
  404. $incItem['td_commission_money'] = $baseInfo['td_deduction_success_money'] * 1; // 官方,提成100%.
  405. }
  406. $startOfDate = Carbon::parse($date)->startOfDay();
  407. $info = AgentAttrsTodayModel::where('date', '=', $startOfDate)->where('agent_uid', '=', $currAgentUid)->first();
  408. if (empty($info)) {
  409. AgentAttrsTodayModel::create($incItem);
  410. } else {
  411. // 有当前的日志,则追加下级的增量.
  412. foreach ($incItem as $k => $v) {
  413. if (!in_array($k, self::getIncExceptFields())) {
  414. $info->{$k} += $v;
  415. }
  416. $info->updated_at = Carbon::now();
  417. }
  418. $info->save();
  419. }
  420. // 递归上级.
  421. self::todayLoopParent($date, $baseInfo, $currAgent);
  422. }
  423. /**
  424. * 循环上级(今天的)
  425. * @param $date
  426. * @param $baseInfo
  427. * @param null $currAgent
  428. */
  429. private function todayLoopParent($date, $baseInfo, $currAgent = null)
  430. {
  431. $startOfDateObj = Carbon::parse($date)->startOfDay();
  432. $dateUtcObj = $startOfDateObj;
  433. if (!empty($currAgent->parent_uid)) {
  434. $parentAgent = $this->getAgentRepo()->makeModel()->query()->where(['uid' => $currAgent->parent_uid])->first();
  435. if (!empty($parentAgent->id)) {
  436. $incItem = $baseInfo;
  437. $info = AgentAttrsTodayModel::where('date', '=', $dateUtcObj)->where('agent_uid', '=', $currAgent->parent_uid)->first();
  438. $parentDiffRatio = !empty($currAgent->commission_diff_ratio) ? $currAgent->commission_diff_ratio : 0;
  439. $incItem['agent_uid'] = $parentAgent->uid;
  440. $incItem['td_order_total'] = $baseInfo['td_order_total'];
  441. $incItem['td_order_success'] = $baseInfo['td_order_success'];
  442. $incItem['td_order_failed'] = $baseInfo['td_order_failed'];
  443. $incItem['td_order_money'] = $baseInfo['td_order_money'];
  444. $incItem['td_order_success_money'] = $baseInfo['td_order_success_money'];
  445. $incItem['td_dau_total'] = $baseInfo['td_dau_total'];
  446. $incItem['td_dau_android'] = $baseInfo['td_dau_android'];
  447. $incItem['td_dau_ios'] = $baseInfo['td_dau_ios'];
  448. $incItem['td_dau_h5'] = $baseInfo['td_dau_h5'];
  449. $incItem['td_android_total'] = $baseInfo['td_android_total'];
  450. $incItem['td_android_failed'] = $baseInfo['td_android_failed'];
  451. $incItem['td_android_money'] = $baseInfo['td_android_money'];
  452. $incItem['td_android_success_money'] = $baseInfo['td_android_success_money'];
  453. $incItem['td_ios_total'] = $baseInfo['td_ios_total'];
  454. $incItem['td_ios_success'] = $baseInfo['td_ios_success'];
  455. $incItem['td_ios_failed'] = $baseInfo['td_ios_failed'];
  456. $incItem['td_ios_money'] = $baseInfo['td_ios_money'];
  457. $incItem['td_ios_success_money'] = $baseInfo['td_ios_success_money'];
  458. $incItem['td_h5_total'] = $baseInfo['td_h5_total'];
  459. $incItem['td_h5_success'] = $baseInfo['td_h5_success'];
  460. $incItem['td_h5_failed'] = $baseInfo['td_h5_failed'];
  461. $incItem['td_h5_money'] = $baseInfo['td_h5_money'];
  462. $incItem['td_h5_success_money'] = $baseInfo['td_h5_success_money'];
  463. $incItem['td_deduction_total'] = $baseInfo['td_deduction_total'];
  464. $incItem['td_deduction_success'] = $baseInfo['td_ios_money'];
  465. $incItem['td_deduction_failed'] = $baseInfo['td_deduction_failed'];
  466. $incItem['td_deduction_money'] = $baseInfo['td_deduction_money'];
  467. $incItem['td_deduction_success_money'] = $baseInfo['td_deduction_success_money'];
  468. $incItem['td_commission_money'] = floatval(number_format($baseInfo['td_deduction_success_money'] * ($parentDiffRatio / 100), 2)); // 提成差
  469. $incItem['td_users_total'] = $baseInfo['td_users_total'];
  470. $incItem['td_users_android_total'] = $baseInfo['td_users_android_total'];
  471. $incItem['td_users_ios_total'] = $baseInfo['td_users_ios_total'];
  472. $incItem['td_users_h5_total'] = $baseInfo['td_users_h5_total'];
  473. $incItem['td_users_deduction'] = $baseInfo['td_users_deduction'];
  474. $incItem['td_users_android_deduction'] = $baseInfo['td_users_android_deduction'];
  475. $incItem['td_users_ios_deduction'] = $baseInfo['td_users_ios_deduction'];
  476. $incItem['td_users_h5_deduction'] = $baseInfo['td_users_h5_deduction'];
  477. $incItem['commission_ratio'] = isset($parentAgent->commission_ratio) ? intval($parentAgent->commission_ratio) : 0;
  478. $incItem['commission_diff_ratio'] = isset($parentAgent->commission_diff_ratio) ? intval($parentAgent->commission_diff_ratio) : 0;
  479. if (empty($info)) {
  480. AgentAttrsTodayModel::create($incItem);
  481. } else {
  482. // 有当前的日志,则追加下级的增量.
  483. foreach ($incItem as $k => $v) {
  484. if (!in_array($k, self::getIncExceptFields())) {
  485. $info->{$k} += $v;
  486. }
  487. $info->updated_at = Carbon::now();
  488. }
  489. $info->save();
  490. }
  491. // 继续无限递归
  492. self::todayLoopParent($date, $baseInfo, $parentAgent);
  493. }
  494. }
  495. }
  496. /**
  497. * 初始化今天的数据(清空).
  498. * @param $date
  499. * @return bool|int|null
  500. * @throws \Exception
  501. */
  502. public function initTodayMongo($date)
  503. {
  504. $startOfDateObj = Carbon::parse($date)->startOfDay();
  505. return AgentAttrsTodayModel::where('date', $startOfDateObj)->delete();
  506. }
  507. /**
  508. * 获取仓库.
  509. * @return StatisticsPayRepository
  510. */
  511. private function getPayRepo()
  512. {
  513. if (!$this->payRepo instanceof StatisticsPayRepository) {
  514. $this->payRepo = new StatisticsPayRepository();
  515. }
  516. return $this->payRepo;
  517. }
  518. /**
  519. * 获取新用户仓库.
  520. * @return StatisticsNewUserRepository
  521. */
  522. private function getUserRepo()
  523. {
  524. if (!$this->userRepo instanceof StatisticsNewUserRepository) {
  525. $this->userRepo = new StatisticsNewUserRepository();
  526. }
  527. return $this->userRepo;
  528. }
  529. /**
  530. * 获取排除的字段.
  531. * @return string[]
  532. */
  533. private function getIncExceptFields()
  534. {
  535. $fields = ['date', 'created_at', 'updated_at', 'uid', 'agent_uid', 'commission_ratio', 'commission_diff_ratio', 'withdraw_money'];
  536. return $fields;
  537. }
  538. /**
  539. * 获取余额变化日志仓库.
  540. * @return BalanceLogsRepository
  541. */
  542. private function getBalanceLogsRepo()
  543. {
  544. if (!$this->balanceLogsRepo instanceof BalanceLogsRepository) {
  545. $this->balanceLogsRepo = new BalanceLogsRepository();
  546. }
  547. return $this->balanceLogsRepo;
  548. }
  549. /**
  550. * 获取日活仓库.
  551. * @return StatisticsActiveRepository
  552. */
  553. private function getActiveRepo()
  554. {
  555. if (!$this->activeRepo instanceof StatisticsActiveRepository) {
  556. $this->activeRepo = new StatisticsActiveRepository();
  557. }
  558. return $this->activeRepo;
  559. }
  560. /**
  561. * 获取代理仓库.
  562. * @return AgentRepository|\Illuminate\Contracts\Foundation\Application|mixed|null
  563. */
  564. private function getAgentRepo()
  565. {
  566. if (!$this->agentRepo instanceof AgentRepository) {
  567. $this->agentRepo = app(AgentRepository::class);
  568. }
  569. return $this->agentRepo;
  570. }
  571. /**
  572. * 获取渠道仓库.
  573. * @return ChannelRepository|\Illuminate\Contracts\Foundation\Application|mixed|null
  574. */
  575. private function getChannelRepo()
  576. {
  577. if (!$this->channelRepo instanceof ChannelRepository) {
  578. $this->channelRepo = app(ChannelRepository::class);
  579. }
  580. return $this->channelRepo;
  581. }
  582. }