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); } }