price; if ($user->dealer) { foreach ($product->lvlRules as $rule) { if ($rule->lvl == $user->dealer->lvl->value) { $salePrice = $rule->sale_price; break; } } } //获取销售规则,判断当前用户购买数量价格 foreach ($product->saleRules as $rule) { if ($number >= $rule->qty) { if ($salePrice > $rule->price) { $salePrice = $rule->price; } break; } } return $salePrice; } /** * 计算订单价格 * * @param DealerProduct $product * @param integer $number * @return string */ public function totalAmount(User $user, DealerProduct $product, int $number = 0, ?int $allNumber = null) { return bcmul($this->getSalePrice($user, $product, $allNumber ?? $number), $number, 2); } /** * 快捷创建订单(单个商品下单) * * @param User $user * @param DealerProduct $product * @param integer $number * @param integer $shippingAddressId * @return DealerOrder $order */ public function quickCreateOrder(User $user, DealerProduct $product, int $number = 0, int $shippingAddressId) { $totalAmount = $this->totalAmount($user, $product, $number); // foreach ($product->lvlRules as $rule) { // $min_order_amount = app_settings('min_order_amount'.$rule->lvl); // if ($user->dealer && $rule->lvl == $user->dealer->lvl->value && $totalAmount < $min_order_amount) { // throw new BizException('当前单次补货价格不能低于'.$min_order_amount.'元'); // } // } $order = $this->createOrder($user, $totalAmount, $shippingAddressId); //保存订单商品-----一个订单对应一个商品 $order->products()->create([ 'order_id' => $order->id, 'product_id'=> $product->id, 'name'=> $product->name, 'subtitle'=> $product->subtitle, 'cover'=> $product->cover, 'price' => $product->price, 'sale_price'=> bcdiv($totalAmount, $number, 2), 'qty'=> $number, ]); if (!$order->consignor) {//如果订单分配给公司,则直接确认 $this->confirmOrder($order); } return $order; } /** * 购物车创建订单 * * @param User $user * @param [type] $cartIds * @param integer $shippingAddressId * @return DealerOrder $order */ public function cartCreateOrder(User $user, $cartIds, int $shippingAddressId) { //获取购物车商品 $shoppingCartItems = $user->dealerShoppingCartItems()->findMany($cartIds); if ($shoppingCartItems->count() !== count($cartIds)) { throw new BizException('购物车商品已丢失'); } $shoppingCartItems->load('product'); $totalQty = $shoppingCartItems->sum('quantity'); $totalAmount = 0; $orderProducts = []; foreach ($shoppingCartItems as $item) { if (!$item->product->isOnline()) { throw new BizException('购物车商品已失效'); } //计算订单价格 $totalAmount += $this->totalAmount($user, $item->product, $item->quantity, $totalQty); //组装订单商品 $orderProducts[] = [ 'product_id' => $item->product_id, 'name'=> $item->name, 'subtitle' => $item->product->subtitle, 'cover' => $item->cover, 'price' => $item->sell_price, 'sale_price' => $this->getSalePrice($user, $item->product, $totalQty), 'qty' => $item->quantity, ]; } $order = $this->createOrder($user, $totalAmount, $shippingAddressId); DealerOrderProduct::insert(array_map(function ($product) use ($order) { return array_merge($product, [ 'order_id'=>$order->id, 'created_at'=> $order->created_at, 'updated_at'=> $order->updated_at, ]); }, $orderProducts)); //清除购物车对应商品 $user->dealerShoppingCartItems()->whereIn('id', $cartIds)->delete(); if (!$order->consignor) {//如果订单分配给公司,则直接确认 $this->confirmOrder($order); } return $order; } /** * 创建订单 * * @param User $user * @param [type] $totalAmount * @param integer $shippingAddressId * @return DealerOrder $order */ protected function createOrder(User $user, $totalAmount, int $shippingAddressId) { //判断是否满足当前等级最低补货价 $min_order_amount = app_settings('dealer.min_order_amount_'.$user->dealer?->lvl->value, 0); if ($user->dealer && $totalAmount < $min_order_amount) { throw new BizException('当前单次补货价格不能低于'.$min_order_amount.'元'); } //找到发货人 $consignor = $this->getConsignor($user, $totalAmount); //找到收货地址 $shippingAddress = $this->getShippingAddress($user, $shippingAddressId); //保存订单 $order = new DealerOrder(); do { try { $order->sn = serial_number(); $order->user_id = $user->id; $order->consignor_id = $consignor?->user_id; $order->total_amount = $totalAmount; $order->consignee_name = $shippingAddress->consignee; $order->consignee_telephone = $shippingAddress->telephone; $order->consignee_zone = $shippingAddress->zone; $order->consignee_address = $shippingAddress->address; $order->allocated_at = now();//记录分配时间 $order->save(); break; } catch (QueryException $e) { if (strpos($e->getMessage(), 'Duplicate entry') === false) { throw $e; } } } while (true); return $order; } /** * 确认接单 * * @param DealerOrder $order * @return DealerOrder $order */ public function confirmOrder(DealerOrder $order) { if (!$order->isPending()) { throw new BizException('无法接单:订单状态异常,请刷新后再试'); } $order->update([ 'status' => DealerOrderStatus::Paying, ]); return $order; } /** * 确认打款 * * @return DealerOrder $order */ public function payOrder(DealerOrder $order, string $payWay, ?string $payImage = null) { if (empty($payWay)) { throw new BizException('请选择付款方式'); } if (!$order->isPendinged()) { throw new BizException('无法付款:订单状态异常,请刷新后再试'); } switch ($payWay) { case PayWay::Wallet->value: /** 付款以及完成确认收款动作 **/ $walletService = new WalletService(); //付款 $walletService->changeBalance($order->user, 0 - $order->total_amount, DealerWalletAction::OrderPaid, '订单:'.$order->sn, $order); $order->update([ 'status'=>DealerOrderStatus::Confirming, 'pay_time' => now(), 'pay_way' => PayWay::Wallet, ]); //收款 if ($order->consignor) { $walletService->changeBalance($order->consignor, $order->total_amount, DealerWalletAction::OrderIncome, '订单:'.$order->sn, $order); } $this->paidOrder($order); break; case PayWay::Offline->value: $order->update([ 'status' => DealerOrderStatus::Confirming, 'pay_image' => $payImage, 'pay_info' => $order->getConsignorPayInfo() ?? null, 'pay_time' => now(), 'pay_way' => PayWay::Offline, ]); break; } return $order; } /** * 支付订单 * * @param DealerOrder $order * @param \App\Enums\PayWay $payWay * @param string|null $payImage * @return array * * @throws \App\Exceptions\BizException */ public function pay(DealerOrder $order, PayWay $payWay, ?string $payImage = null): array { if (! $order->isPendinged()) { throw new BizException('订单状态不是待付款'); } do { $payLog = null; try { $payLog = $order->payLogs()->create([ 'pay_sn' => serial_number(), 'pay_way' => $payWay, ]); } catch (QueryException $e) { if (strpos($e->getMessage(), 'Duplicate entry') === false) { throw $e; } } } while ($payLog === null); $data = [ 'pay_sn' => $payLog->pay_sn, ]; switch ($payLog->pay_way) { case PayWay::Offline: (new PayService())->handleSuccess($payLog, [ 'pay_image' => $payImage, 'pay_info' => $order->getConsignorPayInfo() ?? null, 'pay_at' => now(), ]); $data = null; break; case PayWay::Wallet: $walletService = new WalletService(); // 扣除打款人余额 $walletService->changeBalance( $order->user, bcmul($order->total_amount, '-1', 2), DealerWalletAction::OrderPaid, "订单:{$order->sn}", $order ); // 增加收款人余额 if ($order->consignor) { $walletService->changeBalance( $order->consignor, $order->total_amount, DealerWalletAction::OrderIncome, "订单:{$order->sn}", $order ); } (new PayService())->handleSuccess($payLog, [ 'pay_at' => now(), ]); $data = null; break; case PayWay::WxpayH5: $app = EasyWeChatFactory::payment(config('wechat.payment.yzk')); $data = (new WeChatPayService($app))->pay([ 'body' => app_settings('app.app_name').'-批零订单', 'out_trade_no' => $payLog->pay_sn, 'total_fee' => bcmul($order->total_amount, '100'), 'trade_type' => WeChatPayService::$tradeTypes[$payLog->pay_way], 'notify_url' => url(route('yzk_wxpay.paid_notify', [], false), [], true), ]); break; default: throw new BizException('支付方式不支持'); break; } return [ 'pay_way' => $payLog->pay_way, 'data' => $data, ]; } /** * 确认收款 * * @param DealerOrder $order * @return DealerOrder $order */ public function paidOrder(DealerOrder $order) { if (!$order->isPay()) { throw new BizException('无法收款:订单状态异常,请刷新后再试'); } $order->update([ 'status' => DealerOrderStatus::Paid, 'paied_time' => now(), ]); return $order; } /** * 确认发货 * * @param DealerOrder $order * @return DealerOrder $order */ public function shippingOrder(DealerOrder $order) { if (!$order->isPaid()) { throw new BizException('无法发货:订单状态异常,请刷新后再试'); } //扣减发货人库存 if ($order->consignor) { $this->orderOutQty($order); } $order->update([ 'status' => DealerOrderStatus::Shipped, 'shipping_time' => now(), ]); return $order; } public function shippingedOrder(DealerOrder $order) { if (!$order->isShipping()) { throw new BizException('无法收货:订单状态异常,请刷新后再试'); } //增加自己的库存 $this->orderInQty($order); $order->update([ 'status' => DealerOrderStatus::Completed, 'shippinged_time' => now(), ]); return $order; } public function cancelOrder(DealerOrder $order) { if (!($order->isPending() || $order->isPendinged() || $order->isPay())) { throw new BizException('无法取消:订单状态异常,请刷新后再试'); } $order->update([ 'status' => DealerOrderStatus::Cancelled, ]); return $order; } /** * 更新订单发货人 * * @return void */ public function updateOrderConsignor(DealerOrder $order) { //只处理当前订单有发货人的情况 if ($order->consignor) { $consignor = $this->getConsignor($order->user, $order->total_amount, $order->consignor); $oldConsignor = $order->consignor; $order->update([ 'allocated_at' => now(), 'consignor_id' => $consignor?->user_id, ]); //记录分配日志 DealerOrderAllocateLog::create([ 'order_id'=>$order->id, 'last_consignor_id'=>$oldConsignor->id, 'new_consignor_id' =>$order->consignor_id, ]); } return $order; } /** * 获取收货地址 * * @param \App\Models\User $user * @param int|null $shippingAddressId * @return \App\Models\ShippingAddress|null * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException */ protected function getShippingAddress(User $user, ?int $shippingAddressId = null): ?ShippingAddress { if ($shippingAddressId) { return $user->shippingAddresses()->findOrFail($shippingAddressId); } return $user->shippingAddresses()->where('is_default', true)->first(); } /** * 用户通过下单新增库存 * * @return void */ protected function orderInQty(DealerOrder $order) { foreach ($order->products as $product) { $userProduct = $order->user->dealerProducts()->firstOrCreate([ 'product_id'=> $product->product_id, ]); $userProduct->increment('stock', $product->qty); DealerUserProductLog::create([ 'user_id'=> $order->user_id, 'product_id'=> $product->product_id, 'type' => DealerUserProductLog::TYPE_ORDER_IN, 'qty'=>$product->qty, 'remark'=>'订单:'.$order->sn, ]); } } /** * 用户通过订单扣减库存 * * @return void */ protected function orderOutQty(DealerOrder $order) { foreach ($order->products as $product) { $userProduct = $order->consignor->dealerProducts()->firstOrCreate([ 'product_id'=> $product->product_id, ]); $userProduct->decrement('stock', $product->qty); DealerUserProductLog::create([ 'user_id'=> $order->consignor_id, 'product_id'=> $product->product_id, 'type' => DealerUserProductLog::TYPE_ORDER_OUT, 'qty'=>$product->qty, 'remark' =>'订单:'.$order->sn, ]); } } private function getConsignor(User $user, $totalAmount, ?User $lastConsignor = null) { $rules = [ [ 'amount' => app_settings('dealer.upgrade_amount_'.DealerLvl::Contracted->value), 'lvl' => DealerLvl::Contracted, ], [ 'amount' => app_settings('dealer.upgrade_amount_'.DealerLvl::Special->value), 'lvl' => DealerLvl::Special, ], [ 'amount' => app_settings('dealer.upgrade_amount_'.DealerLvl::Gold->value), 'lvl' => DealerLvl::Gold, ], ]; $lvl = $user->dealer->lvl; //计算通过这个订单可能升级成为的身份 foreach ($rules as $rule) { if ($totalAmount >= $rule['amount'] && $lvl->value < $rule['lvl']->value) { $lvl = $rule['lvl']; } } //如果是签约单,直接抛到公司后台发货 if ($lvl->value >= DealerLvl::Contracted->value) { return null; } // //老逻辑; // $query = UserInfo::with('dealer'); // if ($lastConsignor) { // $query->whereIn('user_id', $lastConsignor->userInfo->real_parent_ids);//上个发货人的上级 // } else { // $query->whereIn('user_id', $user->userInfo->real_parent_ids);//自己的上级 // } // $consignor = $query->whereHas('dealer', function ($q) use ($lvl) { // return $q->where('is_sale', true)->where('lvl', '>', $lvl);//可销售的经销商,且身份大于自己的 // })->orderBy('depth', 'desc')->first();//深度逆序第一个 // if (!$consignor) { // $consignor = $lastConsignor; // } //新逻辑 $consignor = null; $_lastConsignor = $lastConsignor; do { $query = User::with(['userInfo', 'dealer']); if ($_lastConsignor) { $query->where('id', $_lastConsignor->userInfo->real_inviter_id); } else { $query->where('id', $user->userInfo->real_inviter_id); } $consignor = $query->first(); if ($consignor) {//找到老上级 if ($consignor->dealer->is_sale == true && $consignor->dealer->lvl->value > $lvl->value) { break; } else { $_lastConsignor = $consignor; $consignor = null; } } else {//如果找不到人了 $consignor = $lastConsignor; break; } } while (empty($consignor)); return $consignor?->userInfo; } }