Three asks from the 2026-10-08 meeting, all on the OCR receipt queue. - Split: one receipt paid by several customers (411 + 523 sharing water 3014057) posts one charge per part. statement_document_splits holds free amounts that must sum to the receipt in cents, checked on save and again at confirm; "partes iguales" fills them in. Each part's row carries captureRef <docId>#<n>, so the double-post guard still holds. - Sin fondos per receipt: StatementDocument.outstanding, toggled in review. At confirm a line is outstanding if its receipt or the whole check is. - Open batch: POST /statements/batches/:id/files appends scans, numbered after the existing pages; a COMPLETED batch reopens. The confirm card prefills the check the batch was last posted against. Verified on dev against a real batch: 1,892.00 split 946/946 across two customers, a sibling receipt posted outstanding, second confirm refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
73 lines
2.4 KiB
TypeScript
73 lines
2.4 KiB
TypeScript
import {
|
|
ArrayMaxSize,
|
|
IsArray,
|
|
IsBoolean,
|
|
IsEnum,
|
|
IsInt,
|
|
IsNumber,
|
|
IsOptional,
|
|
IsString,
|
|
MinLength,
|
|
ValidateNested,
|
|
} from "class-validator";
|
|
import { Type } from "class-transformer";
|
|
import { Currency, ServiceKind, StatementDocumentStatus } from "@jorgecuadros/database";
|
|
|
|
export class CreateStatementBatchDto {
|
|
@IsEnum(ServiceKind) serviceKind!: ServiceKind;
|
|
@IsOptional() @IsString() label?: string;
|
|
}
|
|
|
|
/** Staff correction of one document's extracted fields or its match. */
|
|
export class ReviewDocumentDto {
|
|
@IsOptional() @IsString() accountRef?: string;
|
|
@IsOptional() @IsNumber() amount?: number;
|
|
@IsOptional() @IsString() period?: string;
|
|
@IsOptional() @IsString() dueDate?: string;
|
|
@IsOptional() @IsString() matchedPropertyServiceId?: string;
|
|
@IsOptional() @IsString() matchedCustomerId?: string;
|
|
// Restricted to the review-reachable states: a client cannot declare a
|
|
// document POSTED, because only a successful ledger write may do that.
|
|
@IsOptional()
|
|
@IsEnum(StatementDocumentStatus)
|
|
status?: Extract<StatementDocumentStatus, "MATCHED" | "NEEDS_REVIEW" | "CONFIRMED">;
|
|
/** Sin fondos for this receipt alone. */
|
|
@IsOptional() @IsBoolean() outstanding?: boolean;
|
|
}
|
|
|
|
export class SplitPartDto {
|
|
@IsString() @MinLength(1) customerId!: string;
|
|
@IsNumber() amount!: number;
|
|
}
|
|
|
|
/** A receipt's split; an empty list removes it. */
|
|
export class SetSplitsDto {
|
|
@IsArray()
|
|
@ArrayMaxSize(20)
|
|
@ValidateNested({ each: true })
|
|
@Type(() => SplitPartDto)
|
|
parts!: SplitPartDto[];
|
|
}
|
|
|
|
/**
|
|
* Post a batch's confirmed documents. The check-level fields are shared by
|
|
* every line, exactly as on the manual batch-capture screen — an OCR batch is
|
|
* still "these receipts, paid by this check".
|
|
*/
|
|
export class ConfirmBatchDto {
|
|
@IsString() @MinLength(1) checkNumber!: string;
|
|
@IsString() @MinLength(1) transactionDate!: string;
|
|
@IsOptional() @IsEnum(Currency) currency?: Currency;
|
|
/** Overrides the concept derived from the batch's service kind. */
|
|
@IsOptional() @IsString() typeId?: string;
|
|
/** Post as outstanding (sin fondos) — captured but not yet funded. */
|
|
@IsOptional() @IsBoolean() outstanding?: boolean;
|
|
/** Also post documents a reviewer explicitly marked CONFIRMED. */
|
|
@IsOptional() @IsBoolean() includeReviewed?: boolean;
|
|
}
|
|
|
|
export class ListBatchesQuery {
|
|
@IsOptional() @IsInt() page?: number;
|
|
@IsOptional() @IsInt() pageSize?: number;
|
|
}
|