You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
8.9 KiB
221 lines
8.9 KiB
<?php
|
|
|
|
namespace App\Http\Controllers\User;
|
|
|
|
use App\Enums\OrderStatusEnum; // 引入订单状态枚举
|
|
use App\Enums\OrderTypeEnum; // 引入订单类型枚举
|
|
use App\Enums\SettingKeyEnum; // 引入设置键枚举
|
|
use App\Exceptions\OrderException; // 引入订单异常
|
|
use App\Http\Controllers\Controller; // 引入基础控制器
|
|
use App\Jobs\CancelUnPayOrder; // 引入取消未支付订单的任务
|
|
use App\Models\Address; // 引入地址模型
|
|
use App\Models\Car; // 引入购物车模型
|
|
use App\Models\Order; // 引入订单模型
|
|
use App\Models\OrderDetail; // 引入订单详情模型
|
|
use App\Models\Product; // 引入产品模型
|
|
use App\Models\User; // 引入用户模型
|
|
use App\Utils\OrderUtil; // 引入订单工具类
|
|
use Carbon\Carbon; // 引入 Carbon 日期处理库
|
|
use Illuminate\Http\Request; // 引入请求类
|
|
use Illuminate\Support\Collection; // 引入集合类
|
|
use Illuminate\Support\Facades\DB; // 引入数据库门面
|
|
use Symfony\Component\HttpFoundation\Response; // 引入响应类
|
|
|
|
class StoreOrderController extends Controller
|
|
{
|
|
/**
|
|
* 创建订单页面
|
|
*
|
|
* @param Request $request 请求对象
|
|
* @return \Illuminate\View\View
|
|
*/
|
|
public function create(Request $request)
|
|
{
|
|
/**
|
|
* @var $user User
|
|
* 获取当前登录用户
|
|
*/
|
|
$user = auth()->user();
|
|
|
|
// 从请求中获取购物车信息和商品 ID
|
|
$cars = $request->input('cars', []);
|
|
$ids = $request->input('ids');
|
|
$numbers = $request->input('numbers');
|
|
|
|
// 验证商品 ID 和数量的有效性
|
|
if (count($ids) === 0 || count($ids) !== count($numbers)) {
|
|
return back()->with('error', '无效的商品'); // 返回错误信息
|
|
}
|
|
|
|
// 查询数据库中存在的商品
|
|
$products = Product::query()->whereIn('uuid', $ids)->get();
|
|
if ($products->count() === 0 || $products->count() !== count($numbers)) {
|
|
return back()->with('error', '无效的商品'); // 返回错误信息
|
|
}
|
|
|
|
$totalAmount = 0; // 初始化总金额
|
|
|
|
// 计算每个商品的总金额并更新商品数量
|
|
$products->transform(function (Product $product, $i) use ($numbers, &$totalAmount) {
|
|
$product->number = $numbers[$i]; // 设置商品数量
|
|
$product->total_amount = round($product->price * $product->number); // 计算商品总金额
|
|
$totalAmount += $product->total_amount; // 累加总金额
|
|
return $product; // 返回更新后的商品
|
|
});
|
|
|
|
// 增加邮费
|
|
$postAmount = \setting(new SettingKeyEnum(SettingKeyEnum::POST_AMOUNT));
|
|
$totalAmount += $postAmount; // 将邮费加到总金额
|
|
|
|
// 获取用户的收货地址
|
|
$addresses = $user->addresses()->latest()->get();
|
|
|
|
// 获取可用的优惠券
|
|
$today = Carbon::today()->toDateString();
|
|
$coupons = $user->coupons()
|
|
->where('start_date', '<=', $today) // 优惠券开始日期
|
|
->where('end_date', '>=', $today) // 优惠券结束日期
|
|
->whereNull('used_at') // 未使用的优惠券
|
|
->where('full_amount', '<=', $totalAmount) // 满足使用条件的优惠券
|
|
->latest()
|
|
->get();
|
|
|
|
// 返回创建订单页面的视图
|
|
return view('orders.create', compact('products', 'cars', 'addresses', 'totalAmount', 'coupons', 'postAmount'));
|
|
}
|
|
|
|
/**
|
|
* 存储订单
|
|
*
|
|
* @param Request $request 请求对象
|
|
* @return \Illuminate\Http\JsonResponse
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
// 验证请求数据的有效性
|
|
if (($response = $this->validateRequest($request)) instanceof Response) {
|
|
return $response; // 返回响应
|
|
}
|
|
|
|
list($ids, $numbers, $productMap, $address, $couponModel) = $response; // 解构响应数据
|
|
|
|
// 构建订单详情数据
|
|
$detailsData = Collection::make($ids)->map(function ($id, $index) use ($numbers, $productMap) {
|
|
return [
|
|
'number' => $numbers[$index], // 商品数量
|
|
'product' => $productMap[$id] // 商品信息
|
|
];
|
|
});
|
|
|
|
DB::beginTransaction(); // 开始数据库事务
|
|
|
|
try {
|
|
// 创建主订单
|
|
$masterOrder = ($orderUtil = new OrderUtil($detailsData))->make(auth()->id(), $address);
|
|
|
|
// 验证优惠券的使用条件
|
|
if (!is_null($couponModel) && $masterOrder->amount < $couponModel->full_amount) {
|
|
throw new \Exception('优惠券门槛金额为 ' . $couponModel->full_amount); // 抛出异常
|
|
}
|
|
|
|
// 计算订单金额
|
|
if (!is_null($couponModel)) {
|
|
$masterOrder->amount = $masterOrder->amount > $couponModel->amount ?
|
|
($masterOrder->amount - $couponModel->amount) : 0.01; // 计算实际支付金额
|
|
|
|
$couponModel->used_at = Carbon::now()->toDateTimeString(); // 标记优惠券为已使用
|
|
$couponModel->save(); // 保存优惠券状态
|
|
|
|
$masterOrder->coupon_id = $couponModel->id; // 关联优惠券 ID
|
|
$masterOrder->coupon_amount = $couponModel->amount; // 记录优惠券金额
|
|
}
|
|
|
|
$masterOrder->save(); // 保存主订单
|
|
|
|
// 创建订单明细
|
|
$details = $orderUtil->getDetails(); // 获取订单明细数据
|
|
data_set($details, '*.order_id', $masterOrder->id); // 设置订单 ID
|
|
OrderDetail::query()->insert($details); // 保存订单明细
|
|
|
|
// 如果存在购物车,删除购物车中的商品
|
|
$cars = $request->input('cars');
|
|
if (is_array($cars) && !empty($cars)) {
|
|
Car::query()->where('user_id', auth()->id())->where('id', $cars)->delete(); // 删除购物车商品
|
|
}
|
|
|
|
// 设置未支付订单的自动取消时间
|
|
$settingKey = new SettingKeyEnum(SettingKeyEnum::UN_PAY_CANCEL_TIME);
|
|
$delay = Carbon::now()->addMinute(setting($settingKey, 30)); // 设置延迟时间
|
|
CancelUnPayOrder::dispatch($masterOrder)->delay($delay); // 调度取消任务
|
|
|
|
DB::commit(); // 提交事务
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollBack(); // 回滚事务
|
|
return responseJsonAsBadRequest($e->getMessage()); // 返回错误响应
|
|
}
|
|
|
|
return responseJson(200, '创建订单成功', ['order_id' => $masterOrder->id]); // 返回成功响应
|
|
}
|
|
|
|
/**
|
|
* 验证请求数据的有效性
|
|
*
|
|
* @param Request $request 请求对象
|
|
* @return array|Response 验证结果
|
|
*/
|
|
private function validateRequest(Request $request)
|
|
{
|
|
/**
|
|
* @var $user User
|
|
* @var $address Address
|
|
*/
|
|
$user = auth()->user(); // 获取当前用户
|
|
|
|
$ids = $request->input('ids'); // 获取商品 ID
|
|
$numbers = $request->input('numbers'); // 获取商品数量
|
|
|
|
// 验证商品 ID 和数量的有效性
|
|
if (count($ids) === 0 || count($ids) !== count($numbers)) {
|
|
return responseJsonAsBadRequest('无效的商品'); // 返回错误响应
|
|
}
|
|
|
|
// 查询数据库中存在的商品
|
|
$productMap = Product::query()->whereIn('uuid', $ids)->get()->mapWithKeys(function (Product $product) {
|
|
return [$product->uuid => $product]; // 将商品映射为 ID 和商品对象
|
|
});
|
|
|
|
if (count($productMap) === 0 || count($productMap) !== count($numbers)) {
|
|
return responseJsonAsBadRequest('无效的商品.'); // 返回错误响应
|
|
}
|
|
|
|
// 验证收货地址的有效性
|
|
$address = $user->addresses()->find($request->input('address_id'));
|
|
if (is_null($address)) {
|
|
return responseJsonAsBadRequest('请选择收货地址'); // 返回错误响应
|
|
}
|
|
|
|
// 验证优惠券的有效性
|
|
$couponModel = null;
|
|
if ($couponId = $request->input('coupon_id')) {
|
|
$couponModel = $user->coupons()->find($couponId); // 查询优惠券
|
|
if (is_null($couponModel)) {
|
|
return responseJsonAsBadRequest('无效的优惠券'); // 返回错误响应
|
|
}
|
|
|
|
$today = Carbon::today();
|
|
$startDate = Carbon::make($couponModel->start_date) ?? Carbon::tomorrow(); // 优惠券开始日期
|
|
$endDate = Carbon::make($couponModel->end_date) ?? Carbon::yesterday(); // 优惠券结束日期
|
|
if ($today->lt($startDate) || $today->gt($endDate)) {
|
|
return responseJsonAsBadRequest('优惠券已过使用期'); // 返回错误响应
|
|
}
|
|
|
|
if (!is_null($couponModel->used_at)) {
|
|
return responseJsonAsBadRequest('优惠券已使用过'); // 返回错误响应
|
|
}
|
|
}
|
|
|
|
return [$ids, $numbers, $productMap, $address, $couponModel]; // 返回验证结果
|
|
}
|
|
}
|