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.

168 lines
6.1 KiB

  1. <?php
  2. namespace App\Service\v3\Implementations;
  3. use App\Constants\v3\ErrorCode;
  4. use App\Constants\v3\LogLabel;
  5. use App\Exception\ErrorCodeException;
  6. use App\Model\v3\CouponRec;
  7. use App\Model\v3\CouponUse;
  8. use App\Model\v3\OrderMain;
  9. use App\Service\v3\Interfaces\CouponServiceInterface;
  10. use Hyperf\DbConnection\Db;
  11. use Hyperf\Redis\Redis;
  12. use Hyperf\Utils\ApplicationContext;
  13. class CouponService implements CouponServiceInterface
  14. {
  15. /**
  16. * @inheritDoc
  17. */
  18. public function do()
  19. {
  20. // TODO: Implement do() method.
  21. }
  22. /**
  23. * @inheritDoc
  24. */
  25. public function check()
  26. {
  27. // TODO: Implement check() method.
  28. }
  29. /**
  30. * @inheritDoc
  31. */
  32. public function undo()
  33. {
  34. // TODO: Implement undo() method.
  35. }
  36. /**
  37. * 缓存优惠券今日使用情况
  38. * @param $userId
  39. * @param $couponId
  40. * @param $couponRecId
  41. * @return bool
  42. */
  43. public function cacheTodayCouponUsed($userId, $couponId, $couponRecId)
  44. {
  45. $redis = ApplicationContext::getContainer()->get(Redis::class);
  46. $setRes = $redis->sAdd('coupon_' . date('Ymd') . '_used_' . $userId, $couponId);
  47. $expireRes = $redis->expire('coupon_' . date('Ymd') . '_used_' . $userId, strtotime(date('Y-m-d') . ' 23:59:59') - time());
  48. return $setRes && $expireRes;
  49. }
  50. public function allTodayCouponUsed($userId)
  51. {
  52. $redis = ApplicationContext::getContainer()->get(Redis::class);
  53. return $couponTodayUsedIds = $redis->sMembers('coupon_'.date('Ymd').'_used_'.$userId);
  54. }
  55. public function orderUseCoupons($globalOrderId, $couponRecs)
  56. {
  57. Db::beginTransaction();
  58. try {
  59. if (is_array($couponRecs)&&!empty($couponRecs)) {
  60. # 使用记录、更新当前优惠券
  61. foreach ($couponRecs as $key => &$coupon) {
  62. $couponUse = [
  63. 'user_id' => $coupon['user_id'],
  64. 'user_receive_id' => $coupon['id'],
  65. 'coupon_id' => $coupon['coupon_id'],
  66. 'order_main_id' => $globalOrderId,
  67. 'use_time' => time(),
  68. 'return_time' => 0,
  69. 'number' => 1,
  70. 'status' => 1,
  71. 'update_time' => 0,
  72. ];
  73. $insertRes = CouponUse::query()->insert($couponUse);
  74. if ($insertRes) {
  75. $status = 0;
  76. $numberRemain = $coupon['number_remain'] - 1;
  77. if ($numberRemain == 0) {
  78. $status = 2;
  79. } elseif ($numberRemain > 0 && $numberRemain < $coupon['number']) {
  80. $status = 1;
  81. } elseif ($numberRemain == $coupon['number']) {
  82. $status = 0;
  83. }
  84. $upRes = CouponRec::query()->where(['id' => $coupon['id']])
  85. ->update(['number_remain' => $numberRemain, 'status' => $status]);
  86. if (!$upRes) {
  87. Db::rollBack();
  88. throw new ErrorCodeException(ErrorCode::COUPON_USE_FAILURE, '更新优惠券数量失败');
  89. }
  90. // 缓存使用记录
  91. $usedRes = $this->cacheTodayCouponUsed($coupon['user_id'], $coupon['coupon_id'], $coupon['id']);
  92. if (!$usedRes) {
  93. Db::rollBack();
  94. throw new ErrorCodeException(ErrorCode::COUPON_USE_FAILURE, '缓存优惠券使用记录失败');
  95. }
  96. } else {
  97. Db::rollBack();
  98. throw new ErrorCodeException(ErrorCode::COUPON_USE_FAILURE, '新增优惠券使用记录到数据库失败');
  99. }
  100. }
  101. }
  102. Db::commit();
  103. } catch (\Exception $e) {
  104. Db::rollBack();
  105. $this->log->event(LogLabel::ORDER_ONLINE_LOG, ['msg' => '下单时优惠券使用失败'.$e->getMessage(), 'data' => '']);
  106. throw new ErrorCodeException(ErrorCode::COUPON_USE_FAILURE);
  107. }
  108. }
  109. /**
  110. * 退还优惠券,订单取消,申请退款成功时
  111. * 先查询是否正常使用优惠券
  112. * 修改状态,退还领取记录库存,删除ssdb缓存
  113. * @param $globalOrderId
  114. * @return bool
  115. */
  116. public function orderRefundCoupons($globalOrderId)
  117. {
  118. $currentTime = time();
  119. Db::beginTransaction();
  120. try {
  121. $couponUses = CouponUse::query()
  122. ->where('order_main_id', $globalOrderId)
  123. ->where('status', 1)
  124. ->get();
  125. if (!empty($couponUses)) {
  126. foreach ($couponUses as $use) {
  127. $use->status = 1;
  128. $use->return_time = $currentTime;
  129. $use->update_time = $currentTime;
  130. $res = $use->save();
  131. $couponReceive = CouponRec::query()
  132. ->where('id', $use->user_receive_id)
  133. ->whereRaw('number >= number_remain+' . $use->number)
  134. ->update([
  135. 'number_remain' => Db::raw('number_remain+' . $use->number),
  136. 'status' => Db::raw('IF(number=number_remain, 0,1)'), 'update_time' => $currentTime
  137. ]);
  138. if ($res && $couponReceive) {
  139. $redis = ApplicationContext::getContainer()->get(Redis::class);
  140. $clearUseRedis = $redis->sRem('coupon_' . date('Ymd') . '_used_' . $use->user_id, $use->coupon_id);
  141. }
  142. }
  143. }
  144. Db::commit();
  145. return true;
  146. } catch (\Exception $e) {
  147. $this->log->event(LogLabel::COUPON_REFUND_LOG, ['msg' => '订单取消/退款退还优惠券', 'exception' => $e->getMessage()]);
  148. Db::rollBack();
  149. return false;
  150. }
  151. }
  152. }