feat(movements): gate StockMovementLine on trackingType QUANTITY

This commit is contained in:
2026-06-25 03:22:08 +02:00
parent 8f7a406e83
commit a0a1e1bdc8
7 changed files with 257 additions and 16 deletions
@@ -1,6 +1,7 @@
import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"
import type { PrismaClient } from "@/generated/prisma/client"
import {
createTestCategory,
createTestItem,
createTestPerson,
createTestUser,
@@ -185,6 +186,102 @@ describe("asset use-cases", () => {
expect(await AssetService.findAll()).toHaveLength(0)
})
it("creates a SERIALIZED asset in AVAILABLE status without writing a stock line or incrementing stock", async () => {
const actor = await createTestUser(prisma)
const category = await createTestCategory(prisma)
const item = await prisma.item.create({
data: {
sku: "PHONE-SKU",
name: "Phone",
trackingType: "SERIALIZED",
stock: 0,
category: { connect: { id: category.id } },
},
})
const result = await createAssetUseCase({
actorId: actor.id,
itemId: item.id,
serialNumber: "SERIALIZED-AVAILABLE-001",
status: "AVAILABLE",
})
expect(result.success).toBe(true)
if (!result.success) throw new Error("Expected asset creation success")
const [updatedItem, movements] = await Promise.all([
prisma.item.findUniqueOrThrow({ where: { id: item.id } }),
prisma.inventoryMovement.findMany({
include: { stockLines: true, assetLines: true },
orderBy: [{ createdAt: "asc" }, { id: "asc" }],
}),
])
expect(updatedItem.stock).toBe(0)
expect(movements).toHaveLength(1)
expect(movements[0]).toMatchObject({
type: "RECEIPT",
performedById: actor.id,
})
expect(movements[0].stockLines).toEqual([])
expect(movements[0].assetLines).toHaveLength(1)
expect(movements[0].assetLines[0]).toMatchObject({
assetId: result.assetId,
})
})
it("updates a SERIALIZED asset from AVAILABLE to ASSIGNED without writing a stock line", async () => {
const actor = await createTestUser(prisma)
const person = await createTestPerson(prisma)
const category = await createTestCategory(prisma)
const item = await prisma.item.create({
data: {
sku: "LAPTOP-SKU",
name: "Laptop",
trackingType: "SERIALIZED",
stock: 0,
category: { connect: { id: category.id } },
},
})
const created = await createAssetUseCase({
actorId: actor.id,
itemId: item.id,
serialNumber: "SERIALIZED-ASSIGN-001",
status: "AVAILABLE",
})
expect(created.success).toBe(true)
if (!created.success) throw new Error("Expected asset creation success")
const updated = await updateAssetUseCase({
actorId: actor.id,
id: created.assetId,
itemId: item.id,
serialNumber: "SERIALIZED-ASSIGN-001",
status: "ASSIGNED",
personId: person.id,
})
expect(updated.success).toBe(true)
const [updatedItem, movements] = await Promise.all([
prisma.item.findUniqueOrThrow({ where: { id: item.id } }),
prisma.inventoryMovement.findMany({
include: { stockLines: true, assetLines: true },
orderBy: [{ createdAt: "asc" }, { id: "asc" }],
}),
])
expect(updatedItem.stock).toBe(0)
expect(movements).toHaveLength(2)
expect(movements[1].stockLines).toEqual([])
expect(movements[1].assetLines).toHaveLength(1)
expect(movements[1].assetLines[0]).toMatchObject({
assetId: created.assetId,
})
})
it("creates an assigned asset with assignment and ASSIGNMENT movement", async () => {
const actor = await createTestUser(prisma)
const person = await createTestPerson(prisma)