98 lines
3.5 KiB
TypeScript
98 lines
3.5 KiB
TypeScript
import { Name, UniqueID } from "@repo/rdx-ddd";
|
|
import { Result } from "@repo/rdx-utils";
|
|
|
|
import type { SaveTicketInput } from "../../common/tickets";
|
|
import { Ticket } from "../domain/ticket.aggregate";
|
|
import { TicketError } from "../domain/ticket-values";
|
|
import { TicketValues } from "../domain/value-objects/ticket-values";
|
|
|
|
import type { ITicketRepository } from "./ticket.repository";
|
|
import { mapTicketInput } from "./ticket-input.mapper";
|
|
export class TicketUseCases {
|
|
constructor(private readonly repository: ITicketRepository) {}
|
|
list(companyId?: string) {
|
|
const company = companyId ? UniqueID.create(companyId) : undefined;
|
|
if (company && !company.isSuccess) {
|
|
return Promise.resolve(Result.fail(new TicketError("INVALID_REQUEST")));
|
|
}
|
|
return this.repository.list(company?.isSuccess ? company.data : undefined);
|
|
}
|
|
lookups(companyId: string) {
|
|
const company = UniqueID.create(companyId);
|
|
return company.isSuccess
|
|
? this.repository.lookups(company.data)
|
|
: Promise.resolve(Result.fail(new TicketError("INVALID_REQUEST")));
|
|
}
|
|
save(companyId: string, id: string | undefined, input: SaveTicketInput, actorId: string) {
|
|
const company = UniqueID.create(companyId);
|
|
const actor = UniqueID.create(actorId);
|
|
const key = UniqueID.create(input.requestKey);
|
|
const identity = id ? UniqueID.create(id) : undefined;
|
|
if (
|
|
!(company.isSuccess && actor.isSuccess && key.isSuccess) ||
|
|
(identity && !identity.isSuccess) ||
|
|
(!id && input.expectedRevisionId !== null)
|
|
) {
|
|
return Promise.resolve(Result.fail(new TicketError("INVALID_REQUEST")));
|
|
}
|
|
const normalizedId = identity?.isSuccess ? identity.data.toPrimitive() : undefined;
|
|
return this.repository.save(company.data, key.data, (context) => {
|
|
const previous = context.tickets.find((item) => item.id.toPrimitive() === normalizedId);
|
|
if (id && !previous) {
|
|
return Result.fail(new TicketError("TICKET_NOT_FOUND"));
|
|
}
|
|
if (!id && context.requestTicket) {
|
|
return replayTicket(context.requestTicket, company.data, actor.data, input);
|
|
}
|
|
if (previous && previous.history.at(-1)?.id.toPrimitive() !== input.expectedRevisionId) {
|
|
return Result.fail(new TicketError("TICKET_CHANGED"));
|
|
}
|
|
const values = mapTicketInput(input.values, context, previous);
|
|
if (!values.isSuccess) {
|
|
return Result.fail(values.error);
|
|
}
|
|
const now = new Date().toISOString();
|
|
if (previous) {
|
|
return previous.update(values.data, actor.data, now);
|
|
}
|
|
return createTicket(company.data, key.data, values.data, actor.data, context.nextNumber, now);
|
|
});
|
|
}
|
|
}
|
|
|
|
function replayTicket(
|
|
original: Ticket,
|
|
company: UniqueID,
|
|
actor: UniqueID,
|
|
input: SaveTicketInput
|
|
): Result<Ticket, TicketError> {
|
|
const values = TicketValues.create(input.values);
|
|
const first = original.history[0];
|
|
if (
|
|
!(
|
|
original.companyId.equals(company) &&
|
|
first?.actorId.equals(actor) &&
|
|
values.isSuccess &&
|
|
first.values.equals(values.data)
|
|
)
|
|
) {
|
|
return Result.fail(new TicketError("REQUEST_KEY_REUSED"));
|
|
}
|
|
return Result.ok(original);
|
|
}
|
|
|
|
function createTicket(
|
|
company: UniqueID,
|
|
key: UniqueID,
|
|
values: TicketValues,
|
|
actor: UniqueID,
|
|
number: number,
|
|
now: string
|
|
): Result<Ticket, TicketError> {
|
|
const reference = Name.create(`T-${String(number).padStart(6, "0")}`, 40);
|
|
if (!reference.isSuccess) {
|
|
return Result.fail(new TicketError("INVALID_REQUEST"));
|
|
}
|
|
return Ticket.create(company, reference.data, key, values, actor, now);
|
|
}
|