refactor(assignments): move workflows into use cases

This commit is contained in:
2026-06-04 22:09:54 +02:00
parent 5034ec0646
commit e88fb2e6d4
14 changed files with 630 additions and 376 deletions
-298
View File
@@ -1,298 +0,0 @@
"use server"
import { revalidatePath } from "next/cache"
import prisma from "@/lib/prisma"
import { AssetService } from "@/services/asset.service"
import { AssignmentService } from "@/services/assignment.service"
import { getAuthenticatedUserId } from "@/services/auth.service"
import { ItemService } from "@/services/item.service"
import { MovementService } from "@/services/movement.service"
import {
assignmentSchema,
type CreateAssignmentFormType,
type ReturnAssignmentFormType,
type UpdateAssignmentFormType,
updateAssignmentSchema,
} from "../schemas/assignment.schemas"
export async function getAssignments() {
return await AssignmentService.findAllWithRecipient()
}
export async function getAssignmentById(id: string) {
return await AssignmentService.findById(id)
}
export async function createAssignment(formData: CreateAssignmentFormType) {
const createdBy = await getAuthenticatedUserId()
const validatedFields = assignmentSchema.safeParse({
...formData,
createdBy,
})
if (!validatedFields.success) {
return {
success: false,
errors: validatedFields.error.flatten().fieldErrors,
}
}
const { itemId, assetId, quantity, recipientId } = validatedFields.data
if (!itemId || !recipientId || quantity <= 0) return
try {
const item = await ItemService.findById(itemId)
if (!item) {
return {
success: false,
errors: { itemId: ["Item not found"] },
}
}
if (item.stock < quantity) {
return {
success: false,
errors: { quantity: ["Item does not have enough stock"] },
}
}
if (assetId) {
const asset = await AssetService.findById(assetId)
if (!asset) {
return {
success: false,
errors: { assetId: ["Asset not found"] },
}
}
if (asset.itemId !== item.id) {
return {
success: false,
errors: { assetId: ["Asset does not belong to item"] },
}
}
}
await ItemService.updateStock(itemId, -quantity)
if (assetId && recipientId) {
await AssetService.update(assetId, {
status: "ASSIGNED",
})
}
const createdAssignment = await AssignmentService.create({
itemId,
assetId: assetId || undefined,
quantity,
recipientId,
})
await MovementService.create({
itemId,
assetId: assetId || undefined,
quantity,
type: "ASSIGNMENT",
recipientId,
assignmentId: createdAssignment.id,
})
revalidatePath("/assignments")
return {
success: true,
message: "Assignment created successfully",
}
} catch (error) {
console.error("Database error:", error)
return {
success: false,
errors: { error: ["Error creating assignment"] },
}
}
}
export async function updateAssignment(formData: UpdateAssignmentFormType) {
const validatedFields = updateAssignmentSchema.safeParse(formData)
if (!validatedFields.success) {
return {
success: false,
errors: validatedFields.error.flatten().fieldErrors,
}
}
try {
const { id, recipientId, itemId, assetId, quantity } = validatedFields.data
const assignment = await prisma.assignment.findUnique({
where: { id },
})
if (!assignment) {
return {
success: false,
errors: { id: ["Assignment not found"] },
}
}
if (itemId) {
const item = await prisma.item.findUnique({
where: { id: itemId },
})
if (!item) {
return {
success: false,
errors: { itemId: ["Item not found"] },
}
}
// if (item.stock < quantity) {
// return {
// success: false,
// errors: { quantity: ["Item does not have enough stock"] },
// }
// }
}
if (assetId) {
const asset = await prisma.asset.findUnique({
where: { id: assetId },
})
if (!asset) {
return {
success: false,
errors: { assetId: ["Asset not found"] },
}
}
if (asset.itemId !== itemId) {
await prisma.asset.update({
where: { id: assetId },
data: { itemId },
})
return {
success: false,
errors: { assetId: ["Asset does not belong to item"] },
}
}
}
const createdBy = await getAuthenticatedUserId()
if (assignment.recipientId !== recipientId) {
await MovementService.create({
type: "RETURN",
quantity: assignment.quantity || 1,
itemId: assignment.itemId || undefined,
assetId: assignment.assetId || undefined,
recipientId: assignment.recipientId || undefined,
assignmentId: id,
})
await MovementService.create({
type: "ASSIGNMENT",
quantity,
itemId,
assetId: assetId || undefined,
recipientId,
assignmentId: id,
})
await prisma.assignment.update({
data: {
...validatedFields.data,
createdBy,
recipientId,
itemId,
assetId,
quantity,
returnDate: null,
},
where: { id },
})
} else {
await prisma.assignment.update({
where: { id },
data: {
...validatedFields.data,
itemId,
assetId,
quantity,
returnDate: new Date(),
},
})
}
revalidatePath("/assignments")
return {
success: true,
message: "Assignment updated successfully",
}
} catch (error) {
console.error("Database error:", error)
return {
success: false,
errors: { error: ["Error creating assignment"] },
}
}
}
export async function returnAssignment(formData: ReturnAssignmentFormType) {
const { id } = formData
const assignment = await AssignmentService.findById(id)
if (!assignment) {
return {
success: false,
errors: { id: ["Assignment not found"] },
}
}
if (assignment.returnDate) {
return {
success: false,
errors: { id: ["Assignment already returned"] },
}
}
if (assignment.itemId && assignment.quantity) {
await ItemService.update(assignment.itemId, {
stock: { increment: assignment.quantity || 1 },
})
}
if (assignment.assetId) {
await AssetService.update(assignment.assetId, {
status: "AVAILABLE",
})
}
await AssignmentService.delete(id)
await MovementService.create({
type: "RETURN",
quantity: assignment.quantity || 1,
itemId: assignment.itemId || undefined,
assetId: assignment.assetId || undefined,
assignmentId: id,
})
revalidatePath("/assignments")
return {
success: true,
message: "Assignment returned successfully",
}
}
-52
View File
@@ -1,52 +0,0 @@
import { z } from "zod"
export const assignmentSchema = z.object({
id: z.string().optional(),
quantity: z.coerce
.number()
.int()
.nonnegative()
.min(1, {
error: "Quantity is required"
}),
notes: z.string().optional(),
itemId: z.string().min(1, {
error: "Item is required"
}).optional(),
assetId: z.string().optional(),
recipientId: z.string().min(1, {
error: "Recipient is required"
}),
assignmentDate: z.date().optional(),
returnDate: z.date().optional(),
})
export const createAssignmentSchema = assignmentSchema.omit({
id: true,
returnDate: true,
})
export type CreateAssignmentFormType = z.input<typeof createAssignmentSchema>
export type CreateAssignmentData = z.output<typeof createAssignmentSchema>
export const updateAssignmentSchema = assignmentSchema
.omit({
returnDate: true,
})
.superRefine((data, ctx) => {
if (data.itemId && !data.assetId) {
ctx.addIssue({
code: "custom",
message: "Asset ID is required when item ID is provided",
path: ["assetId"],
})
}
})
export type UpdateAssignmentFormType = z.input<typeof updateAssignmentSchema>
export const returnAssignmentSchema = z.object({
id: z.string().min(1, {
error: "Assignment ID is required"
}),
})
export type ReturnAssignmentFormType = z.infer<typeof returnAssignmentSchema>