订单详情表```php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
//mysql的配置:default-storage-engine=INNODB 创建的表默认存储引擎为innodb存储引擎
use HasFactory;
protected $fillable = [
'no',
'address',
'total_amount',
'remark',
'paid_at',
'payment_method',
'payment_no',
'refund_status',
'refund_no',
'closed',
'reviewed',
'ship_status',
'ship_data',
'extra',
];
protected $casts = [
'closed' => 'boolean',
'reviewed' => 'boolean',
'address' => 'json',
'ship_data' => 'json',
'extra' => 'json',
];
/**
* @var array 支付时间
*/
protected $dates = [
'paid_at',
];
protected static function boot()
{
parent::boot(); // TODO: Change the autogenerated stub
static::creating(function ($model){
if (!$model->no){
$model->no = static::findAvailableNo();
//如果编号生成失败,终止订单的创建
if (!$model->no){
return false;
}
}
});
}
public static function findAvailableNo()
{
// 订单流水号前缀
$prefix = date('YmdHis');
for ($i = 0; $i < 10; $i++) {
// 随机生成 6 位的数字
$no = $prefix.str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
// 判断是否已经存在
if (!static::query()->where('no', $no)->exists()) {
return $no;
}
}
\Log::warning('find order no failed');
return false;
}
public function user()
{
return $this->belongsTo(User::class);
}
//一个订单可以有多个详情
public function items()
{
return $this->hasMany(OrderItem::class);
}
}
![下单全过程4](https://cdn.learnku.com/uploads/images/202208/16/55573/GkKzWS7uQ2.png!large)
![下单全过程4](https://cdn.learnku.com/uploads/images/202208/16/55573/RjyLfeYswF.png!large)
创建契约
![下单全过程4](https://cdn.learnku.com/uploads/images/202208/16/55573/nx4gKxyxuD.png!large)
```html
<?php
namespace App\Contracts\Order;
interface OrderContracts
{
/**
* @param $address
* @param $user
* @param $remark
* @param $items
* @return mixed
* 订单生成 对于控制器
*/
public function store($address,$user,$remark,$items);
/**
* @param $addressId
* @return mixed
* 更新收货地址使用时间
*/
public function updateMemberAddressTime($addressId);
/**
* @param $address
* @param $remark
* @param $user
* @return mixed
* 创建订单
*/
public function orderSave($address,$remark,$user);
/**
* @param $order
* @param $sku
* @return mixed
* 订单详情数据生成
*/
public function orderItemSave($order,$sku);
/**
* @param $order
* @param $total_amount
* @return mixed
* 修改订单总金额
*/
public function updateTotalAmount($order,$total_amount);
/**
* @param $user
* @param $sku
* @return mixed
* 移除购物车商品
*/
public function RemoveCart($user,$sku);
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ProductSku extends Model
{
use HasFactory;
protected $fillable = [
'title','on_sale','price','stock'
];
protected $dates = [
'on_sale' => 'boolean',//on_sale是布尔类型的数据
];
public function product()
{
return $this->belongsTo(Product::class);
}
public function cartItems()
{
return $this->hasMany(CartItem::class);
}
public function attribute()
{
return $this->belongsToMany(Attribute::class,ProductSkuAttribute::class,'product_sku_id','attribute_id');
}
public function decreaseStock($amount)
{
if ($amount < 0){
throw new \Exception('减库存不能小于0');
}
return $this->where('id',$this->id)->where('stock','>=',$amount)->decrement('stock',$amount);
}
public function addStock($amount)
{
if ($amount < 0){
throw new \Exception('加库存不能小于0');
}
return $this->increment('stock',$amount);
}
}
<?php
namespace App\Services\Order;
use App\Contracts\Order\OrderContracts;
use App\Jobs\CloseOrder;
use App\Models\MemberAddress;
use App\Models\Order;
use App\Models\ProductSku;
use Carbon\Carbon;
use Illuminate\Contracts\Container\Container;
class OrderService implements OrderContracts
{
protected $app;
protected $config;
public function __construct(Container $container)
{
$this->app = $container;
$this->config = $container->make('config');
}
public function store($address, $user, $remark, $items)
{
$order = \DB::transaction(function () use ($user,$address,$remark,$items){
if (!$address = $this->updateMemberAddressTime($address)){
return [
'code' => 400,
'error' => $this->config->get('error.order.address'),
];
}
if (!$order = $this->orderSave($address,$remark,$user)){
return [
'code' => 400,
'error' => $this->config->get('error.order.order_save'),
];
}
if (!$total_amount = $this->orderItemSave($order,$items)){
return [
'code' => 400,
'error' => $this->config->get('error.order.order_items'),
];
}
$this->updateTotalAmount($order,$total_amount);
if (!$cart = $this->RemoveCart($user,$items)){
return [
'code' => 400,
'error' => $this->config->get('error.order.cart'),
];
}
return $order;
});
dispatch(new CloseOrder($order,3));
return $order;
}
//修改地址
public function updateMemberAddressTime($addressId)
{
$address = MemberAddress::query()->find($addressId);
$address->update([
'last_used_at' => Carbon::now()//获取当前时间
]);
return $address;
}
public function orderSave($address, $remark, $user)
{
$order = new Order([
'address' => [
'address' => $address->full_address,
'zip' => $address->zip,
'contact_name' => $address->contact_name,
'contact_phone' => $address->contact_phone
],
'remark' => $remark,
'total_amount' => 0
]);
$order->user()->associate($user);
$order->save();
return $order;
}
//计算订单总金额
public function orderItemSave($order, $skus)
{
$total_amount = 0;
foreach ($skus as $data){
$sku = ProductSku::query()->find($data["sku_id"]);
$item = $order->items()->make([
'amount' => $data["amount"],
'price' => $sku->price
]);
$item->product()->associate($sku->product_id);
$item->productSku()->associate($sku);
$item->save();
$total_amount += $sku->price * $data["amount"];
if ($sku->decreaseStock($data["amount"]) <= 0){
throw new \Exception("该商品库存不足");
}
}
return $total_amount;
}
public function updateTotalAmount($order, $total_amount)
{
return $order->update([
'total_amount' => $total_amount
]);
}
public function RemoveCart($user, $sku)
{
$skuIds = collect($sku)->pluck('sku_id')->all();
if (!is_array($skuIds)){
$skuIds = [$skuIds];
}
$cart = $user->cartItems()->whereIn('product_sku_id',$skuIds)->delete();
return $cart;
}
}
订单延迟处理