生成采购单基础

This commit is contained in:
liu
2026-08-11 21:08:01 +08:00
parent 06c7bd9f88
commit 5d26f04ba2
13 changed files with 362 additions and 68 deletions
@@ -10,6 +10,7 @@ use App\Models\StoreOrderModel;
use App\Models\UserModel;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
@@ -74,7 +75,7 @@ class StoreOrderController extends BaseController
}
/**
* 待汇总预览:聚合所有待汇总订单明细(按商品分组),
* 已接单预览:聚合所有已接单订单明细(按商品分组),
* 供生成采购单前确认(C1 前置)
*/
#[GetRoute('/summary', 'query')]
@@ -87,7 +88,7 @@ class StoreOrderController extends BaseController
->selectRaw('SUM(quantity) as total_quantity')
->selectRaw('COUNT(DISTINCT store_id) as store_count')
->whereHas('order', function ($query) {
$query->where('status', StoreOrderModel::STATUS_PENDING);
$query->where('status', StoreOrderModel::STATUS_SUMMARIZED);
})
->groupBy('product_id')
->orderBy('product_id')
@@ -117,13 +118,13 @@ class StoreOrderController extends BaseController
}
/**
* 状态流转(待汇总→配送中完成;待汇总可取消;已汇总可转配送中)
* 状态流转:待接单→已接单/已取消;采购中→配送中/已完成;配送中→已完成
*/
#[PutRoute(route: '/{id}/status', authorize: 'update', where: ['id' => '[0-9]+'])]
public function status(int $id, Request $request): JsonResponse
{
$data = $request->validate([
'status' => 'required|integer|in:2,3,9',
'status' => 'required|integer|in:1,3,4,9',
], [
'status.required' => '目标状态不能为空',
'status.in' => '目标状态值不正确',
@@ -135,20 +136,7 @@ class StoreOrderController extends BaseController
}
$target = (int) $data['status'];
$allowed = match ($order->status) {
StoreOrderModel::STATUS_PENDING => [
StoreOrderModel::STATUS_DELIVERING,
StoreOrderModel::STATUS_CANCELLED,
],
StoreOrderModel::STATUS_SUMMARIZED => [
StoreOrderModel::STATUS_DELIVERING,
],
StoreOrderModel::STATUS_DELIVERING => [
StoreOrderModel::STATUS_COMPLETED,
],
default => [],
};
if (! in_array($target, $allowed, true)) {
if (! in_array($target, $this->allowedTransitions($order->status), true)) {
throw new RepositoryException(
'订单当前状态为「' . (self::STATUS_NAMES[$order->status] ?? $order->status) . '」,不允许该操作'
);
@@ -162,6 +150,75 @@ class StoreOrderController extends BaseController
return $this->success();
}
/**
* 批量状态流转:先全量校验流转路径,任一订单不允许则整批中止;
* 全部合法时在事务内流转并逐单通知门店
*/
#[PutRoute(route: '/batchStatus', authorize: 'update')]
public function batchStatus(Request $request): JsonResponse
{
$data = $request->validate([
'ids' => 'required|array|min:1',
'ids.*' => 'integer|exists:store_order,id',
'status' => 'required|integer|in:1,3,4,9',
], [
'ids.required' => '请选择要流转的订单',
'ids.min' => '请选择要流转的订单',
'ids.*.exists' => '订单不存在',
'status.required' => '目标状态不能为空',
'status.in' => '目标状态值不正确',
]);
$target = (int) $data['status'];
$orders = StoreOrderModel::query()->whereIn('id', $data['ids'])->get();
// 全量预校验:任一订单不满足流转条件,整批中止,不做任何修改
$blocked = [];
foreach ($orders as $order) {
if (! in_array($target, $this->allowedTransitions($order->status), true)) {
$blocked[] = $order->order_no . '' . (self::STATUS_NAMES[$order->status] ?? $order->status) . '';
}
}
if (! empty($blocked)) {
throw new RepositoryException(
'以下订单不允许流转为「' . (self::STATUS_NAMES[$target] ?? $target) . '」,批量操作已中止:' . implode('、', $blocked)
);
}
DB::transaction(function () use ($orders, $target) {
foreach ($orders as $order) {
$order->status = $target;
$order->save();
$this->notifyStore($order);
}
});
return $this->success(['success' => $orders->count()]);
}
/**
* 状态流转合法路径(与迁移状态定义一致):
* 待接单→已接单/已取消;采购中→配送中/已完成;配送中→已完成
* (已接单→采购中 只能经「生成采购单」完成,不在本流转内)
*
* @return int[]
*/
private function allowedTransitions(int $status): array
{
return match ($status) {
StoreOrderModel::STATUS_PENDING => [
StoreOrderModel::STATUS_SUMMARIZED,
StoreOrderModel::STATUS_CANCELLED,
],
StoreOrderModel::STATUS_DELIVERING => [
StoreOrderModel::STATUS_DISTRIBUTION,
StoreOrderModel::STATUS_COMPLETED,
],
StoreOrderModel::STATUS_DISTRIBUTION => [StoreOrderModel::STATUS_COMPLETED],
default => [],
};
}
/**
* 修改周转框/周转托盘数量(仅已接单、采购中、配送中可改),
* 自动重算附加金额与订单总金额
@@ -78,20 +78,28 @@ class PurchaseOrderController extends BaseController
return $this->success();
}
/** C1 按门店订单汇总生成采购单 */
/**
* C1 生成采购单:合并全部「已接单」门店订单(或指定的 order_ids),
* 生成后源订单转为「采购中」并回写 purchase_id
*/
#[PostRoute('/generate', 'generate')]
public function generate(Request $request): JsonResponse
{
$data = $request->validate([
'purchase_date' => 'required|date_format:Y-m-d',
'order_ids' => 'sometimes|array|min:1',
'order_ids.*' => 'integer|exists:store_order,id',
], [
'purchase_date.required' => '请选择采购日期',
'purchase_date.date_format' => '采购日期格式为 Y-m-d',
'order_ids.min' => '请选择要合并的订单',
'order_ids.*.exists' => '订单不存在',
]);
$purchase = app(PurchaseGenerateService::class)->generate(
$data['purchase_date'],
(int) $request->user()->id,
array_map('intval', $data['order_ids'] ?? []),
);
return $this->success(