diff --git a/app/Admin/Controllers/Store/StockController.php b/app/Admin/Controllers/Store/StockController.php index e78c1e96..3d9beba0 100644 --- a/app/Admin/Controllers/Store/StockController.php +++ b/app/Admin/Controllers/Store/StockController.php @@ -58,7 +58,8 @@ class StockController extends Controller 'amount' => $product->pivot->amount + $amount ]); $store->stockLogs()->create([ - 'administrator_id' => $administrator->id, + 'operator_type' => get_class($administrator), + 'operator_id' => $administrator->id, 'amount' => $request->input('amount'), 'product_sku_id' => $product->id, 'remarks' => $request->input('remarks'), diff --git a/app/Admin/Controllers/Store/StoreController.php b/app/Admin/Controllers/Store/StoreController.php index ae0c94d9..32d6026c 100644 --- a/app/Admin/Controllers/Store/StoreController.php +++ b/app/Admin/Controllers/Store/StoreController.php @@ -182,7 +182,7 @@ class StoreController extends AdminController protected function gridStock($id) { - $grid = new Grid(StockLog::with(['productSku', 'administrator', 'source', 'tag'])); + $grid = new Grid(StockLog::with(['productSku', 'operator', 'source', 'tag'])); $grid->model()->where('store_id', $id)->orderBy('created_at', 'desc'); @@ -191,7 +191,15 @@ class StoreController extends AdminController $grid->column('productSku.name', '商品'); $grid->column('amount', '库存'); $grid->column('tag.name', '类目'); - $grid->column('administrator.name', '操作人'); + $grid->column('operator', '操作人')->display(function ($v) { + if ($v instanceof \App\Models\Admin\Administrator) { + return $v->name . '管理员'; + } else if ($v instanceof \App\Models\User) { + return $v->phone . '用户'; + } + + return '未知身份'; + }); $grid->column('remarks', '备注'); $grid->column('created_at', '操作时间'); diff --git a/app/Admin/Forms/OrderPackage.php b/app/Admin/Forms/OrderPackage.php index a491e16a..392bdf52 100644 --- a/app/Admin/Forms/OrderPackage.php +++ b/app/Admin/Forms/OrderPackage.php @@ -4,12 +4,13 @@ namespace App\Admin\Forms; use App\Admin\Services\OrderPackageService; use App\Exceptions\BizException; -use App\Models\Order; +use App\Models\{Order, Tag}; use Dcat\Admin\Contracts\LazyRenderable; use Dcat\Admin\Traits\LazyWidget; use Dcat\Admin\Widgets\Form; use Illuminate\Support\Facades\DB; use Throwable; +use Dcat\Admin\Admin; class OrderPackage extends Form implements LazyRenderable { @@ -43,6 +44,39 @@ class OrderPackage extends Form implements LazyRenderable DB::beginTransaction(); $orderPackageService = new OrderPackageService(); $orderPackageService->createPackage($order, $input); + // 店铺发货, 添加出库记录 + if ($order->store) { + $packageProducts = $input['packages']; + $operator = Admin::user(); + $store = $order->store; + $tag = Tag::firstOrCreate([ + 'type' => Tag::TYPE_STORE_STOCK, + 'name' => '发货' + ]); + foreach($packageProducts as $item) { + $order_product = $order->products()->findOrFail($item['order_product_id']); + $amount = $item['quantity']; + $sku_id = $order_product->sku_id; + $product = $store->productSkus()->findOrFail($sku_id); + if ($product->pivot->amount - $amount < 0) { + throw new BizException('店铺的 ' . $product->name .' 库存不足'); + } + + $store->productSkus()->updateExistingPivot($product->id, [ + 'amount' => $product->pivot->amount - $amount + ]); + $store->stockLogs()->create([ + 'operator_type' => get_class($operator), + 'operator_id' => $operator->id, + 'source_type' => Order::class, + 'source_id' => $order->id, + 'amount' => $amount, + 'product_sku_id' => $product->id, + 'remarks' => '后台发货', + 'tag_id' => $tag->id + ]); + } + } DB::commit(); } catch (BizException $e) { DB::rollBack(); diff --git a/app/Admin/Services/OrderPackageService.php b/app/Admin/Services/OrderPackageService.php index 48a6e7ac..c43bfde8 100644 --- a/app/Admin/Services/OrderPackageService.php +++ b/app/Admin/Services/OrderPackageService.php @@ -6,14 +6,19 @@ use App\Exceptions\BizException; use App\Models\Order; use App\Models\OrderPackage; use App\Models\OrderPackageProduct; -use App\Models\OrderProduct; +use App\Models\{OrderProduct, Tag}; use App\Services\Kuaidi100Service; use Illuminate\Support\Arr; +use Dcat\Admin\Admin; class OrderPackageService { /** * 创建订单发货单 + * + * @param Order $order + * @param array $params {shipping_company, shipping_number, packages => {order_product_id, quantity}} + * @param OrderPackage $package * * @return void */ diff --git a/app/Endpoint/Api/Http/Controllers/Order/OrderPreController.php b/app/Endpoint/Api/Http/Controllers/Order/OrderPreController.php index 5bfd67e2..9bce38ed 100644 --- a/app/Endpoint/Api/Http/Controllers/Order/OrderPreController.php +++ b/app/Endpoint/Api/Http/Controllers/Order/OrderPreController.php @@ -104,26 +104,10 @@ class OrderPreController extends Controller $order_pre = OrderPre::findOrFail($id); $user = $request->user(); - $products = []; - foreach($order_pre->products as $item) { - array_push($products, [ - 'sku' => ProductSku::findOrFail($item['sku_id']), - 'quantity' => $item['quantity'] - ]); - } - $coupon_id = data_get($order_pre, 'others.coupon_id'); - $note = data_get($order_pre, 'others.note'); - try { DB::beginTransaction(); $service = new OrderService(); - $order = $service->createOrder($user, $products, null, $coupon_id, $note); - $order->update([ - 'store_id' => $order_pre->store_id, - 'inviter_id' => $order_pre->user_id, - 'source_type' => OrderPre::class, - 'source_id' => $order_pre->id, - ]); + $order = $service->createOrderByPre($user, $order_pre); DB::commit(); return response()->json([ diff --git a/app/Endpoint/Api/Http/Controllers/Order/UnlineController.php b/app/Endpoint/Api/Http/Controllers/Order/UnlineController.php index bea873fe..3b172c2b 100644 --- a/app/Endpoint/Api/Http/Controllers/Order/UnlineController.php +++ b/app/Endpoint/Api/Http/Controllers/Order/UnlineController.php @@ -4,7 +4,7 @@ namespace App\Endpoint\Api\Http\Controllers\Order; use App\Endpoint\Api\Http\Controllers\Controller; use App\Helpers\Paginator; -use App\Models\{Order, OrderPre}; +use App\Models\{Order, OrderPre, Tag}; use App\Endpoint\Api\Http\Resources\{OrderResource, OrderResourceCollection}; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -53,11 +53,16 @@ class UnlineController extends Controller 'products.required' => '发货商品必填', ]); $order = Order::where('source_type', OrderPre::class)->findOrFail($id); + $store = $order->store; // 订单来源为 帮客户下单 order_pres try { DB::beginTransaction(); $order_products = $order->products; + $tag = Tag::firstOrCreate([ + 'type' => Tag::TYPE_STORE_STOCK, + 'name' => '提货' + ]); // 根据 order_pres 发货数量, 自动发货 $service_package = new \App\Admin\Services\OrderPackageService(); // order_product_id: 订单商品ID, quantity: 发货数量 @@ -69,6 +74,27 @@ class UnlineController extends Controller 'order_product_id' => $order_product->id, 'quantity' => $item['amount'], ]); + // 添加出库记录 + $amount = $item['amount']; + $sku_id = $order_product->sku_id; + $product = $store->productSkus()->findOrFail($sku_id); + if ($product->pivot->amount - $amount < 0) { + throw new BizException('店铺的 ' . $product->name .' 库存不足'); + } + + $store->productSkus()->updateExistingPivot($product->id, [ + 'amount' => $product->pivot->amount - $amount + ]); + $store->stockLogs()->create([ + 'operator_type' => get_class($user), + 'operator_id' => $user->id, + 'source_type' => Order::class, + 'source_id' => $order->id, + 'amount' => $amount, + 'product_sku_id' => $product->id, + 'remarks' => '店铺提货', + 'tag_id' => $tag->id + ]); } } // 发货 diff --git a/app/Models/Order.php b/app/Models/Order.php index c2bf1bde..3ad34e92 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -7,6 +7,7 @@ use App\Enums\PayWay; use Dcat\Admin\Traits\HasDateTimeFormatter; use EloquentFilter\Filterable; use Illuminate\Database\Eloquent\Model; +use App\Models\Store\Store; class Order extends Model { @@ -141,6 +142,14 @@ class Order extends Model return $this->belongsTo(UserInfo::class, 'user_id', 'user_id'); } + /** + * 门店 + */ + public function store() + { + return $this->belongsTo(Store::class, 'store_id'); + } + /** * 使用的优惠券 * diff --git a/app/Models/Store/Administrator.php b/app/Models/Store/Administrator.php index 359d81ae..9a6ff1ff 100644 --- a/app/Models/Store/Administrator.php +++ b/app/Models/Store/Administrator.php @@ -20,6 +20,6 @@ class Administrator extends Model public function administrator() { - return $this->belongsTo(\Dcat\Admin\Models\Administrator::class, 'administrator_id'); + return $this->belongsTo(\App\Models\Admin\Administrator::class, 'administrator_id'); } } diff --git a/app/Models/Store/StockLog.php b/app/Models/Store/StockLog.php index 68c71271..aa49c18a 100644 --- a/app/Models/Store/StockLog.php +++ b/app/Models/Store/StockLog.php @@ -12,7 +12,7 @@ class StockLog extends Model protected $table = 'store_stock_logs'; - protected $fillable = ['administrator_id', 'amount', 'product_sku_id', 'remarks', 'source_id', 'source_type', 'store_id', 'tag_id']; + protected $fillable = ['operator_type', 'operator_id', 'amount', 'product_sku_id', 'remarks', 'source_id', 'source_type', 'store_id', 'tag_id']; public function store() { @@ -24,9 +24,9 @@ class StockLog extends Model return $this->belongsTo(\App\Models\ProductSku::class, 'product_sku_id'); } - public function administrator() + public function operator() { - return $this->belongsTo(\Dcat\Admin\Models\Administrator::class, 'administrator_id'); + return $this->morphTo(); } public function source() diff --git a/app/Services/OrderService.php b/app/Services/OrderService.php index e01712e0..5eb4fc3a 100644 --- a/app/Services/OrderService.php +++ b/app/Services/OrderService.php @@ -20,7 +20,8 @@ use App\Models\ProductPartSku; use App\Models\ProductSku; use App\Models\ShippingAddress; use App\Models\SocialiteUser; -use App\Models\User; +use App\Models\{User, OrderPre, Tag}; +use App\Models\Store\Store; use App\Models\UserCoupon; use App\Services\Payment\WxpayService; use Illuminate\Database\Eloquent\Builder; @@ -110,13 +111,11 @@ class OrderService ?string $note = null, ?BargainOrder $bargainOrder = null, ): Order { - if ($shippingAddressId) { - foreach ($products as $product) { - $sku = $product['sku']; - - if ($product['quantity'] > $sku->saleable_stock) { - throw new BizException('商品库存不足'); - } + foreach ($products as $product) { + $sku = $product['sku']; + + if ($product['quantity'] > $sku->saleable_stock) { + throw new BizException('商品库存不足'); } } @@ -168,6 +167,70 @@ class OrderService return $order; } + /** + * 添加店铺订单 + * + */ + public function createOrderByPre(User $user, OrderPre $order_pre) + { + $products = []; + foreach($order_pre->products as $item) { + array_push($products, [ + 'sku' => ProductSku::findOrFail($item['sku_id']), + 'quantity' => $item['quantity'] + ]); + } + + $coupon_id = data_get($order_pre, 'others.coupon_id'); + $note = data_get($order_pre, 'others.note'); + + // 优惠券 + $coupon = null; + + if ($coupon_id) { + $coupon = $user->coupons()->onlyAvailable()->lockForUpdate()->findOrFail($coupon_id); + } + + $mapProducts = $this->mapProducts($user, $products, $coupon); + + list( + $productsTotalAmount, + $vipDiscountAmount, + $couponDiscountAmount, + $salesValue + ) = $this->calculateFees($mapProducts); + + $order = $this->storeOrder( + $user, + $productsTotalAmount, + $couponDiscountAmount, + $vipDiscountAmount, + 0, + $salesValue, + null, + $note, + $coupon + ); + $order->update([ + 'store_id' => $order_pre->store_id, + 'inviter_id' => $order_pre->user_id, + 'source_type' => OrderPre::class, + 'source_id' => $order_pre->id, + ]); + $this->storeOrderProducts($order, $mapProducts); + + // 将优惠券标记为已使用 + $coupon?->markAsUse(); + + if ($order->total_amount === 0) { + $this->pay($order, PayWay::Balance); + + $order->refresh(); + } + + return $order; + } + /** * 保存订单 * @@ -284,7 +347,9 @@ class OrderService ]; // 扣除商品库存 - $this->deductProduct($sku, $qty); + if (!$order->store_id) { + $this->deductProduct($sku, $qty); + } } //根据订单参加的活动添加赠品; $gifts = $this->activityGifts($order, $orderProducts); @@ -323,6 +388,30 @@ class OrderService // } while (true); } + /** + * 从门店中扣除商品库存 + */ + protected function deductProductFromStore(Store $store, ProductSku $sku, int $amount) + { + $sku = $store->productSkus()->findOrFail($sku->id); + + // 添加出库记录 + $tag = Tag::firstOrCreate([ + 'type' => Tag::TYPE_STORE_STOCK, + 'name' => '下单出库' + ]); + $store->stockLogs()->create([ + 'amount' => 0-$amount, + 'product_sku_id' => $sku->id, + 'remarks' => '购买', + 'tag_id' => $tag->id + ]); + + $store->productSkus()->updateExistingPivot($sku->id, [ + 'amount' => $sku->pivot->amount - $amount + ]); + } + /** * 扣出商品的赠品 * @@ -691,7 +780,7 @@ class OrderService * 准备商品信息 * * @param \App\Models\User $user - * @param array $products + * @param array $products {sku: App\Models\ProductSku, quantity: 数量} * @param \App\Models\UserCoupon|null $coupon * @return array * diff --git a/database/migrations/2022_05_06_161251_create_stores_table.php b/database/migrations/2022_05_06_161251_create_stores_table.php index 3bfd98f8..cd381a19 100644 --- a/database/migrations/2022_05_06_161251_create_stores_table.php +++ b/database/migrations/2022_05_06_161251_create_stores_table.php @@ -43,7 +43,7 @@ class CreateStoresTable extends Migration $table->unsignedBigInteger('product_sku_id'); $table->integer('amount')->comment('库存变更数量(正/负值)'); $table->unsignedBigInteger('tag_id')->comment('变更类目(tags.id)'); - $table->unsignedBigInteger('administrator_id')->nullable()->comment('操作管理员'); + $table->nullableMorphs('operator'); $table->string('remarks')->nullable()->comment('备注'); $table->string('source_type')->nullable()->comment('来源'); $table->unsignedBigInteger('source_id')->nullable()->comment('来源');