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.

175 lines
6.0 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. * @inheritDoc
  38. */
  39. public function countAvailableByUser($userId)
  40. {
  41. return mt_rand(0,10);
  42. }
  43. /**
  44. * 缓存优惠券今日使用情况
  45. * @param $userId
  46. * @param $couponId
  47. * @param $couponRecId
  48. * @return bool
  49. */
  50. public function cacheTodayCouponUsed($userId, $couponId, $couponRecId)
  51. {
  52. $redis = ApplicationContext::getContainer()->get(Redis::class);
  53. $setRes = $redis->sAdd('coupon_' . date('Ymd') . '_used_' . $userId, $couponId);
  54. $expireRes = $redis->expire('coupon_' . date('Ymd') . '_used_' . $userId, strtotime(date('Y-m-d') . ' 23:59:59') - time());
  55. return $setRes && $expireRes;
  56. }
  57. public function allTodayCouponUsed($userId)
  58. {
  59. $redis = ApplicationContext::getContainer()->get(Redis::class);
  60. return $couponTodayUsedIds = $redis->sMembers('coupon_'.date('Ymd').'_used_'.$userId);
  61. }
  62. public function orderUseCoupons($orderMainId, $couponRecs)
  63. {
  64. Db::beginTransaction();
  65. try {
  66. if (is_array($couponRecs)&&!empty($couponRecs)) {
  67. # 使用记录、更新当前优惠券
  68. foreach ($couponRecs as $key => &$coupon) {
  69. $couponUse = [
  70. 'user_id' => $coupon['user_id'],
  71. 'user_receive_id' => $coupon['id'],
  72. 'coupon_id' => $coupon['coupon_id'],
  73. 'order_main_id' => $orderMainId,
  74. 'use_time' => time(),
  75. 'return_time' => 0,
  76. 'number' => 1,
  77. 'status' => 1,
  78. 'update_time' => 0,
  79. ];
  80. $insertRes = CouponUse::query()->insert($couponUse);
  81. if ($insertRes) {
  82. $status = 0;
  83. $numberRemain = $coupon['number_remain'] - 1;
  84. if ($numberRemain == 0) {
  85. $status = 2;
  86. } elseif ($numberRemain > 0 && $numberRemain < $coupon['number']) {
  87. $status = 1;
  88. } elseif ($numberRemain == $coupon['number']) {
  89. $status = 0;
  90. }
  91. $upRes = CouponRec::query()->where(['id' => $coupon['id']])
  92. ->update(['number_remain' => $numberRemain, 'status' => $status]);
  93. if (!$upRes) {
  94. Db::rollBack();
  95. throw new ErrorCodeException(ErrorCode::COUPON_USE_FAILURE);
  96. }
  97. // 缓存使用记录
  98. $usedRes = $this->cacheTodayCouponUsed($coupon['user_id'], $coupon['coupon_id'], $coupon['id']);
  99. if (!$usedRes) {
  100. Db::rollBack();
  101. throw new ErrorCodeException(ErrorCode::COUPON_USE_FAILURE);
  102. }
  103. } else {
  104. Db::rollBack();
  105. throw new ErrorCodeException(ErrorCode::COUPON_USE_FAILURE);
  106. }
  107. }
  108. }
  109. Db::commit();
  110. } catch (\Exception $e) {
  111. Db::rollBack();
  112. throw new ErrorCodeException(ErrorCode::COUPON_USE_FAILURE, $e->getMessage());
  113. }
  114. }
  115. /**
  116. * 退还优惠券,订单取消,申请退款成功时
  117. * 先查询是否正常使用优惠券
  118. * 修改状态,退还领取记录库存,删除ssdb缓存
  119. * @param $orderMainId
  120. * @return bool
  121. */
  122. public function orderRefundCoupons($orderMainId)
  123. {
  124. $currentTime = time();
  125. Db::beginTransaction();
  126. try {
  127. $couponUses = CouponUse::query()
  128. ->where('order_main_id', $orderMainId)
  129. ->where('status', 1)
  130. ->get();
  131. if (!empty($couponUses)) {
  132. foreach ($couponUses as $use) {
  133. $use->status = 1;
  134. $use->return_time = $currentTime;
  135. $use->update_time = $currentTime;
  136. $res = $use->save();
  137. $couponReceive = CouponRec::query()
  138. ->where('id', $use->user_receive_id)
  139. ->whereRaw('number >= number_remain+' . $use->number)
  140. ->update([
  141. 'number_remain' => Db::raw('number_remain+' . $use->number),
  142. 'status' => Db::raw('IF(number=number_remain, 0,1)'), 'update_time' => $currentTime
  143. ]);
  144. if ($res && $couponReceive) {
  145. $redis = ApplicationContext::getContainer()->get(Redis::class);
  146. $clearUseRedis = $redis->sRem('coupon_' . date('Ymd') . '_used_' . $use->user_id, $use->coupon_id);
  147. }
  148. }
  149. }
  150. Db::commit();
  151. return true;
  152. } catch (\Exception $e) {
  153. $this->log->event(LogLabel::COUPON_REFUND_LOG, ['msg' => '订单取消/退款退还优惠券', 'exception' => $e->getMessage()]);
  154. Db::rollBack();
  155. return false;
  156. }
  157. }
  158. }