feat(inventory): support line-based assignments and movements

This commit is contained in:
2026-06-19 01:05:33 +02:00
parent 8e6a00c2a9
commit 6d34a2f74f
17 changed files with 713 additions and 189 deletions
@@ -59,30 +59,36 @@ describe("assignment use-cases", () => {
prisma.item.findUniqueOrThrow({ where: { id: item.id } }),
prisma.assignment.findUniqueOrThrow({
where: { id: result.assignmentId },
include: { stockLines: true },
}),
prisma.movement.findMany({
prisma.inventoryMovement.findMany({
include: { stockLines: true },
orderBy: [{ createdAt: "asc" }, { id: "asc" }],
}),
])
expect(updatedItem.stock).toBe(3)
expect(assignment).toMatchObject({
itemId: item.id,
personId: person.id,
quantity: 2,
notes: "Initial assignment",
createdBy: actor.id,
returnDate: null,
createdById: actor.id,
closedAt: null,
})
expect(assignment.assignedAt).toEqual(assignmentDate)
expect(assignment.stockLines[0]).toMatchObject({
itemId: item.id,
quantity: 2,
returnedQuantity: 0,
})
expect(assignment.assignmentDate).toEqual(assignmentDate)
expect(movements).toHaveLength(1)
expect(movements[0]).toMatchObject({
type: "ASSIGNMENT",
itemId: item.id,
personId: person.id,
assignmentId: result.assignmentId,
quantity: 2,
userId: actor.id,
performedById: actor.id,
})
expect(movements[0].stockLines[0]).toMatchObject({
itemId: item.id,
stockDelta: -2,
})
})
@@ -109,7 +115,7 @@ describe("assignment use-cases", () => {
prisma.item.findUniqueOrThrow({ where: { id: item.id } }),
).resolves.toMatchObject({ stock: 1 })
await expect(prisma.assignment.count()).resolves.toBe(0)
await expect(prisma.movement.count()).resolves.toBe(0)
await expect(prisma.inventoryMovement.count()).resolves.toBe(0)
})
it("returns an assignment, restores stock, closes it, and records a RETURN movement", async () => {
@@ -139,34 +145,43 @@ describe("assignment use-cases", () => {
prisma.item.findUniqueOrThrow({ where: { id: item.id } }),
prisma.assignment.findUniqueOrThrow({
where: { id: created.assignmentId },
include: { stockLines: true },
}),
prisma.movement.findMany({
prisma.inventoryMovement.findMany({
include: { stockLines: true },
orderBy: [{ createdAt: "asc" }, { id: "asc" }],
}),
])
expect(updatedItem.stock).toBe(4)
expect(assignment.returnDate).toBeInstanceOf(Date)
expect(assignment.closedAt).toBeInstanceOf(Date)
expect(assignment).toMatchObject({
itemId: null,
assetId: null,
personId: null,
quantity: null,
personId: person.id,
status: "RETURNED",
})
expect(assignment.stockLines[0]).toMatchObject({
itemId: item.id,
quantity: 3,
returnedQuantity: 3,
})
expect(movements).toHaveLength(2)
expect(movements[0]).toMatchObject({
type: "ASSIGNMENT",
itemId: item.id,
assignmentId: created.assignmentId,
quantity: 3,
userId: actor.id,
performedById: actor.id,
})
expect(movements[0].stockLines[0]).toMatchObject({
itemId: item.id,
stockDelta: -3,
})
expect(movements[1]).toMatchObject({
type: "RETURN",
itemId: item.id,
assignmentId: created.assignmentId,
quantity: 3,
userId: actor.id,
performedById: actor.id,
})
expect(movements[1].stockLines[0]).toMatchObject({
itemId: item.id,
stockDelta: 3,
})
})
@@ -197,6 +212,6 @@ describe("assignment use-cases", () => {
errors: { id: ["Assignment already returned"] },
})
await expect(prisma.movement.count()).resolves.toBe(2)
await expect(prisma.inventoryMovement.count()).resolves.toBe(2)
})
})