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.

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