4
0
Fork 0
panliang 2022-09-23 16:53:25 +08:00
parent ba11205bea
commit aa923701d8
5 changed files with 130 additions and 91 deletions

View File

@ -2,11 +2,21 @@
订单管理 订单管理
## 依赖
- [peidikeji/dcat-admin-user](https://gitea.peidikeji.cn/pdkj/dcat-admin-user)
- [peidikeji/dcat-admin-goods](https://gitea.peidikeji.cn/pdkj/dcat-admin-goods)
## 安装 ## 安装
- `composer config repositories.peidikeji/dcat-admin-order git git@gitea.peidikeji.cn:dcat-admin/dcat-admin-order.git` - 进入项目根目录
- `composer require peidikeji/dcat-admin-order dev-develop` - `mkdir packages && cd packages`
- `php artisan vendor:publish --provider=Peidikeji\Order\OrderServiceProvider` - `git clone https://gitea.peidikeji.cn/pdkj/dcat-admin-order.git`
- `rm -rf dcat-admin-order/.git`
- 返回项目根目录
- `composer config repositories.peidikeji/dcat-admin-order path ./packages/dcat-admin-order`
- `composer require peidikeji/dcat-admin-order:dev-develop`
- `php artisan migrate`
## 配置 ## 配置

View File

@ -12,12 +12,6 @@
"email": "1163816051@qq.com" "email": "1163816051@qq.com"
} }
], ],
"require": {
"php": "^8.0.2",
"peidikeji/dcat-admin": "*",
"laravel/framework": "^9.0",
"peidikeji/dcat-admin-user": "*"
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Peidikeji\\Order\\": "src/" "Peidikeji\\Order\\": "src/"

View File

@ -55,14 +55,12 @@ return new class extends Migration
Schema::create('order_goods', function (Blueprint $table) { Schema::create('order_goods', function (Blueprint $table) {
$table->id('id'); $table->id('id');
$table->unsignedBigInteger('order_id')->comment('订单ID, orders.id'); $table->unsignedBigInteger('order_id')->comment('订单ID, orders.id');
$table->unsignedBigInteger('merchant_id')->nullable()->comment('商户ID');
$table->unsignedBigInteger('goods_id')->comment('所属商品, 关联 goods.id');
$table->string('goods_name'); $table->string('goods_name');
$table->string('goods_sn')->nullable();
$table->string('cover_image')->nullable()->comment('封面图'); $table->string('cover_image')->nullable()->comment('封面图');
$table->string('goods_sn')->nullable();
$table->unsignedBigInteger('goods_id')->nullable()->comment('所属商品, 关联 goods.id');
$table->decimal('price', 12, 2)->comment('售价'); $table->decimal('price', 12, 2)->comment('售价');
$table->decimal('score_max_amount', 12, 2)->default(0)->comment('积分抵扣最大值');
$table->string('goods_sku_sn')->nullable(); $table->string('goods_sku_sn')->nullable();
$table->unsignedBigInteger('goods_sku_id')->nullable()->comment('所属商品SKU, 关联 goods_skus.id'); $table->unsignedBigInteger('goods_sku_id')->nullable()->comment('所属商品SKU, 关联 goods_skus.id');
@ -76,10 +74,6 @@ return new class extends Migration
$table->unsignedInteger('ship_amount')->default(0)->comment('累计发货数量'); $table->unsignedInteger('ship_amount')->default(0)->comment('累计发货数量');
$table->unsignedBigInteger('shipping_tmp_id')->nullable()->comment('配送模板id');
$table->decimal('weight', 12, 2)->nullable()->comment('重量');
$table->decimal('volume', 12, 2)->nullable()->comment('体积');
$table->comment('订单-商品'); $table->comment('订单-商品');
}); });

View File

@ -28,7 +28,7 @@ class OrderServiceProvider extends ServiceProvider
__DIR__.'/../database/' => database_path('migrations') __DIR__.'/../database/' => database_path('migrations')
], 'dcat-admin-order-migrations'); ], 'dcat-admin-order-migrations');
// $this->loadMigrationsFrom(__DIR__.'/../database/'); $this->loadMigrationsFrom(__DIR__.'/../database/');
$this->loadTranslationsFrom(__DIR__.'/../lang', 'dcat-admin-order'); $this->loadTranslationsFrom(__DIR__.'/../lang', 'dcat-admin-order');
} }

View File

@ -2,10 +2,10 @@
namespace Peidikeji\Order; namespace Peidikeji\Order;
use App\Services\ShippingMoneyService; use Peidikeji\Coupon\CouponService;
use Peidikeji\Coupon\Models\UserCoupon;
use Peidikeji\Goods\Models\Goods; use Peidikeji\Goods\Models\Goods;
use Peidikeji\Order\Enums\OrderScene; use Peidikeji\Order\Enums\OrderScene;
use Peidikeji\Order\Enums\ShipWay;
use Peidikeji\Order\Events\OrderCreated; use Peidikeji\Order\Events\OrderCreated;
use Peidikeji\Order\Exceptions\OrderException; use Peidikeji\Order\Exceptions\OrderException;
use Peidikeji\Order\Models\Order; use Peidikeji\Order\Models\Order;
@ -43,34 +43,37 @@ class OrderStore
// address: 配送地址, money: 配送费, way: 配送方式 // address: 配送地址, money: 配送费, way: 配送方式
public $ship = ['address' => null, 'money' => 0, 'way' => null]; public $ship = ['address' => null, 'money' => 0, 'way' => null];
// 使用优惠券
public $coupon = ['id' => null, 'money' => 0];
public function __construct($scene = null) public function __construct($scene = null)
{ {
$this->scene = $scene; $this->scene = $scene;
$this->orderGoodsList = collect(); $this->orderGoodsList = collect();
} }
public function scene($scene) public function scene($scene): static
{ {
$this->scene = $scene; $this->scene = $scene;
return $this; return $this;
} }
public function user($user) public function user($user): static
{ {
$this->user = $user; $this->user = $user;
return $this; return $this;
} }
public function merchant($merchant) public function merchant($merchant): static
{ {
$this->merchant = $merchant; $this->merchant = $merchant;
return $this; return $this;
} }
public function remarks($remarks) public function remarks($remarks): static
{ {
$this->remarks = $remarks; $this->remarks = $remarks;
@ -80,23 +83,33 @@ class OrderStore
/** /**
* 购买商品 * 购买商品
* *
* @param array $goods 商品参数 [{id, amount, spec: [{name, value}]}] * @param array $params 商品参数 [{id, amount, spec: [{name, value}]}]
* @param bool $vip 是否使用Vip价格 * @param mixed $vip 是否使用Vip价格(null: 根据用户判断, bool: 是否强制使用)
* @throws OrderException
*/ */
public function goods($params, $vip = null) public function goods(array $params, mixed $vip = null): static
{ {
$merchant = $this->merchant; $merchant = $this->merchant;
$query = Goods::show()->whereIn('id', array_column($params, 'id')); $goodsList = null;
if ($this->scene === OrderScene::Online->value) { if ($this->scene === OrderScene::Online->value) {
$query->whereNull('merchant_id'); $goodsList = Goods::show()->whereNull('merchant_id')->whereIn('id', array_column($params, 'id'))->get();
} elseif ($this->scene === OrderScene::Merchant->value) {
$goodsList = Goods::show()->where('merchant_id', $merchant->id)->whereIn('id', array_column($params, 'id'))->get();
} elseif ($this->scene === OrderScene::Scan->value) {
$money = $this->money;
$goodsList = collect()->push([
'id' => data_get($params, '0.id'),
'name' => $merchant->name,
'merchant_id' => $merchant->id,
'goods_name' => '线下交易',
'cover_image' => $merchant->logo,
'price' => $money,
'vip_price' => $money,
'amount' => 1,
'on_sale' => 1,
'stock' => 1
]);
} }
else if ($this->scene === OrderScene::Merchant->value || $this->scene === OrderScene::Scan->value) {
if (!$merchant) {
throw new OrderException('请选择店铺');
}
$query->where('merchant_id', $merchant->id);
}
$goodsList = $query->get();
if ($goodsList->count() === 0) { if ($goodsList->count() === 0) {
throw new OrderException('请选择有效商品'); throw new OrderException('请选择有效商品');
} }
@ -106,34 +119,40 @@ class OrderStore
if ($vip === null && $user) { if ($vip === null && $user) {
$vip = $user->isVip(); $vip = $user->isVip();
} }
foreach($params as $item) { foreach ($params as $item) {
$goods = $goodsList->firstWhere('id', $item['id']); $goods = $goodsList->firstWhere('id', $item['id']);
if (!$goods->on_sale) { if (! data_get($goods, 'on_sale')) {
throw new OrderException($goods->name . ' 未上架'); throw new OrderException($goods->name.' 未上架');
} }
$stock = $goods->stock;
// 最大抵扣积分
$scoreRatio = data_get($goods, 'score_max_amount', $merchant->score_max_ratio);
$price = data_get($goods, $vip ? 'vip_price' : 'price');
$scoreMaxAmount = $price * $scoreRatio / 100 / Setting::where('slug', 'discount_profit_ratio')->value('value');
$stock = data_get($goods, 'stock');
$orderGoods = [ $orderGoods = [
'goods_id' => $goods->id, 'goods_id' => data_get($goods, 'id'),
'merchant_id' => $goods->merchant_id, 'merchant_id' => data_get($goods, 'merchant_id'),
'goods_name' => $goods->name, 'goods_name' => data_get($goods, 'name'),
'goods_sn' => $goods->sn, 'goods_sn' => data_get($goods, 'sn'),
'cover_image' => $goods->cover_image, 'cover_image' => data_get($goods, 'cover_image'),
'price' => $goods->price, 'price' => data_get($goods, 'price'),
'vip_price' => $goods->vip_price, 'vip_price' => data_get($goods, 'vip_price'),
'score_max_amount' => $goods->score_max_amount, 'score_max_amount' => $scoreMaxAmount,
'attr' => $goods->attr, 'attr' => data_get($goods, 'attr'),
'spec' => data_get($item, 'spec'), 'spec' => data_get($item, 'spec'),
'part' => data_get($item, 'part'), 'part' => data_get($item, 'part'),
'amount' => data_get($item, 'amount', 1), 'amount' => data_get($item, 'amount', 1),
'money' => 0, 'money' => 0,
'shipping_tmp_id' => $goods->shipping_tmp_id, 'shipping_tmp_id' => data_get($goods, 'shipping_tmp_id'),
'weight' => $goods->weight, 'weight' => data_get($goods, 'weight'),
'volume' => $goods->volume, 'volume' => data_get($goods, 'volume'),
]; ];
if (isset($item['spec']) && $item['spec']) { if (data_get($item, 'spec')) {
$sku = $goods->skus()->jsonArray($item['spec'])->first(); $sku = $goods->skus()->jsonArray($item['spec'])->first();
if (!$sku) { if (! $sku) {
throw new OrderException($goods->name . ' 规格不存在'); throw new OrderException($goods->name.' 规格不存在');
} }
$stock = $sku->stock; $stock = $sku->stock;
$orderGoods['goods_sku_id'] = $sku->id; $orderGoods['goods_sku_id'] = $sku->id;
@ -146,7 +165,7 @@ class OrderStore
} }
if ($orderGoods['amount'] > $stock) { if ($orderGoods['amount'] > $stock) {
throw new OrderException($goods->name . ' 库存不足'); throw new OrderException($goods->name.' 库存不足');
} }
$orderGoods['money'] = round($orderGoods['price'] * $orderGoods['amount'], 2, PHP_ROUND_HALF_DOWN); $orderGoods['money'] = round($orderGoods['price'] * $orderGoods['amount'], 2, PHP_ROUND_HALF_DOWN);
@ -157,7 +176,7 @@ class OrderStore
$this->goodsList = $goodsList; $this->goodsList = $goodsList;
$this->orderGoodsList = $orderGoodsList; $this->orderGoodsList = $orderGoodsList;
$this->money = $orderGoodsList->sum('money'); $this->money = $orderGoodsList->sum('money');
$this->vip = ['is' => $vip, 'money' => $vip ? $orderGoodsList->sum(fn($item) => $item['price'] - $item['vip_price']) : 0]; $this->vip = ['is' => $vip, 'money' => $vip ? $orderGoodsList->sum(fn ($item) => $item['price'] - $item['vip_price']) : 0];
return $this; return $this;
} }
@ -165,32 +184,41 @@ class OrderStore
/** /**
* 配送 * 配送
* *
* @param string $way 配送方式 * @param string $way 配送方式
* @param array $address 地址 ['name' => '收货人', 'phone' => '18223350967', 'region' => ['重庆市', '重庆市', '渝北区'], 'zone' => [2221, 2222, 2234], 'address' => '线外城市花园3栋20楼']; * @param array $address 地址 ['name' => '收货人', 'phone' => '18223350967', 'region' => ['重庆市', '重庆市', '渝北区'], 'zone' => [2221, 2222, 2234], 'address' => '线外城市花园3栋20楼'];
*/ */
public function ship($way, $address = null) public function ship($way, $address = null)
{ {
$money = 0; $money = 0;
if ($way === ShipWay::Express->value && $address) {
$shipService = new ShippingMoneyService();
$money = $shipService->getShippingMoney($this->orderGoodsList->map(fn($item) => [
'shipping_tmp_id' => $item['shipping_tmp_id'],
'weight' => $item['weight'],
'volume' => $item['volume'],
'num' => $item['amount'],
'price' => $item['price'],
]), data_get($address, 'zone.2'));
}
$this->ship = ['way' => $way, 'address' => $address, 'money' => $money]; $this->ship = ['way' => $way, 'address' => $address, 'money' => $money];
return $this; 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];
}
/** /**
* 设置订单总金额 * 设置订单总金额
*/ */
public function money($money) public function money($money)
{ {
if ($this->scene !== OrderScene::Scan->value) {
throw new OrderException('非扫码付款, 无法设置订单金额');
}
$this->money = $money; $this->money = $money;
return $this; return $this;
@ -199,11 +227,12 @@ class OrderStore
/** /**
* 使用积分抵扣 * 使用积分抵扣
* *
* @param float $amount 积分数量 * @param int $amount 积分数量
* @param float $ratio 抵扣比例(0-1) * @param float|null $ratio 抵扣比例(0-1)
* @param float $money 金额(默认 = $amount * $ratio) * @param int|null $money 金额(默认 = $amount * $ratio)
* @throws OrderException
*/ */
public function score($amount, $ratio = null, $money = null) public function score(int $amount, float $ratio = null, int $money = null): static
{ {
$user = $this->user; $user = $this->user;
if ($amount > 0 && $user) { if ($amount > 0 && $user) {
@ -225,7 +254,7 @@ class OrderStore
if ($money === null) { if ($money === null) {
$money = $amount * $ratio; $money = $amount * $ratio;
} }
$money = round($money, 2, PHP_ROUND_HALF_DOWN); $money = floor($money);
$this->score = compact('money', 'amount', 'ratio'); $this->score = compact('money', 'amount', 'ratio');
} }
@ -237,8 +266,9 @@ class OrderStore
* 生成订单 * 生成订单
* *
* @return Order * @return Order
* @throws OrderException
*/ */
public function create() public function create(): Order
{ {
$order = new Order([ $order = new Order([
'sn' => OrderService::make()->generateSn(), 'sn' => OrderService::make()->generateSn(),
@ -257,6 +287,9 @@ class OrderStore
$order->score_discount_ratio = $this->score['ratio']; $order->score_discount_ratio = $this->score['ratio'];
$order->score_discount_money = $this->score['money']; $order->score_discount_money = $this->score['money'];
$order->coupon_money = $this->coupon['money'];
$order->coupon_id = $this->coupon['id'];
$order->vip_discount_money = $this->vip['money']; $order->vip_discount_money = $this->vip['money'];
$order->pay_money = $this->getPayMoney(); $order->pay_money = $this->getPayMoney();
@ -285,31 +318,39 @@ class OrderStore
// Vip 优惠 // Vip 优惠
$money -= $this->vip['money']; $money -= $this->vip['money'];
// 优惠券抵扣
$money -= $this->coupon['money'];
// 配送费 // 配送费
$money += $this->ship['money']; $money += $this->ship['money'];
return $money; return max($money, 0);
} }
/** /**
* 用户应得奖励 * 用户应得奖励
* *
* @param float $payMoney 支付金额 * @param float|null $payMoney 支付金额
* @return float * @return float
* @throws OrderException
*/ */
public function getUserBonus($payMoney = null) public function getUserBonus(float $payMoney = null): float
{ {
$money = 0; $money = 0;
if ($this->scene === OrderScene::Merchant->value && $this->merchant) { if ($this->merchant) {
$payMoney = is_null($payMoney) ? $this->getPayMoney() : $payMoney; $payMoney = is_null($payMoney) ? $this->getPayMoney() : $payMoney;
$money = round($payMoney * ($this->merchant->profit_ratio / 100), 2, PHP_ROUND_HALF_DOWN); $money = floor($payMoney * ($this->merchant->profit_ratio / 100));
$merchantUser = $this->merchant->user;
if ($merchantUser->profit < $money) {
throw new OrderException('店铺返现账户余额不足');
}
} }
return $money; return $money;
} }
public static function init(...$params) public static function init(...$params): static
{ {
return new static(...$params); return new static(...$params);
} }