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.

167 lines
5.9 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. throw new ErrorCodeException(ErrorCode::COUPON_USE_FAILURE, $e->getMessage());
  106. }
  107. }
  108. /**
  109. * 退还优惠券,订单取消,申请退款成功时
  110. * 先查询是否正常使用优惠券
  111. * 修改状态,退还领取记录库存,删除ssdb缓存
  112. * @param $globalOrderId
  113. * @return bool
  114. */
  115. public function orderRefundCoupons($globalOrderId)
  116. {
  117. $currentTime = time();
  118. Db::beginTransaction();
  119. try {
  120. $couponUses = CouponUse::query()
  121. ->where('order_main_id', $globalOrderId)
  122. ->where('status', 1)
  123. ->get();
  124. if (!empty($couponUses)) {
  125. foreach ($couponUses as $use) {
  126. $use->status = 1;
  127. $use->return_time = $currentTime;
  128. $use->update_time = $currentTime;
  129. $res = $use->save();
  130. $couponReceive = CouponRec::query()
  131. ->where('id', $use->user_receive_id)
  132. ->whereRaw('number >= number_remain+' . $use->number)
  133. ->update([
  134. 'number_remain' => Db::raw('number_remain+' . $use->number),
  135. 'status' => Db::raw('IF(number=number_remain, 0,1)'), 'update_time' => $currentTime
  136. ]);
  137. if ($res && $couponReceive) {
  138. $redis = ApplicationContext::getContainer()->get(Redis::class);
  139. $clearUseRedis = $redis->sRem('coupon_' . date('Ymd') . '_used_' . $use->user_id, $use->coupon_id);
  140. }
  141. }
  142. }
  143. Db::commit();
  144. return true;
  145. } catch (\Exception $e) {
  146. $this->log->event(LogLabel::COUPON_REFUND_LOG, ['msg' => '订单取消/退款退还优惠券', 'exception' => $e->getMessage()]);
  147. Db::rollBack();
  148. return false;
  149. }
  150. }
  151. }