4
0
Fork 0
dcat-admin-order/src/OrderStore.php

245 lines
6.9 KiB
PHP

<?php
namespace Peidikeji\Order;
use Peidikeji\Coupon\CouponService;
use Peidikeji\Coupon\Models\UserCoupon;
use Peidikeji\Goods\Models\Goods;
use Peidikeji\Order\Events\OrderCreated;
use Peidikeji\Order\Exceptions\OrderException;
use Peidikeji\Order\Models\Order;
use Peidikeji\Setting\Models\Setting;
class OrderStore
{
// 订单商品列表
public $orderGoodsList;
// 商品列表
public $goodsList;
// 下单用户
public $user;
// 订单总额/商品总额
public $money;
// 用户备注
public $remarks;
// amount: 使用积分, money: 积分抵扣金额, ratio: 抵扣比例
public $score = ['amount' => 0, 'money' => 0, 'ratio' => 0];
// address: 配送地址, money: 配送费, way: 配送方式
public $ship = ['address' => null, 'money' => 0, 'way' => null];
// 使用优惠券
public $coupon = ['id' => null, 'money' => 0];
public function __construct()
{
$this->orderGoodsList = collect();
}
public function user($user): static
{
$this->user = $user;
return $this;
}
public function remarks($remarks): static
{
$this->remarks = $remarks;
return $this;
}
/**
* 购买商品
*
* @param array $params 商品参数 [{id, amount, spec: [{name, value}]}]
* @throws OrderException
*/
public function goods(array $params): static
{
$goodsList = Goods::show()->whereIn('id', array_column($params, 'id'))->get();
if ($goodsList->count() === 0) {
throw new OrderException('请选择有效商品');
}
$orderGoodsList = collect();
foreach ($params as $item) {
$goods = $goodsList->firstWhere('id', $item['id']);
if (!$goods) {
throw new OrderException('商品不存在');
}
if (! data_get($goods, 'on_sale')) {
throw new OrderException($goods->name.' 未上架');
}
$stock = data_get($goods, 'stock');
$orderGoods = [
'goods_id' => data_get($goods, 'id'),
'goods_name' => data_get($goods, 'name'),
'goods_sn' => data_get($goods, 'goods_sn'),
'cover_image' => data_get($goods, 'cover_image'),
'price' => floatval(data_get($goods, 'price')),
'attr' => data_get($goods, 'attr'),
'spec' => data_get($item, 'spec'),
'part' => data_get($item, 'part'),
'amount' => data_get($item, 'amount', 1),
'money' => 0,
];
$spec = data_get($item, 'spec');
if ($goods->spec) {
if (!$spec) {
throw new OrderException('请选择 '.$goods->name.' 的规格');
}
$sku = $goods->skus()->jsonArray($item['spec'])->first();
if (! $sku) {
throw new OrderException($goods->name.' 规格不存在');
}
$stock = $sku->stock;
$orderGoods['goods_sku_id'] = $sku->id;
$orderGoods['goods_sku_sn'] = $sku->sn;
$orderGoods['price'] = floatval($sku->price);
}
if ($orderGoods['amount'] > $stock) {
throw new OrderException($goods->name.' 库存不足');
}
$orderGoods['money'] = round($orderGoods['price'] * $orderGoods['amount'], 2, PHP_ROUND_HALF_DOWN);
$orderGoodsList->push($orderGoods);
}
$this->goodsList = $goodsList;
$this->orderGoodsList = $orderGoodsList;
$this->money = $orderGoodsList->sum('money');
return $this;
}
/**
* 配送
*
* @param string $way 配送方式
* @param array $address 地址 ['name' => '收货人', 'phone' => '18223350967', 'region' => ['重庆市', '重庆市', '渝北区'], 'zone' => [2221, 2222, 2234], 'address' => '线外城市花园3栋20楼'];
*/
public function ship($way, $address = null)
{
$money = 0;
$this->ship = ['way' => $way, 'address' => $address, 'money' => $money];
return $this;
}
/**
* 使用优惠券
*
* @param UserCoupon $info 优惠券领取记录
*/
public function coupon(UserCoupon $info)
{
$info->canUse(true);
$couponMoney = CouponService::make()->available($info, $this->orderGoodsList);
if ($couponMoney === false) {
throw new OrderException('优惠券不可用');
}
$this->coupon = ['id' => $info->id, 'money' => $couponMoney];
}
/**
* 使用积分抵扣
*
* @param int $amount 积分数量
* @param float|null $ratio 抵扣比例(0-1)
* @param int|null $money 金额(默认 = $amount * $ratio)
* @throws OrderException
*/
public function score(int $amount, float $ratio = null, int $money = null): static
{
$user = $this->user;
if ($amount > 0 && $user) {
if ($user->balance < $amount) {
throw new OrderException('用户积分不足');
}
// 积分抵扣比例: 1 积分 = ? 金额
$ratio = 1;
if ($money === null) {
$money = $amount * $ratio;
}
$money = floor($money);
$this->score = compact('money', 'amount', 'ratio');
}
return $this;
}
/**
* 生成订单
*
* @return Order
* @throws OrderException
*/
public function create(): Order
{
$order = new Order([
'sn' => OrderService::make()->generateSn(),
]);
$order->user_id = $this->user?->id;
$order->ship_address = $this->ship['address'];
$order->ship_way = $this->ship['way'];
$order->ship_money = $this->ship['money'];
$order->user_remarks = $this->remarks;
$order->total_money = $this->money;
$order->score_discount_amount = $this->score['amount'];
$order->score_discount_ratio = $this->score['ratio'];
$order->score_discount_money = $this->score['money'];
if ($this->coupon['id']) {
$order->coupon_money = $this->coupon['money'];
$order->coupon_id = $this->coupon['id'];
}
$order->pay_money = $this->getPayMoney();
$order->save();
$order->goods()->createMany($this->orderGoodsList);
return $order;
}
/**
* 获取付款金额
*
* @return float
*/
public function getPayMoney()
{
$money = $this->money;
// 积分抵扣
$money -= $this->score['money'];
// 优惠券抵扣
$money -= $this->coupon['money'];
// 配送费
$money += $this->ship['money'];
return max($money, 0);
}
public static function init(...$params): static
{
return new static(...$params);
}
}