UserCoupon.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. <?php
  2. namespace app\api\model;
  3. use app\common\library\helper;
  4. use app\common\model\UserCoupon as UserCouponModel;
  5. /**
  6. * 用户优惠券模型
  7. * Class UserCoupon
  8. * @package app\api\model
  9. */
  10. class UserCoupon extends UserCouponModel
  11. {
  12. /**
  13. * 获取用户优惠券列表
  14. * @param $userId
  15. * @param bool $isUse 是否已使用
  16. * @param bool $isExpire 是否已过期
  17. * @param float $amount 订单消费金额
  18. * @return false|\PDOStatement|string|\think\Collection
  19. * @throws \think\db\exception\DataNotFoundException
  20. * @throws \think\db\exception\ModelNotFoundException
  21. * @throws \think\exception\DbException
  22. */
  23. public function getList($userId, $isUse = false, $isExpire = false, $amount = null)
  24. {
  25. // 构建查询对象
  26. $query = $this->where('user_id', '=', $userId)
  27. ->where('is_use', '=', $isUse)
  28. ->where('is_expire', '=', $isExpire);
  29. // 最低消费金额
  30. if (!is_null($amount) && $amount > 0) {
  31. $query->where('min_price', '<=', $amount);
  32. }
  33. return $query->select();
  34. }
  35. /**
  36. * 获取用户优惠券总数量(可用)
  37. * @param $user_id
  38. * @return int|string
  39. * @throws \think\Exception
  40. */
  41. public function getCount($user_id)
  42. {
  43. return $this->where('user_id', '=', $user_id)
  44. ->where('is_use', '=', 0)
  45. ->where('is_expire', '=', 0)
  46. ->count();
  47. }
  48. /**
  49. * 获取用户优惠券ID集
  50. * @param $user_id
  51. * @return array
  52. */
  53. public function getUserCouponIds($user_id)
  54. {
  55. return $this->where('user_id', '=', $user_id)->column('coupon_id');
  56. }
  57. /**
  58. * 领取优惠券
  59. * @param $user
  60. * @param $coupon_id
  61. * @return bool|false|int
  62. * @throws \think\exception\DbException
  63. */
  64. public function receive($user, $coupon_id)
  65. {
  66. // 获取优惠券信息
  67. $coupon = Coupon::detail($coupon_id);
  68. // 验证优惠券是否可领取
  69. if (!$this->checkReceive($user, $coupon)) {
  70. return false;
  71. }
  72. // 添加领取记录
  73. return $this->add($user, $coupon);
  74. }
  75. /**
  76. * 添加领取记录
  77. * @param $user
  78. * @param Coupon $coupon
  79. * @return bool
  80. */
  81. private function add($user, $coupon)
  82. {
  83. // 计算有效期
  84. if ($coupon['expire_type'] == 10) {
  85. $start_time = time();
  86. $end_time = $start_time + ($coupon['expire_day'] * 86400);
  87. } else {
  88. $start_time = $coupon['start_time']['value'];
  89. $end_time = $coupon['end_time']['value'];
  90. }
  91. // 整理领取记录
  92. $data = [
  93. 'coupon_id' => $coupon['coupon_id'],
  94. 'name' => $coupon['name'],
  95. 'color' => $coupon['color']['value'],
  96. 'coupon_type' => $coupon['coupon_type']['value'],
  97. 'reduce_price' => $coupon['reduce_price'],
  98. 'discount' => $coupon->getData('discount'),
  99. 'min_price' => $coupon['min_price'],
  100. 'expire_type' => $coupon['expire_type'],
  101. 'expire_day' => $coupon['expire_day'],
  102. 'start_time' => $start_time,
  103. 'end_time' => $end_time,
  104. 'apply_range' => $coupon['apply_range'],
  105. 'apply_range_config' => $coupon['apply_range_config'],
  106. 'user_id' => $user['user_id'],
  107. 'wxapp_id' => self::$wxapp_id
  108. ];
  109. return $this->transaction(function () use ($data, $coupon) {
  110. // 添加领取记录
  111. $status = $this->save($data);
  112. if ($status) {
  113. // 更新优惠券领取数量
  114. $coupon->setIncReceiveNum();
  115. }
  116. return $status;
  117. });
  118. }
  119. /**
  120. * 验证优惠券是否可领取
  121. * @param $user
  122. * @param Coupon $coupon
  123. * @return bool
  124. */
  125. private function checkReceive($user, $coupon)
  126. {
  127. if (!$coupon) {
  128. $this->error = '优惠券不存在';
  129. return false;
  130. }
  131. if (!$coupon->checkReceive()) {
  132. $this->error = $coupon->getError();
  133. return false;
  134. }
  135. // 验证是否已领取
  136. $userCouponIds = $this->getUserCouponIds($user['user_id']);
  137. if (in_array($coupon['coupon_id'], $userCouponIds)) {
  138. $this->error = '该优惠券已领取';
  139. return false;
  140. }
  141. return true;
  142. }
  143. /**
  144. * 订单结算优惠券列表
  145. * @param int $userId 用户id
  146. * @param double $orderPayPrice 订单商品总金额
  147. * @return mixed
  148. * @throws \think\db\exception\DataNotFoundException
  149. * @throws \think\db\exception\ModelNotFoundException
  150. * @throws \think\exception\DbException
  151. */
  152. public static function getUserCouponList($userId, $orderPayPrice)
  153. {
  154. // 获取用户可用的优惠券列表
  155. $list = (new static)->getList($userId, false, false, $orderPayPrice);
  156. $data = [];
  157. foreach ($list as $coupon) {
  158. // 最低消费金额
  159. // if ($orderPayPrice < $coupon['min_price']) continue;
  160. // 有效期范围内
  161. if ($coupon['start_time']['value'] > time()) continue;
  162. $key = $coupon['user_coupon_id'];
  163. $data[$key] = [
  164. 'user_coupon_id' => $coupon['user_coupon_id'],
  165. 'name' => $coupon['name'],
  166. 'color' => $coupon['color'],
  167. 'coupon_type' => $coupon['coupon_type'],
  168. 'reduce_price' => $coupon['reduce_price'],
  169. 'discount' => $coupon['discount'],
  170. 'min_price' => $coupon['min_price'],
  171. 'expire_type' => $coupon['expire_type'],
  172. 'start_time' => $coupon['start_time'],
  173. 'end_time' => $coupon['end_time'],
  174. 'apply_range' => $coupon['apply_range'],
  175. 'apply_range_config' => $coupon['apply_range_config']
  176. ];
  177. // 计算打折金额
  178. if ($coupon['coupon_type']['value'] == 20) {
  179. $reducePrice = helper::bcmul($orderPayPrice, $coupon['discount'] / 10);
  180. $data[$key]['reduced_price'] = bcsub($orderPayPrice, $reducePrice, 2);
  181. } else
  182. $data[$key]['reduced_price'] = $coupon['reduce_price'];
  183. }
  184. // 根据折扣金额排序并返回
  185. return array_sort($data, 'reduced_price', true);
  186. }
  187. /**
  188. * 判断当前优惠券是否满足订单使用条件
  189. * @param $couponList
  190. * @param $orderGoodsIds
  191. * @return mixed
  192. */
  193. public static function couponListApplyRange($couponList, $orderGoodsIds)
  194. {
  195. // 名词解释(is_apply):允许用于抵扣当前订单
  196. foreach ($couponList as &$item) {
  197. if ($item['apply_range'] == 10) {
  198. // 1. 全部商品
  199. $item['is_apply'] = true;
  200. } elseif ($item['apply_range'] == 20) {
  201. // 2. 指定商品, 判断订单商品是否存在可用
  202. $applyGoodsIds = array_intersect($item['apply_range_config']['applyGoodsIds'], $orderGoodsIds);
  203. $item['is_apply'] = !empty($applyGoodsIds);
  204. } elseif ($item['apply_range'] == 30) {
  205. // 2. 排除商品, 判断订单商品是否全部都在排除行列
  206. $excludedGoodsIds = array_intersect($item['apply_range_config']['excludedGoodsIds'], $orderGoodsIds);
  207. $item['is_apply'] = count($excludedGoodsIds) != count($orderGoodsIds);
  208. }
  209. !$item['is_apply'] && $item['not_apply_info'] = '该优惠券不支持当前商品';
  210. }
  211. return $couponList;
  212. }
  213. }