You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

426 lines
20 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. <?php
  2. namespace App\Service\v3\Implementations;
  3. use App\Commons\Log;
  4. use App\Constants\v3\LogLabel;
  5. use App\Constants\v3\OrderState;
  6. use App\Constants\v3\OrderType;
  7. use App\Model\v3\FinancialRecord;
  8. use App\Model\v3\Market;
  9. use App\Model\v3\MmInfo;
  10. use App\Model\v3\MpInfo;
  11. use App\Model\v3\Order;
  12. use App\Model\v3\OrderMain;
  13. use App\Model\v3\ServiceReward;
  14. use App\Model\v3\Store;
  15. use App\Model\v3\SystemConfig;
  16. use App\Model\v3\UserRelationBind;
  17. use App\Model\v3\User;
  18. use App\Service\v3\Interfaces\FinancialRecordServiceInterface;
  19. use App\Service\v3\Interfaces\MiniprogramServiceInterface;
  20. use App\Service\v3\Interfaces\OrderOnlineServiceInterface;
  21. use App\Service\v3\Interfaces\SeparateAccountsServiceInterface;
  22. use App\Service\v3\Interfaces\SmsSendServiceInterface;
  23. use App\Service\v3\Interfaces\UserServiceInterface;
  24. use App\TaskWorker\SSDBTask;
  25. use Hyperf\DbConnection\Db;
  26. use Hyperf\Di\Annotation\Inject;
  27. use Hyperf\Utils\ApplicationContext;
  28. class SeparateAccountsService implements SeparateAccountsServiceInterface
  29. {
  30. /**
  31. * @Inject
  32. * @var Log
  33. */
  34. protected $log;
  35. /**
  36. * @Inject
  37. * @var UserServiceInterface
  38. */
  39. protected $userService;
  40. /**
  41. * @Inject
  42. * @var FinancialRecordServiceInterface
  43. */
  44. protected $financialRecordService;
  45. /**
  46. * @Inject
  47. * @var MiniprogramServiceInterface
  48. */
  49. protected $miniprogramService;
  50. /**
  51. * @Inject
  52. * @var OrderOnlineServiceInterface
  53. */
  54. protected $orderOnlineService;
  55. /**
  56. * @Inject
  57. * @var SmsSendServiceInterface
  58. */
  59. protected $smsAliSendService;
  60. /**
  61. * @inheritDoc
  62. */
  63. public function orderOnlinePaid($globalOrderId)
  64. {
  65. try {
  66. // 线上订单支付完成
  67. // 订单
  68. $orderMain = OrderMain::query()->where(['global_order_id' => $globalOrderId])->first();
  69. if (empty($orderMain)) {
  70. return false;
  71. }
  72. // =======用户支付流水 / Start=======
  73. $this->financialRecordService->userByOLOrderPaid($orderMain->user_id, $orderMain->global_order_id, $orderMain->money);
  74. // =======用户支付流水 / End=======
  75. return true;
  76. } catch (\Exception $e) {
  77. $this->log->event(LogLabel::SEPARATE_ACCOUNTS_LOG, ['exception' => $e->getMessage()]);
  78. return false;
  79. }
  80. }
  81. /**
  82. * @inheritDoc
  83. */
  84. public function orderOnlineCompleted($globalOrderId, $userId)
  85. {
  86. // 线上订单完成(用户点击确认收货完成/管理后台点击完成/配送员点击完成/自动收货等),进行相关分账
  87. // 订单
  88. $orderMain = $this->orderOnlineService->check($globalOrderId, $userId,OrderState::FINISH);
  89. $currentTime = time();
  90. Db::beginTransaction();
  91. try {
  92. $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
  93. // =======商户订单收入流水 / Start=======
  94. // 查询子订单
  95. $orders = Order::query()
  96. ->where(['order_main_id' => $orderMain->global_order_id])
  97. ->get()->toArray();
  98. // 新商户流水
  99. foreach ($orders as $key => &$order) {
  100. $store = Store::query()->withoutGlobalScope('normal')->find($order['store_id']);
  101. $this->financialRecordService->storeByOLOrderComp($store->user_id, $orderMain->global_order_id ,$order['money']);
  102. }
  103. // =======商户订单收入流水 / End=======
  104. // =======社区服务点分账 / Start=======
  105. // 前提:用户线上下单并且订单完成
  106. // 奖励规则A:用户是平台新用户,奖励社区服务点平台新用户奖励x元+平台新用户首单奖励y元+订单商品金额z%的分成
  107. // 奖励规则B:用户是非新用户,奖励社区服务点订单实际支付金额z%的分成
  108. // =======社区服务点分账 / Start=======
  109. // 当前用户的社区服务点绑定关系
  110. $communityBind = UserRelationBind::query()
  111. ->where(['bind_type' => UserRelationBind::BIND_TYPE_COMMUNITY, 'user_id' => $orderMain->user_id])
  112. ->first();
  113. if ($communityBind) {
  114. // 奖励/分账金额
  115. $award = ServiceReward::query()->where(['type' => ServiceReward::TYPE_COMMUNITY])->first();
  116. if (empty($award)) {
  117. Db::rollBack();
  118. return false;
  119. }
  120. $award = $award->set_reward;
  121. // 平台新用户
  122. if ($this->userService->isPlatformNewUser($orderMain->user_id, $orderMain->global_order_id)) {
  123. $this->financialRecordService->communityAwardByPlatNewUser(
  124. $communityBind->source_id,
  125. $orderMain->global_order_id,
  126. $award['new_user_reward']
  127. );
  128. // 发送短信
  129. co(function () use ($communityBind, $award) {
  130. $this->smsAliSendService->doCommunityFinancial($communityBind->source_id, $award['new_user_reward']);
  131. });
  132. $this->financialRecordService->communityAwardByPlatNewUserFirstOLOrder(
  133. $communityBind->source_id,
  134. $orderMain->global_order_id,
  135. $award['first_reward']
  136. );
  137. // 发送短信
  138. co(function () use ($communityBind, $award) {
  139. $this->smsAliSendService->doCommunityFinancial($communityBind->source_id, $award['first_reward']);
  140. });
  141. }
  142. // 账单分成
  143. $money = bcmul($orderMain->money, bcdiv($award['flow_reward'], 100, 6), 2);
  144. $this->financialRecordService->communitySeparateAccountsByOrderComp($communityBind->source_id, $orderMain->global_order_id, $money);
  145. // 发送短信
  146. co(function () use ($communityBind, $money) {
  147. $this->smsAliSendService->doCommunityFinancial($communityBind->source_id, $money);
  148. });
  149. }
  150. // =======社区服务点分账 / End=======
  151. // =======服务商、市场经理奖励分账 / Start=======
  152. // 前提A:新用户下单并且订单完成(线上、线下都行)
  153. // 奖励规则A:用户是平台新用户,奖励市场经理 1 元,服务商 0.5 元,如果是线上订单,服务商有6%的订单分成
  154. // 前提B:新商户旗下产生 10 个新用户
  155. // 奖励规则B:奖励市场经理 25 元,服务商 10 元(仅仅奖励一次)
  156. // 前提C:用户线上下单并且订单完成
  157. // 奖励规则C:奖励服务商账单 6% 分成
  158. // 判断是新商户:入驻绑定的时候把关系存在SSDB
  159. // =======服务商、市场经理奖励分账 / Start=======
  160. // TODO 后续移到某些地方进行更方便的管理
  161. $MmMpAwardConfig = [
  162. 'mm_new_user' => 1,
  163. 'mm_new_store' => 25,
  164. 'mp_new_user' => 0.5,
  165. 'mp_new_store' => 10,
  166. 'separate_rate' => 6,
  167. 'limit_new_user_number' => 10,
  168. ];
  169. foreach ($orders as $key => &$order) {
  170. // 当前订单(子)对应商户是否有市场经理绑定关系
  171. $store = Store::query()->withoutGlobalScope('normal')->find($order['store_id']); // 商户
  172. // $mmInfo = MmInfo::query()->where(['user_id' => $store->mm_user_id])->first(); // 市场经理
  173. // if (empty($mmInfo)) continue;
  174. // $market = Market::query()->find($mmInfo->market_id); // 市场
  175. $market = Market::query()->find($orderMain->market_id); // 市场
  176. if (empty($market)) continue;
  177. $mpInfo = MpInfo::query()->find($market->mp_id); // 服务商
  178. if (empty($mpInfo)) continue;
  179. // $ssdbName = 'mm_'.$mmInfo->id.'_award_'.$store->id;
  180. $ssdbName = 'mm_'.$mpInfo->id.'_award_'.$store->id;
  181. // TODO 暂时在这里初始化
  182. if (!$ssdb->exec('hexists', $ssdbName, 'is_awarded')) {
  183. $ssdb->exec('hset', $ssdbName, 'is_awarded', 0);
  184. }
  185. if (!$ssdb->exec('hexists', $ssdbName, 'new_user_number')) {
  186. $ssdb->exec('hset', $ssdbName, 'new_user_number', 0);
  187. }
  188. // 平台新用户
  189. if ($this->userService->isPlatformNewUser($orderMain->user_id, $orderMain->id)) {
  190. $ssdb->exec('hincr', $ssdbName, 'new_user_number', 1);
  191. // $this->financialRecordService->mmAwardByPlatNewUser($mmInfo->admin_user_id, $globalOrderId, $MmMpAwardConfig['mm_new_user'], '发展新用户'); // 市场经理新用户奖励
  192. // $this->financialRecordService->mpAwardByPlatNewUser($mpInfo->admin_user_id, $globalOrderId, $MmMpAwardConfig['mp_new_user'], '市场经理「'.$mmInfo->name.'」发展新用户'); // 服务商新用户奖励
  193. $this->financialRecordService->mpAwardByPlatNewUser($mpInfo->admin_user_id, $globalOrderId, $MmMpAwardConfig['mp_new_user'], '发展新用户'); // 服务商新用户奖励
  194. }
  195. $record = $ssdb->exec('hgetall', $ssdbName);
  196. // 判断是否已经奖励过新拓展商户的奖励,没有的话判断新用户个数是否达到要求,进行奖励
  197. if (
  198. !empty($record)
  199. &&$record['is_awarded']==0
  200. &&$record['new_user_number']>=$MmMpAwardConfig['limit_new_user_number']
  201. ) { // 存在记录且未发放奖励,同时新用户数已经超过10
  202. $ssdb->exec('hset', $ssdbName, 'is_awarded', 1);
  203. // $this->financialRecordService->mmAwardByNewStore($mmInfo->admin_user_id, $globalOrderId, $MmMpAwardConfig['mm_new_store'], '发展新商户【'.$store->name.'】'); // 市场经理新商户奖励
  204. // $this->financialRecordService->mpAwardByNewStore($mpInfo->admin_user_id, $globalOrderId, $MmMpAwardConfig['mp_new_store'], '市场经理「'.$mmInfo->name.'」发展新商户【'.$store->name.'】'); // 服务商新商户奖励
  205. $this->financialRecordService->mpAwardByNewStore($mpInfo->admin_user_id, $globalOrderId, $MmMpAwardConfig['mp_new_store'], '发展新商户【'.$store->name.'】'); // 服务商新商户奖励
  206. }
  207. // 线上订单服务商分账
  208. if ($orderMain->type == OrderType::ONLINE) {
  209. $rate = bcdiv($order['money'], $orderMain->total_money, 6);
  210. $preMoney = bcmul($orderMain->money, $rate, 6);
  211. $money = bcmul($preMoney, bcdiv($MmMpAwardConfig['separate_rate'], 100, 6), 2);
  212. $this->financialRecordService->mpSeparateAccountByOLOrderComp($mpInfo->admin_user_id, $globalOrderId, $money);
  213. }
  214. }
  215. // =======服务商、市场经理奖励分账 / End=======
  216. Db::commit();
  217. return true;
  218. } catch (\Exception $e) {
  219. $this->log->event(LogLabel::SEPARATE_ACCOUNTS_LOG, ['exception' => $e->getMessage(), 'order_main' => json_encode($orderMain)]);
  220. Db::rollBack();
  221. return false;
  222. }
  223. }
  224. /**
  225. * @inheritDoc
  226. */
  227. public function orderOfflinePaid($globalOrderId)
  228. {
  229. // 线下订单支付完成
  230. // 订单
  231. $orderMain = OrderMain::query()->where(['global_order_id' => $globalOrderId])->first();
  232. if (empty($orderMain)) {
  233. return false;
  234. }
  235. // 查询子订单,当面付目前实际上只有一个子订单
  236. $order = Order::query()
  237. ->where(['order_main_id' => $orderMain->global_order_id])
  238. ->first();
  239. if (empty($order)) {
  240. return false;
  241. }
  242. $currentTime = time();
  243. Db::beginTransaction();
  244. try {
  245. // =======用户支付流水 / Start=======
  246. $this->financialRecordService->userByOFLOrderPaid($orderMain->user_id, $orderMain->global_order_id, $orderMain->money);
  247. // =======用户支付流水 / End=======
  248. // =======线下订单支付完成商户分账 / Start=======
  249. // 前提:用户线上下单并且支付完成
  250. // 奖励规则A:用户是平台新用户,奖励商户2元
  251. // 奖励规则B:用户是非新用户,但是是商户当日首单,奖励商户0.05元
  252. // =======线下订单支付完成商户分账 / Start=======
  253. $message = [];
  254. // 商户
  255. $store = Store::query()->withoutGlobalScope('normal')->find($order->store_id);
  256. // 新商户订单流水
  257. $this->financialRecordService->storeByOFLOrderComp($store->user_id, $orderMain->global_order_id, $order->money);
  258. $needAward = false;
  259. $awardAmount = 0;
  260. // 新用户商户奖励
  261. if ($this->userService->isPlatformNewUser($orderMain->user_id, $orderMain->global_order_id)) {
  262. $awardAmount = SystemConfig::query()->where('menu_name','award_new_user')->value('value');
  263. // 旧商户流水 TODO 直接移除或后续考虑移除
  264. $message = [
  265. 'money' => $awardAmount,
  266. 'note' => '新用户下单成功,平台奖励',
  267. ];
  268. // 新商户流水
  269. $this->financialRecordService->storeAwardByPlatNewUserOFLOrder($store->user_id, $orderMain->global_order_id, $awardAmount);
  270. $needAward = true;
  271. } else {
  272. // 商户当日首单奖励
  273. if (
  274. $this->userService->isStoreFirstOrderToday(
  275. $order->user_id,
  276. $order->store_id,
  277. $order->id,
  278. FinancialRecord::OFL_FIRST_AWARD_LIMIT_AMOUNT
  279. )
  280. && $order->money >= FinancialRecord::OFL_FIRST_AWARD_LIMIT_AMOUNT
  281. ) {
  282. $awardAmount = SystemConfig::query()->where('menu_name','award_each_order')->value('value');;
  283. // 旧商户流水 TODO 直接移除或后续考虑移除
  284. $message = [
  285. 'money' => $awardAmount,
  286. 'note' => '用户下单成功,平台奖励',
  287. ];
  288. // 新商户流水
  289. $this->financialRecordService->storeAwardByTodayFirstOFLOrder($store->user_id, $orderMain->global_order_id, $awardAmount);
  290. $needAward = true;
  291. }
  292. }
  293. if ($needAward && $awardAmount) {
  294. // 发模板消息
  295. $openid = User::query()->where(['id' => $store['user_id']])->value('openid');
  296. $res = $this->miniprogramService->sendTemMsgForAward($message['money'], $message['note'], $openid, date('Y-m-d H:i:s', $currentTime));
  297. }
  298. // =======线下订单支付完成商户分账 / End=======
  299. // =======线下订单支付完成商户分账 / End=======
  300. // =======服务商、市场经理奖励分账 / Start=======
  301. // 前提A:新用户下单并且订单完成(线上、线下都行)
  302. // 奖励规则A:用户是平台新用户,奖励市场经理 1 元,服务商 0.5 元,如果是线上订单,服务商有6%的订单分成
  303. // 前提B:新商户旗下产生 10 个新用户
  304. // 奖励规则B:奖励市场经理 25 元,服务商 10 元(仅仅奖励一次)
  305. // 前提C:用户线上下单并且订单完成
  306. // 奖励规则C:奖励服务商账单 6% 分成
  307. // 判断是新商户:入驻绑定的时候把关系存在SSDB
  308. // =======服务商、市场经理奖励分账 / Start=======
  309. $MmMpAwardConfig = [
  310. 'mm_new_user' => 1,
  311. 'mm_new_store' => 25,
  312. 'mp_new_user' => 0.5,
  313. 'mp_new_store' => 10,
  314. 'separate_rate' => 6,
  315. 'limit_new_user_number' => 10,
  316. ];
  317. // 当前订单(子)对应商户是否有市场经理绑定关系
  318. $store = Store::query()->withoutGlobalScope('normal')->find($order['store_id']); // 商户
  319. // $mmInfo = MmInfo::query()->where(['user_id' => $store->mm_user_id])->first(); // 市场经理
  320. $market = Market::query()->find($orderMain->market_id); // 市场
  321. $mpInfo = MpInfo::query()->find($market->mp_id); // 服务商
  322. if (!empty($mpInfo)) {
  323. $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
  324. // $ssdbName = 'mm_'.$mmInfo->id.'_award_'.$store->id;
  325. $ssdbName = 'mm_'.$mpInfo->id.'_award_'.$store->id;
  326. // TODO 暂时在这里初始化
  327. if (!$ssdb->exec('hexists', $ssdbName, 'is_awarded')) {
  328. $ssdb->exec('hset', $ssdbName, 'is_awarded', 0);
  329. }
  330. if (!$ssdb->exec('hexists', $ssdbName, 'new_user_number')) {
  331. $ssdb->exec('hset', $ssdbName, 'new_user_number', 0);
  332. }
  333. // 平台新用户
  334. if ($this->userService->isPlatformNewUser($orderMain->user_id, $orderMain->id)) {
  335. $ssdb->exec('hincr', $ssdbName, 'new_user_number', 1);
  336. // $this->financialRecordService->mmAwardByPlatNewUser($mmInfo->admin_user_id, $global_order_id, $MmMpAwardConfig['mm_new_user'], '发展新用户'); // 市场经理新用户奖励
  337. // $this->financialRecordService->mpAwardByPlatNewUser($mpInfo->admin_user_id, $global_order_id, $MmMpAwardConfig['mp_new_user'], '市场经理「'.$mmInfo->name.'」发展新用户'); // 服务商新用户奖励
  338. $this->financialRecordService->mpAwardByPlatNewUser($mpInfo->admin_user_id, $globalOrderId, $MmMpAwardConfig['mp_new_user'], '发展新用户'); // 服务商新用户奖励
  339. }
  340. $record = $ssdb->exec('hgetall', $ssdbName);
  341. // 判断是否已经奖励过新拓展商户的奖励,没有的话判断新用户个数是否达到要求,进行奖励
  342. if (
  343. !empty($record)
  344. &&$record['is_awarded']==0
  345. &&$record['new_user_number']>=$MmMpAwardConfig['limit_new_user_number']
  346. ) { // 存在记录且未发放奖励,同时新用户数已经超过10
  347. $ssdb->exec('hset', $ssdbName, 'is_awarded', 1);
  348. // $this->financialRecordService->mmAwardByNewStore($mmInfo->admin_user_id, $global_order_id, $MmMpAwardConfig['mm_new_store'], '发展新商户【'.$store->name.'】'); // 市场经理新商户奖励
  349. // $this->financialRecordService->mpAwardByNewStore($mpInfo->admin_user_id, $global_order_id, $MmMpAwardConfig['mp_new_store'], '市场经理「'.$mmInfo->name.'」发展新新商户【'.$store->name.'】'); // 服务商新商户奖励
  350. $this->financialRecordService->mpAwardByNewStore($mpInfo->admin_user_id, $globalOrderId, $MmMpAwardConfig['mp_new_store'], '发展新商户【'.$store->name.'】'); // 服务商新商户奖励
  351. }
  352. }
  353. // =======服务商、市场经理奖励分账 / End=======
  354. Db::commit();
  355. return true;
  356. } catch (\Exception $e) {
  357. $this->log->event(LogLabel::SEPARATE_ACCOUNTS_LOG, ['exception' => $e->getMessage(), 'order_main' => json_encode($orderMain)]);
  358. Db::rollBack();
  359. return false;
  360. }
  361. }
  362. }