- Introduced a new Sales module, consolidating routes for managing sales requests and orders. - Added a Products module for handling product details, including creation, editing, and viewing functionalities. - Implemented UI components for product forms and detail views, with validation schemas for product data. - Integrated language support for English and Indonesian in the new modules. - Developed unit tests for sales and product remote data services and transformers to ensure functionality and reliability. These changes enhance the application by providing a structured approach to sales management, improving user experience and data handling.
151 lines
5.0 KiB
TypeScript
151 lines
5.0 KiB
TypeScript
import { formatDateValue, parseDateValue } from '@repo/ui/form';
|
|
import { emptyToNull, omitEmptyFields } from '../../../../../core/domain/configuration-field-validators';
|
|
import type { SalesDocumentDto, SalesDocumentEntity, SalesImageEntity, SalesLineEntity } from './sales-document.entity';
|
|
|
|
export function relationId(value: unknown): string | undefined {
|
|
if (value && typeof value === 'object' && 'id' in value) {
|
|
const id = (value as { id?: unknown }).id;
|
|
return id == null ? undefined : String(id);
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export function toRelationStub(id?: string | null) {
|
|
return id ? { id } : null;
|
|
}
|
|
|
|
export function mapSalesLinesFromDto(dto: SalesDocumentDto): SalesLineEntity[] {
|
|
return (dto.products ?? []).map((line) => ({
|
|
id: line.id,
|
|
productId: line.productId,
|
|
product: toRelationStub(line.productId),
|
|
quantity: line.quantity,
|
|
price: line.price ?? null,
|
|
}));
|
|
}
|
|
|
|
export function mapSalesImagesFromDto(dto: SalesDocumentDto): SalesImageEntity[] {
|
|
return (dto.images ?? []).map((image) => ({
|
|
id: image.id,
|
|
url: image.url,
|
|
description: image.description ?? null,
|
|
}));
|
|
}
|
|
|
|
export function mapSalesDocumentFromDto(dto: SalesDocumentDto): SalesDocumentEntity {
|
|
return {
|
|
id: dto.id,
|
|
code: dto.code ?? null,
|
|
date: formatDateValue(parseDateValue(dto.date) ?? undefined),
|
|
salesPersonId: dto.salesPersonId,
|
|
salesPerson: toRelationStub(dto.salesPersonId),
|
|
branchId: dto.branchId,
|
|
branch: toRelationStub(dto.branchId),
|
|
divisionId: dto.divisionId,
|
|
division: toRelationStub(dto.divisionId),
|
|
customerId: dto.customerId,
|
|
customer: toRelationStub(dto.customerId),
|
|
address: dto.address,
|
|
latitude: dto.latitude ?? null,
|
|
longitude: dto.longitude ?? null,
|
|
notes: dto.notes ?? null,
|
|
products: mapSalesLinesFromDto(dto),
|
|
images: mapSalesImagesFromDto(dto),
|
|
status: dto.status,
|
|
createdAt: dto.createdAt,
|
|
updatedAt: dto.updatedAt,
|
|
createdBy: dto.createdBy,
|
|
updatedBy: dto.updatedBy,
|
|
};
|
|
}
|
|
|
|
export function toSalesWritePayload(
|
|
entity: Partial<SalesDocumentEntity>,
|
|
options?: { includeSalesRequestId?: boolean },
|
|
): Record<string, unknown> {
|
|
const products = (entity.products ?? [])
|
|
.map((line) => {
|
|
const productId = relationId(line.product) ?? line.productId;
|
|
if (!productId) return null;
|
|
return omitEmptyFields({
|
|
productId,
|
|
quantity: line.quantity,
|
|
price: line.price,
|
|
});
|
|
})
|
|
.filter(Boolean);
|
|
|
|
const images = (entity.images ?? [])
|
|
.filter((image) => Boolean(image?.url))
|
|
.map((image) => omitEmptyFields({ url: image.url, description: image.description }));
|
|
|
|
const payload: Record<string, unknown> = {
|
|
code: entity.code,
|
|
date: formatDateValue(entity.date),
|
|
salesPersonId: relationId(entity.salesPerson) ?? entity.salesPersonId,
|
|
branchId: relationId(entity.branch) ?? entity.branchId,
|
|
divisionId: relationId(entity.division) ?? entity.divisionId,
|
|
customerId: relationId(entity.customer) ?? entity.customerId,
|
|
address: entity.address,
|
|
latitude: emptyToNull(entity.latitude),
|
|
longitude: emptyToNull(entity.longitude),
|
|
notes: emptyToNull(entity.notes),
|
|
products,
|
|
images,
|
|
};
|
|
|
|
if (options?.includeSalesRequestId) {
|
|
payload.salesRequestId = relationId((entity as { salesRequest?: unknown }).salesRequest) ?? (entity as { salesRequestId?: string }).salesRequestId;
|
|
}
|
|
|
|
return payload;
|
|
}
|
|
|
|
export function toSalesFilterPayload(filter: Record<string, any>): Record<string, any> {
|
|
const next = { ...filter };
|
|
if (next.salesPerson && typeof next.salesPerson === 'object') {
|
|
next.salesPersonId = next.salesPerson.id;
|
|
delete next.salesPerson;
|
|
}
|
|
if (next.branch && typeof next.branch === 'object') {
|
|
next.branchId = next.branch.id;
|
|
delete next.branch;
|
|
}
|
|
if (next.division && typeof next.division === 'object') {
|
|
next.divisionId = next.division.id;
|
|
delete next.division;
|
|
}
|
|
if (next.customer && typeof next.customer === 'object') {
|
|
next.customerId = next.customer.id;
|
|
delete next.customer;
|
|
}
|
|
if (next.salesRequest && typeof next.salesRequest === 'object') {
|
|
next.salesRequestId = next.salesRequest.id;
|
|
delete next.salesRequest;
|
|
}
|
|
return omitEmptyFields(next);
|
|
}
|
|
|
|
export function salesRequestToFormValues(request: SalesDocumentEntity) {
|
|
return {
|
|
date: request.date,
|
|
salesPerson: request.salesPerson ?? toRelationStub(request.salesPersonId),
|
|
branch: request.branch ?? toRelationStub(request.branchId),
|
|
division: request.division ?? toRelationStub(request.divisionId),
|
|
customer: request.customer ?? toRelationStub(request.customerId),
|
|
address: request.address,
|
|
latitude: request.latitude ?? null,
|
|
longitude: request.longitude ?? null,
|
|
notes: request.notes ?? '',
|
|
products: (request.products ?? []).map((line) => ({
|
|
product: line.product ?? toRelationStub(line.productId),
|
|
quantity: line.quantity,
|
|
price: line.price ?? '',
|
|
})),
|
|
images: (request.images ?? []).map((image) => ({
|
|
url: image.url,
|
|
description: image.description ?? '',
|
|
})),
|
|
};
|
|
}
|