feat(clientes): alta de cliente in one screen, opening balance as a payment
The 2026-10-08 ask: open an account without four screens — cliente, propiedad, servicios and the saldo inicial, taken as the first payment. POST /customers/onboard writes it all in one Prisma transaction; a bad service or a taken folder number leaves nothing behind (rolled back on dev). A cash opening balance goes through the EFE receipt book inside that same transaction, so it gets its folio and its C<folio> credit; a check posts a CHECK DEPOSIT against the number given. /clientes/alta pre-fills the next free folder number and links the receipt for printing. The old customer-only form stays as "Solo cliente". Built without the screen sketch from the meeting (it never arrived); the fields are the legacy ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ca76f4d57a
commit
6468811955
11 files changed
+568
-8
No files matched your search
@@ -0,0 +1,56 @@
|
||||
import {
|
||||
ArrayMaxSize,
|
||||
IsArray,
|
||||
IsEnum,
|
||||
IsIn,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
MinLength,
|
||||
ValidateNested,
|
||||
} from "class-validator";
|
||||
import { Type } from "class-transformer";
|
||||
import { Currency } from "@jorgecuadros/database";
|
||||
import { CreateCustomerDto } from "./create-customer.dto";
|
||||
import { ServiceDto } from "../properties/property.dto";
|
||||
|
||||
/** The property, minus the customer it is being created for. */
|
||||
export class OnboardPropertyDto {
|
||||
@IsOptional() @IsString() addressLine1?: string;
|
||||
@IsOptional() @IsString() addressLine2?: string;
|
||||
@IsOptional() @IsString() phone1?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The opening balance the office takes when an account is opened, captured as
|
||||
* the customer's first payment. Cash issues an EFE receipt; a check posts a
|
||||
* CHECK DEPOSIT against that check number.
|
||||
*/
|
||||
export class OpeningPaymentDto {
|
||||
@IsIn(["CASH", "CHECK"]) method!: "CASH" | "CHECK";
|
||||
@IsNumber() amount!: number;
|
||||
@IsEnum(Currency) currency!: Currency;
|
||||
@IsString() @MinLength(1) receivedAt!: string;
|
||||
@IsOptional() @IsString() checkNumber?: string;
|
||||
/** Cash only: dollars credited to a pesos ledger. */
|
||||
@IsOptional() @IsNumber() exchangeRate?: number;
|
||||
@IsOptional() @IsString() concept?: string;
|
||||
}
|
||||
|
||||
/** One screen: cliente + propiedad + servicios + saldo inicial. */
|
||||
export class OnboardCustomerDto {
|
||||
@ValidateNested() @Type(() => CreateCustomerDto) customer!: CreateCustomerDto;
|
||||
|
||||
@IsOptional() @ValidateNested() @Type(() => OnboardPropertyDto)
|
||||
property?: OnboardPropertyDto;
|
||||
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@ArrayMaxSize(12)
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => ServiceDto)
|
||||
services?: ServiceDto[];
|
||||
|
||||
@IsOptional() @ValidateNested() @Type(() => OpeningPaymentDto)
|
||||
openingPayment?: OpeningPaymentDto;
|
||||
}
|
||||
Reference in new issue
Block a user