Merge pull request #636 from Luca-Timo/feat/accounting-inbound-invoices
feat(accounting): incoming-invoice workflow v2 + VAT/financial settings consolidation
This commit is contained in:
@@ -35,6 +35,14 @@ export interface InboundDocument {
|
||||
markupPercent: number | null;
|
||||
markupFlatMinor: number | null;
|
||||
billedInvoiceId: number | null;
|
||||
/** Client a rebill/passthrough is attached to (migration 132). */
|
||||
customerAccountId: number | null;
|
||||
customerName: string | null;
|
||||
customerEmail: string | null;
|
||||
/** ISO-2 supplier country — auto-defaults the tax treatment (reclaim list). */
|
||||
supplierCountry: string | null;
|
||||
/** Free-text categorisation note. */
|
||||
note: string | null;
|
||||
supplierPaid: boolean;
|
||||
supplierPaidAt: string | null;
|
||||
supplierPaymentMethod: PaymentMethod | null;
|
||||
@@ -79,6 +87,20 @@ export interface InvoiceExpensePayload {
|
||||
markupFlatMinor?: number | null;
|
||||
}
|
||||
|
||||
/** One customer with categorised-but-unbilled rebill/passthrough docs. */
|
||||
export interface PendingRebillSummary {
|
||||
customerAccountId: number;
|
||||
companyName: string | null;
|
||||
displayName: string | null;
|
||||
firstName: string | null;
|
||||
lastName: string | null;
|
||||
email: string | null;
|
||||
isPassive: boolean;
|
||||
billingCadence: string | null;
|
||||
itemCount: number;
|
||||
openAmountMinor: number;
|
||||
}
|
||||
|
||||
export interface ExpenseCategory { id: number; name: string; color: string | null; is_seed: boolean; display_order: number; }
|
||||
export interface Paginated<T> { items: T[]; pagination: { page: number; pageSize: number; total: number; totalPages: number }; }
|
||||
|
||||
@@ -92,6 +114,8 @@ export interface AccountingSettings {
|
||||
/** ISO-2 countries whose input VAT can be reclaimed (drives cost
|
||||
* tax-treatment + the report's VAT-payable). */
|
||||
accounting_vat_reclaim_countries: string[];
|
||||
/** Output VAT code stamped onto NEW invoices/quotes ('' = none). */
|
||||
accounting_default_output_vat_code: string;
|
||||
}
|
||||
|
||||
export interface CategorizePayload {
|
||||
@@ -148,6 +172,10 @@ export const accountingService = {
|
||||
async updateInbound(id: number, fields: Partial<InboundDocument>): Promise<InboundDocument> { const { data } = await api.patch(`/admin/expenses/inbound/${id}`, fields); return data.document; },
|
||||
async categorizeInbound(id: number, payload: CategorizePayload): Promise<InboundDocument> { const { data } = await api.post(`/admin/expenses/inbound/${id}/categorize`, payload); return data.document; },
|
||||
async rebillInbound(id: number, payload: CategorizePayload): Promise<{ document: InboundDocument; invoiceId: number }> { const { data } = await api.post(`/admin/expenses/inbound/${id}/rebill`, payload); return data; },
|
||||
/** Per-event customers with pending (categorised, unbilled) re-bills. */
|
||||
async listPendingRebills(): Promise<PendingRebillSummary[]> { const { data } = await api.get('/admin/expenses/inbound/pending-summary'); return data.items; },
|
||||
/** Bundle one customer's pending re-bills into a single invoice. */
|
||||
async billPendingRebills(customerAccountId: number): Promise<{ invoiceId: number; count: number }> { const { data } = await api.post('/admin/expenses/inbound/bill-pending', { customerAccountId }); return data; },
|
||||
async markInboundPaid(id: number, payload: { paid: boolean; paidAt?: string; paymentMethod?: PaymentMethod; paymentReference?: string }): Promise<InboundDocument> { const { data } = await api.post(`/admin/expenses/inbound/${id}/supplier-payment`, payload); return data.document; },
|
||||
async getInboundFileBlob(id: number): Promise<Blob> { const { data } = await api.get(`/admin/expenses/inbound/${id}/file`, { responseType: 'blob' }); return data; },
|
||||
async getInboundPageBlob(id: number, page: number): Promise<Blob> { const { data } = await api.get(`/admin/expenses/inbound/${id}/page/${page}`, { responseType: 'blob' }); return data; },
|
||||
@@ -186,6 +214,8 @@ export const accountingService = {
|
||||
accounting_vat_registered: data.accounting_vat_registered === true,
|
||||
accounting_vat_reclaim_countries: Array.isArray(data.accounting_vat_reclaim_countries)
|
||||
? data.accounting_vat_reclaim_countries : [],
|
||||
accounting_default_output_vat_code: typeof data.accounting_default_output_vat_code === 'string'
|
||||
? data.accounting_default_output_vat_code : '',
|
||||
};
|
||||
},
|
||||
async updateSettings(payload: Partial<AccountingSettings>): Promise<{ updated: string[] }> {
|
||||
|
||||
Reference in New Issue
Block a user