87 lines
2.3 KiB
TypeScript
87 lines
2.3 KiB
TypeScript
/**
|
|
* Value Object: SettlementAmount
|
|
* Encapsulates a financial amount with validation.
|
|
* Amounts are stored as strings to preserve precision (matches DB numeric type).
|
|
*/
|
|
export class SettlementAmount {
|
|
private constructor(private readonly _value: string) {}
|
|
|
|
/**
|
|
* Create a SettlementAmount from a string value.
|
|
* Validates that the value is a positive numeric string with up to 20 digits
|
|
* and 8 decimal places.
|
|
*/
|
|
static create(value: string): SettlementAmount {
|
|
if (!value || value.trim() === '') {
|
|
throw new Error('Settlement amount cannot be empty');
|
|
}
|
|
|
|
const numeric = parseFloat(value);
|
|
if (isNaN(numeric)) {
|
|
throw new Error(`Invalid settlement amount: "${value}" is not a valid number`);
|
|
}
|
|
|
|
if (numeric < 0) {
|
|
throw new Error(`Settlement amount must be non-negative, got: ${value}`);
|
|
}
|
|
|
|
// Validate precision: up to 20 digits total, 8 decimal places
|
|
const parts = value.split('.');
|
|
const integerPart = parts[0].replace(/^-/, '');
|
|
const decimalPart = parts[1] || '';
|
|
|
|
if (integerPart.length > 12) {
|
|
throw new Error(
|
|
`Settlement amount integer part exceeds maximum 12 digits: ${integerPart.length}`,
|
|
);
|
|
}
|
|
|
|
if (decimalPart.length > 8) {
|
|
throw new Error(
|
|
`Settlement amount decimal part exceeds maximum 8 digits: ${decimalPart.length}`,
|
|
);
|
|
}
|
|
|
|
return new SettlementAmount(value);
|
|
}
|
|
|
|
/**
|
|
* Reconstruct from a persisted string value (no validation, trusted source).
|
|
*/
|
|
static fromPersisted(value: string): SettlementAmount {
|
|
return new SettlementAmount(value);
|
|
}
|
|
|
|
get value(): string {
|
|
return this._value;
|
|
}
|
|
|
|
toNumber(): number {
|
|
return parseFloat(this._value);
|
|
}
|
|
|
|
/**
|
|
* Subtract another amount and return the result.
|
|
*/
|
|
subtract(other: SettlementAmount): SettlementAmount {
|
|
const result = this.toNumber() - other.toNumber();
|
|
return SettlementAmount.create(String(result));
|
|
}
|
|
|
|
/**
|
|
* Add another amount and return the result.
|
|
*/
|
|
add(other: SettlementAmount): SettlementAmount {
|
|
const result = this.toNumber() + other.toNumber();
|
|
return SettlementAmount.create(String(result));
|
|
}
|
|
|
|
equals(other: SettlementAmount): boolean {
|
|
return this._value === other._value;
|
|
}
|
|
|
|
toString(): string {
|
|
return this._value;
|
|
}
|
|
}
|