feat(items): adapt item flows to inventory schema defaults and SKU generation

This commit is contained in:
2026-06-19 17:14:22 +02:00
parent 7b8a415c6a
commit 965a04a468
7 changed files with 306 additions and 19 deletions
+46 -17
View File
@@ -3,10 +3,12 @@ import prisma from "@/lib/prisma"
import type { CreateItemData, UpdateItemData } from "@/schemas/item.schema"
import { ItemService } from "@/services/item.service"
import { MovementService } from "@/services/movement.service"
import { buildItemSku } from "./item.helpers"
type FieldErrors = Record<string, string[]>
type CreateItemUseCaseInput = CreateItemData & {
type CreateItemUseCaseInput = Omit<CreateItemData, "trackingType" | "status"> &
Partial<Pick<CreateItemData, "trackingType" | "status">> & {
actorId: string
}
@@ -37,18 +39,19 @@ function isUniqueConstraintError(error: unknown) {
)
}
function buildSkuFromName(name: string) {
return name
.trim()
.toUpperCase()
.replace(/[^A-Z0-9]+/g, "-")
.replace(/^-|-$/g, "")
}
export async function createItemUseCase(
input: CreateItemUseCaseInput,
): Promise<ItemUseCaseResult> {
const { actorId, name, categoryId, stock } = input
const {
actorId,
name,
categoryId,
stock,
trackingType = "QUANTITY",
status = "ACTIVE",
minStock,
targetStock,
} = input
if (stock < 0) {
return itemError({ stock: ["Stock cannot be negative"] })
@@ -64,11 +67,23 @@ export async function createItemUseCase(
})
}
const skuBase = buildItemSku(name)
const existingSkuCount = await tx.item.count({
where: {
sku: {
startsWith: skuBase,
},
},
})
const item = await ItemService.create(
{
sku: buildSkuFromName(name),
sku: buildItemSku(name, existingSkuCount),
name,
trackingType: "QUANTITY",
trackingType,
status,
minStock,
targetStock,
category: { connect: { id: categoryId } },
stock: stock || 0,
},
@@ -103,7 +118,17 @@ export async function createItemUseCase(
export async function updateItemUseCase(
input: UpdateItemUseCaseInput,
): Promise<ItemUseCaseResult> {
const { actorId, id, stock, name, categoryId } = input
const {
actorId,
id,
stock,
name,
categoryId,
trackingType,
status,
minStock,
targetStock,
} = input
try {
return await prisma.$transaction(async (tx) => {
@@ -122,21 +147,25 @@ export async function updateItemUseCase(
await ItemService.update(
id,
{
stock: stock || existingItem.stock,
stock: stock ?? existingItem.stock,
name: name || existingItem.name,
trackingType: trackingType ?? existingItem.trackingType,
status: status ?? existingItem.status,
minStock: minStock ?? existingItem.minStock,
targetStock: targetStock ?? existingItem.targetStock,
category: { connect: { id: categoryId } },
},
tx,
)
const quantity = stock - existingItem.stock
const updatedStock = stock ?? existingItem.stock
if (stock && stock > existingItem.stock) {
if (updatedStock > existingItem.stock) {
await MovementService.create(
{
type: "IN",
itemId: id,
quantity,
quantity: updatedStock - existingItem.stock,
userId: actorId,
},
tx,