PayService.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <?php
  2. /**
  3. * 描述.
  4. *
  5. * @author nj
  6. * @date 2021-07-10 16:47
  7. */
  8. namespace Modules\InnerApi\Services;
  9. use App\Constants\RedisKeysConstant;
  10. use App\Events\InnerUserOrderIncEvent;
  11. use App\Models\Mongo\PayLogsModel;
  12. use App\Models\Mongo\UsersModel;
  13. use App\Repositories\AgentRepository;
  14. use App\Repositories\AppDeductionRuleRepository;
  15. use App\Repositories\ConfigRepoistory;
  16. use App\Repositories\PayLogRepository;
  17. use Carbon\Carbon;
  18. use Illuminate\Support\Facades\Redis;
  19. use LuckyBox\Card\IdCard;
  20. use LuckyBox\LuckyBox;
  21. class PayService
  22. {
  23. /**
  24. * 增量写入或者修改支付订单.
  25. * @param array $data
  26. * @return mixed
  27. */
  28. public function inc(array $data)
  29. {
  30. $eventParams = [];
  31. foreach ($data as $item) {
  32. $item['created_at'] = Carbon::parse($item['created_at']);
  33. $item['updated_at'] = !empty($item['updated_at']) ? Carbon::parse($item['updated_at'])
  34. : Carbon::now();
  35. $item['paid_at'] = !empty($item['paid_at']) ? Carbon::parse($item['paid_at']) : null;
  36. $item['invite_uid'] = !empty($item['invite_uid']) ? $item['invite_uid'] : '';
  37. $item['order_amount'] = floatval(number_format($item['order_amount'] ?? 0, 2));
  38. $item['real_amount'] = floatval(number_format($item['real_amount'] ?? 0, 2));
  39. $item['pay_status'] = isset($item['pay_status']) ? intval($item['pay_status']) : 3;
  40. $item['order_status'] = isset($item['order_status']) ? intval($item['order_status']) : 3;
  41. $item['buy_type'] = isset($item['buy_type']) ? intval($item['buy_type']) : 0;
  42. $item['buy_gold_num'] = isset($item['buy_gold_num']) ? intval($item['buy_gold_num']) : 0;
  43. $item['user_uid'] = !empty($item['user_uid']) ? $item['user_uid']: '';
  44. if (!empty($item['invite_uid'])) {
  45. if ($item['invite_uid'] == $item['user_uid']) {
  46. // 不能等于自己.
  47. $item['invite_uid'] = '';
  48. }
  49. }
  50. $oldLogObj = null;
  51. $isOldLog = false;
  52. $logObj = PayLogsModel::where(['mom_app_uid' => $item['mom_app_uid']])->where(['order_sn' => $item['order_sn']])->first();
  53. if (!empty($logObj)) {
  54. // 存在.
  55. $isOldLog = true;
  56. $oldLogObj = clone $logObj; // 克隆老订单.
  57. $logObj->updated_at = $item['updated_at'];
  58. $logObj->paid_at = $item['paid_at'];
  59. $logObj->invite_uid = $item['invite_uid'];
  60. $logObj->transaction_no = $item['transaction_no'];
  61. $logObj->pay_status = $item['pay_status'];
  62. $logObj->order_status = $item['order_status'];
  63. $logObj->is_deduction = $item['is_deduction'];
  64. $logObj->save();
  65. } else {
  66. // 不存在,新建.
  67. $logObj = PayLogsModel::create($item);
  68. }
  69. if (!empty($logObj->_id)) {
  70. $eventParams[] = [
  71. 'log_id' => $logObj->_id,
  72. 'old_log' => [
  73. 'pay_status' => $isOldLog ? $oldLogObj->pay_status : 0,
  74. 'order_status' => $isOldLog ? $oldLogObj->order_status : 0,
  75. ]
  76. ];
  77. }
  78. }
  79. // 触发事件.
  80. event(new InnerUserOrderIncEvent($eventParams));
  81. return true;
  82. }
  83. /**
  84. * 随机扣量标记.
  85. * @param array $item
  86. * @return array
  87. */
  88. public function oneRandDeduction(array $item)
  89. {
  90. //订单成功才参与扣量
  91. if ($item['pay_status'] != 1 && $item['order_status'] != 1) {
  92. return $item;
  93. }
  94. $deductionConfig = app(ConfigRepoistory::class)->pickByKeys(['preferential_order', 'user_deduction_switch'], 'sys');
  95. // 判断总扣规则是否开启
  96. if ($deductionConfig['user_deduction_switch']['svalue'] == 0) {
  97. return $item;
  98. }
  99. $iTodayPayOrder = PayLogsModel::query()->where([
  100. 'channel_uid' => $item['channel_uid'],
  101. 'pay_status' => 1,
  102. 'order_status' => 1,
  103. ])->count();
  104. //每日前多少单不扣
  105. if ($iTodayPayOrder < $deductionConfig['preferential_order']['svalue']) {
  106. return $item;
  107. }
  108. //代理扣量验证
  109. $agentInfo = app(AgentRepository::class)->findBy('uid', $item['agent_uid'], ['deduction_switch', 'jdata', 'preferential_order']);
  110. if ($agentInfo->deduction_switch == 1) {
  111. if ($iTodayPayOrder >= $agentInfo->preferential_order) {
  112. $aData = json_decode($agentInfo->jdata, true);
  113. $item['is_deduction'] = $this->isDeduction($item, $aData);
  114. }
  115. } else if ($agentInfo->deduction_switch == 0) {
  116. // 总扣量规则
  117. $ruleData = app(AppDeductionRuleRepository::class)->findWhere(['app_uid' => $item['mom_app_uid'], 'deduction_type' => 'cps', 'deduction_rule' => 2])->keyBy('deduction_method');
  118. $userSuccessOrder = PayLogsModel::query()->where(['user_uid' => $item['user_uid'], 'pay_status' => 1, 'order_status' => 1])->count();
  119. if ($userSuccessOrder > 0) {
  120. if (isset($ruleData[2])) {
  121. $aData = json_decode($ruleData[2]->jdata, true);
  122. $item['is_deduction'] = $this->isDeduction($item, $aData, 1);
  123. }
  124. } else {
  125. //首充扣量
  126. if (isset($ruleData[1])) {
  127. $aData = json_decode($ruleData[1]->jdata, true);
  128. $item['is_deduction'] = $this->isDeduction($item, $aData, 2);
  129. }
  130. }
  131. } else {
  132. $item['is_deduction'] = 0;
  133. }
  134. return $item;
  135. }
  136. /**
  137. * 判断是否扣量
  138. *
  139. * @param array $item
  140. * @param array $aData
  141. * @param string $method
  142. * @return int
  143. */
  144. private function isDeduction(array $item,array $aData, $method = '')
  145. {
  146. $isDeduction = 0;
  147. $scope = [];
  148. $deduction = [];
  149. $deductionPrice = $aData['deduction_price'];
  150. $deductionNumber = $aData['deduction_number'];
  151. foreach ($deductionPrice as $key => $val) {
  152. if ($item['real_amount'] >= $val['min_price'] && $item['real_amount'] <= $val['max_price']) {
  153. $scope = $val;
  154. $deduction = $deductionNumber[$key];
  155. }
  156. }
  157. //如果没有符合的金额规则,就返回
  158. if (empty($scope) || $deduction['deduction'] == 0) {
  159. return $isDeduction;
  160. }
  161. $hashKey = RedisKeysConstant::DEDUCTION_RULES_HASH . $item['mom_app_uid'] . $item['channel_uid'] . $method;
  162. //获取扣量标记
  163. $areaKey = $scope['min_price'] . '-' . $scope['max_price'];
  164. $deductionMark = Redis::hget($hashKey, $areaKey);
  165. $mark = [0,0];
  166. if ($deductionMark) {
  167. $mark = explode('-', $deductionMark);
  168. //如果一轮规则达到 且扣量完成 则删除并初始化标记
  169. if ($mark[0] == $deduction['number'] && $mark[1] == $deduction['deduction']) {
  170. Redis::hDel($hashKey, $areaKey);
  171. $mark = [0,0];
  172. }
  173. //如果扣量达到,但是一轮还没结束则直接返回
  174. if ($mark[1] == $deduction['deduction']) {
  175. // $mark[0] + 1 参与订单总数加1
  176. Redis::hset($hashKey, $areaKey, $mark[0] + 1 . '-' . $mark[1]);
  177. return $isDeduction;
  178. }
  179. }
  180. //必扣计算
  181. if (($deduction['number'] - $mark[0]) <= ($deduction['deduction'] - $mark[1])) {
  182. $isDeduction = 1;
  183. } else {
  184. $boxItems = [
  185. 1 => ['name' => 0, 'rate' => 80],
  186. 2 => ['name' => 1, 'rate' => 20]
  187. ];
  188. $luckyBox = new LuckyBox();
  189. foreach ($boxItems as $id => $items) {
  190. $card = new IdCard();
  191. $card->setId($id)->setRate($items['rate']);
  192. $luckyBox->add($card);
  193. }
  194. $boxValue = $boxItems[$luckyBox->draw()->getId()];
  195. $isDeduction = $boxValue['name'];
  196. }
  197. if ($isDeduction == 1) {
  198. $mark[1] += 1;
  199. }
  200. $mark[0] += 1;
  201. Redis::hset($hashKey, $areaKey, $mark[0] . '-' . $mark[1]);
  202. return $isDeduction;
  203. }
  204. }