245 lines
6.9 KiB
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);
|
|
}
|
|
}
|