订单详情表```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); | |
} |
}
 | |
 | |
创建契约 | |
 | |
```html | |
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); | |
} |
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); | |
} | |
} | |
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; | |
} | |
} |
订单延迟处理