feat(P18B-1,P18B-2): 新增资产流转模型与受控接口

这个提交包含在:
2026-03-07 23:20:34 +08:00
父节点 1b2527eee0
当前提交 946a357f8b
共修改 8 个文件,包含 1276 行新增和 7 行删除
+15 -7
查看文件
@@ -56,7 +56,7 @@ const ASSET_CREATE_SCHEMA = z
})
.strict();
const ASSET_PATCH_SCHEMA = ASSET_CREATE_SCHEMA.omit({ purchaseRequestId: true }).partial();
const ASSET_PATCH_SCHEMA = ASSET_CREATE_SCHEMA.omit({ purchaseRequestId: true, assigneeEmployeeId: true }).partial();
const ASSET_CATEGORY_SELECT = {
id: true,
@@ -796,6 +796,8 @@ async function assetsRoutes(fastify) {
actorId: request.employee.id,
});
const resolvedStatus = payload.assigneeEmployeeId ? "in_use" : payload.status ?? "in_stock";
const created = await tx.assetCard.create({
data: {
asset_no: issued.documentNumber,
@@ -806,7 +808,7 @@ async function assetsRoutes(fastify) {
purchase_request_id: payload.purchaseRequestId ?? null,
serial_no: payload.serialNo ?? null,
location: payload.location ?? null,
status: payload.status ?? "in_stock",
status: resolvedStatus,
assignee_employee_id: payload.assigneeEmployeeId ?? null,
activated_at: payload.activatedAt ? parseDateOnlyString(payload.activatedAt) : null,
retired_at: payload.retiredAt ? parseDateOnlyString(payload.retiredAt) : null,
@@ -816,6 +818,17 @@ async function assetsRoutes(fastify) {
select: ASSET_CARD_SELECT,
});
if (created.assignee_employee_id) {
await tx.assetAssignment.create({
data: {
asset_id: created.id,
employee_id: created.assignee_employee_id,
assigned_at: created.activated_at ?? created.created_at,
note: null,
},
});
}
await tx.auditLog.create({
data: buildAuditLogData(request, {
actorId: request.employee.id,
@@ -894,7 +907,6 @@ async function assetsRoutes(fastify) {
const nextCategoryId = payload.categoryId ?? current.category_id;
const nextLegalEntityId = payload.legalEntityId ?? current.legal_entity_id;
const nextCostCenterId = payload.costCenterId ?? current.cost_center_id;
const nextAssigneeId = payload.assigneeEmployeeId === undefined ? current.assignee_employee_id : payload.assigneeEmployeeId;
if (payload.categoryId !== undefined) {
await ensureAssetCategoryExists(tx, nextCategoryId, { requireActive: true });
@@ -905,9 +917,6 @@ async function assetsRoutes(fastify) {
if (payload.costCenterId !== undefined || payload.legalEntityId !== undefined) {
await ensureCostCenterAvailable(tx, nextCostCenterId, nextLegalEntityId);
}
if (payload.assigneeEmployeeId !== undefined) {
await ensureAssigneeEmployee(tx, nextAssigneeId);
}
const updated = await tx.assetCard.update({
where: { id: assetId },
@@ -919,7 +928,6 @@ async function assetsRoutes(fastify) {
...(payload.serialNo !== undefined ? { serial_no: payload.serialNo } : {}),
...(payload.location !== undefined ? { location: payload.location } : {}),
...(payload.status !== undefined ? { status: payload.status } : {}),
...(payload.assigneeEmployeeId !== undefined ? { assignee_employee_id: payload.assigneeEmployeeId } : {}),
...(payload.activatedAt !== undefined
? { activated_at: payload.activatedAt ? parseDateOnlyString(payload.activatedAt) : null }
: {}),