6
0
Fork 0

创建订单时,如果有赠品需扣赠品

release
李静 2021-12-21 11:34:10 +08:00
parent 8f4866ff05
commit 07256db41b
7 changed files with 227 additions and 56 deletions

View File

@ -10,10 +10,9 @@ use App\Exceptions\BizException;
use App\Helpers\Paginator as PaginatorHelper;
use App\Models\KuaidiLog;
use App\Services\OrderService;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Throwable;
class OrderController extends Controller
{
@ -94,13 +93,13 @@ class OrderController extends Controller
$request->input('coupon_id'),
$request->input('note'),
);
}, 3);
} catch (ModelNotFoundException | BizException $e) {
throw $e;
} catch (Throwable $e) {
report($e);
});
} catch (QueryException $e) {
if (strpos($e->getMessage(), 'Numeric value out of range') !== false) {
$e = new BizException('商品库存不足');
}
throw new BizException('系统繁忙,请稍后再试');
throw $e;
}
return OrderResource::make($order);
@ -133,19 +132,11 @@ class OrderController extends Controller
{
$user = $request->user();
try {
return DB::transaction(function () use ($id, $user) {
$order = $user->orders()->lockForUpdate()->findOrFail($id);
DB::transaction(function () use ($id, $user) {
$order = $user->orders()->lockForUpdate()->findOrFail($id);
(new OrderService())->confirm($order);
});
} catch (ModelNotFoundException | BizException $e) {
throw $e;
} catch (Throwable $e) {
report($e);
throw new BizException('确认失败,请重试');
}
(new OrderService())->confirm($order);
});
return response()->noContent();
}
@ -161,19 +152,11 @@ class OrderController extends Controller
{
$user = $request->user();
try {
return DB::transaction(function () use ($id, $user) {
$order = $user->orders()->lockForUpdate()->findOrFail($id);
DB::transaction(function () use ($id, $user) {
$order = $user->orders()->lockForUpdate()->findOrFail($id);
(new OrderService())->cancel($order);
});
} catch (ModelNotFoundException | BizException $e) {
throw $e;
} catch (Throwable $e) {
report($e);
throw new BizException('取消失败,请重试');
}
(new OrderService())->cancel($order);
});
return response()->noContent();
}
@ -193,19 +176,11 @@ class OrderController extends Controller
$user = $request->user();
try {
return DB::transaction(function () use ($id, $user, $input) {
$order = $user->orders()->findOrFail($id);
return DB::transaction(function () use ($id, $user, $input) {
$order = $user->orders()->findOrFail($id);
return (new OrderService())->pay($order, $input['pay_way']);
});
} catch (ModelNotFoundException | BizException $e) {
throw $e;
} catch (Throwable $e) {
report($e);
throw new BizException('支付失败,请重试');
}
return (new OrderService())->pay($order, $input['pay_way']);
});
}
/**

View File

@ -17,6 +17,7 @@ class OrderProduct extends Model
* @var array
*/
protected $fillable = [
'gift_for_sku_id',
'user_id',
'order_id',
'spu_id',
@ -76,6 +77,16 @@ class OrderProduct extends Model
return $this->belongsTo(ProductSku::class, 'sku_id');
}
/**
* 确认此订单商品是否是赠品
*
* @return bool
*/
public function isGift()
{
return $this->gift_for_sku_id !== null;
}
/**
* 获取订单商品是否能发起售后
*

View File

@ -2,13 +2,10 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ProductGift extends Model
{
use HasFactory;
/**
* @var array
*/
@ -17,5 +14,14 @@ class ProductGift extends Model
'gift_sku_id',
'num',
'sent',
'remaining',
];
/**
* 赠送的商品 SKU
*/
public function giftSku()
{
return $this->belongsTo(ProductSku::class, 'gift_sku_id');
}
}

View File

@ -16,6 +16,7 @@ use App\Models\ProductSku;
use App\Models\ShippingAddress;
use App\Models\User;
use App\Models\UserCoupon;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
class OrderService
@ -170,11 +171,13 @@ class OrderService
foreach ($mapProducts as $product) {
$sku = $product['sku'];
$qty = $product['quantity'];
// 支付金额 = 商品总额 - 优惠券折扣金额- 会员折扣金额
$totalAmount = $product['total_amount'] - $product['coupon_discount_amount'] - $product['vip_discount_amount'];
$orderProducts[] = [
'gift_for_sku_id' => null,
'user_id' => $order->user_id,
'order_id' => $order->id,
'spu_id' => $sku->spu_id,
@ -186,8 +189,8 @@ class OrderService
'weight' => $sku->weight,
'sell_price' => $sku->sell_price,
'vip_price' => $sku->vip_price,
'quantity' => $product['quantity'],
'remain_quantity' => $product['quantity'],
'quantity' => $qty,
'remain_quantity' => $qty, // 剩余发货数量
'coupon_discount_amount' => $product['coupon_discount_amount'],
'vip_discount_amount' => $product['vip_discount_amount'],
'total_amount' => $totalAmount,
@ -195,9 +198,34 @@ class OrderService
'updated_at' => $order->updated_at,
];
$sku->update([
'stock' => DB::raw("stock - {$product['quantity']}"), // 库存
]);
// 将赠品加入订单中
$gifts = $this->deductProduct($sku, $qty);
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,
'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,
];
}
}
// 处理赠品
@ -209,6 +237,90 @@ class OrderService
return $order;
}
/**
* 扣商品的库存和赠品数量
*
* @param \App\Models\ProductSku $sku
* @param int $qty
* @return array
*/
protected function deductProduct(ProductSku $sku, int $qty)
{
// 扣商品库存
$sku->update([
'stock' => DB::raw("stock - {$qty}"), // 库存
]);
try {
return retry(5, function () use ($sku, $qty) {
return $this->deductGifts($sku, $qty);
}, 0, function ($e) {
// 如果赠品库存不足时,需重试
return $e instanceof QueryException
&& strpos($e->getMessage(), 'Numeric value out of range') !== false;
});
} catch (QueryException $e) {
// 赠品库存不足
if (strpos($e->getMessage(), 'Numeric value out of range') !== false) {
$e = new BizException('下单人数过多,请稍后再试!');
}
throw $e;
}
}
/**
* 扣出商品的赠品
*
* @param \App\Models\ProductSku $sku
* @param int $qty
* @return array
*/
protected function deductGifts(ProductSku $sku, int $qty)
{
// 赠品
$gifts = [];
if ($qty < 1) {
return $gifts;
}
$sku->gifts->loadMissing('giftSku');
foreach ($sku->gifts as $gift) {
// 如果未找到赠品,则不赠送
if ($gift->giftSku === null) {
continue;
}
// 如果赠品有限,且剩余数量不足时,直接赠送剩余赠品
if ($gift->limit !== 0 && $gift->remaining < $qty) {
$qty = $gift->remaining;
}
// 如果赠送的份数小于1则不赠送
if ($qty < 1) {
continue;
}
if ($gift->limit === 0) {
$gift->increment('sent', $qty);
} else {
$gift->update([
'remaining' => DB::raw("remaining-{$qty}"),
'sent' => DB::raw("sent+{$qty}"),
]);
}
$gifts[] = [
'sku' => $gift->giftSku,
'num' => $qty*$gift->num, // 赠送商品总数
];
}
return $gifts;
}
/**
* 确认快速下单
*
@ -678,7 +790,10 @@ class OrderService
$products = $order->products()->get();
foreach ($products->load('sku') as $product) {
$product->sku?->increment('stock', $product->quantity);
// 取消订单时,赠品不退回
if (! $product->isGift()) {
$product->sku?->increment('stock', $product->quantity);
}
}
$order->update([

View File

@ -17,9 +17,9 @@ class CreateProductGiftsTable extends Migration
$table->id();
$table->unsignedBigInteger('sku_id')->comment('主SKU商品ID');
$table->unsignedBigInteger('gift_sku_id')->comment('赠品SKU商品ID');
$table->unsignedInteger('num')->default(0)->comment('赠送数量');
$table->unsignedInteger('limit')->default(0)->comment('上限数量');
$table->unsignedInteger('sent')->default(0)->comment('已送数量');
$table->unsignedInteger('num')->default(0)->comment('每份赠送数量');
$table->unsignedInteger('limit')->default(0)->comment('上限(份)');
$table->unsignedInteger('sent')->default(0)->comment('已送(份)');
$table->timestamps();
});
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddRemainingToProductGiftsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('product_gifts', function (Blueprint $table) {
$table->unsignedInteger('remaining')->default(0)->comment('剩余(份)');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('product_gifts', function (Blueprint $table) {
$table->dropColumn(['remaining']);
});
}
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddGiftForSkuIdToOrderProductsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('order_products', function (Blueprint $table) {
$table->unsignedBigInteger('gift_for_sku_id')->nullable()->comment('礼品所属的商品 SKU');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('order_products', function (Blueprint $table) {
$table->dropColumn(['gift_for_sku_id']);
});
}
}