CustomCoupon.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. <?php namespace App\Models;
  2. use App\Facades\Servers\Redis\RedisLock;
  3. use Illuminate\Database\Eloquent\Factories\HasFactory;
  4. use Illuminate\Database\Eloquent\Model;
  5. /**
  6. * 客户优惠券模型
  7. *
  8. */
  9. class CustomCoupon extends Model
  10. {
  11. use HasFactory;
  12. // 与模型关联的表名
  13. protected $table = 'custom_coupon';
  14. // 是否主动维护时间戳
  15. public $timestamps = false;
  16. // 定义时间戳字段名
  17. // const CREATED_AT = 'insert_time';
  18. // const UPDATED_AT = 'update_time';
  19. /**
  20. * 添加数据
  21. *
  22. */
  23. public function add($data)
  24. {
  25. // 时间
  26. $data['insert_time'] = time();
  27. $data['update_time'] = time();
  28. // 写入数据表
  29. $id = $this->query()->insertGetId($data);
  30. // 返回结果
  31. return $id;
  32. }
  33. /**
  34. * 添加数据
  35. *
  36. */
  37. public function edit($id,$data)
  38. {
  39. // 更新时间
  40. $data['update_time'] = time();
  41. // 写入数据表
  42. $result = $this->query()->where(['id'=>$id])->update($data);
  43. // 返回结果
  44. return $result;
  45. }
  46. /**
  47. * 获取优惠券
  48. *
  49. * @param int $id 客户优惠券ID(注意:不是优惠券的id)
  50. * @param int $uid 客户ID
  51. *
  52. */
  53. public function getCouponById($id,$uid)
  54. {
  55. // 返回结果
  56. if( !$id ) return [];
  57. // 查询条件
  58. $map = [['custom_coupon.id','=',$id],['custom_coupon.custom_uid','=',$uid],['custom_coupon.status','=',0]];
  59. // 查询优惠券
  60. $coupon = $this->query()->join('coupon','custom_coupon.coupon_id','=','coupon.id')->where($map)->first(['custom_coupon.id','coupon.id as coupon_id','coupon.name','coupon.type_id','coupon.rebate_type','coupon.std_pay','coupon.rebate','custom_coupon.status','custom_coupon.exp_time']);
  61. // 如果不存在优惠券
  62. if( !$coupon ) return [];
  63. // 转数组方便操作
  64. $coupon = $coupon->toArray();
  65. // 查询优惠券的商品范围
  66. $coupon['product_scope'] = $coupon['type_id'] == 1 ? (new CouponProduct())->getProducts($coupon['coupon_id']) : [];
  67. // 查询优惠券的商品范围
  68. $coupon['product_exclude'] = $coupon['type_id'] == 3 ? (new CouponProductExclude())->getProducts($coupon['coupon_id']) : [];
  69. // 获取赠品信息
  70. $coupon['rebate_scope'] = $coupon['rebate_type'] == 3 ? (new CouponRebate())->getProductByCouponId($coupon['coupon_id']) : [];
  71. // 返回结果
  72. return $coupon;
  73. }
  74. /**
  75. * 是否已有优惠券
  76. *
  77. * @param array $couponIds 多个优惠券ID
  78. *
  79. */
  80. public function isHaveCoupon($couponIds,$uid)
  81. {
  82. // 查询优惠券
  83. $haveList = $this->query()->where([['custom_uid','=',$uid]])->whereIn('coupon_id',$couponIds)->pluck('id','coupon_id')->toArray();
  84. // 如果不存在优惠券
  85. if( !$haveList ) return [];
  86. // 返回结果
  87. return $haveList;
  88. }
  89. /**
  90. * 过期状态设置
  91. *
  92. */
  93. public function setStatusByExpire()
  94. {
  95. // 上锁
  96. if(RedisLock::lock('customcoupon::set::status::by::expire',1,30)){
  97. // 修改
  98. $result = $this->query()->where([['status','=',0],['exp_time','<=',time()]])->update(['status'=>3,'update_time'=>time()]);
  99. // 不管成功失败,都解锁
  100. RedisLock::unlock('customcoupon::set::status::by::expire',1);
  101. // 返回结果
  102. return $result;
  103. }
  104. }
  105. /**
  106. * 过期状态设置
  107. *
  108. */
  109. public function setStatusByCouponId($couponId,$status)
  110. {
  111. // 修改未使用以及暂停的为对应的状态,其他状态的保持不变
  112. return $this->query()->where([['coupon_id','=',$couponId]])->whereIn('status',[0,2])->update(['status'=>$status,'update_time'=>time()]);
  113. }
  114. /**
  115. * 获取优惠券扣减金额
  116. *
  117. */
  118. public function getRebatePrice($customCouponId,$uid,$productPrice){
  119. // 如果有优惠券
  120. if( !$customCouponId ) return ['is_used'=>0,'product_price'=>$productPrice,'rebate_product'=>[]];
  121. // 查询用户的指定优惠券
  122. $coupon = $this->getCouponById($customCouponId,$uid);
  123. // 如果有优惠券
  124. if( !$coupon ) return ['is_used'=>0,'product_price'=>$productPrice,'rebate_product'=>[]];
  125. // 总价格
  126. $totalPrice = 0;
  127. // 判断是否指定商品范围
  128. if( $coupon['product_scope'] ) {
  129. // 去重,避免重复计算
  130. $coupon['product_scope'] = array_values(array_unique($coupon['product_scope']));
  131. // 循环商品范围
  132. foreach ( $coupon['product_scope'] as $productId ) {
  133. // 如果在商品范围
  134. if( isset($productPrice[$productId]['price_total']) ) $totalPrice = $totalPrice + $productPrice[$productId]['price_total'];
  135. }
  136. // 排除的商品,不参与
  137. } elseif ( $coupon['product_exclude'] ) {
  138. // 去重,避免重复计算
  139. $coupon['product_exclude'] = array_values(array_unique($coupon['product_exclude']));
  140. // 循环产品价格
  141. foreach ( $productPrice as $productId=>$value ) {
  142. // 如果产品在排除范围内
  143. if( in_array($productId,$coupon['product_exclude']) ) continue;
  144. // 计算总价
  145. $totalPrice = $totalPrice + $value['price_total'];
  146. }
  147. } else{
  148. $totalPrice = array_sum(array_column($productPrice,'price_total'));
  149. }
  150. // 如果没有达标
  151. if( $coupon['std_pay'] > $totalPrice ) return ['is_used'=>0,'product_price'=>$productPrice,'rebate_product'=>[]];
  152. // 达标结果
  153. $rebatePrice = 0;
  154. // 满减 扣减金额
  155. if( $coupon['rebate_type'] == 1 ) $rebatePrice = (float) $coupon['rebate'];
  156. // 折扣 扣减金额
  157. if( $coupon['rebate_type'] == 2 ) $rebatePrice = (float) $totalPrice - ( $totalPrice * $coupon['rebate'] * 0.1);
  158. // 赠品 赠送产品
  159. if( $coupon['rebate_type'] == 3 ) {
  160. // 如果没有赠品范围
  161. if( !$coupon['rebate_scope'] ) return ['is_used'=>1,'product_price'=>$productPrice,'rebate_product'=>[]];
  162. // 返回结果
  163. $productList = (new Product())->getListByIds(array_column($coupon['rebate_scope'],'product_id'));
  164. // 返回赠品数据
  165. $rebateProduct = [];
  166. // 循环处理
  167. foreach ($coupon['rebate_scope'] as $scope) {
  168. foreach ($productList as $product) {
  169. // 如果商品ID相等
  170. if( $scope['product_id'] == $product['id'] ){
  171. // 产品ID
  172. $product['product_id'] = $product['id'];
  173. $product['buy_num'] = $scope['rebate_num'];
  174. $product['price_total'] = $scope['rebate_num'] * $product['price'];
  175. $product['pay_total'] = 0;
  176. $product['coupon_total']= $product['price_total'];
  177. // 写入到赠品中
  178. $rebateProduct[$product['business_id']][$product['product_id']] = $product;
  179. }
  180. }
  181. }
  182. // 返回扣减结果
  183. return ['is_used'=>$customCouponId,'product_price'=>$productPrice,'rebate_product'=>$rebateProduct];
  184. }
  185. // 判断每个产品扣减多少钱
  186. // 循环产品
  187. foreach ($productPrice as $productId => $value) {
  188. // 如果有商品范围,且产品id不在商品范围的
  189. if( !empty($coupon['product_scope']) && !in_array($productId,$coupon['product_scope']) ) {
  190. // 跳过,不做计算
  191. continue;
  192. }
  193. // 如果有商品排除范围,且产品id在商品排除范围的
  194. if( !empty($coupon['product_exclude']) && in_array($productId,$coupon['product_exclude']) ) {
  195. // 跳过,不做计算
  196. continue;
  197. }
  198. // 优惠价格 = 价格占总价的比例 * 优惠的总价
  199. $value['rebate_price'] = number_format( $rebatePrice * ($value['price_total'] / $totalPrice) , 2 , '.' ,'');
  200. // 重组
  201. $productPrice[$productId] = $value;
  202. }
  203. // 返回扣减结果
  204. return ['is_used'=>$customCouponId,'product_price'=>$productPrice,'rebate_product'=>[]];
  205. }
  206. /**
  207. * 发放优惠券
  208. *
  209. * @param int $couponId 优惠券ID
  210. * @param int $customUid 客户ID
  211. *
  212. */
  213. public function giveCoupon($couponId,$customUid){
  214. // 达标的是否已经发送过优惠券
  215. $havaCoupon = $this->query()->where([['custom_uid','=',$customUid],['coupon_id','=',$couponId]])->first(['status']);
  216. // 已经发过优惠券的,不发
  217. if( $havaCoupon ) return 0;
  218. // 优惠券
  219. $Coupon = new \App\Models\Coupon();
  220. // 获取优惠券的可用时间
  221. $couponData = $Coupon->query()->where([['id','=',$couponId],['status','=','0']])->first(['issue_total','status','exp_time']);
  222. // 如果不存在数据,发送失败
  223. if( !$couponData || $couponData['status'] ) return 0;
  224. // 查询总共发放数量
  225. $total = $this->query()->where([['coupon_id','=',$couponId]])->count();
  226. // 数量超过的话。不发
  227. if( $total >= $couponData['issue_total'] ) return 0;
  228. // 时间转时间
  229. $expTime = $Coupon->getExpTime($couponData['exp_time']);
  230. // 发送优惠券
  231. return $this->add(['coupon_id'=>$couponId,'custom_uid'=>$customUid,'exp_time'=>$expTime]);
  232. }
  233. }