Files
water_new/modules/Mall/Facades/Order.php
2023-03-08 09:16:04 +08:00

387 lines
8.6 KiB
PHP

<?php
namespace Modules\Mall\Facades;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Modules\Mall\Events\OrderCreated;
use Modules\Mall\Models\Address;
use Modules\Mall\Models\Goods;
use Modules\Mall\Models\Order as OrderModel;
use Modules\User\Models\User;
class Order
{
/**
* @var int
*/
protected int $user_id;
/**
* @var float
*/
protected float $total;
/**
* @var Address
*/
protected Address $address;
/**
* @var array
*/
protected Collection $items;
/**
* @var string
*/
protected string $remark;
/**
* @var int
*/
protected int $type;
protected int $channel = 1;
/**
* @var array
*/
protected array $source;
/**
* Notes: 设置当前用户
*
* @Author: 玄尘
* @Date : 2021/5/19 10:40
* @param User $user
* @return $this
*/
public function user(User $user): Order
{
$this->user_id = $user->getAuthIdentifier();;
return $this;
}
/**
* Notes: 设置类型
*
* @Author: 玄尘
* @Date : 2021/10/18 10:03
* @param $type
* @return $this
*/
public function type($type): Order
{
$this->type = $type;
return $this;
}
/**
* Notes: 订单渠道
*
* @Author: 玄尘
* @Date: 2022/9/8 15:51
*/
public function channel($channel): self
{
$this->channel = $channel;
return $this;
}
/**
* Notes: 设置订单备注信息
*
* @Author: 玄尘
* @Date : 2021/5/19 10:40
* @param string|null $remark
* @return $this
*/
public function remark(?string $remark = ''): Order
{
$this->remark = $remark;
return $this;
}
/**
* Notes: 附加数据
*
* @Author: 玄尘
* @Date : 2021/5/19 10:40
* @param array $source
* @return $this
*/
public function source(array $source): Order
{
$this->source = $source;
return $this;
}
/**
* Notes: 设置商品数据
*
* @Author: 玄尘
* @Date : 2021/5/14 13:58
* @param $items
* @return $this
*/
public function items($items): Order
{
$this->items = new Collection($items);
return $this;
}
/**
* Notes: 设置订单收货地址
*
* @Author: 玄尘
* @Date : 2021/5/19 10:41
* @param Address $address
* @return $this
*/
public function address(Address $address): Order
{
$this->address = $address;
return $this;
}
/**
* Notes: 创建订单
*
* @Author: 玄尘
* @Date : 2021/5/19 10:42
* @return Collection
* @throws \Exception
*/
public function create(): Collection
{
if ($this->items->isEmpty()) {
throw new Exception('无法创建无内容的订单');
}
if (! is_numeric($this->user_id)) {
throw new Exception('必须先设置订单用户');
}
$splits = $this->splitOrderByShop();
DB::beginTransaction();
try {
$orders = [];
foreach ($splits as $split) {
$orders[] = $this->createOne($split['items']);
}
DB::commit();
$result = new Collection($orders);
$result->total = $this->total();
return $result;
} catch (Exception $exception) {
DB::rollBack();
throw new Exception($exception->getMessage());
}
}
/**
* Notes: 按照商户,对订单进行分组
*
* @Author: 玄尘
* @Date : 2021/5/19 10:43
* @return mixed
* @throws \Exception
*/
public function splitOrderByShop()
{
if (empty($this->items)) {
throw new Exception('无法创建无内容的订单');
}
return $this->items->groupBy('orderby')->map(function ($items, $key) {
/**
* 计算分订单总价格
*/
$items->amount = $items->reduce(function ($total, $item) {
return $total + $item->total();
});
/**
* 计算分订单总数量
*/
$items->qty = $items->reduce(function ($qty, $item) {
return $qty + $item->qty;
});
/**
* 计算分订单运费
*/
$items->freight = $items->reduce(function ($total, $item) {
return $total + $item->freight();
});
/**
* 回传店铺ID
*/
$items->shop_id = $items->first()->shop_id;
return [
'shop' => $items->first()->shop(),
'items' => $items,
];
});
}
/**
* Notes: 创建一条订单记录
*
* @Author: 玄尘
* @Date : 2021/5/21 10:24
* @param Collection $split
* @return Builder|Model
* @throws \Exception
*/
protected function createOne(Collection $split)
{
/**
* 创建主订单
*/
$order = OrderModel::query()
->create([
'shop_id' => $split->shop_id,
'user_id' => $this->user_id,
'amount' => $split->amount,
'type' => $this->type,
'channel' => $this->channel,
'freight' => $split->freight,
'remark' => $this->remark,
'source' => $this->source ?? null,
]);
/**
* 创建订单子条目
*/
foreach ($split as $item) {
// 库存校验
if ($item->qty > $item->model->getGoodsStock()) {
throw new Exception(sprintf('[%s]库存不足', $item->model->getGoodsName()));
}
$order->items()
->create([
'item_type' => get_class($item->model),
'item_id' => $item->sku_id,
'qty' => $item->qty,
'price' => $item->price,
'source' => $item->getSource(),
]);
if ($item->model->goods->deduct_stock_type == Goods::DEDUCT_STOCK_ORDER) {
// 扣减库存
$item->model->deductStock($item->qty, $order->user_id);
}
}
/**
* 自动更新地址
*/
if ($this->address instanceof Address) {
$this->setOrderAddress($order, $this->address);
}
/**
* 订单自动审核
*/
if (config('order.auto_audit')) {
$order->audit();
}
event(new OrderCreated($order));
return $order;
}
/**
* Notes: 计算订单总价格
*
* @Author: 玄尘
* @Date : 2021/5/21 10:26
* @return float|int|string
*/
public function total()
{
$this->total = 0;
foreach ($this->items as $item) {
$this->total = bcadd($this->total, $item->total(), 2);
}
return $this->total;
}
/**
* Notes: 设置订单收货地址
*
* @Author: 玄尘
* @Date : 2021/5/21 10:26
* @param $order
* @param $address
*/
protected function setOrderAddress($order, $address)
{
$order->express()
->create([
'name' => $address->name,
'mobile' => $address->mobile,
'province_id' => $address->province_id,
'city_id' => $address->city_id,
'district_id' => $address->district_id,
'address' => $address->address,
]);
}
/**
* Notes: 魔术方法,获取一些参数
*
* @Author: 玄尘
* @Date : 2021/5/21 10:27
* @param $attr
* @return float|int|string|null
*/
public function __get($attr)
{
switch ($attr) {
case 'total':
return $this->total();
}
return null;
}
/**
* Notes: 获取订单详情
*
* @Author: <C.Jason>
* @Date : 2019/11/22 1:51 下午
* @param string $order_no
* @return mixed
*/
public function get(string $order_no)
{
return OrderModel::where('user_id', $this->user_id)
->with(['user', 'items', 'express', 'seller', 'logs'])
->where('order_no', $order_no)
->first();
}
}