6
0
Fork 0

添加活动管理,以及订单参与活动发券发赠品

release
vine_liutk 2022-03-17 16:09:31 +08:00
parent 6b7d6d6ba1
commit 831d49533e
12 changed files with 240 additions and 56 deletions

View File

@ -322,8 +322,8 @@ class OrderController extends AdminController
$builder = OrderProduct::withCount('afterSales')->where('order_id', $id); $builder = OrderProduct::withCount('afterSales')->where('order_id', $id);
$productGrid = Grid::make($builder, function (Grid $grid) { $productGrid = Grid::make($builder, function (Grid $grid) {
$grid->column('name')->display(function ($value) { $grid->column('name')->display(function ($value) {
if ($this->gift_for_sku_id) { if ($this->isGift()) {
$value .= '-【赠品】'; $value = '【赠品】'.$value;
} }
return $value; return $value;
}); });

View File

@ -110,7 +110,7 @@ class ProductSkuTable extends Grid
$grid->filter(function (Grid\Filter $filter) { $grid->filter(function (Grid\Filter $filter) {
$filter->panel(); $filter->panel();
$filter->expand(); $filter->expand();
$filter->equal('name')->width(3); $filter->like('name')->width(3);
}); });
}); });

View File

@ -3,6 +3,7 @@
namespace App\Admin\Services; namespace App\Admin\Services;
use App\Enums\PayWay; use App\Enums\PayWay;
use App\Events\OrderPaid;
use App\Exceptions\BizException; use App\Exceptions\BizException;
use App\Models\Order; use App\Models\Order;
use App\Models\OrderLog; use App\Models\OrderLog;
@ -44,7 +45,8 @@ class OrderService
//操作订单状态-需要调整为统一支付方法 //操作订单状态-需要调整为统一支付方法
$orderService = new EndpointOrderService(); $orderService = new EndpointOrderService();
$orderService->pay($order, PayWay::Offline); $orderService->pay($order, PayWay::Offline);
//注册支付成功事件
OrderPaid::dispatch($order);
//记录操作日志 //记录操作日志
OrderLog::create([ OrderLog::create([
'order_id'=> $order->id, 'order_id'=> $order->id,

View File

@ -3,7 +3,11 @@
namespace App\Listeners; namespace App\Listeners;
use App\Events\OrderPaid; use App\Events\OrderPaid;
use App\Models\ActivityProductPart;
use App\Models\ProductPartSku;
use App\Models\UserCoupon;
use App\Services\CouponService; use App\Services\CouponService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Throwable; use Throwable;
@ -34,26 +38,37 @@ class SendCoupons
// 处理购买分区商品送券 // 处理购买分区商品送券
try { try {
DB::beginTransaction(); DB::beginTransaction();
$products = $order->products()->where('is_gift', false)->get()->toArray();
$products = $order->products()->with('sku.parts')->get(); $_products = array_column($products, 'total_amount', 'sku_id');
$partSkus = ProductPartSku::with('part')->whereIn('sku_id', array_keys($_products))->get();
// 整理订单商品的分区 foreach ($partSkus as $partSku) {
$inValidParts = []; if ($partSku->part?->is_show) {
if (isset($inValidParts[$partSku->part_id])) {
foreach ($products->pluck('sku.parts') as $parts) { $inValidParts[$partSku->part_id] += $_products[$partSku->sku_id] ?? 0;
foreach ($parts as $part) { } else {
if ($part->is_show) { $inValidParts[$partSku->part_id] = $_products[$partSku->sku_id] ?? 0;
// 分区去重
$inValidParts[$part->id] = $part;
} }
} }
} }
//根据分区整理参与的活动--todo //根据分区获取活动
//根据活动规则计算发送券--todo $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());
// foreach ($inValidParts as $inValidPart) { })->whereIn('part_id', array_keys($inValidParts))->get();
// $this->couponService->receivePartCoupon($inValidPart, $order->user); //根据活动规则计算发送券
// } 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(); DB::commit();
} catch (Throwable $th) { } catch (Throwable $th) {

View File

@ -39,11 +39,11 @@ class Activity extends Model
public function coupons() 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() 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');
} }
} }

View File

@ -12,4 +12,14 @@ class ActivityProductPart extends Model
protected $fillable = [ protected $fillable = [
'activity_id', 'part_id', 'activity_id', 'part_id',
]; ];
public function part()
{
return $this->belongsTo(Part::class, 'part_id');
}
public function activity()
{
return $this->belongsTo(Activity::class, 'activity_id');
}
} }

View File

@ -0,0 +1,14 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class OrderActivityInfo extends Model
{
use HasFactory;
public const TYPE_GIFT = 1;
public const TYPE_COUPON = 2;
}

View File

@ -11,6 +11,7 @@ class OrderProduct extends Model
*/ */
protected $casts = [ protected $casts = [
'specs' => 'json', 'specs' => 'json',
'is_gift'=>'boolean',
]; ];
/** /**
@ -38,6 +39,8 @@ class OrderProduct extends Model
'after_sale_state', 'after_sale_state',
'after_expire_at', 'after_expire_at',
'remain_quantity', 'remain_quantity',
'is_gift',
'activity_id',
]; ];
public function packageProducts() public function packageProducts()
@ -97,7 +100,7 @@ class OrderProduct extends Model
*/ */
public function isGift() public function isGift()
{ {
return $this->gift_for_sku_id !== null; return $this->gift_for_sku_id !== null || $this->is_gift == true;
} }
/** /**

View File

@ -2,6 +2,7 @@
namespace App\Services; namespace App\Services;
use App\Models\Activity;
use App\Models\Coupon; use App\Models\Coupon;
use App\Models\ProductPart; use App\Models\ProductPart;
use App\Models\ReceivePartCouponLog; use App\Models\ReceivePartCouponLog;
@ -84,6 +85,22 @@ class CouponService
ReceivePartCouponLog::create(['user_id'=>$user->id, 'part_id'=>$part->id]); 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 * @param array $coupons
* @return void * @return void
*/ */
protected function receiveSomeCoupons(User $user, array $coupons) protected function receiveSomeCoupons(User $user, array $coupons, ?int $activityId = null)
{ {
$userCoupons = []; $userCoupons = [];
foreach ($coupons as $coupon) { foreach ($coupons as $coupon) {
for ($i=0; $i<$coupon['num']; $i++) { for ($i = 0; $i < $coupon['num']; $i++) {
$userCoupons[] = self::createUserCouponData($user->id, $coupon['coupon']); $userCoupons[] = self::createUserCouponData($user->id, $coupon['coupon'], $activityId ?? null);
} }
//更新对应券发送量,余量; //更新对应券发送量,余量;
$coupon['coupon']->increment('sent', $coupon['num']); $coupon['coupon']->increment('sent', $coupon['num']);
@ -126,7 +143,7 @@ class CouponService
* *
* @return array * @return array
*/ */
public static function createUserCouponData(int $userId, Coupon $coupon) public static function createUserCouponData(int $userId, Coupon $coupon, ?int $activityId = null)
{ {
//如果userId小于等于0直接退出 //如果userId小于等于0直接退出
if ($userId <= 0) { if ($userId <= 0) {
@ -150,6 +167,7 @@ class CouponService
'use_end_at' => $useEndAt, 'use_end_at' => $useEndAt,
'created_at' => now(), 'created_at' => now(),
'updated_at' => now(), 'updated_at' => now(),
'activity_id' => $activityId ?? null,
]; ];
} }
} }

View File

@ -10,16 +10,19 @@ use App\Enums\SocialiteType;
use App\Enums\WxpayTradeType; use App\Enums\WxpayTradeType;
use App\Exceptions\BizException; use App\Exceptions\BizException;
use App\Exceptions\ShippingNotSupportedException; use App\Exceptions\ShippingNotSupportedException;
use App\Models\ActivityProductPart;
use App\Models\DistributionPreIncomeJob; use App\Models\DistributionPreIncomeJob;
use App\Models\Order; use App\Models\Order;
use App\Models\OrderProduct; use App\Models\OrderProduct;
use App\Models\ProductGift; use App\Models\ProductGift;
use App\Models\ProductPartSku;
use App\Models\ProductSku; use App\Models\ProductSku;
use App\Models\ShippingAddress; use App\Models\ShippingAddress;
use App\Models\SocialiteUser; use App\Models\SocialiteUser;
use App\Models\User; use App\Models\User;
use App\Models\UserCoupon; use App\Models\UserCoupon;
use App\Services\Payment\WxpayService; use App\Services\Payment\WxpayService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@ -240,6 +243,7 @@ class OrderService
$orderProducts[] = [ $orderProducts[] = [
'gift_for_sku_id' => null, 'gift_for_sku_id' => null,
'is_gift'=> false,
'user_id' => $order->user_id, 'user_id' => $order->user_id,
'order_id' => $order->id, 'order_id' => $order->id,
'spu_id' => $sku->spu_id, 'spu_id' => $sku->spu_id,
@ -263,35 +267,10 @@ class OrderService
// 扣除商品库存 // 扣除商品库存
$this->deductProduct($sku, $qty); $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); OrderProduct::insert($orderProducts);
} }
@ -384,6 +363,80 @@ class OrderService
return $gifts; 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;
}
/** /**
* 确认快速下单 * 确认快速下单
* *

View File

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddIsGiftToOrderProductsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('order_products', function (Blueprint $table) {
//
$table->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']);
});
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddActivityIdToUserCouponsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('user_coupons', function (Blueprint $table) {
//
$table->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']);
});
}
}