mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 11:55:42 +00:00
feat(billing): filter, show and export invoice payment method
The settled method is split across two stores: a gateway settlement records the real provider on the linked freight.payments row (cbe-bill, telebirr) while the invoice's own payments ledger only writes a flat "GATEWAY"; a manual settlement has no payments row at all and the ledger is the only source (BANK_TRANSFER, OFFLINE, or whatever PayInvoiceDto.method carried). invoicePaymentMethodExpr folds both into one UPPER_SNAKE vocabulary — provider first, newest ledger entry as the fallback — and the list filter, the export field and the export filter all use that same expression, so the screen and the file can never disagree. The paymentMethods param is deliberately not validated against a fixed list: the manual pay endpoint takes a free-form method, so an IsIn would silently drop real values.
This commit is contained in:
@@ -1,11 +1,16 @@
|
||||
import { FREIGHT_PERMS } from '../../../seed/freight-permissions.registry';
|
||||
import { Invoice } from '../../billing/entities/invoice.entity';
|
||||
import { invoicePaymentMethodExpr } from '../../billing/invoice-settlement.util';
|
||||
import { PaymentEntity } from '../../payment/entities/payment.entity';
|
||||
import { Company } from '../../companies/entities/company.entity';
|
||||
import { CompanyProfile } from '../../companies/entities/company-profile.entity';
|
||||
import { ShippingLineCompany } from '../../shipping-lines/entities/shipping-line-company.entity';
|
||||
import { applyBookingRefDirectionScope } from '../../user-trade-access/trade-scope.util';
|
||||
import { ExportDataset } from '../export.types';
|
||||
|
||||
/** Same expression the list endpoint filters by, in this dataset's aliases. */
|
||||
const PAYMENT_METHOD = invoicePaymentMethodExpr('i', 'p');
|
||||
|
||||
/**
|
||||
* Sensitive EIMS internals are deliberately absent: `eims_signed_qr` (a
|
||||
* signature blob) and `eims_last_error` (a raw error dump). The
|
||||
@@ -26,8 +31,11 @@ export const invoicesDataset: ExportDataset = {
|
||||
// with a second query. In a dataset it is just a join by column.
|
||||
{ alias: 'slc', entity: ShippingLineCompany, on: 'slc.id = i.shipping_line_company_id' },
|
||||
{ alias: 'rel', entity: Invoice, on: 'rel.id = i.related_invoice_id' },
|
||||
// The gateway payment behind the invoice — provider method and its
|
||||
// transaction reference. Always joined: `scope()` filters on it.
|
||||
{ alias: 'p', entity: PaymentEntity, on: 'p.id = i.payment_id' },
|
||||
],
|
||||
alwaysJoin: ['c'],
|
||||
alwaysJoin: ['c', 'p'],
|
||||
|
||||
groups: [
|
||||
{ id: 'invoice', label: 'Invoice' },
|
||||
@@ -66,6 +74,9 @@ export const invoicesDataset: ExportDataset = {
|
||||
{ key: 'currency', label: 'Currency', type: 'string', group: 'amounts', default: true, select: 'i.currency' },
|
||||
|
||||
{ key: 'paidAt', label: 'Paid at', type: 'datetime', group: 'payment', select: `to_char(i.paid_at, 'YYYY-MM-DD HH24:MI')` },
|
||||
{ key: 'paymentMethod', label: 'Payment method', type: 'string', group: 'payment', default: true, requires: ['p'], select: PAYMENT_METHOD, sortExpr: PAYMENT_METHOD },
|
||||
{ key: 'transactionRef', label: 'Transaction ref', type: 'string', group: 'payment', requires: ['p'], select: 'p.transaction_id' },
|
||||
{ key: 'paymentStatus', label: 'Payment status', type: 'string', group: 'payment', requires: ['p'], select: 'p.status::text' },
|
||||
{
|
||||
key: 'daysOverdue', label: 'Days overdue', type: 'number', group: 'payment',
|
||||
select: `CASE WHEN i.balance_amount > 0 AND i.due_at < now()
|
||||
@@ -104,6 +115,7 @@ export const invoicesDataset: ExportDataset = {
|
||||
{ key: 'status', label: 'Status (single)', type: 'text' },
|
||||
{ key: 'sources', label: 'Source', type: 'multiselect' },
|
||||
{ key: 'eimsStatuses', label: 'EIMS status', type: 'multiselect' },
|
||||
{ key: 'paymentMethods', label: 'Payment method', type: 'multiselect' },
|
||||
{ key: 'currency', label: 'Currency', type: 'select', options: [
|
||||
{ value: 'ETB', label: 'ETB' },
|
||||
{ value: 'USD', label: 'USD' },
|
||||
@@ -132,6 +144,10 @@ export const invoicesDataset: ExportDataset = {
|
||||
if (sources?.length) qb.andWhere('i.source IN (:...sources)', { sources });
|
||||
const eimsStatuses = params.eimsStatuses as string[] | null;
|
||||
if (eimsStatuses?.length) qb.andWhere('i.eims_status IN (:...eimsStatuses)', { eimsStatuses });
|
||||
const paymentMethods = params.paymentMethods as string[] | null;
|
||||
if (paymentMethods?.length) {
|
||||
qb.andWhere(`${PAYMENT_METHOD} IN (:...paymentMethods)`, { paymentMethods });
|
||||
}
|
||||
// Casing has drifted in the data ("usd" rows exist) — normalise both sides,
|
||||
// same as the list endpoint does.
|
||||
if (params.currency) {
|
||||
|
||||
Reference in New Issue
Block a user