mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 08:20:58 +00:00
feat(billing): issue credit/debit memos against registered invoices
POST billing/invoices/:id/memo files a MoR DEB/CRE memo by reusing createInvoice unchanged. sourceId is the original invoice's own id, not its source's — this structurally keeps memos out of findPayable/expirePayable/ billQuery's sourceId-keyed lookups regardless of status. Credit notes are created settled; debit notes are created open/unpaid as a genuine new receivable, not force-settled. memoIssue is granted to the chief position, not the general finance role. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import {
|
||||
IsArray,
|
||||
IsIn,
|
||||
IsNumber,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
Length,
|
||||
ValidateNested,
|
||||
} from "class-validator";
|
||||
|
||||
/** One line on a memo; omit the whole `lines` array on the parent DTO to copy the original's. */
|
||||
export class MemoLineDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
chargeType!: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
quantity?: number;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
unitRate?: number;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
amount?: number;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
currency?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/** `POST billing/invoices/:id/memo` body — see `BillingService.issueMemo`. */
|
||||
export class IssueMemoDto {
|
||||
@ApiProperty({ enum: ["CRE", "DEB"], description: "MoR DocumentDetails.Type for the memo." })
|
||||
@IsIn(["CRE", "DEB"])
|
||||
type!: "CRE" | "DEB";
|
||||
|
||||
@ApiProperty({ description: "Why the memo was issued — MoR DocumentDetails.Reason." })
|
||||
@IsString()
|
||||
@Length(1, 500)
|
||||
reason!: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
type: [MemoLineDto],
|
||||
description: "Omit to copy every line of the original invoice verbatim.",
|
||||
})
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => MemoLineDto)
|
||||
lines?: MemoLineDto[];
|
||||
}
|
||||
Reference in New Issue
Block a user