CouponService.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. <?php
  2. namespace app\frontend\modules\coupon\services;
  3. use app\common\helpers\ArrayHelper;
  4. use app\common\models\coupon\OrderGoodsCoupon;
  5. use app\common\models\goods\GoodsCoupon;
  6. use app\frontend\modules\coupon\services\models\Coupon;
  7. use app\frontend\modules\order\models\PreOrder;
  8. use app\Jobs\addGoodsCouponQueueJob;
  9. use Illuminate\Foundation\Bus\DispatchesJobs;
  10. use Illuminate\Support\Collection;
  11. class CouponService
  12. {
  13. use DispatchesJobs;
  14. /**
  15. * @var PreOrder
  16. */
  17. private $order;
  18. private $orderGoods;
  19. private $coupon_method;
  20. private $selectedMemberCoupon;
  21. public function __construct($order, $coupon_method = null, $orderGoods = [])
  22. {
  23. $this->order = $order;
  24. $this->orderGoods = $orderGoods;
  25. $this->coupon_method = $coupon_method;
  26. }
  27. /**
  28. * 获取订单优惠金额
  29. * @return float
  30. */
  31. public function getOrderDiscountPrice()
  32. {
  33. return $this->getAllValidCoupons()->sum(function (Coupon $coupon) {
  34. if (!$coupon->valid()) {
  35. return 0;
  36. }
  37. /**
  38. * @var $coupon Coupon
  39. */
  40. $coupon->activate();
  41. return $coupon->getDiscountAmount();
  42. });
  43. }
  44. /**
  45. * 获取订单可算的优惠券
  46. * @return Collection
  47. */
  48. public function getOptionalCoupons()
  49. {
  50. //用户所有优惠券
  51. $coupons = $this->getMemberCoupon()->map(function ($memberCoupon) {
  52. return new Coupon($memberCoupon, $this->order);
  53. });
  54. //其他优惠组合后可选的优惠券(未选中)
  55. $coupons = $coupons->filter(function ($coupon) {
  56. /**
  57. * @var $coupon Coupon
  58. */
  59. //不可选
  60. if (!$coupon->isOptional()) {
  61. trace_log()->coupon("优惠券{$coupon->getMemberCoupon()->id}", '不可选');
  62. return false;
  63. }
  64. //商城开启了多张优惠券 并且当前优惠券组合可以继续添加这张
  65. $coupon->getMemberCoupon()->valid = (!\Setting::get('coupon.is_singleton') || $this->order->orderCoupons->isEmpty()) && $coupon->valid();//界面标蓝(是否可选)
  66. $coupon->getMemberCoupon()->checked = false;//界面选中
  67. return true;
  68. })->values();
  69. //已选的优惠券
  70. $coupons = collect($this->order->orderCoupons)->map(function ($orderCoupon) {
  71. // 已参与订单价格计算的优惠券
  72. $orderCoupon->coupon->getMemberCoupon()->valid = true;
  73. $orderCoupon->coupon->getMemberCoupon()->checked = true;
  74. return $orderCoupon->coupon;
  75. })->merge($coupons); //合并已选中和可用未选中优惠券
  76. if ($this->order->orderCoupons->isNotEmpty() && !\Setting::get('shop.order.order_apart')) {
  77. //商品里设置的可使用优惠券数量
  78. $sum_goods = $this->order->orderGoods->sum(function ($orderGoods) {
  79. if ($orderGoods->goods->hasOneGoodsCoupon->is_use_num == 0) {
  80. return 0;
  81. }
  82. return $orderGoods->goods->hasOneGoodsCoupon->use_num * $orderGoods->total;
  83. });
  84. if (count($this->order->orderCoupons) > 0 && $sum_goods > 0 && count($this->order->orderCoupons) >= $sum_goods) {
  85. //如果选中优惠券大于商品里设置的优惠券总和
  86. $coupons = $coupons->map(function ($coupon, $key) use ($sum_goods) {
  87. if ($sum_goods == 0) {
  88. return $coupon;
  89. }
  90. if ($key >= $sum_goods) {
  91. $coupon->getMemberCoupon()->valid = false;
  92. $coupon->getMemberCoupon()->checked = false;
  93. }
  94. return $coupon;
  95. });
  96. }
  97. }
  98. //按member_coupon的id倒序
  99. $coupons = $coupons->sortByDesc(function ($coupon) {
  100. return $coupon->getMemberCoupon()->id;
  101. })->values();
  102. return $coupons;
  103. }
  104. /**
  105. * 获取所有选中并有效的优惠券
  106. * @return Collection
  107. */
  108. public function getAllValidCoupons()
  109. {
  110. $coupon = $this->getSelectedMemberCoupon()->map(function ($memberCoupon) {
  111. return new Coupon($memberCoupon, $this->order);
  112. });
  113. $result = $coupon->filter(function ($coupon) {
  114. /**
  115. * @var $coupon Coupon
  116. */
  117. return $coupon->valid();
  118. });
  119. return $result;
  120. }
  121. /**
  122. * 用户拥有的优惠券
  123. * @return Collection
  124. */
  125. private function getMemberCoupon()
  126. {
  127. $coupon_method = $this->coupon_method;
  128. $result = MemberCouponService::getCurrentMemberCouponCache($this->order->belongsToMember);
  129. if (isset($coupon_method)) {// 折扣/立减
  130. $result = $result->filter(function ($memberCoupon) use ($coupon_method) {
  131. return $memberCoupon->belongsToCoupon->coupon_method == $coupon_method;
  132. });
  133. }
  134. return $result;
  135. }
  136. /**
  137. * 用户拥有并选中的优惠券
  138. * @return Collection
  139. */
  140. private function getSelectedMemberCoupon()
  141. {
  142. if (!isset($this->selectedMemberCoupon)) {
  143. $member_coupon_ids = ArrayHelper::unreliableDataToArray(\Request::input('member_coupon_ids'));
  144. if (\Setting::get('coupon.is_singleton')) {
  145. $member_coupon_ids = array_slice($member_coupon_ids, 0, 1);
  146. }
  147. $coupon_list = [];
  148. //不实用集合方法是因为集合会把选中的顺序重新排序
  149. foreach ($member_coupon_ids as $k => $v) {
  150. $coupon = $this->getMemberCoupon()->where('id', $v);
  151. $this->getMemberCoupon()->push($coupon);
  152. $coupon_list[$k] = $coupon;
  153. }
  154. $this->selectedMemberCoupon = collect($coupon_list)->collapse();
  155. }
  156. return $this->selectedMemberCoupon;
  157. }
  158. public function sendCoupon()
  159. {
  160. $orderGoods = $this->orderGoods;
  161. foreach ($orderGoods as $goods) {
  162. $goodsCoupon = GoodsCoupon::ofGoodsId($goods->goods_id)->first();
  163. //未开启 或 已关闭 或 未设置优惠券
  164. if (!$goodsCoupon || !$goodsCoupon->is_give || !$goodsCoupon->coupon) {
  165. continue;
  166. }
  167. //每月发送时,发送月数 为空 或为 0
  168. if ($goodsCoupon->send_type == '0' && empty($goodsCoupon->send_num)) {
  169. continue;
  170. }
  171. for ($i = 1; $i <= $goods->total; $i++) {
  172. switch ($goodsCoupon->send_type) {
  173. //订单完成立即发送
  174. case '1':
  175. $this->promptlySendCoupon($goodsCoupon);
  176. break;
  177. //每月发送
  178. case '0':
  179. $this->everyMonthSendCoupon($goodsCoupon);
  180. break;
  181. }
  182. }
  183. }
  184. }
  185. /**
  186. * 商品消费赠送优惠券新方式
  187. */
  188. public function sendCouponLog()
  189. {
  190. $orderGoods = $this->orderGoods;
  191. foreach ($orderGoods as $goods) {
  192. $goodsCoupon = GoodsCoupon::ofGoodsId($goods->goods_id)->first();
  193. //未开启 或 已关闭 或 未设置优惠券
  194. if (!$goodsCoupon || !$goodsCoupon->is_give || !$goodsCoupon->coupon) {
  195. continue;
  196. }
  197. //每月发送时,发送月数 为空 或为 0
  198. if ($goodsCoupon->send_type == '0' && empty($goodsCoupon->send_num)) {
  199. continue;
  200. }
  201. $this->doCouponLog($goodsCoupon,$goods->id,$goods->total);
  202. }
  203. }
  204. public function promptlySendCoupon($goodsCoupon)
  205. {
  206. $coupon_ids = [];
  207. foreach ($goodsCoupon->coupon as $key => $item) {
  208. if ($item['coupon_several'] > 1) {
  209. for ($i = 1; $i <= $item['coupon_several']; $i++) {
  210. $coupon_ids[] = $item['coupon_id'];
  211. }
  212. } else {
  213. $coupon_ids[] = $item['coupon_id'];
  214. }
  215. }
  216. (new CouponSendService())->sendCouponsToMember($this->order->uid, $coupon_ids, 4, $this->order->order_sn);
  217. }
  218. public function everyMonthSendCoupon($goodsCoupon)
  219. {
  220. foreach ($goodsCoupon->coupon as $key => $item) {
  221. if ($item['coupon_several'] > 1) {
  222. for ($i = 1; $i <= $item['coupon_several']; $i++) {
  223. $this->addSendCouponQueue($goodsCoupon, $item['coupon_id']);
  224. }
  225. } else {
  226. $this->addSendCouponQueue($goodsCoupon, $item['coupon_id']);
  227. }
  228. }
  229. }
  230. /**
  231. * @param $goodsCoupon
  232. * @param $orderGoodsId
  233. * @param $total
  234. * 为了不多发少发,从源头控制锁定原因,定时发放
  235. */
  236. public function doCouponLog($goodsCoupon,$orderGoodsId,$total)
  237. {
  238. foreach ($goodsCoupon->coupon as $key => $item) {
  239. $insertArr = [
  240. 'uniacid' => \YunShop::app()->uniacid,
  241. 'order_goods_id' => $orderGoodsId,
  242. 'coupon_id' => $item['coupon_id'],
  243. 'coupon_several' => bcmul($item['coupon_several'],$total),
  244. 'send_type' => $goodsCoupon->send_type,
  245. 'remark' => json_encode($goodsCoupon->coupon)
  246. ];
  247. if($goodsCoupon->send_type == 0)
  248. {
  249. $monthArr = [
  250. 'send_num' => $goodsCoupon->send_num,
  251. 'end_send_num' => 0,
  252. ];
  253. $insertArr = array_merge($insertArr,$monthArr);
  254. }
  255. $model = new OrderGoodsCoupon();
  256. $model->fill($insertArr);
  257. $model->save();
  258. }
  259. }
  260. public function addSendCouponQueue($goodsCoupon, $coupon_id)
  261. {
  262. $queueData = [
  263. 'uniacid' => \YunShop::app()->uniacid,
  264. 'goods_id' => $goodsCoupon->goods_id,
  265. 'uid' => $this->order->uid,
  266. 'coupon_id' => $coupon_id,
  267. 'send_num' => $goodsCoupon->send_num,
  268. 'end_send_num' => 0,
  269. 'status' => 0,
  270. 'created_at' => time()
  271. ];
  272. $this->dispatch((new addGoodsCouponQueueJob($queueData)));
  273. }
  274. }