批量对账

This commit is contained in:
liu
2026-09-07 22:53:50 +08:00
parent 379aeac2b3
commit 7de51391e4
9 changed files with 469 additions and 39 deletions
@@ -13,6 +13,7 @@ use App\Http\Requests\Purchase\PurchaseStoreItemRequest;
use App\Models\BillModel;
use App\Models\CustomerLevelModel;
use App\Models\ProductModel;
use App\Models\PurchaseItemCheckModel;
use App\Models\PurchaseOrderModel;
use App\Models\StoreModel;
use App\Models\StoreOrderItemModel;
@@ -173,6 +174,12 @@ class PurchaseOrderController extends BaseController
return $row;
}, $rows),
'bills' => $bills,
// 单品「已对账」标记(入库持久化,商品ID列表)
'checked_product_ids' => PurchaseItemCheckModel::query()
->where('purchase_id', $purchase->id)
->pluck('product_id')
->map(static fn ($v) => (int) $v)
->all(),
]);
}
@@ -795,6 +802,103 @@ class PurchaseOrderController extends BaseController
});
}
/**
* 切换单品「已对账」标记(入库持久化:未标记→标记,已标记→取消;与采购单状态无关,对账期间可反复勾选)
*/
#[PutRoute(route: '/{id}/check/{productId}', authorize: 'query', where: ['id' => '[0-9]+', 'productId' => '[0-9]+'])]
public function toggleItemCheck(int $id, int $productId, Request $request): JsonResponse
{
$purchase = PurchaseOrderModel::find($id);
if (empty($purchase)) {
throw new RepositoryException('采购单不存在');
}
$hasItem = StoreOrderItemModel::query()
->where('purchase_id', $purchase->id)
->where('product_id', $productId)
->exists();
if (! $hasItem) {
throw new RepositoryException('该采购单下无此商品的订货明细');
}
$marked = PurchaseItemCheckModel::query()
->where('purchase_id', $purchase->id)
->where('product_id', $productId)
->first();
if ($marked !== null) {
$marked->delete();
return $this->success(['checked' => false], '已取消对账标记');
}
PurchaseItemCheckModel::create([
'purchase_id' => $purchase->id,
'product_id' => $productId,
'operator_id' => (int) $request->user()->id,
]);
return $this->success(['checked' => true], '已标记为已对账');
}
/**
* 批量设置单品「已对账」标记(全选用:checked=true 批量标记 / false 批量取消;
* 仅处理本采购单内有订货明细的商品,重复标记幂等;与采购单状态无关)
*/
#[PutRoute(route: '/{id}/check', authorize: 'query', where: ['id' => '[0-9]+'])]
public function batchItemCheck(int $id, Request $request): JsonResponse
{
$data = $request->validate([
'product_ids' => 'required|array|min:1',
'product_ids.*' => 'integer',
'checked' => 'required|boolean',
], [
'product_ids.required' => '请选择商品',
'product_ids.min' => '请选择商品',
]);
$purchase = PurchaseOrderModel::find($id);
if (empty($purchase)) {
throw new RepositoryException('采购单不存在');
}
// 仅处理本采购单内有订货明细的商品(无效商品静默忽略)
$productIds = StoreOrderItemModel::query()
->where('purchase_id', $purchase->id)
->whereIn('product_id', array_map('intval', $data['product_ids']))
->distinct()
->pluck('product_id')
->map(static fn ($v) => (int) $v);
if (! (bool) $data['checked']) {
PurchaseItemCheckModel::query()
->where('purchase_id', $purchase->id)
->whereIn('product_id', $productIds)
->delete();
return $this->success(['count' => $productIds->count()], '已取消对账标记');
}
// 批量标记:跳过已标记行,仅补插缺失行(幂等)
$marked = PurchaseItemCheckModel::query()
->where('purchase_id', $purchase->id)
->whereIn('product_id', $productIds)
->pluck('product_id')
->map(static fn ($v) => (int) $v);
$operatorId = (int) $request->user()->id;
$now = now();
$rows = $productIds->diff($marked)
->map(static fn (int $productId) => [
'purchase_id' => $purchase->id,
'product_id' => $productId,
'operator_id' => $operatorId,
'created_at' => $now,
'updated_at' => $now,
])
->values()
->all();
if ($rows !== []) {
PurchaseItemCheckModel::insert($rows);
}
return $this->success(['count' => $productIds->count()], '已标记为已对账');
}
/**
* 采购单编辑闸:仅进行中(待采购)允许修改明细
*/