From 07256db41bef37d26993740afebed08de97f4efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=9D=99?= Date: Tue, 21 Dec 2021 11:34:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E8=AE=A2=E5=8D=95=E6=97=B6,?= =?UTF-8?q?=E5=A6=82=E6=9E=9C=E6=9C=89=E8=B5=A0=E5=93=81=E9=9C=80=E6=89=A3?= =?UTF-8?q?=E8=B5=A0=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Order/OrderController.php | 63 +++------ app/Models/OrderProduct.php | 11 ++ app/Models/ProductGift.php | 12 +- app/Services/OrderService.php | 127 +++++++++++++++++- ...2_06_135928_create_product_gifts_table.php | 6 +- ...9_add_remaining_to_product_gifts_table.php | 32 +++++ ...ift_for_sku_id_to_order_products_table.php | 32 +++++ 7 files changed, 227 insertions(+), 56 deletions(-) create mode 100644 database/migrations/2021_12_20_202109_add_remaining_to_product_gifts_table.php create mode 100644 database/migrations/2021_12_20_212555_add_gift_for_sku_id_to_order_products_table.php diff --git a/app/Endpoint/Api/Http/Controllers/Order/OrderController.php b/app/Endpoint/Api/Http/Controllers/Order/OrderController.php index e8dc784e..2b86c985 100644 --- a/app/Endpoint/Api/Http/Controllers/Order/OrderController.php +++ b/app/Endpoint/Api/Http/Controllers/Order/OrderController.php @@ -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']); + }); } /** diff --git a/app/Models/OrderProduct.php b/app/Models/OrderProduct.php index 1301f87b..5a7e31a1 100644 --- a/app/Models/OrderProduct.php +++ b/app/Models/OrderProduct.php @@ -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; + } + /** * 获取订单商品是否能发起售后 * diff --git a/app/Models/ProductGift.php b/app/Models/ProductGift.php index bae2fe46..dc445125 100644 --- a/app/Models/ProductGift.php +++ b/app/Models/ProductGift.php @@ -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'); + } } diff --git a/app/Services/OrderService.php b/app/Services/OrderService.php index 875da72e..4ea0fedc 100644 --- a/app/Services/OrderService.php +++ b/app/Services/OrderService.php @@ -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([ diff --git a/database/migrations/2021_12_06_135928_create_product_gifts_table.php b/database/migrations/2021_12_06_135928_create_product_gifts_table.php index 0268ca33..ee38623d 100644 --- a/database/migrations/2021_12_06_135928_create_product_gifts_table.php +++ b/database/migrations/2021_12_06_135928_create_product_gifts_table.php @@ -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(); }); } diff --git a/database/migrations/2021_12_20_202109_add_remaining_to_product_gifts_table.php b/database/migrations/2021_12_20_202109_add_remaining_to_product_gifts_table.php new file mode 100644 index 00000000..0ef162a5 --- /dev/null +++ b/database/migrations/2021_12_20_202109_add_remaining_to_product_gifts_table.php @@ -0,0 +1,32 @@ +unsignedInteger('remaining')->default(0)->comment('剩余(份)'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('product_gifts', function (Blueprint $table) { + $table->dropColumn(['remaining']); + }); + } +} diff --git a/database/migrations/2021_12_20_212555_add_gift_for_sku_id_to_order_products_table.php b/database/migrations/2021_12_20_212555_add_gift_for_sku_id_to_order_products_table.php new file mode 100644 index 00000000..2436bc34 --- /dev/null +++ b/database/migrations/2021_12_20_212555_add_gift_for_sku_id_to_order_products_table.php @@ -0,0 +1,32 @@ +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']); + }); + } +}