f266c386f3
* chore: repo-wide bloat sweep, remove dead code and fold duplicate helpers Remove 33 dead files, ~270 unreferenced exports/types, 13 dead i18n namespaces and 4 unused dependencies; fold byte-identical helper copies into one canonical home each (lib/utils chunk/sleep/utcDateStamp, lib/dates/iso, lib/invariants/uuid, lib/xml/escape, lib/reports/sru/format, lib/pdf/number-text, lib/browser/panel-request, lib/api/v1/body + v1ValidationError rolled out to ~55 v1 routes, booking-template schemas). No behaviour change: v1 bodies and status codes, MCP tool schemas, DB writes and money math are untouched. Naive ore rounding was deliberately not swapped for roundOre; see DECISIONS.md 2026-09-02 for the full list of things left alone on purpose. tsc, lint, 19588 unit tests and check:guards green; antipattern baseline ratcheted (naive-ore-round 622 -> 620, hand-rolled-invariant 115 -> 113). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(transactions): import RawTransaction from @/types after the ingest re-export removal CI's type ratchet (check:types, full tsconfig) caught the one test file that still imported the type through lib/transactions/ingest. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
371 lines
9.2 KiB
TypeScript
371 lines
9.2 KiB
TypeScript
// Canonical DTO types for provider data normalization
|
|
|
|
// ============================================
|
|
// Resource Type
|
|
// ============================================
|
|
|
|
export const ResourceType = {
|
|
SalesInvoices: 'salesinvoices',
|
|
SupplierInvoices: 'supplierinvoices',
|
|
Customers: 'customers',
|
|
Suppliers: 'suppliers',
|
|
Journals: 'journals',
|
|
AccountingAccounts: 'accountingaccounts',
|
|
CompanyInformation: 'companyinformation',
|
|
AccountingPeriods: 'accountingperiods',
|
|
FinancialDimensions: 'financialdimensions',
|
|
BalanceSheet: 'balancesheet',
|
|
IncomeStatement: 'incomestatement',
|
|
TrialBalances: 'trialbalances',
|
|
Payments: 'payments',
|
|
Attachments: 'attachments',
|
|
} as const;
|
|
|
|
export type ResourceType = (typeof ResourceType)[keyof typeof ResourceType];
|
|
|
|
// ============================================
|
|
// Common
|
|
// ============================================
|
|
|
|
export interface AmountType {
|
|
value: number;
|
|
currencyCode: string;
|
|
}
|
|
|
|
export interface PostalAddress {
|
|
streetName?: string;
|
|
additionalStreetName?: string;
|
|
buildingNumber?: string;
|
|
cityName?: string;
|
|
postalZone?: string;
|
|
countrySubentity?: string;
|
|
countryCode?: string;
|
|
}
|
|
|
|
export interface Contact {
|
|
name?: string;
|
|
telephone?: string;
|
|
email?: string;
|
|
website?: string;
|
|
}
|
|
|
|
export interface PartyIdentification {
|
|
id: string;
|
|
schemeId?: string;
|
|
}
|
|
|
|
export interface PartyLegalEntity {
|
|
registrationName: string;
|
|
companyId?: string;
|
|
companyIdSchemeId?: string;
|
|
}
|
|
|
|
export interface PartyDto {
|
|
name: string;
|
|
identifications: PartyIdentification[];
|
|
postalAddress?: PostalAddress;
|
|
legalEntity?: PartyLegalEntity;
|
|
contact?: Contact;
|
|
}
|
|
|
|
export interface FinancialDimensionRef {
|
|
dimensionId: string;
|
|
dimensionValueId: string;
|
|
name?: string;
|
|
}
|
|
|
|
export interface AllowanceChargeDto {
|
|
chargeIndicator: boolean;
|
|
reason?: string;
|
|
amount: AmountType;
|
|
taxPercent?: number;
|
|
}
|
|
|
|
export interface TaxTotalDto {
|
|
taxAmount: AmountType;
|
|
taxSubtotals?: TaxSubtotalDto[];
|
|
}
|
|
|
|
export interface TaxSubtotalDto {
|
|
taxableAmount: AmountType;
|
|
taxAmount: AmountType;
|
|
taxCategory?: string;
|
|
percent?: number;
|
|
}
|
|
|
|
export interface PaginatedResponse<T> {
|
|
data: T[];
|
|
page: number;
|
|
pageSize: number;
|
|
totalCount: number;
|
|
hasMore: boolean;
|
|
}
|
|
|
|
/**
|
|
* The verifikat that booked the invoice in the SOURCE system, as the provider
|
|
* reports it ("A329"). Optional: only providers that expose it (Visma
|
|
* eAccounting, Fortnox) set it, and only on booked invoices. The migration
|
|
* uses it to link the imported invoice to the SIE-imported registration
|
|
* voucher; see lib/providers/source-voucher.ts for the parsing rules.
|
|
*/
|
|
export interface SourceVoucherRefDto {
|
|
series: string | null;
|
|
number: number;
|
|
}
|
|
|
|
// ============================================
|
|
// Sales Invoice
|
|
// ============================================
|
|
|
|
export type InvoiceStatusCode = 'draft' | 'sent' | 'booked' | 'paid' | 'overdue' | 'cancelled' | 'credited';
|
|
|
|
export interface LegalMonetaryTotalDto {
|
|
/**
|
|
* Sum of the line amounts, excluding VAT.
|
|
*
|
|
* Optional because several providers omit it from their list payloads
|
|
* (Fortnox `Net`, Briox `net_amount`) and one never exposes it at all.
|
|
* Absent means "the net was not established", NOT "the net equals the
|
|
* gross": mappers must leave it undefined rather than fall back to
|
|
* `payableAmount`, which silently turns every such invoice into a 0 kr VAT
|
|
* record that still balances and so goes unnoticed.
|
|
*/
|
|
lineExtensionAmount?: AmountType;
|
|
taxExclusiveAmount?: AmountType;
|
|
taxInclusiveAmount?: AmountType;
|
|
allowanceTotalAmount?: AmountType;
|
|
chargeTotalAmount?: AmountType;
|
|
payableRoundingAmount?: AmountType;
|
|
payableAmount: AmountType;
|
|
}
|
|
|
|
export interface PaymentStatusDto {
|
|
paid: boolean;
|
|
balance: AmountType;
|
|
lastPaymentDate?: string;
|
|
}
|
|
|
|
export interface SalesInvoiceLineDto {
|
|
id: string;
|
|
description?: string;
|
|
quantity?: number;
|
|
unitCode?: string;
|
|
unitPrice?: AmountType;
|
|
lineExtensionAmount: AmountType;
|
|
taxPercent?: number;
|
|
taxAmount?: AmountType;
|
|
accountNumber?: string;
|
|
itemName?: string;
|
|
articleNumber?: string;
|
|
financialDimensions?: FinancialDimensionRef[];
|
|
}
|
|
|
|
export interface SalesInvoiceDto {
|
|
id: string;
|
|
invoiceNumber: string;
|
|
issueDate: string;
|
|
dueDate?: string;
|
|
deliveryDate?: string;
|
|
invoiceTypeCode?: string;
|
|
currencyCode: string;
|
|
status: InvoiceStatusCode;
|
|
supplier: PartyDto;
|
|
customer: PartyDto;
|
|
lines: SalesInvoiceLineDto[];
|
|
allowanceCharges?: AllowanceChargeDto[];
|
|
taxTotal?: TaxTotalDto;
|
|
legalMonetaryTotal: LegalMonetaryTotalDto;
|
|
paymentStatus: PaymentStatusDto;
|
|
paymentTerms?: string;
|
|
note?: string;
|
|
buyerReference?: string;
|
|
orderReference?: string;
|
|
financialDimensions?: FinancialDimensionRef[];
|
|
sourceVoucher?: SourceVoucherRefDto;
|
|
createdAt?: string;
|
|
updatedAt?: string;
|
|
_raw?: Record<string, unknown>;
|
|
}
|
|
|
|
// ============================================
|
|
// Supplier Invoice
|
|
// ============================================
|
|
|
|
export interface SupplierInvoiceLineDto {
|
|
id: string;
|
|
description?: string;
|
|
quantity?: number;
|
|
unitCode?: string;
|
|
unitPrice?: AmountType;
|
|
lineExtensionAmount: AmountType;
|
|
taxPercent?: number;
|
|
taxAmount?: AmountType;
|
|
accountNumber?: string;
|
|
itemName?: string;
|
|
articleNumber?: string;
|
|
financialDimensions?: FinancialDimensionRef[];
|
|
}
|
|
|
|
export interface SupplierInvoiceDto {
|
|
id: string;
|
|
invoiceNumber: string;
|
|
issueDate: string;
|
|
dueDate?: string;
|
|
deliveryDate?: string;
|
|
invoiceTypeCode?: string;
|
|
currencyCode: string;
|
|
status: InvoiceStatusCode;
|
|
supplier: PartyDto;
|
|
buyer: PartyDto;
|
|
lines: SupplierInvoiceLineDto[];
|
|
allowanceCharges?: AllowanceChargeDto[];
|
|
taxTotal?: TaxTotalDto;
|
|
legalMonetaryTotal: LegalMonetaryTotalDto;
|
|
paymentStatus: PaymentStatusDto;
|
|
paymentTerms?: string;
|
|
note?: string;
|
|
ocrNumber?: string;
|
|
financialDimensions?: FinancialDimensionRef[];
|
|
sourceVoucher?: SourceVoucherRefDto;
|
|
createdAt?: string;
|
|
updatedAt?: string;
|
|
_raw?: Record<string, unknown>;
|
|
}
|
|
|
|
// ============================================
|
|
// Customer
|
|
// ============================================
|
|
|
|
export type CustomerType = 'company' | 'private';
|
|
|
|
export interface CustomerDto {
|
|
id: string;
|
|
customerNumber: string;
|
|
type?: CustomerType;
|
|
party: PartyDto;
|
|
invoiceEmailCcAddresses?: string[];
|
|
invoiceEmailBccAddresses?: string[];
|
|
deliveryAddresses?: PostalAddress[];
|
|
financialDimensions?: FinancialDimensionRef[];
|
|
active: boolean;
|
|
vatNumber?: string;
|
|
defaultPaymentTermsDays?: number;
|
|
note?: string;
|
|
createdAt?: string;
|
|
updatedAt?: string;
|
|
_raw?: Record<string, unknown>;
|
|
}
|
|
|
|
// ============================================
|
|
// Supplier
|
|
// ============================================
|
|
|
|
export interface SupplierDto {
|
|
id: string;
|
|
supplierNumber: string;
|
|
party: PartyDto;
|
|
deliveryAddresses?: PostalAddress[];
|
|
financialDimensions?: FinancialDimensionRef[];
|
|
active: boolean;
|
|
vatNumber?: string;
|
|
bankAccount?: string;
|
|
bankGiro?: string;
|
|
plusGiro?: string;
|
|
defaultPaymentTermsDays?: number;
|
|
note?: string;
|
|
createdAt?: string;
|
|
updatedAt?: string;
|
|
_raw?: Record<string, unknown>;
|
|
}
|
|
|
|
// ============================================
|
|
// Journal
|
|
// ============================================
|
|
|
|
export interface AccountingEntryDto {
|
|
accountNumber: string;
|
|
accountName?: string;
|
|
debit: number;
|
|
credit: number;
|
|
transactionDate?: string;
|
|
description?: string;
|
|
financialDimensions?: FinancialDimensionRef[];
|
|
}
|
|
|
|
export interface AccountingSeriesDto {
|
|
id: string;
|
|
description?: string;
|
|
}
|
|
|
|
export interface JournalDto {
|
|
id: string;
|
|
journalNumber: string;
|
|
series?: AccountingSeriesDto;
|
|
description?: string;
|
|
registrationDate: string;
|
|
fiscalYear?: number;
|
|
entries: AccountingEntryDto[];
|
|
totalDebit?: AmountType;
|
|
totalCredit?: AmountType;
|
|
createdAt?: string;
|
|
updatedAt?: string;
|
|
_raw?: Record<string, unknown>;
|
|
}
|
|
|
|
// ============================================
|
|
// Accounting Account
|
|
// ============================================
|
|
|
|
export type AccountType = 'asset' | 'liability' | 'equity' | 'revenue' | 'expense' | 'other';
|
|
|
|
export interface AccountingAccountDto {
|
|
accountNumber: string;
|
|
name: string;
|
|
description?: string;
|
|
type?: AccountType;
|
|
vatCode?: string;
|
|
active: boolean;
|
|
balanceBroughtForward?: number;
|
|
balanceCarriedForward?: number;
|
|
sruCode?: string;
|
|
createdAt?: string;
|
|
updatedAt?: string;
|
|
_raw?: Record<string, unknown>;
|
|
}
|
|
|
|
// ============================================
|
|
// Company Information
|
|
// ============================================
|
|
|
|
export interface CompanyInformationDto {
|
|
companyName: string;
|
|
organizationNumber?: string;
|
|
legalEntity?: PartyLegalEntity;
|
|
address?: PostalAddress;
|
|
contact?: Contact;
|
|
vatNumber?: string;
|
|
fiscalYearStart?: string;
|
|
baseCurrency?: string;
|
|
_raw?: Record<string, unknown>;
|
|
}
|
|
|
|
// ============================================
|
|
// Payment
|
|
// ============================================
|
|
|
|
export type PaymentMethodCode = 'bank_transfer' | 'card' | 'cash' | 'autogiro' | 'bankgiro' | 'plusgiro' | 'swish' | 'other';
|
|
|
|
export interface PaymentDto {
|
|
id: string;
|
|
paymentNumber?: string;
|
|
invoiceId: string;
|
|
paymentDate: string;
|
|
amount: AmountType;
|
|
paymentMethod?: PaymentMethodCode;
|
|
reference?: string;
|
|
note?: string;
|
|
createdAt?: string;
|
|
updatedAt?: string;
|
|
_raw?: Record<string, unknown>;
|
|
}
|