6
0
Fork 0
jiqu-library-server/app/Services/OrderService.php

1020 lines
32 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Services;
use App\Endpoint\Api\Http\Resources\ProductSkuSimpleResource;
use App\Endpoint\Api\Http\Resources\ShippingAddressResource;
use App\Endpoint\Api\Http\Resources\UserCouponResource;
use App\Enums\PayWay;
use App\Enums\SocialiteType;
use App\Enums\WxpayTradeType;
use App\Exceptions\BizException;
use App\Exceptions\ShippingNotSupportedException;
use App\Models\ActivityProductPart;
use App\Models\DistributionPreIncomeJob;
use App\Models\Order;
use App\Models\OrderActivity;
use App\Models\OrderProduct;
use App\Models\ProductGift;
use App\Models\ProductPartSku;
use App\Models\ProductSku;
use App\Models\ShippingAddress;
use App\Models\SocialiteUser;
use App\Models\User;
use App\Models\UserCoupon;
use App\Services\Payment\WxpayService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
class OrderService
{
/**
* 快速下单
*
* @param \App\Models\User $user
* @param int $skuId
* @param int $quantity
* @param int $shippingAddressId
* @param int|null $couponId
* @param string|null $note
* @return \App\Models\Order
*/
public function createQuickOrder(
User $user,
int $skuId,
int $quantity,
int $shippingAddressId,
?int $couponId = null,
?string $note = null
): Order {
$sku = ProductSku::online()->findOrFail($skuId);
$product = [
'sku' => $sku,
'quantity' => $quantity,
];
return $this->createOrder($user, [$product], $shippingAddressId, $couponId, $note);
}
/**
* 购物车下单
*
* @param \App\Models\User $user
* @param int $skuId
* @param int $quantity
* @param int $shippingAddressId
* @param int|null $couponId
* @param string|null $note
* @return \App\Models\Order
*/
public function createShoppingCartOrder(
User $user,
array $shoppingCartItemIds,
int $shippingAddressId,
?int $couponId = null,
?string $note = null,
): Order {
$order = $this->createOrder(
$user,
$this->getProductsByShoppingCart($user, $shoppingCartItemIds),
$shippingAddressId,
$couponId,
$note
);
$user->shoppingCartItems()->whereIn('id', $shoppingCartItemIds)->delete();
return $order;
}
/**
* 创建订单
*
* @param \App\Models\User $user
* @param array $products
* @param int $shippingAddressId
* @param int|null $couponId
* @param string|null $note
* @return \App\Models\Order
*/
protected function createOrder(
User $user,
array $products,
int $shippingAddressId,
?int $couponId = null,
?string $note = null,
): Order {
foreach ($products as $product) {
$sku = $product['sku'];
if ($product['quantity'] > $sku->saleable_stock) {
throw new BizException('商品库存不足');
}
}
$shippingAddress = $this->getShippingAddress($user, $shippingAddressId);
// 优惠券
$coupon = null;
if ($couponId) {
$coupon = $user->coupons()->onlyAvailable()->lockForUpdate()->findOrFail($couponId);
}
$mapProducts = $this->mapProducts($user, $products, $coupon);
// 计算运费
$shippingFee = $this->calculateShippingFee($mapProducts, $shippingAddress);
list(
$productsTotalAmount,
$vipDiscountAmount,
$couponDiscountAmount,
$salesValue
) = $this->calculateFees($mapProducts);
$order = $this->storeOrder(
$user,
$shippingAddress,
$productsTotalAmount,
$couponDiscountAmount,
$vipDiscountAmount,
$shippingFee,
$salesValue,
$note,
$coupon
);
$this->storeOrderProducts($order, $mapProducts);
// 将优惠券标记为已使用
$coupon?->markAsUse();
if ($order->total_amount === 0) {
$this->pay($order, PayWay::Balance);
$order->refresh();
}
return $order;
}
/**
* 保存订单
*
* @param \App\Models\User $user
* @param \App\Models\ShippingAddress $shippingAddress
* @param int $productsTotalAmount
* @param int $couponDiscountAmount
* @param int $vipDiscountAmount
* @param int $shippingFee
* @param float $salesValue
* @param string|null $note
* @param \App\Models\UserCoupon|null $coupon
* @return \App\Models\Order
*/
protected function storeOrder(
User $user,
ShippingAddress $shippingAddress,
int $productsTotalAmount,
int $couponDiscountAmount,
int $vipDiscountAmount,
int $shippingFee,
$salesValue,
?string $note = null,
?UserCoupon $coupon = null,
): Order {
// 订单支付金额=商品总额-券折扣金额-会员折扣金额+邮费
$totalAmount = $productsTotalAmount - $couponDiscountAmount - $vipDiscountAmount;
if ($totalAmount < 0) {
$totalAmount = 0;
}
$totalAmount += $shippingFee;
do {
// 如果订单号重复,则直接重试
try {
$attrs = [
'sn' => serial_number(),
'user_coupon_id' => $coupon?->id,
'coupon_discount_amount' => $couponDiscountAmount,
'vip_discount_amount' => $vipDiscountAmount,
'shipping_fee' => $shippingFee,
'products_total_amount' => $productsTotalAmount,
'total_amount' => $totalAmount, // 商品总额-券折扣金额-会员折扣金额+邮费
'sales_value' => $salesValue, // 订单总销售值
'note' => $note,
// 收货地址
'consignee_name' => $shippingAddress->consignee,
'consignee_telephone' => $shippingAddress->telephone,
'consignee_zone' => $shippingAddress->zone,
'consignee_address' => $shippingAddress->address,
];
return $user->orders()->create($attrs);
} catch (QueryException $e) {
if (strpos($e->getMessage(), 'Duplicate entry') === false) {
throw $e;
}
}
} while (true);
}
/**
* 保存订单商品
*
* @param \App\Models\Order $order
* @param array $mapProducts
* @return void
*/
public function storeOrderProducts(Order $order, array $mapProducts)
{
$orderProducts = [];
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,
'activity_id'=>null,
'is_gift'=> false,
'user_id' => $order->user_id,
'order_id' => $order->id,
'spu_id' => $sku->spu_id,
'sku_id' => $sku->id,
'category_id' => $sku->category_id,
'name' => $sku->name,
'specs' => json_encode($sku->specs),
'cover' => $sku->cover,
'weight' => $sku->weight,
'sell_price' => $sku->sell_price,
'vip_price' => $sku->vip_price,
'sales_value' => $sku->sales_value,
'quantity' => $qty,
'remain_quantity' => $qty, // 剩余发货数量
'coupon_discount_amount' => $product['coupon_discount_amount'],
'vip_discount_amount' => $product['vip_discount_amount'],
'total_amount' => $totalAmount,
'created_at' => $order->created_at,
'updated_at' => $order->updated_at,
];
// 扣除商品库存
$this->deductProduct($sku, $qty);
}
//根据订单参加的活动添加赠品;
$gifts = $this->activityGifts($order, $orderProducts);
$orderProducts = array_merge($orderProducts, $gifts);
OrderProduct::insert($orderProducts);
}
/**
* 扣商品的库存
* 03-04取消根据商品赠送赠品
*
* @param \App\Models\ProductSku $sku
* @param int $qty
* @return array
*/
protected function deductProduct(ProductSku $sku, int $qty)
{
// 扣商品库存
$sku->update([
'sales' => DB::Raw("sales + {$qty}"),
'stock' => DB::raw("stock - {$qty}"), // 库存
]);
$sku->spu?->increment('sales', $qty);
// // 如果是因为赠品库存不足引起的异常,则需重试
// do {
// try {
// return $this->deductGifts($sku, $qty);
// } catch (QueryException $e) {
// if (strpos($e->getMessage(), 'Numeric value out of range') === false) {
// throw $e;
// }
// }
// } while (true);
}
/**
* 扣出商品的赠品
*
* @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;
}
// 需赠送礼品的总数
$num = $gift->num * $qty;
if ($gift->isLimit()) {
if ($gift->remaining === 0) {
continue;
}
if ($num > $gift->remaining) {
// 计算剩余可赠送的份数
$remainingQty = (int) ($gift->remaining / $gift->num);
$num = $gift->num * $remainingQty;
}
}
if ($gift->isLimit()) {
$gift->update([
'remaining' => DB::raw("remaining-{$num}"),
'sent' => DB::raw("sent+{$num}"),
]);
} else {
$gift->increment('sent', $num);
}
$gifts[] = [
'sku' => $gift->giftSku,
'num' => $num, // 赠送商品总数
];
}
return $gifts;
}
/**
* Undocumented function
*
* @param Order $order
* @param [type] $products
* @return array $gifts
*/
protected function activityGifts(Order $order, $products)
{
$_products = array_column($products, 'total_amount', 'sku_id');
$inValidParts = [];
// 整理订单商品的分区
$partSkus = ProductPartSku::with('part')->whereIn('sku_id', array_keys($_products))->get();
foreach ($partSkus as $partSku) {
if ($partSku->part?->is_show) {
if (isset($inValidParts[$partSku->part_id])) {
$inValidParts[$partSku->part_id] += $_products[$partSku->sku_id] ?? 0;
} else {
$inValidParts[$partSku->part_id] = $_products[$partSku->sku_id] ?? 0;
}
}
}
//根据分区获取活动
$partActivities = ActivityProductPart::with(['activity', 'activity.gifts'])->whereHas('activity', function (Builder $query) {
return $query->where('is_use', true)->where('started_at', '<', now())->where('ended_at', '>=', now());
})->whereIn('part_id', array_keys($inValidParts))->get();
$giveGifts = [];
foreach ($partActivities as $partActivity) {
//获取活动的赠品赠送规则
$_giftsRule = $partActivity->activity?->gifts_rule;
//判断是否首单times=0为仅首单赠送, 1为不限
if ($_giftsRule['times'] == 0 && OrderProduct::where('activity_id', $partActivity->activity_id)->exists()) {
continue;//提前结束本次循环
}
//判断是否满足门槛
if (bcdiv($_giftsRule['value'], 100) > $inValidParts[$partActivity->part_id]) {
continue;//提前结束本次循环
}
//返回赠品
$_gifts = $partActivity->activity->gifts;
foreach ($_gifts as $_gift) {
$giveGifts[] = [
'gift_for_sku_id'=> null,
'user_id' => $order->user_id,
'order_id' => $order->id,
'spu_id' => $_gift->spu_id,
'sku_id' => $_gift->id,
'category_id' => $_gift->category_id,
'name' => $_gift->name,
'specs' => json_encode($_gift->specs),
'cover' => $_gift->cover,
'weight' => $_gift->weight,
'sell_price' => $_gift->sell_price,
'vip_price' => $_gift->vip_price,
'sales_value' => 0, // 赠品不算销售值
'quantity' => $_gift->pivot->qty,
'remain_quantity' => $_gift->pivot->qty, // 剩余发货数量
'coupon_discount_amount' => 0,
'vip_discount_amount' => 0,
'total_amount' => 0,
'created_at' => $order->created_at,
'updated_at' => $order->updated_at,
'is_gift'=> true,
'activity_id'=>$partActivity->activity_id,
];
// 扣除商品库存
$this->deductProduct($_gift, $_gift->pivot->qty);
}
//记录订单参与活动信息
OrderActivity::firstOrCreate([
'order_id'=>$order->id,
'activity_id'=>$partActivity->activity_id,
]);
}
return $giveGifts;
}
/**
* 确认快速下单
*
* @param \App\Models\User $user
* @param int $skuId
* @param int $quantity
* @param int|null $shippingAddressId
* @param int|null $couponId
* @return array
*/
public function verifyQuickOrder(User $user, int $skuId, int $quantity, ?int $shippingAddressId = null, ?int $couponId = null)
{
$sku = ProductSku::online()->findOrFail($skuId);
$product = [
'sku' => $sku,
'quantity' => $quantity,
];
return $this->verifyOrder($user, [$product], $shippingAddressId, $couponId);
}
/**
* 确认购物车订单
*
* @param \App\Models\User $user
* @param array $shoppingCartItemIds
* @param int|null $shippingAddressId
* @param int|null $couponId
* @return array
*/
public function verifyShoppingCartOrder(User $user, array $shoppingCartItemIds, ?int $shippingAddressId = null, ?int $couponId = null)
{
// 获取购买商品
$products = $this->getProductsByShoppingCart($user, $shoppingCartItemIds);
return $this->verifyOrder($user, $products, $shippingAddressId, $couponId);
}
/**
* 确认订单
*
* @param \App\Models\User $user
* @param array $products
* @param int|null $shippingAddressId
* @param int|null $couponId
* @return array
*/
protected function verifyOrder(User $user, array $products, ?int $shippingAddressId = null, ?int $couponId = null): array
{
// 获取收货地址
$shippingAddress = $this->getShippingAddress($user, $shippingAddressId);
// 优惠券
$coupon = null;
if ($couponId) {
$coupon = $user->coupons()->onlyAvailable()->findOrFail($couponId);
}
$mapProducts = $this->mapProducts($user, $products, $coupon);
// 是否支持配送
$shippingSupported = true;
// 运费
$shippingFee = 0;
if ($shippingAddress) {
try {
$shippingFee = $this->calculateShippingFee($mapProducts, $shippingAddress);
} catch (ShippingNotSupportedException $e) {
$shippingFee = 0;
$shippingSupported = false;
}
}
list(
$productsTotalAmount,
$vipDiscountAmount,
$couponDiscountAmount,
$salesValue,
) = $this->calculateFees($mapProducts);
$totalAmount = $productsTotalAmount - $couponDiscountAmount - $vipDiscountAmount;
if ($totalAmount < 0) {
$totalAmount = 0;
}
$totalAmount += $shippingFee;
return [
'products' => collect($mapProducts)->map(function ($item) {
return [
'sku' => ProductSkuSimpleResource::make($item['sku']),
'quantity' => $item['quantity'],
];
}),
'coupons' => UserCouponResource::collection((new CouponService())->getAvailableCoupons($user, $products)),
'shipping_address' => $shippingAddress ? ShippingAddressResource::make($shippingAddress) : null, // 收货地址
'shipping_supported' => $shippingSupported,
'shipping_fee' => trim_trailing_zeros(bcdiv($shippingFee, 100, 2)), // 运费
'products_total_amount' => trim_trailing_zeros(bcdiv($productsTotalAmount, 100, 2)), // 商品总额
'vip_discount_amount' => trim_trailing_zeros(bcdiv($vipDiscountAmount, 100, 2)), // 会员折扣金额
'coupon_discount_amount' => trim_trailing_zeros(bcdiv($couponDiscountAmount, 100, 2)), // 优惠券折扣金额
'total_amount' => trim_trailing_zeros(bcdiv($totalAmount, 100, 2)), // 实付金额
];
}
/**
* 计算费用
*
* @param array $products
* @return array
*/
protected function calculateFees(array $products)
{
$productsTotalAmount = 0;
$vipDiscountAmount = 0;
$couponDiscountAmount = 0;
$salesValue = 0;
foreach ($products as $product) {
$productsTotalAmount += $product['total_amount'];
$vipDiscountAmount += $product['vip_discount_amount'];
$couponDiscountAmount += $product['coupon_discount_amount'];
$salesValue = bcadd($salesValue, $product['total_sales_value']);
}
return [
$productsTotalAmount,
$vipDiscountAmount,
$couponDiscountAmount,
$salesValue,
];
}
/**
* 计算运费
*
* @param array $products
* @param \App\Models\ShippingAddress $shippingAddress
* @return int
*/
protected function calculateShippingFee(array $products, ShippingAddress $shippingAddress): int
{
// 运费
$shippingFee = 0;
$shippings = [];
foreach ($products as $product) {
$sku = $product['sku'];
if (is_null($sku->shipping_template_id)) {
continue;
}
$shipping = $shippings[$sku->shipping_template_id] ?? [
'total_weight' => 0,
'total_amount' => 0,
];
$shipping['total_weight'] += $sku->weight * $product['quantity'];
$shipping['total_amount'] += $product['total_amount'] - $product['vip_discount_amount'] - $product['coupon_discount_amount'];
$shippings[$sku->shipping_template_id] = $shipping;
}
$shippingService = new ShippingService();
foreach ($shippings as $templateId => $shipping) {
$shippingFee += $shippingService->countShippingAmount(
$shipping['total_weight'],
$shipping['total_amount'],
$templateId,
$shippingAddress->zone_id
);
}
return $shippingFee;
}
/**
* 准备商品信息
*
* @param \App\Models\User $user
* @param array $products
* @param \App\Models\UserCoupon|null $coupon
* @return array
*
* @throws \App\Exceptions\BizException
*/
protected function mapProducts(User $user, array $products, ?UserCoupon $coupon): array
{
$_products = collect($products)->map(function ($item) use ($user) {
$sku = $item['sku'];
return array_merge($item, [
// 优惠券折扣金额
'coupon_discount_amount' => 0,
// 会员折扣金额
'vip_discount_amount' => $this->calculateVipDiscountAmount(
$user, $sku, $item['quantity']
),
// 总金额
'total_amount' => $sku->sell_price * $item['quantity'],
// 总销售值
'total_sales_value' => bcmul($sku->sales_value, $item['quantity'], 2),
]);
});
if ($coupon === null) {
return $_products->all();
}
$couponDiscountAmounts = $this->getCouponDiscountAmounts($coupon, $_products->all());
return $_products->map(function ($item) use ($couponDiscountAmounts) {
$item['coupon_discount_amount'] = $couponDiscountAmounts[$item['sku']->id] ?? 0;
return $item;
})->all();
}
/**
* 计算会员折扣金额
*
* @param \App\Models\User $user
* @param \App\Models\ProductSku $sku
* @param int $quantity
* @return int
*/
protected function calculateVipDiscountAmount(User $user, ProductSku $sku, int $quantity)
{
$price = $sku->getRealPrice($user);
if ($price > $sku->sell_price) {
return 0;
}
return ($sku->sell_price - $price) * $quantity;
}
/**
* 获取商品的优惠券折扣金额
*
* @param \App\Models\UserCoupon $coupon
* @param array $products
* @return array
*
* @throws \App\Exceptions\BizException
*/
protected function getCouponDiscountAmounts(UserCoupon $coupon, array $products): array
{
// 启用的券的使用规则
$coupon->loadMissing(['ranges' => function ($query) {
$query->isEnable();
}]);
// 可使用优惠券的商品总额
$amounts = [];
foreach ($products as $item) {
$sku = $item['sku'];
if (! $coupon->isSupport($sku)) {
throw new BizException('优惠券不满足使用条件');
}
$amount = $item['total_amount'] - $item['vip_discount_amount'];
// 仅保留商品真实总额大于0的商品
if ($amount > 0) {
$amounts[$sku->id] = $amount;
}
}
// 全部商品总额
$totalAmount = array_sum($amounts);
if ($coupon->coupon_threshold > $totalAmount) {
throw new BizException('优惠券不满足使用条件');
}
// 优惠券折扣金额
$couponAmount = value(function ($coupon, $totalAmount) {
// 如果优惠券是折扣券,则需算出优惠总额
if ($coupon->isDiscountCoupon()) {
return (int) bcmul($totalAmount, bcdiv(100 - $coupon->coupon_amount, 100, 2));
}
// 如果优惠券的折扣金额超过商品总额,则优惠金额为商品总额
if ($coupon->coupon_amount > $totalAmount) {
return $totalAmount;
}
return $coupon->coupon_amount;
}, $coupon, $totalAmount);
// 待计算优惠的商品总数
$i = count($amounts);
foreach ($amounts as &$amount) {
$i--;
if ($i > 0) {
$amount = (int) bcdiv(bcmul($couponAmount, $amount, 0), $totalAmount, 2);
$couponAmount -= $amount;
} else {
$amount = $couponAmount;
}
unset($amount);
}
return $amounts;
}
/**
* 根据购物车获取商品
*
* @param \App\Models\User $user
* @param array $shoppingCartItemIds
* @return array
*
* @throws \App\Exceptions\BizException
*/
protected function getProductsByShoppingCart(User $user, array $shoppingCartItemIds): array
{
$shoppingCartItems = $user->shoppingCartItems()->findMany($shoppingCartItemIds);
if ($shoppingCartItems->count() !== count($shoppingCartItemIds)) {
throw new BizException('购物车商品已丢失');
}
$shoppingCartItems->load('sku.spu');
$lostShoppingCartItems = $shoppingCartItems->filter(function ($item) {
return $item->sku === null;
});
if ($lostShoppingCartItems->count() > 0) {
throw new BizException('购物车商品已失效');
}
return $shoppingCartItems->map(function ($item) {
return [
'sku' => $item->sku,
'quantity' => $item->quantity,
];
})->all();
}
/**
* 获取收货地址
*
* @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();
}
/**
* 订单付款
*
* @param \App\Models\Order $order
* @param \App\Enums\PayWay $payWay
* @return mixed
*
* @throws \App\Exceptions\WeChatPayException
*/
public function pay(Order $order, PayWay $payWay)
{
if (! $order->isPending()) {
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,
];
// 如果支付方式为线下支付,或支付金额为 0则按支付完成处理
if ($order->total_amount === 0 || $payLog->isOffline()) {
(new PayService())->handleSuccess($payLog, [
'pay_at' => now(),
]);
$data = null;
} elseif ($payLog->isWxpay()) {
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' => $order->total_amount,
'trade_type' => $tradeType->value,
];
if ($tradeType === WxpayTradeType::JSAPI) {
$socialite = match ($payLog->pay_way) {
PayWay::WxpayMiniProgram => SocialiteUser::where([
'user_id' => $order->user_id,
'socialite_type' => SocialiteType::WechatMiniProgram,
])->first(),
};
if ($socialite === null) {
throw new BizException('未绑定微信小程序');
}
$params['openid'] = $socialite->socialite_id;
}
$data = (new WxpayService())->pay($params, match ($payLog->pay_way) {
PayWay::WxpayMiniProgram => 'mini_program',
default => 'default',
});
} elseif ($payLog->isAlipay()) {
$params = [
'subject' => app_settings('app.app_name').'-商城订单',
'out_trade_no' => $payLog->pay_sn,
'total_amount' => bcdiv($order->total_amount, 100, 2),
];
$data = app(AlipayService::class)->pay($params);
}
return [
'pay_way' => $payLog->pay_way,
'data' => $data,
];
}
/**
* 确认订单
*
* @param \App\Models\Order $order
* @param bool $isSettlable
* @return void
*/
public function confirm(Order $order, $isSettlable = false)
{
if (! $order->isShipped()) {
throw new BizException('订单包裹未发完');
}
if ($isSettlable && $order->afterSales()->processing()->count() > 0) {
throw new BizException('订单商品售后中,不能完成此订单');
}
$orderPackageService = new OrderPackageService();
$order->loadMissing('packages');
$packages = $order->packages->filter(function ($item) {
return ! $item->is_failed && ! $item->isChecked();
});
foreach ($packages as $package) {
$orderPackageService->checkPackage($package, true);
}
$order->update([
'is_settlable' => $isSettlable,
'status' => Order::STATUS_COMPLETED,
'completed_at' => now(),
]);
}
/**
* 取消订单
*
* @param \App\Models\Order $order
* @return void
*/
public function cancel(Order $order)
{
if (! $order->isPending() && ! $order->isWaitShipping()) {
throw new BizException('订单状态不是待付款或待发货');
}
if ($order->isWaitShipping()) {
$refundLog = $order->refundLogs()->create([
'sn' => serial_number(),
'amount' => $order->total_amount,
'reason' => '取消订单',
]);
// 扣除用户的预成长值
$order->user->userInfo->incrPreGrowthValue(bcmul($order->sales_value, '-1', 2));
DistributionPreIncomeJob::create([
'jobable_id' => $refundLog->id,
'jobable_type' => $refundLog->getMorphClass(),
'remarks' => '取消订单',
]);
}
$products = $order->products()->get();
foreach ($products->load(['sku', 'spu']) as $product) {
if ($product->sku === null) {
continue;
}
// 如果商品不是赠品,则直接增加商品库存
if (! $product->isGift()) {
$product->spu?->increment('sales', -$product->quantity);
$product->sku?->update([
'stock' => DB::Raw("stock + {$product->quantity}"),
'sales' => DB::Raw("sales - {$product->quantity}"),
]);
continue;
}
$gift = ProductGift::where('sku_id', $product->gift_for_sku_id)
->where('gift_sku_id', $product->sku_id)
->first();
if ($gift === null) {
continue;
}
if ($gift->isLimit()) {
$gift->update([
'remaining' => DB::raw("remaining+{$product->quantity}"),
'sent' => DB::raw("sent-{$product->quantity}"),
]);
} else {
$gift->decrement('sent', $product->quantity);
}
}
// 取消订单,退券
if ($order->user_coupon_id) {
UserCoupon::where('user_id', $order->user_id)->where('id', $order->user_coupon_id)->update([
'is_use'=>false,
]);
}
$order->update([
'status' => Order::STATUS_CANCELLED,
]);
}
}