feat(assignments): support line-based returns and authenticated updates
This commit is contained in:
@@ -7,20 +7,37 @@ import { AssetService } from "@/services/asset.service"
|
||||
import { AssignmentService } from "@/services/assignment.service"
|
||||
import { ItemService } from "@/services/item.service"
|
||||
import { MovementService } from "@/services/movement.service"
|
||||
import type {
|
||||
AssignmentStockLineInput,
|
||||
AssignmentStockReturnInput,
|
||||
} from "@/types"
|
||||
|
||||
type FieldErrors = Record<string, string[]>
|
||||
|
||||
type CreateAssignmentUseCaseInput = CreateAssignmentData & {
|
||||
type CreateAssignmentUseCaseInput = Omit<
|
||||
CreateAssignmentData,
|
||||
"itemId" | "quantity"
|
||||
> & {
|
||||
actorId: string
|
||||
itemId?: string
|
||||
quantity?: number
|
||||
lines?: AssignmentStockLineInput[]
|
||||
}
|
||||
|
||||
type ReturnAssignmentUseCaseInput = {
|
||||
id: string
|
||||
actorId: string
|
||||
returns?: AssignmentStockReturnInput[]
|
||||
}
|
||||
|
||||
type UpdateAssignmentUseCaseInput = UpdateAssignmentData & {
|
||||
type UpdateAssignmentUseCaseInput = Omit<
|
||||
UpdateAssignmentData,
|
||||
"itemId" | "quantity"
|
||||
> & {
|
||||
actorId: string
|
||||
itemId?: string
|
||||
quantity?: number
|
||||
lines?: AssignmentStockLineInput[]
|
||||
}
|
||||
|
||||
type CreateAssignmentUseCaseResult =
|
||||
@@ -78,10 +95,45 @@ function updateAssignmentError(
|
||||
}
|
||||
}
|
||||
|
||||
function resolveAssignmentLine(
|
||||
input:
|
||||
| Pick<
|
||||
CreateAssignmentUseCaseInput,
|
||||
"itemId" | "quantity" | "notes" | "lines"
|
||||
>
|
||||
| Pick<
|
||||
UpdateAssignmentUseCaseInput,
|
||||
"itemId" | "quantity" | "notes" | "lines"
|
||||
>,
|
||||
): AssignmentStockLineInput | null {
|
||||
const providedLine = input.lines?.[0]
|
||||
|
||||
if (providedLine) {
|
||||
return providedLine
|
||||
}
|
||||
|
||||
if (!input.itemId || typeof input.quantity !== "number") {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
itemId: input.itemId,
|
||||
quantity: input.quantity,
|
||||
notes: input.notes,
|
||||
}
|
||||
}
|
||||
|
||||
export async function createAssignmentUseCase(
|
||||
input: CreateAssignmentUseCaseInput,
|
||||
): Promise<CreateAssignmentUseCaseResult> {
|
||||
const { actorId, itemId, assetId, quantity, personId } = input
|
||||
const { actorId, assetId, personId } = input
|
||||
const line = resolveAssignmentLine(input)
|
||||
|
||||
if (!line || !personId || line.quantity <= 0) {
|
||||
return createAssignmentError({ error: ["Invalid assignment data"] })
|
||||
}
|
||||
|
||||
const { itemId, quantity, notes } = line
|
||||
|
||||
if (!itemId || !personId || quantity <= 0) {
|
||||
return createAssignmentError({ error: ["Invalid assignment data"] })
|
||||
@@ -142,7 +194,7 @@ export async function createAssignmentUseCase(
|
||||
assetId: assetId || undefined,
|
||||
quantity,
|
||||
personId,
|
||||
notes: input.notes,
|
||||
notes: notes ?? input.notes,
|
||||
assignmentDate: input.assignmentDate,
|
||||
createdBy: actorId,
|
||||
},
|
||||
@@ -172,16 +224,12 @@ export async function createAssignmentUseCase(
|
||||
export async function updateAssignmentUseCase(
|
||||
input: UpdateAssignmentUseCaseInput,
|
||||
): Promise<UpdateAssignmentUseCaseResult> {
|
||||
const {
|
||||
actorId,
|
||||
id,
|
||||
personId,
|
||||
itemId,
|
||||
assetId,
|
||||
quantity,
|
||||
notes,
|
||||
assignmentDate,
|
||||
} = input
|
||||
const { actorId, id, personId, assetId } = input
|
||||
const line = resolveAssignmentLine(input)
|
||||
const itemId = line?.itemId ?? input.itemId
|
||||
const quantity = line?.quantity ?? input.quantity ?? 0
|
||||
const notes = line?.notes ?? input.notes
|
||||
const assignmentDate = input.assignmentDate
|
||||
|
||||
if (!id) {
|
||||
return updateAssignmentError({ id: ["Assignment ID is required"] })
|
||||
@@ -282,7 +330,7 @@ export async function updateAssignmentUseCase(
|
||||
export async function returnAssignmentUseCase(
|
||||
input: ReturnAssignmentUseCaseInput,
|
||||
): Promise<ReturnAssignmentUseCaseResult> {
|
||||
const { id, actorId } = input
|
||||
const { id, actorId, returns } = input
|
||||
|
||||
if (!id) {
|
||||
return returnAssignmentError({ id: ["Assignment ID is required"] })
|
||||
@@ -299,18 +347,35 @@ export async function returnAssignmentUseCase(
|
||||
return returnAssignmentError({ id: ["Assignment already returned"] })
|
||||
}
|
||||
|
||||
const assignmentWasReturned = await AssignmentService.markReturnedIfActive(
|
||||
const returnResult = await AssignmentService.returnStockAssignment(
|
||||
id,
|
||||
actorId,
|
||||
returns,
|
||||
tx,
|
||||
)
|
||||
|
||||
if (!assignmentWasReturned) {
|
||||
return returnAssignmentError({ id: ["Assignment already returned"] })
|
||||
if (!returnResult) {
|
||||
return returnAssignmentError({ error: ["Invalid assignment data"] })
|
||||
}
|
||||
|
||||
if (assignment.itemId && assignment.quantity) {
|
||||
await ItemService.updateStock(assignment.itemId, assignment.quantity, tx)
|
||||
for (const returnedLine of returnResult.returnedLines) {
|
||||
await ItemService.updateStock(
|
||||
returnedLine.itemId,
|
||||
returnedLine.quantity,
|
||||
tx,
|
||||
)
|
||||
|
||||
await MovementService.create(
|
||||
{
|
||||
type: "RETURN",
|
||||
quantity: returnedLine.quantity,
|
||||
itemId: returnedLine.itemId,
|
||||
assetId: assignment.assetId || undefined,
|
||||
assignmentId: id,
|
||||
userId: actorId,
|
||||
},
|
||||
tx,
|
||||
)
|
||||
}
|
||||
|
||||
if (assignment.assetId) {
|
||||
@@ -323,18 +388,6 @@ export async function returnAssignmentUseCase(
|
||||
)
|
||||
}
|
||||
|
||||
await MovementService.create(
|
||||
{
|
||||
type: "RETURN",
|
||||
quantity: assignment.quantity || 1,
|
||||
itemId: assignment.itemId || undefined,
|
||||
assetId: assignment.assetId || undefined,
|
||||
assignmentId: id,
|
||||
userId: actorId,
|
||||
},
|
||||
tx,
|
||||
)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user