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.

178 lines
6.7 KiB

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