Files
edr-platform/apps/edr-freight-api/src/modules/exports/datasets/contracts.dataset.ts
Nathnael 1f11c3a4ca feat(export-ui): mount the export button on the eight remaining list pages
customers, contracts, invoices, payments, train schedules, and locomotives /
trains / wagons via the fleet page's config.

FilterBar pages pass controls.params into the children slot. The four pages
still on ad-hoc filtering pass their own hand-built filter object instead,
which is why ExportButton takes plain params rather than a UseFilters — it
would otherwise have been blocked behind migrating those pages. FleetResource
serves seven slugs from config, so it gets an optional exportKey there and
renders nothing for the four slugs with no dataset yet.

Auditing each page's real filter keys against the dataset declarations turned
up three gaps where an on-screen filter would have silently not applied to the
export: invoices sends a singular "status" (the dataset only had the
multiselect "statuses"), contracts sends paymentCurrency, serviceTypeId and
route origin/destination, and train schedules sends freightType. Added all of
them — contract routes filter through EXISTS on contract_routes since they are
one-to-many, and train-schedule freightType through EXISTS on the bookings
aboard, matching the list service.

Verified in the browser: the button renders on each page, and the invoices
dialog follows that page's own filter object — selecting Paid moves the count
from 126 to 100, which matches the database. Filter pass-through checked
against the database for invoices, payments, wagons, contracts and train
schedules.
2026-08-20 07:17:25 +00:00

162 lines
11 KiB
TypeScript

import { FREIGHT_PERMS } from '../../../seed/freight-permissions.registry';
import { Company } from '../../companies/entities/company.entity';
import { CompanyProfile } from '../../companies/entities/company-profile.entity';
import { Contract } from '../../contracts/entities/contract.entity';
import { ServiceType } from '../../rule-engine/entities/service-type.entity';
import { applyDirectionScope } from '../../user-trade-access/trade-scope.util';
import { ExportDataset } from '../export.types';
export const contractsDataset: ExportDataset = {
key: 'contracts',
title: 'Contracts',
description: 'Contracts with customer, terms, routes, approval and clearance detail',
group: 'Commercial',
permission: FREIGHT_PERMS.contracts.view,
base: { entity: Contract, alias: 'ct' },
joins: [
{ alias: 'c', entity: Company, on: 'c.id = ct.company_id' },
{ alias: 'cp', entity: CompanyProfile, on: 'cp.id = ct.company_profile_id' },
{ alias: 'st', entity: ServiceType, on: 'st.id = ct.service_type_id' },
{ alias: 'ren', entity: Contract, on: 'ren.id = ct.renewal_of_id' },
],
// `search` matches the customer name.
alwaysJoin: ['c'],
groups: [
{ id: 'contract', label: 'Contract' },
{ id: 'customer', label: 'Customer' },
{ id: 'terms', label: 'Terms' },
{ id: 'routes', label: 'Routes & cargo' },
{ id: 'approval', label: 'Approval' },
{ id: 'clearance', label: 'Clearance' },
],
fields: [
{ key: 'reference', label: 'Reference', type: 'string', group: 'contract', default: true, select: 'ct.reference', sortExpr: 'ct.reference' },
{ key: 'status', label: 'Status', type: 'string', group: 'contract', default: true, select: 'ct.status', sortExpr: 'ct.status' },
{ key: 'contractKind', label: 'Kind', type: 'string', group: 'contract', default: true, select: 'ct.contract_kind' },
{ key: 'contractType', label: 'Type', type: 'string', group: 'contract', select: 'ct.contract_type' },
{ key: 'createdAt', label: 'Created', type: 'date', group: 'contract', default: true, select: `to_char(ct.created_at, 'YYYY-MM-DD')`, sortExpr: 'ct.created_at' },
{ key: 'submittedAt', label: 'Submitted', type: 'datetime', group: 'contract', select: `to_char(ct.submitted_at, 'YYYY-MM-DD HH24:MI')` },
{ key: 'versionNumber', label: 'Version', type: 'number', group: 'contract', select: 'ct.version_number' },
{ key: 'renewalOf', label: 'Renewal of', type: 'string', group: 'contract', requires: ['ren'], select: 'ren.reference' },
{ key: 'statusBeforeSuspension', label: 'Status before suspension', type: 'string', group: 'contract', select: 'ct.status_before_suspension' },
{ key: 'customer', label: 'Customer', type: 'string', group: 'customer', default: true, requires: ['c'], select: 'c.name', sortExpr: 'c.name' },
{ key: 'customerTin', label: 'Customer TIN', type: 'string', group: 'customer', requires: ['c'], select: 'c.tin' },
{ key: 'customerPhone', label: 'Customer phone', type: 'string', group: 'customer', requires: ['c'], select: 'c.phone' },
{ key: 'customerEmail', label: 'Customer email', type: 'string', group: 'customer', requires: ['c'], select: 'c.email' },
{ key: 'customerType', label: 'Customer type', type: 'string', group: 'customer', requires: ['c'], select: 'c.type' },
{ key: 'customerProfileRef', label: 'Profile reference', type: 'string', group: 'customer', requires: ['cp'], select: 'cp.reference' },
{ key: 'isGovernment', label: 'Government', type: 'boolean', group: 'customer', select: 'ct.is_government' },
{ key: 'governmentInstitution', label: 'Government institution', type: 'string', group: 'customer', select: 'ct.government_institution' },
{ key: 'tradeDirection', label: 'Direction', type: 'string', group: 'terms', default: true, select: 'ct.trade_direction', sortExpr: 'ct.trade_direction' },
{ key: 'freightType', label: 'Freight type', type: 'string', group: 'terms', default: true, select: 'ct.freight_type' },
{ key: 'serviceType', label: 'Service type', type: 'string', group: 'terms', requires: ['st'], select: 'st.service_name' },
{ key: 'paymentCurrency', label: 'Currency', type: 'string', group: 'terms', select: 'ct.payment_currency' },
{ key: 'validFrom', label: 'Valid from', type: 'date', group: 'terms', default: true, select: `to_char(ct.contract_valid_from, 'YYYY-MM-DD')`, sortExpr: 'ct.contract_valid_from' },
{ key: 'validUntil', label: 'Valid until', type: 'date', group: 'terms', default: true, select: `to_char(ct.contract_valid_until, 'YYYY-MM-DD')` },
{ key: 'validityDays', label: 'Validity (days)', type: 'number', group: 'terms', select: 'ct.contract_validity_days' },
{ key: 'expiresAt', label: 'Expires', type: 'date', group: 'terms', select: `to_char(ct.expires_at, 'YYYY-MM-DD')` },
{ key: 'estimatedShipmentDate', label: 'Est. shipment date', type: 'date', group: 'terms', select: `to_char(ct.estimated_shipment_date, 'YYYY-MM-DD')` },
{ key: 'equipmentReturn', label: 'Equipment return', type: 'string', group: 'terms', select: 'ct.equipment_return' },
{ key: 'pricingDisplayMode', label: 'Pricing display mode', type: 'string', group: 'terms', select: 'ct.pricing_display_mode' },
{
key: 'routes', label: 'Routes', type: 'string', group: 'routes',
select: `(SELECT string_agg(o.label || ' -> ' || d.label, ' | ' ORDER BY cr.sort_order)
FROM freight.contract_routes cr
JOIN freight.yards o ON o.id = cr.origin_yard_id
JOIN freight.yards d ON d.id = cr.destination_yard_id
WHERE cr.contract_id = ct.id AND cr.deleted_at IS NULL)`,
},
{
key: 'routeCount', label: 'Route count', type: 'number', group: 'routes',
select: `(SELECT COUNT(*)::int FROM freight.contract_routes cr
WHERE cr.contract_id = ct.id AND cr.deleted_at IS NULL)`,
},
{
key: 'bookingCount', label: 'Bookings', type: 'number', group: 'routes',
select: `(SELECT COUNT(*)::int FROM freight.bookings b
WHERE b.contract_id = ct.id AND b.deleted_at IS NULL)`,
},
{ key: 'isHazardous', label: 'Hazardous', type: 'boolean', group: 'routes', select: 'ct.is_hazardous' },
{ key: 'hazardClass', label: 'Hazard class', type: 'string', group: 'routes', select: 'ct.hazard_class' },
{ key: 'unNumber', label: 'UN number', type: 'string', group: 'routes', select: 'ct.un_number' },
{ key: 'isReefer', label: 'Reefer', type: 'boolean', group: 'routes', select: 'ct.is_reefer' },
{ key: 'approvedAt', label: 'Approved at', type: 'datetime', group: 'approval', select: `to_char(ct.approved_by_staff_at, 'YYYY-MM-DD HH24:MI')` },
{ key: 'signedByDirectorAt', label: 'Director signed', type: 'datetime', group: 'approval', select: `to_char(ct.signed_by_director_at, 'YYYY-MM-DD HH24:MI')` },
{ key: 'signedByCeoAt', label: 'CEO signed', type: 'datetime', group: 'approval', select: `to_char(ct.signed_by_ceo_at, 'YYYY-MM-DD HH24:MI')` },
{ key: 'customerSignedAt', label: 'Customer signed', type: 'datetime', group: 'approval', select: `to_char(ct.customer_signed_at, 'YYYY-MM-DD HH24:MI')` },
{ key: 'fullyExecutedAt', label: 'Fully executed', type: 'datetime', group: 'approval', default: true, select: `to_char(ct.fully_executed_at, 'YYYY-MM-DD HH24:MI')` },
{ key: 'lockedAt', label: 'Locked at', type: 'datetime', group: 'approval', select: `to_char(ct.locked_at, 'YYYY-MM-DD HH24:MI')` },
{ key: 'contractGeneratedAt', label: 'Document generated', type: 'datetime', group: 'approval', select: `to_char(ct.contract_generated_at, 'YYYY-MM-DD HH24:MI')` },
{ key: 'clearanceStatus', label: 'Clearance status', type: 'string', group: 'clearance', select: 'ct.clearance_status' },
{ key: 'clearanceCycleNumber', label: 'Clearance cycle', type: 'number', group: 'clearance', select: 'ct.clearance_cycle_number' },
{ key: 'customsClearingEnabled', label: 'Customs clearing', type: 'boolean', group: 'clearance', select: 'ct.customs_clearing_enabled' },
{ key: 'customsClearingAgent', label: 'Clearing agent', type: 'string', group: 'clearance', select: 'ct.customs_clearing_agent' },
{ key: 'firstMileAddress', label: 'Pickup address', type: 'string', group: 'clearance', select: 'ct.first_mile_pickup_address' },
{ key: 'lastMileAddress', label: 'Delivery address', type: 'string', group: 'clearance', select: 'ct.last_mile_delivery_address' },
],
filters: [
{ key: 'created', label: 'Created', type: 'daterange' },
{ key: 'statuses', label: 'Status', type: 'multiselect' },
{ key: 'contractKind', label: 'Kind', type: 'text' },
{ key: 'tradeDirection', label: 'Direction', type: 'select', options: ['IMPORT', 'EXPORT', 'DOMESTIC'].map((v) => ({ value: v, label: v })) },
{ key: 'freightType', label: 'Freight type', type: 'select', options: ['CONTAINER', 'BULK'].map((v) => ({ value: v, label: v })) },
{ key: 'paymentCurrency', label: 'Currency', type: 'select', options: [
{ value: 'ETB', label: 'ETB' },
{ value: 'USD', label: 'USD' },
] },
{ key: 'serviceTypeId', label: 'Service type', type: 'text' },
// Routes are one-to-many on contract_routes, so these filter via EXISTS
// rather than a column comparison.
{ key: 'originYardId', label: 'Origin', type: 'text' },
{ key: 'destinationYardId', label: 'Destination', type: 'text' },
{ key: 'companyId', label: 'Customer', type: 'text' },
{ key: 'search', label: 'Search reference or customer', type: 'text' },
],
defaultSort: { key: 'createdAt', dir: 'DESC' },
scope(ctx, qb) {
const { params, directions } = ctx;
qb.andWhere('ct.deleted_at IS NULL');
if (params.createdFrom) qb.andWhere('ct.created_at >= :createdFrom', { createdFrom: params.createdFrom });
if (params.createdTo) qb.andWhere('ct.created_at < :createdTo', { createdTo: params.createdTo });
const statuses = params.statuses as string[] | null;
if (statuses?.length) qb.andWhere('ct.status IN (:...statuses)', { statuses });
if (params.contractKind) qb.andWhere('ct.contract_kind = :contractKind', { contractKind: params.contractKind });
if (params.tradeDirection) qb.andWhere('ct.trade_direction = :tradeDirection', { tradeDirection: params.tradeDirection });
if (params.freightType) qb.andWhere('ct.freight_type = :freightType', { freightType: params.freightType });
if (params.paymentCurrency) qb.andWhere('ct.payment_currency = :paymentCurrency', { paymentCurrency: params.paymentCurrency });
if (params.serviceTypeId) qb.andWhere('ct.service_type_id = :serviceTypeId', { serviceTypeId: params.serviceTypeId });
if (params.originYardId) {
qb.andWhere(
`EXISTS (SELECT 1 FROM freight.contract_routes cr
WHERE cr.contract_id = ct.id AND cr.deleted_at IS NULL
AND cr.origin_yard_id = :originYardId)`,
{ originYardId: params.originYardId },
);
}
if (params.destinationYardId) {
qb.andWhere(
`EXISTS (SELECT 1 FROM freight.contract_routes cr2
WHERE cr2.contract_id = ct.id AND cr2.deleted_at IS NULL
AND cr2.destination_yard_id = :destinationYardId)`,
{ destinationYardId: params.destinationYardId },
);
}
if (params.companyId) qb.andWhere('ct.company_id = :companyId', { companyId: params.companyId });
if (params.search) {
qb.andWhere('(ct.reference ILIKE :search OR c.name ILIKE :search)', { search: `%${params.search as string}%` });
}
applyDirectionScope(qb, 'ct.trade_direction', directions);
},
};