diff --git a/app/Admin/Controllers/OrderController.php b/app/Admin/Controllers/OrderController.php index cb32b8da..51fb463c 100644 --- a/app/Admin/Controllers/OrderController.php +++ b/app/Admin/Controllers/OrderController.php @@ -322,8 +322,8 @@ class OrderController extends AdminController $builder = OrderProduct::withCount('afterSales')->where('order_id', $id); $productGrid = Grid::make($builder, function (Grid $grid) { $grid->column('name')->display(function ($value) { - if ($this->gift_for_sku_id) { - $value .= '-【赠品】'; + if ($this->isGift()) { + $value = '【赠品】'.$value; } return $value; }); diff --git a/app/Admin/Renderable/ProductSkuTable.php b/app/Admin/Renderable/ProductSkuTable.php index a4e63ef1..a38c5079 100644 --- a/app/Admin/Renderable/ProductSkuTable.php +++ b/app/Admin/Renderable/ProductSkuTable.php @@ -110,7 +110,7 @@ class ProductSkuTable extends Grid $grid->filter(function (Grid\Filter $filter) { $filter->panel(); $filter->expand(); - $filter->equal('name')->width(3); + $filter->like('name')->width(3); }); }); diff --git a/app/Admin/Services/OrderService.php b/app/Admin/Services/OrderService.php index 5a22d39d..966b2a88 100644 --- a/app/Admin/Services/OrderService.php +++ b/app/Admin/Services/OrderService.php @@ -3,6 +3,7 @@ namespace App\Admin\Services; use App\Enums\PayWay; +use App\Events\OrderPaid; use App\Exceptions\BizException; use App\Models\Order; use App\Models\OrderLog; @@ -44,7 +45,8 @@ class OrderService //操作订单状态-需要调整为统一支付方法 $orderService = new EndpointOrderService(); $orderService->pay($order, PayWay::Offline); - + //注册支付成功事件 + OrderPaid::dispatch($order); //记录操作日志 OrderLog::create([ 'order_id'=> $order->id, diff --git a/app/Listeners/SendCoupons.php b/app/Listeners/SendCoupons.php index 8b763205..18fc4272 100644 --- a/app/Listeners/SendCoupons.php +++ b/app/Listeners/SendCoupons.php @@ -3,7 +3,11 @@ namespace App\Listeners; use App\Events\OrderPaid; +use App\Models\ActivityProductPart; +use App\Models\ProductPartSku; +use App\Models\UserCoupon; use App\Services\CouponService; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; use Throwable; @@ -34,26 +38,37 @@ class SendCoupons // 处理购买分区商品送券 try { DB::beginTransaction(); - - $products = $order->products()->with('sku.parts')->get(); - - // 整理订单商品的分区 - $inValidParts = []; - - foreach ($products->pluck('sku.parts') as $parts) { - foreach ($parts as $part) { - if ($part->is_show) { - // 分区去重 - $inValidParts[$part->id] = $part; + $products = $order->products()->where('is_gift', false)->get()->toArray(); + $_products = array_column($products, 'total_amount', 'sku_id'); + $partSkus = ProductPartSku::with('part')->whereIn('sku_id', array_keys($_products))->get(); + foreach ($partSkus as $partSku) { + if ($partSku->part?->is_show) { + if (isset($inValidParts[$partSku->part_id])) { + $inValidParts[$partSku->part_id] += $_products[$partSku->sku_id] ?? 0; + } else { + $inValidParts[$partSku->part_id] = $_products[$partSku->sku_id] ?? 0; } } } - //根据分区整理参与的活动--todo - //根据活动规则计算发送券--todo - - // foreach ($inValidParts as $inValidPart) { - // $this->couponService->receivePartCoupon($inValidPart, $order->user); - // } + //根据分区获取活动 + $partActivities = ActivityProductPart::with(['activity', 'activity.gifts'])->whereHas('activity', function (Builder $query) { + return $query->where('is_use', true)->where('started_at', '<', now())->where('ended_at', '>=', now()); + })->whereIn('part_id', array_keys($inValidParts))->get(); + //根据活动规则计算发送券 + foreach ($partActivities as $partActivity) { + //获取活动的赠送规则 + $_giftsRule = $partActivity->activity?->gifts_rule; + //判断是否首单:times=0为仅首单赠送, 1为不限 + if ($_giftsRule['times'] == 0 && UserCoupon::where('activity_id', $partActivity->activity_id)->exists()) { + continue;//提前结束本次循环 + } + //判断是否满足门槛 + if (bcdiv($_giftsRule['value'], 100) > $inValidParts[$partActivity->part_id]) { + continue;//提前结束本次循环 + } + //赠券 + (new CouponService())->receiveActivityCoupons($partActivity->activity, $order->user, $order->id); + } DB::commit(); } catch (Throwable $th) { diff --git a/app/Models/Activity.php b/app/Models/Activity.php index de2d2dab..92df503f 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -39,11 +39,11 @@ class Activity extends Model public function coupons() { - return $this->belongsToMany(Coupon::class, 'activity_coupons', 'activity_id', 'coupon_id'); + return $this->belongsToMany(Coupon::class, 'activity_coupons', 'activity_id', 'coupon_id')->withPivot('qty'); } public function gifts() { - return $this->belongsToMany(ProductSku::class, 'activity_gifts', 'activity_id', 'sku_id'); + return $this->belongsToMany(ProductSku::class, 'activity_gifts', 'activity_id', 'sku_id')->withPivot('qty'); } } diff --git a/app/Models/ActivityProductPart.php b/app/Models/ActivityProductPart.php index b5eba95a..77b61ea2 100644 --- a/app/Models/ActivityProductPart.php +++ b/app/Models/ActivityProductPart.php @@ -12,4 +12,14 @@ class ActivityProductPart extends Model protected $fillable = [ 'activity_id', 'part_id', ]; + + public function part() + { + return $this->belongsTo(Part::class, 'part_id'); + } + + public function activity() + { + return $this->belongsTo(Activity::class, 'activity_id'); + } } diff --git a/app/Models/OrderActivityInfo.php b/app/Models/OrderActivityInfo.php new file mode 100644 index 00000000..f5ea351b --- /dev/null +++ b/app/Models/OrderActivityInfo.php @@ -0,0 +1,14 @@ + 'json', + 'is_gift'=>'boolean', ]; /** @@ -38,6 +39,8 @@ class OrderProduct extends Model 'after_sale_state', 'after_expire_at', 'remain_quantity', + 'is_gift', + 'activity_id', ]; public function packageProducts() @@ -97,7 +100,7 @@ class OrderProduct extends Model */ public function isGift() { - return $this->gift_for_sku_id !== null; + return $this->gift_for_sku_id !== null || $this->is_gift == true; } /** diff --git a/app/Services/CouponService.php b/app/Services/CouponService.php index ce428aff..de955f88 100644 --- a/app/Services/CouponService.php +++ b/app/Services/CouponService.php @@ -2,6 +2,7 @@ namespace App\Services; +use App\Models\Activity; use App\Models\Coupon; use App\Models\ProductPart; use App\Models\ReceivePartCouponLog; @@ -84,6 +85,22 @@ class CouponService ReceivePartCouponLog::create(['user_id'=>$user->id, 'part_id'=>$part->id]); } + /** + * 根据活动领取优惠券 + * + * @return void + */ + public function receiveActivityCoupons(Activity $activity, User $user) + { + foreach ($activity->coupons as $coupon) { + $someCoupons[] = [ + 'coupon'=>$coupon, + 'num'=>$coupon->pivot->qty, + ]; + } + $this->receiveSomeCoupons($user, $someCoupons, $activity->id); + } + /** * 领取一批券 * @@ -91,12 +108,12 @@ class CouponService * @param array $coupons * @return void */ - protected function receiveSomeCoupons(User $user, array $coupons) + protected function receiveSomeCoupons(User $user, array $coupons, ?int $activityId = null) { $userCoupons = []; foreach ($coupons as $coupon) { - for ($i=0; $i<$coupon['num']; $i++) { - $userCoupons[] = self::createUserCouponData($user->id, $coupon['coupon']); + for ($i = 0; $i < $coupon['num']; $i++) { + $userCoupons[] = self::createUserCouponData($user->id, $coupon['coupon'], $activityId ?? null); } //更新对应券发送量,余量; $coupon['coupon']->increment('sent', $coupon['num']); @@ -126,7 +143,7 @@ class CouponService * * @return array */ - public static function createUserCouponData(int $userId, Coupon $coupon) + public static function createUserCouponData(int $userId, Coupon $coupon, ?int $activityId = null) { //如果userId小于等于0,直接退出 if ($userId <= 0) { @@ -150,6 +167,7 @@ class CouponService 'use_end_at' => $useEndAt, 'created_at' => now(), 'updated_at' => now(), + 'activity_id' => $activityId ?? null, ]; } } diff --git a/app/Services/OrderService.php b/app/Services/OrderService.php index dc816a5a..2b7e91de 100644 --- a/app/Services/OrderService.php +++ b/app/Services/OrderService.php @@ -10,16 +10,19 @@ use App\Enums\SocialiteType; use App\Enums\WxpayTradeType; use App\Exceptions\BizException; use App\Exceptions\ShippingNotSupportedException; +use App\Models\ActivityProductPart; use App\Models\DistributionPreIncomeJob; use App\Models\Order; use App\Models\OrderProduct; use App\Models\ProductGift; +use App\Models\ProductPartSku; use App\Models\ProductSku; use App\Models\ShippingAddress; use App\Models\SocialiteUser; use App\Models\User; use App\Models\UserCoupon; use App\Services\Payment\WxpayService; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\QueryException; use Illuminate\Support\Facades\DB; @@ -240,6 +243,7 @@ class OrderService $orderProducts[] = [ 'gift_for_sku_id' => null, + 'is_gift'=> false, 'user_id' => $order->user_id, 'order_id' => $order->id, 'spu_id' => $sku->spu_id, @@ -263,35 +267,10 @@ class OrderService // 扣除商品库存 $this->deductProduct($sku, $qty); - //根据订单参加的活动添加赠品 --todo; - $gifts = []; - foreach ($gifts as $gift) { - $giftSku = $gift['sku']; - - $orderProducts[] = [ - 'gift_for_sku_id' => $sku->id, - 'user_id' => $order->user_id, - 'order_id' => $order->id, - 'spu_id' => $giftSku->spu_id, - 'sku_id' => $giftSku->id, - 'category_id' => $giftSku->category_id, - 'name' => $giftSku->name, - 'specs' => json_encode($giftSku->specs), - 'cover' => $giftSku->cover, - 'weight' => $giftSku->weight, - 'sell_price' => $giftSku->sell_price, - 'vip_price' => $giftSku->vip_price, - 'sales_value' => 0, // 赠品不算销售值 - 'quantity' => $gift['num'], - 'remain_quantity' => $gift['num'], // 剩余发货数量 - 'coupon_discount_amount' => 0, - 'vip_discount_amount' => 0, - 'total_amount' => 0, - 'created_at' => $order->created_at, - 'updated_at' => $order->updated_at, - ]; - } } + //根据订单参加的活动添加赠品; + $gifts = $this->activityGifts($order, $orderProducts); + $orderProducts = array_merge($orderProducts, $gifts); OrderProduct::insert($orderProducts); } @@ -384,6 +363,80 @@ class OrderService return $gifts; } + /** + * Undocumented function + * + * @param Order $order + * @param [type] $products + * @return array $gifts + */ + protected function activityGifts(Order $order, $products) + { + $_products = array_column($products, 'total_amount', 'sku_id'); + + $inValidParts = []; + // 整理订单商品的分区 + $partSkus = ProductPartSku::with('part')->whereIn('sku_id', array_keys($_products))->get(); + foreach ($partSkus as $partSku) { + if ($partSku->part?->is_show) { + if (isset($inValidParts[$partSku->part_id])) { + $inValidParts[$partSku->part_id] += $_products[$partSku->sku_id] ?? 0; + } else { + $inValidParts[$partSku->part_id] = $_products[$partSku->sku_id] ?? 0; + } + } + } + //根据分区获取活动 + $partActivities = ActivityProductPart::with(['activity', 'activity.gifts'])->whereHas('activity', function (Builder $query) { + return $query->where('is_use', true)->where('started_at', '<', now())->where('ended_at', '>=', now()); + })->whereIn('part_id', array_keys($inValidParts))->get(); + + $giveGifts = []; + foreach ($partActivities as $partActivity) { + //获取活动的赠送规则 + $_giftsRule = $partActivity->activity?->gifts_rule; + //判断是否首单:times=0为仅首单赠送, 1为不限 + if ($_giftsRule['times'] == 0 && OrderProduct::where('activity_id', $partActivity->activity_id)->exists()) { + continue;//提前结束本次循环 + } + //判断是否满足门槛 + if (bcdiv($_giftsRule['value'], 100) > $inValidParts[$partActivity->part_id]) { + continue;//提前结束本次循环 + } + //返回赠品 + $_gifts = $partActivity->activity->gifts; + foreach ($_gifts as $_gift) { + $giveGifts[] = [ + 'gift_for_sku_id'=> null, + 'user_id' => $order->user_id, + 'order_id' => $order->id, + 'spu_id' => $_gift->spu_id, + 'sku_id' => $_gift->id, + 'category_id' => $_gift->category_id, + 'name' => $_gift->name, + 'specs' => json_encode($_gift->specs), + 'cover' => $_gift->cover, + 'weight' => $_gift->weight, + 'sell_price' => $_gift->sell_price, + 'vip_price' => $_gift->vip_price, + 'sales_value' => 0, // 赠品不算销售值 + 'quantity' => $_gift->pivot->qty, + 'remain_quantity' => $_gift->pivot->qty, // 剩余发货数量 + 'coupon_discount_amount' => 0, + 'vip_discount_amount' => 0, + 'total_amount' => 0, + 'created_at' => $order->created_at, + 'updated_at' => $order->updated_at, + 'is_gift'=> true, + ]; + // 扣除商品库存 + $this->deductProduct($_gift, $_gift->pivot->qty); + } + } + + return $giveGifts; + } + /** * 确认快速下单 * diff --git a/database/migrations/2022_03_17_111153_add_is_gift_to_order_products_table.php b/database/migrations/2022_03_17_111153_add_is_gift_to_order_products_table.php new file mode 100644 index 00000000..4b379634 --- /dev/null +++ b/database/migrations/2022_03_17_111153_add_is_gift_to_order_products_table.php @@ -0,0 +1,35 @@ +unsignedTinyInteger('is_gift')->nullable()->default(0)->comment('是否赠品'); + $table->unsignedBigInteger('activity_id')->nullable()->comment('参与活动ID'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('order_products', function (Blueprint $table) { + // + $table->dropColumn(['is_gift', 'activity_id']); + }); + } +} diff --git a/database/migrations/2022_03_17_145215_add_activity_id_to_user_coupons_table.php b/database/migrations/2022_03_17_145215_add_activity_id_to_user_coupons_table.php new file mode 100644 index 00000000..f1ed1f77 --- /dev/null +++ b/database/migrations/2022_03_17_145215_add_activity_id_to_user_coupons_table.php @@ -0,0 +1,34 @@ +unsignedBigInteger('activity_id')->nullable()->comment('参与活动ID'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('user_coupons', function (Blueprint $table) { + // + $table->dropColumn(['activity_id']); + }); + } +}