mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
109 lines
3.8 KiB
TypeScript
109 lines
3.8 KiB
TypeScript
import { BaseEntity } from "@edr/api-common";
|
|
import { Freight } from "@edr/types";
|
|
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
import { PaymentEntity } from "../../payment/entities/payment.entity";
|
|
import { Company } from "../../companies/entities/company.entity";
|
|
import { CompanyProfile } from "../../companies/entities/company-profile.entity";
|
|
|
|
/** A single recorded settlement against an invoice (payment ledger entry). */
|
|
export interface InvoicePayment {
|
|
amount: number;
|
|
method?: string | null;
|
|
reference?: string | null;
|
|
/** ISO timestamp of when the settlement was recorded. */
|
|
paidAt: string;
|
|
metadata?: Record<string, unknown> | null;
|
|
}
|
|
|
|
@Entity({ schema: "freight", name: "invoices" })
|
|
@Index(["companyId"])
|
|
@Index(["companyProfileId"])
|
|
export class Invoice extends BaseEntity {
|
|
@Column({ name: "invoice_number", type: "varchar", length: 64, unique: true })
|
|
invoiceNumber!: string;
|
|
|
|
/** The customer (company) this invoice is billed to. */
|
|
@Column({ name: "company_id", type: "uuid" })
|
|
companyId!: string;
|
|
|
|
@ManyToOne(() => Company)
|
|
@JoinColumn({ name: "company_id" })
|
|
company?: Company;
|
|
|
|
/** The specific company profile (importer/exporter/forwarder/...) billed. */
|
|
@Column({ name: "company_profile_id", type: "uuid" })
|
|
companyProfileId!: string;
|
|
|
|
@ManyToOne(() => CompanyProfile)
|
|
@JoinColumn({ name: "company_profile_id" })
|
|
companyProfile?: CompanyProfile;
|
|
|
|
/** Sum of line amounts before tax; defaults to `totalAmount` for tax-free invoices. */
|
|
@Column({ name: "subtotal_amount", type: "numeric", precision: 14, scale: 2, default: 0 })
|
|
subtotalAmount!: number;
|
|
|
|
@Column({ name: "tax_amount", type: "numeric", precision: 14, scale: 2, default: 0 })
|
|
taxAmount!: number;
|
|
|
|
@Column({ name: "total_amount", type: "numeric", precision: 14, scale: 2 })
|
|
totalAmount!: number;
|
|
|
|
/** Cumulative amount settled so far (supports partial payment). */
|
|
@Column({ name: "paid_amount", type: "numeric", precision: 14, scale: 2, default: 0 })
|
|
paidAmount!: number;
|
|
|
|
/** Outstanding balance = `totalAmount - paidAmount` (0 once fully paid). */
|
|
@Column({ name: "balance_amount", type: "numeric", precision: 14, scale: 2, default: 0 })
|
|
balanceAmount!: number;
|
|
|
|
@Column({ name: "currency", type: "varchar", length: 8, default: "ETB" })
|
|
currency!: string;
|
|
|
|
@Column({
|
|
name: "status",
|
|
type: "enum",
|
|
enum: Freight.InvoiceStatus,
|
|
default: Freight.InvoiceStatus.Draft,
|
|
})
|
|
status!: Freight.InvoiceStatus;
|
|
|
|
/** The source of the payment (e.g. booking, customer, etc.). */
|
|
@Column({ name: "source", type: "varchar", length: 255, nullable: false })
|
|
source!: string;
|
|
|
|
/** The ID of the source (e.g. booking ID, customer ID, etc.). */
|
|
@Column({ name: "source_id", type: "varchar", length: 255, nullable: false })
|
|
sourceId!: string;
|
|
|
|
/** The type of Invoice (e.g. prepaid, credit, etc.). it suppose to answer the question "what is the invoice for?" */
|
|
@Column({
|
|
type: "varchar",
|
|
length: 255,
|
|
nullable: false,
|
|
})
|
|
type!: string;
|
|
|
|
/** Set when the invoice is actually issued (DRAFT invoices leave this null). */
|
|
@Column({ name: "issued_at", type: "timestamptz", nullable: true })
|
|
issuedAt?: Date | null;
|
|
|
|
/** Set when the invoice is fully settled. */
|
|
@Column({ name: "paid_at", type: "timestamptz", nullable: true })
|
|
paidAt?: Date | null;
|
|
|
|
/** Ledger of individual settlements (manual or gateway), newest last. */
|
|
@Column({ name: "payments", type: "jsonb", default: () => "'[]'" })
|
|
payments!: InvoicePayment[];
|
|
|
|
/** The ID of the payment that generated this invoice. */
|
|
@Column({ name: "payment_id", type: "uuid", nullable: true })
|
|
paymentId?: string | null;
|
|
|
|
@ManyToOne(() => PaymentEntity)
|
|
@JoinColumn({ name: "payment_id" })
|
|
payment?: PaymentEntity;
|
|
|
|
@Column({ name: "due_at", type: "timestamptz" })
|
|
dueAt!: Date;
|
|
}
|