count()) { throw new BizException('提货单商品已丢失'); } // 经销商的商品库存 $dealerProducts = $user->dealerProducts() ->whereIn('product_id', $deliveryProductIds) ->get(); // 创建提货单 $deliveryBill = DealerDeliveryBill::create([ 'user_id' => $user->id, 'shipping_fee' => app_settings('dealer.delivery_bill_shipping_fee', 0), 'remark' => $remark, 'consignee_name' => $consignee['name'], 'consignee_telephone' => $consignee['telephone'], 'consignee_zone' => $consignee['zone'], 'consignee_address' => $consignee['address'], 'status' => DealerDeliveryBillStatus::Pending, 'order_id' => $dealerOrder?->id, ]); $mapProducts = $products->keyBy('id'); $mapDealerProducts = $dealerProducts->keyBy('product_id'); $dealerProductLogs = []; $deliveryBillProducts = []; foreach ($deliveryProducts as $deliveryProduct) { $product = Arr::get($mapProducts, $deliveryProduct['id']); $dealerProduct = Arr::get($mapDealerProducts, $product->id); if ($dealerProduct?->deposit_stock < $deliveryProduct['qty']) { throw new BizException("{$product->name} 库存不足"); } $dealerProduct->decrement('deposit_stock', $deliveryProduct['qty']); $dealerProductLogs[] = [ 'user_id' => $dealerProduct->user_id, 'product_id' => $dealerProduct->product_id, 'type' => DealerUserProductLog::TYPE_DEPOSIT_TRANSFER_OUT, 'qty' => $deliveryProduct['qty'], 'remark' => "提货单【{$deliveryBill->sn}】", 'is_deposit' => true, 'created_at' => $deliveryBill->created_at, 'updated_at' => $deliveryBill->updated_at, ]; $deliveryBillProducts[] = [ 'delivery_bill_id' => $deliveryBill->id, 'product_id' => $product->id, 'qty' => $deliveryProduct['qty'], 'created_at' => $deliveryBill->created_at, 'updated_at' => $deliveryBill->updated_at, ]; } DealerUserProductLog::insert($dealerProductLogs); DealerDeliveryProduct::insert($deliveryBillProducts); return $deliveryBill; } /** * 提货单付款 * * @param \App\Models\DealerDeliveryBill $deliveryBill * @param \App\Enums\PayWay $payWay * @return array * * @throws \App\Exceptions\BizException */ public function pay(DealerDeliveryBill $deliveryBill, PayWay $payWay): array { if (! $deliveryBill->isPending()) { throw new BizException('提货单状态不是待付款'); } $method = match ($payWay) { PayWay::Wallet => 'payUsingWallet', PayWay::WxpayH5, PayWay::WxpayJsApi => 'payUsingWxpay', default => 'payUsingDefault', }; if (! method_exists($this, $method)) { throw new BizException('交易非法'); } $payLog = $deliveryBill->payLogs()->create([ 'pay_way' => $payWay, ]); return [ 'pay_way' => $payLog->pay_way, 'data' => $this->{$method}($deliveryBill, $payLog), ]; } /** * 取消提货单 * * @param DealerDeliveryBill $deliveryBill * @return void */ public function cancel(DealerDeliveryBill $deliveryBill) { if (! $deliveryBill->isPending()) { throw new BizException('提货单状态不是待付款'); } $deliveryBill->update([ 'status' => DealerDeliveryBillStatus::Cancelled, ]); $dealerProductLogs = []; foreach ($deliveryBill->deliveryProducts as $deliveryProduct) { DealerUserProduct::where([ 'user_id' => $deliveryBill->user_id, 'product_id' => $deliveryProduct->product_id, ])->update([ 'deposit_stock' => DB::raw("deposit_stock + {$deliveryProduct->qty}"), ]); $dealerProductLogs[] = [ 'user_id' => $deliveryBill->user_id, 'product_id' => $deliveryProduct->product_id, 'type' => DealerUserProductLog::TYPE_DEPOSIT_TRANSFER_REVOKE, 'qty' => $deliveryProduct->qty, 'remark' => "撤销提货单【{$deliveryBill->sn}】", 'is_deposit' => true, 'created_at' => $deliveryBill->updated_at, 'updated_at' => $deliveryBill->updated_at, ]; } //撤回已发货的本地库存 if ($deliveryBill->order_id) { $dealerOrder = DealerOrder::with('products')->find($deliveryBill->order_id); foreach ($dealerOrder->products as $product) { if ($product->qty > 0 && $dealerOrder->local_status == 1) { $userProduct = $dealerOrder->consignor->dealerProducts()->firstOrCreate([ 'product_id'=> $product->product_id, ]); $userProduct->increment('stock', $product->qty); $dealerProductLogs[] = [ 'user_id' => $dealerOrder->consignor_id, 'product_id' => $product->product_id, 'type' => DealerUserProductLog::TYPE_ORDER_OUT_REVOKE, 'qty' => $product->qty, 'remark' => "撤销订单发货【{$dealerOrder->sn}】", 'is_deposit' => false, 'created_at' => $deliveryBill->updated_at, 'updated_at' => $deliveryBill->updated_at, ]; } //将云仓发货的数量挪回来 DealerOrderProduct::where('id', $product->id)->update([ 'qty' => $product->qty + $product->deposit_qty, 'deposit_qty' => 0, ]); } $dealerOrder->update([ 'local_status'=>0, ]); } DealerUserProductLog::insert($dealerProductLogs); } /** * 使用余额支付 * * @param \App\Models\DealerDeliveryBill $deliveryBill * @param \App\Models\PayLog $payLog * @return void */ protected function payUsingWallet(DealerDeliveryBill $deliveryBill, PayLog $payLog) { (new WalletService())->changeBalance( $deliveryBill->user, bcmul($deliveryBill->shipping_fee, '-1', 2), DealerWalletAction::DeliveryBillPaid, "提货单号:{$deliveryBill->sn}", $deliveryBill ); (new PayService())->handleSuccess($payLog, [ 'pay_at' => now(), ]); } /** * 使用微信支付 * * @param \App\Models\DealerDeliveryBill $deliveryBill * @param \App\Models\PayLog $payLog * @return array */ protected function payUsingWxpay(DealerDeliveryBill $deliveryBill, PayLog $payLog): array { if (is_null($tradeType = WxpayTradeType::tryFromPayWay($payLog->pay_way))) { throw new BizException('支付方式 非法'); } $params = [ 'body' => app_settings('app.app_name').'-批零订单', 'out_trade_no' => $payLog->pay_sn, 'total_fee' => bcmul($deliveryBill->shipping_fee, '100'), 'trade_type' => $tradeType->value, ]; return (new WxpayService())->pay($params, 'yzk_h5'); } }