mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 16:28:12 +00:00
make a contrat template
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
import { parseArticleBody, interpolateTemplateText } from './contract-article.util';
|
||||
import { ContractRendererService } from './contract-renderer.service';
|
||||
import { getTemplateMeta } from './contract-template.registry';
|
||||
import type { ContractViewModel } from './contract-view-model.builder';
|
||||
|
||||
describe('parseArticleBody', () => {
|
||||
it('numbers each non-empty line as a clause', () => {
|
||||
const parsed = parseArticleBody('First clause.\nSecond clause.\n\nThird clause.');
|
||||
expect(parsed.paragraph).toBeUndefined();
|
||||
expect(parsed.clauses.map((c) => c.text)).toEqual([
|
||||
'First clause.',
|
||||
'Second clause.',
|
||||
'Third clause.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('nests "- " lines as bullets under the previous clause', () => {
|
||||
const parsed = parseArticleBody('Rates are:\n- USD 10 per ton\n- USD 20 per wagon\nPayment in advance.');
|
||||
expect(parsed.clauses).toHaveLength(2);
|
||||
expect(parsed.clauses[0].bullets).toEqual(['USD 10 per ton', 'USD 20 per wagon']);
|
||||
expect(parsed.clauses[1].text).toBe('Payment in advance.');
|
||||
});
|
||||
|
||||
it('renders a single bare line as a paragraph', () => {
|
||||
const parsed = parseArticleBody('This Agreement becomes effective when signed.');
|
||||
expect(parsed.paragraph).toBe('This Agreement becomes effective when signed.');
|
||||
expect(parsed.clauses).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('interpolateTemplateText', () => {
|
||||
it('fills placeholders from the view model', () => {
|
||||
expect(
|
||||
interpolateTemplateText('Valid until August 31, {{contractYear}}.', {
|
||||
contractYear: 2026,
|
||||
}),
|
||||
).toBe('Valid until August 31, 2026.');
|
||||
});
|
||||
|
||||
it('falls back to raw text on malformed placeholders', () => {
|
||||
expect(interpolateTemplateText('Broken {{#if}} tag', {})).toBe('Broken {{#if}} tag');
|
||||
});
|
||||
});
|
||||
|
||||
describe('dynamic template rendering (edr-dynamic.hbs)', () => {
|
||||
const renderer = new ContractRendererService();
|
||||
renderer.onModuleInit();
|
||||
|
||||
function dynamicView(): ContractViewModel {
|
||||
const meta = getTemplateMeta('IMP_BULK_USD_FORWARDING');
|
||||
return {
|
||||
bookingId: 'test-id',
|
||||
reference: 'EDR/CT/2026/0042',
|
||||
status: 'CONTRACT_READY',
|
||||
templateKey: 'IMP_BULK_USD_FORWARDING',
|
||||
template: { ...meta, title: 'Bulk Import Contract', templateFile: 'edr-dynamic.hbs' },
|
||||
contractDate: '1 January 2026',
|
||||
contractYear: 2026,
|
||||
client: {
|
||||
companyName: 'Abyssinia Trading PLC',
|
||||
companyAddress: 'Bole Sub-city, Addis Ababa',
|
||||
companyLocation: 'Ethiopia',
|
||||
phone: '+251900000000',
|
||||
email: 'test@example.com',
|
||||
tinNumber: '1234567890',
|
||||
vatNumber: 'VAT-001',
|
||||
fanNumber: 'FAN-001',
|
||||
businessLicense: 'BL-001',
|
||||
},
|
||||
provider: {
|
||||
name: 'Ethio-Djibouti Standard Gauge Railway Share Company',
|
||||
address: 'Nifas Silk Lafto Sub City, Addis Ababa, Ethiopia',
|
||||
phone: '+251 11 872 0000',
|
||||
email: 'info@edr.gov.et',
|
||||
tinNumber: '—',
|
||||
},
|
||||
schedule: {
|
||||
originLabel: 'Nagad',
|
||||
destinationLabel: 'Galaan Multipurpose Port',
|
||||
tradeDirection: 'IMPORT',
|
||||
freightType: 'BULK',
|
||||
serviceType: 'Rail + clearance',
|
||||
scheduledDate: '—',
|
||||
contractType: 'GENERAL',
|
||||
cargoDescription: 'Steel billets',
|
||||
totalWeightVgm: '—',
|
||||
equipmentReturn: '—',
|
||||
hazardousLabel: 'No',
|
||||
firstMilePickupAddress: '—',
|
||||
lastMileDeliveryAddress: '—',
|
||||
},
|
||||
pricing: {
|
||||
displayMode: 'UNIT_RATES',
|
||||
unitRates: [
|
||||
{ label: 'Rail transport', unitPrice: 59.4, unit: 'ton', currency: 'USD' },
|
||||
],
|
||||
currency: 'USD',
|
||||
equipmentReturn: '—',
|
||||
originLabel: 'Nagad',
|
||||
destinationLabel: 'Galaan Multipurpose Port',
|
||||
} as unknown as ContractViewModel['pricing'],
|
||||
signatures: [],
|
||||
canSignCustomer: false,
|
||||
canSignStaff: false,
|
||||
hasContractDocument: false,
|
||||
hasCustomerSignature: false,
|
||||
hasStaffSignature: false,
|
||||
dynamicTemplate: {
|
||||
code: 'IMPORT_BULK',
|
||||
name: 'Bulk Import Contract',
|
||||
documentTitle: 'Bulk Cargo Transportation and Customs Clearance Services',
|
||||
whereasClauses: ['The Client has agreed to engage the Service Provider.'],
|
||||
articles: [
|
||||
{
|
||||
id: 'objective',
|
||||
title: 'Objective of the Services',
|
||||
body: 'Integrated logistics services including:\n- Rail transport to GMP\n- Customs clearance',
|
||||
order: 1,
|
||||
},
|
||||
{
|
||||
id: 'duration',
|
||||
title: 'Duration',
|
||||
body: 'Valid until August 31, {{contractYear}}.',
|
||||
order: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
it('renders numbered dynamic articles with bullets and interpolation', () => {
|
||||
const html = renderer.render(dynamicView());
|
||||
expect(html).toContain('Bulk Cargo Transportation and Customs Clearance Services');
|
||||
expect(html).toContain('Article 1');
|
||||
expect(html).toContain('Objective of the Services');
|
||||
expect(html).toContain('Rail transport to GMP');
|
||||
expect(html).toContain('Valid until August 31, 2026.');
|
||||
expect(html).toContain('Abyssinia Trading PLC');
|
||||
expect(html).toContain('Annex A — Commercial Schedule');
|
||||
// Greenish theme marker from styles.hbs
|
||||
expect(html).toContain('#1b9e7a');
|
||||
});
|
||||
|
||||
it('keeps the generic layout when no dynamic template is attached', () => {
|
||||
const view = dynamicView();
|
||||
delete view.dynamicTemplate;
|
||||
view.template = getTemplateMeta('IMP_BULK_USD_FORWARDING');
|
||||
const html = renderer.render(view);
|
||||
expect(html).toContain('Article 5: Contract Price');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user