task-4.3.1
This commit is contained in:
@@ -5,6 +5,7 @@ import type { ResolvedDocumentTemplate } from '@/features/foundation/document-te
|
||||
import type { QuotationDocumentData } from '../types';
|
||||
import { buildQuotationPdfRuntime } from './quotation-pdf-runtime';
|
||||
import { resolveTemplatePages } from './page-resolver';
|
||||
import { assembleTemplate } from './template-assembler';
|
||||
import type { ResolvedTemplate } from './runtime-contracts';
|
||||
import { adaptTemplateForSectionRuntime } from './template-compatibility-adapter';
|
||||
|
||||
@@ -238,3 +239,54 @@ test('runtime keeps signature block on the last generated topic page', async ()
|
||||
assert.equal(fieldNames.has('app1'), false);
|
||||
}
|
||||
});
|
||||
|
||||
test('runtime restores legacy static labels into final template input', async () => {
|
||||
const schema = createLegacyTemplate();
|
||||
const template = createResolvedDocumentTemplate(schema);
|
||||
const runtime = await buildQuotationPdfRuntime({
|
||||
documentData: createDocumentData(1),
|
||||
template,
|
||||
mappings: [],
|
||||
templateInput: {
|
||||
customer_name: 'Customer',
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(runtime.assembled.templateInput.tel_label, 'Tel');
|
||||
assert.equal(runtime.assembled.templateInput.email_label, 'Email');
|
||||
assert.equal(runtime.assembled.templateInput.att_label, 'Att');
|
||||
assert.equal(runtime.assembled.templateInput.project_label, 'Project');
|
||||
assert.equal(runtime.assembled.templateInput.site_label, 'Location');
|
||||
});
|
||||
|
||||
test('template assembler does not overwrite populated values with nullish or blank patches', () => {
|
||||
const assembled = assembleTemplate({
|
||||
template: createLegacyTemplate(),
|
||||
templateInput: {
|
||||
tel_label: 'Tel',
|
||||
customer_name: 'Customer',
|
||||
},
|
||||
staticInputPatch: {
|
||||
tel_label: '',
|
||||
email_label: 'Email',
|
||||
},
|
||||
sections: [
|
||||
{
|
||||
role: 'topics',
|
||||
enabled: true,
|
||||
rendered: false,
|
||||
anchorPageIndex: 1,
|
||||
pages: [],
|
||||
templateInputPatch: {
|
||||
tel_label: undefined,
|
||||
project_label: 'Project',
|
||||
},
|
||||
issues: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
assert.equal(assembled.templateInput.tel_label, 'Tel');
|
||||
assert.equal(assembled.templateInput.email_label, 'Email');
|
||||
assert.equal(assembled.templateInput.project_label, 'Project');
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import type { QuotationDocumentData } from '../types';
|
||||
import { buildPdfTopicPages } from './pdf-topic-engine';
|
||||
import { resolveTemplatePages } from './page-resolver';
|
||||
import { createRenderContext, resolveRenderPolicies } from './render-context';
|
||||
import { resolveQuotationStaticTemplateInputs } from './static-input-resolver';
|
||||
import type {
|
||||
BuiltSection,
|
||||
QuotationPdfRuntimeResult,
|
||||
@@ -129,6 +130,7 @@ export async function buildQuotationPdfRuntime(args: {
|
||||
const compatibleTemplate = adaptTemplateForSectionRuntime(resolvedTemplate);
|
||||
const pages = resolveTemplatePages(compatibleTemplate);
|
||||
const policies = resolveRenderPolicies();
|
||||
const staticInputPatch = resolveQuotationStaticTemplateInputs(args.documentData);
|
||||
const context = createRenderContext({
|
||||
documentData: args.documentData,
|
||||
template: resolvedTemplate,
|
||||
@@ -141,6 +143,7 @@ export async function buildQuotationPdfRuntime(args: {
|
||||
const assembled = assembleTemplate({
|
||||
template: resolvedTemplate.schema,
|
||||
templateInput: args.templateInput,
|
||||
staticInputPatch,
|
||||
sections: composed.sections,
|
||||
});
|
||||
const issues = [...pages.issues, ...composed.issues, ...assembled.issues];
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import type { QuotationDocumentData } from '../types';
|
||||
|
||||
const LEGACY_STATIC_LABEL_DEFAULTS = {
|
||||
tel_label: 'Tel',
|
||||
email_label: 'Email',
|
||||
att_label: 'Att',
|
||||
project_label: 'Project',
|
||||
site_label: 'Location',
|
||||
} as const;
|
||||
|
||||
function normalizeStringValue(
|
||||
value: string | null | undefined,
|
||||
fallback: string,
|
||||
): string {
|
||||
if (typeof value !== 'string') {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
const trimmed = value.trim();
|
||||
return trimmed.length > 0 ? trimmed : fallback;
|
||||
}
|
||||
|
||||
export function resolveQuotationStaticTemplateInputs(
|
||||
documentData: QuotationDocumentData,
|
||||
): Record<string, unknown> {
|
||||
const labels = documentData.pdfme.labels;
|
||||
|
||||
return {
|
||||
tel_label: normalizeStringValue(
|
||||
labels.tel,
|
||||
LEGACY_STATIC_LABEL_DEFAULTS.tel_label,
|
||||
),
|
||||
email_label: normalizeStringValue(
|
||||
labels.email,
|
||||
LEGACY_STATIC_LABEL_DEFAULTS.email_label,
|
||||
),
|
||||
att_label: normalizeStringValue(
|
||||
labels.att,
|
||||
LEGACY_STATIC_LABEL_DEFAULTS.att_label,
|
||||
),
|
||||
project_label: normalizeStringValue(
|
||||
labels.project,
|
||||
LEGACY_STATIC_LABEL_DEFAULTS.project_label,
|
||||
),
|
||||
site_label: normalizeStringValue(
|
||||
labels.location,
|
||||
LEGACY_STATIC_LABEL_DEFAULTS.site_label,
|
||||
),
|
||||
};
|
||||
}
|
||||
@@ -9,9 +9,29 @@ function cloneTemplate<T>(value: T): T {
|
||||
return JSON.parse(JSON.stringify(value)) as T;
|
||||
}
|
||||
|
||||
function mergeTemplateInputPatch(
|
||||
target: Record<string, unknown>,
|
||||
patch: Record<string, unknown>,
|
||||
): Record<string, unknown> {
|
||||
for (const [key, value] of Object.entries(patch)) {
|
||||
if (value === null || value === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof value === 'string' && value.trim().length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
target[key] = value;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
export function assembleTemplate(args: {
|
||||
template: Template;
|
||||
templateInput: Record<string, unknown>;
|
||||
staticInputPatch?: Record<string, unknown>;
|
||||
sections: BuiltSection[];
|
||||
}): AssembledTemplate {
|
||||
const baseTemplate = cloneTemplate(args.template);
|
||||
@@ -62,13 +82,15 @@ export function assembleTemplate(args: {
|
||||
|
||||
baseTemplate.schemas = nextPages;
|
||||
|
||||
const templateInput = args.sections.reduce<Record<string, unknown>>(
|
||||
(accumulator, section) => ({
|
||||
...accumulator,
|
||||
...section.templateInputPatch,
|
||||
}),
|
||||
{ ...args.templateInput },
|
||||
);
|
||||
const templateInput = mergeTemplateInputPatch({}, args.templateInput);
|
||||
|
||||
if (args.staticInputPatch) {
|
||||
mergeTemplateInputPatch(templateInput, args.staticInputPatch);
|
||||
}
|
||||
|
||||
for (const section of args.sections) {
|
||||
mergeTemplateInputPatch(templateInput, section.templateInputPatch);
|
||||
}
|
||||
|
||||
return {
|
||||
template: baseTemplate,
|
||||
|
||||
Reference in New Issue
Block a user