chore(repo): initialize planarchy workspace
This commit is contained in:
@@ -0,0 +1,639 @@
|
||||
import * as XLSX from "xlsx";
|
||||
import {
|
||||
EstimateExportFormat,
|
||||
type EstimateExportArtifactPayload,
|
||||
type EstimateExportSummary,
|
||||
type EstimateStatus,
|
||||
type EstimateVersionStatus,
|
||||
} from "@planarchy/shared";
|
||||
import { summarizeEstimateDemandLines } from "./metrics.js";
|
||||
|
||||
type ExportProjectRef = {
|
||||
id: string;
|
||||
name: string;
|
||||
shortCode?: string | null;
|
||||
status?: string | null;
|
||||
startDate?: Date | string | null;
|
||||
endDate?: Date | string | null;
|
||||
} | null;
|
||||
|
||||
type ExportAssumption = {
|
||||
id: string;
|
||||
category: string;
|
||||
key: string;
|
||||
label: string;
|
||||
valueType: string;
|
||||
value: unknown;
|
||||
sortOrder: number;
|
||||
notes?: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
|
||||
type ExportScopeItem = {
|
||||
id: string;
|
||||
sequenceNo: number;
|
||||
scopeType: string;
|
||||
packageCode?: string | null;
|
||||
name: string;
|
||||
description?: string | null;
|
||||
scene?: string | null;
|
||||
page?: string | null;
|
||||
location?: string | null;
|
||||
assumptionCategory?: string | null;
|
||||
technicalSpec: unknown;
|
||||
frameCount?: number | null;
|
||||
itemCount?: number | null;
|
||||
unitMode?: string | null;
|
||||
internalComments?: string | null;
|
||||
externalComments?: string | null;
|
||||
metadata: unknown;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
|
||||
type ExportDemandLine = {
|
||||
id: string;
|
||||
scopeItemId?: string | null;
|
||||
roleId?: string | null;
|
||||
resourceId?: string | null;
|
||||
lineType: string;
|
||||
name: string;
|
||||
chapter?: string | null;
|
||||
hours: number;
|
||||
days?: number | null;
|
||||
fte?: number | null;
|
||||
rateSource?: string | null;
|
||||
costRateCents: number;
|
||||
billRateCents: number;
|
||||
currency: string;
|
||||
costTotalCents: number;
|
||||
priceTotalCents: number;
|
||||
monthlySpread: unknown;
|
||||
staffingAttributes: unknown;
|
||||
metadata: unknown;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
|
||||
type ExportResourceSnapshot = {
|
||||
id: string;
|
||||
resourceId?: string | null;
|
||||
sourceEid?: string | null;
|
||||
displayName: string;
|
||||
chapter?: string | null;
|
||||
roleId?: string | null;
|
||||
currency: string;
|
||||
lcrCents: number;
|
||||
ucrCents: number;
|
||||
fte?: number | null;
|
||||
location?: string | null;
|
||||
country?: string | null;
|
||||
level?: string | null;
|
||||
workType?: string | null;
|
||||
attributes: unknown;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
|
||||
type ExportMetric = {
|
||||
id: string;
|
||||
key: string;
|
||||
label: string;
|
||||
metricGroup?: string | null;
|
||||
valueDecimal: number;
|
||||
valueCents?: number | null;
|
||||
currency?: string | null;
|
||||
metadata: unknown;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
|
||||
export interface EstimateExportSource {
|
||||
estimate: {
|
||||
id: string;
|
||||
projectId?: string | null;
|
||||
name: string;
|
||||
opportunityId?: string | null;
|
||||
baseCurrency: string;
|
||||
status: EstimateStatus | string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
version: {
|
||||
id: string;
|
||||
versionNumber: number;
|
||||
label?: string | null;
|
||||
status: EstimateVersionStatus | string;
|
||||
notes?: string | null;
|
||||
lockedAt?: Date | null;
|
||||
projectSnapshot: unknown;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
assumptions: ExportAssumption[];
|
||||
scopeItems: ExportScopeItem[];
|
||||
demandLines: ExportDemandLine[];
|
||||
resourceSnapshots: ExportResourceSnapshot[];
|
||||
metrics: ExportMetric[];
|
||||
};
|
||||
project: ExportProjectRef;
|
||||
}
|
||||
|
||||
function serializeDate(value: Date | string | null | undefined) {
|
||||
if (value instanceof Date) {
|
||||
return value.toISOString();
|
||||
}
|
||||
|
||||
return value ?? null;
|
||||
}
|
||||
|
||||
function stringifyValue(value: unknown) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "number" || typeof value === "boolean") {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
function toNumericRecord(value: unknown) {
|
||||
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
||||
return {} as Record<string, number>;
|
||||
}
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(value).filter(
|
||||
(entry): entry is [string, number] => typeof entry[1] === "number",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function escapeDelimitedValue(value: unknown, delimiter: string) {
|
||||
const rendered = stringifyValue(value);
|
||||
if (
|
||||
rendered.includes(delimiter) ||
|
||||
rendered.includes('"') ||
|
||||
rendered.includes("\n") ||
|
||||
rendered.includes("\r")
|
||||
) {
|
||||
return `"${rendered.replaceAll('"', '""')}"`;
|
||||
}
|
||||
|
||||
return rendered;
|
||||
}
|
||||
|
||||
function serializeDelimited(
|
||||
rows: Array<Record<string, unknown>>,
|
||||
delimiter: string,
|
||||
) {
|
||||
if (rows.length === 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const columns = Array.from(
|
||||
rows.reduce((keys, row) => {
|
||||
for (const key of Object.keys(row)) {
|
||||
keys.add(key);
|
||||
}
|
||||
return keys;
|
||||
}, new Set<string>()),
|
||||
);
|
||||
const header = columns.map((column) => escapeDelimitedValue(column, delimiter));
|
||||
const body = rows.map((row) =>
|
||||
columns.map((column) => escapeDelimitedValue(row[column], delimiter)).join(delimiter),
|
||||
);
|
||||
|
||||
return [header.join(delimiter), ...body].join("\n");
|
||||
}
|
||||
|
||||
function buildSummary(source: EstimateExportSource): EstimateExportSummary {
|
||||
const summarized = summarizeEstimateDemandLines(source.version.demandLines);
|
||||
const metricsByKey = new Map(
|
||||
source.version.metrics.map((metric) => [metric.key, metric]),
|
||||
);
|
||||
|
||||
const totalHours =
|
||||
metricsByKey.get("total_hours")?.valueDecimal ?? summarized.totalHours;
|
||||
const totalCostCents =
|
||||
metricsByKey.get("total_cost")?.valueCents ?? summarized.totalCostCents;
|
||||
const totalPriceCents =
|
||||
metricsByKey.get("total_price")?.valueCents ?? summarized.totalPriceCents;
|
||||
const marginCents =
|
||||
metricsByKey.get("margin")?.valueCents ?? summarized.marginCents;
|
||||
const marginPercent =
|
||||
metricsByKey.get("margin_percent")?.valueDecimal ?? summarized.marginPercent;
|
||||
|
||||
return {
|
||||
estimateId: source.estimate.id,
|
||||
estimateName: source.estimate.name,
|
||||
versionId: source.version.id,
|
||||
versionNumber: source.version.versionNumber,
|
||||
versionStatus: source.version.status as EstimateVersionStatus,
|
||||
projectId: source.estimate.projectId ?? source.project?.id ?? null,
|
||||
projectName: source.project?.name ?? null,
|
||||
baseCurrency: source.estimate.baseCurrency,
|
||||
assumptionCount: source.version.assumptions.length,
|
||||
scopeItemCount: source.version.scopeItems.length,
|
||||
demandLineCount: source.version.demandLines.length,
|
||||
resourceSnapshotCount: source.version.resourceSnapshots.length,
|
||||
totalHours,
|
||||
totalCostCents,
|
||||
totalPriceCents,
|
||||
marginCents,
|
||||
marginPercent,
|
||||
};
|
||||
}
|
||||
|
||||
function buildOverviewRows(
|
||||
source: EstimateExportSource,
|
||||
summary: EstimateExportSummary,
|
||||
) {
|
||||
return [
|
||||
{ field: "estimate_id", value: summary.estimateId },
|
||||
{ field: "estimate_name", value: summary.estimateName },
|
||||
{ field: "estimate_status", value: source.estimate.status },
|
||||
{ field: "version_id", value: summary.versionId },
|
||||
{ field: "version_number", value: summary.versionNumber },
|
||||
{ field: "version_status", value: summary.versionStatus },
|
||||
{ field: "version_label", value: source.version.label ?? "" },
|
||||
{ field: "version_notes", value: source.version.notes ?? "" },
|
||||
{ field: "project_id", value: summary.projectId ?? "" },
|
||||
{ field: "project_name", value: summary.projectName ?? "" },
|
||||
{ field: "project_code", value: source.project?.shortCode ?? "" },
|
||||
{ field: "base_currency", value: summary.baseCurrency },
|
||||
{ field: "opportunity_id", value: source.estimate.opportunityId ?? "" },
|
||||
{ field: "locked_at", value: serializeDate(source.version.lockedAt) ?? "" },
|
||||
{ field: "generated_from_project_start", value: serializeDate(source.project?.startDate) ?? "" },
|
||||
{ field: "generated_from_project_end", value: serializeDate(source.project?.endDate) ?? "" },
|
||||
{ field: "assumption_count", value: summary.assumptionCount },
|
||||
{ field: "scope_item_count", value: summary.scopeItemCount },
|
||||
{ field: "demand_line_count", value: summary.demandLineCount },
|
||||
{ field: "resource_snapshot_count", value: summary.resourceSnapshotCount },
|
||||
{ field: "total_hours", value: summary.totalHours },
|
||||
{ field: "total_cost_cents", value: summary.totalCostCents },
|
||||
{ field: "total_price_cents", value: summary.totalPriceCents },
|
||||
{ field: "margin_cents", value: summary.marginCents },
|
||||
{ field: "margin_percent", value: summary.marginPercent },
|
||||
];
|
||||
}
|
||||
|
||||
function buildAssumptionRows(assumptions: ExportAssumption[]) {
|
||||
return assumptions.map((assumption) => ({
|
||||
id: assumption.id,
|
||||
category: assumption.category,
|
||||
key: assumption.key,
|
||||
label: assumption.label,
|
||||
value_type: assumption.valueType,
|
||||
value: stringifyValue(assumption.value),
|
||||
notes: assumption.notes ?? "",
|
||||
sort_order: assumption.sortOrder,
|
||||
}));
|
||||
}
|
||||
|
||||
function buildScopeRows(scopeItems: ExportScopeItem[]) {
|
||||
return scopeItems.map((scopeItem) => ({
|
||||
id: scopeItem.id,
|
||||
sequence_no: scopeItem.sequenceNo,
|
||||
scope_type: scopeItem.scopeType,
|
||||
package_code: scopeItem.packageCode ?? "",
|
||||
name: scopeItem.name,
|
||||
description: scopeItem.description ?? "",
|
||||
scene: scopeItem.scene ?? "",
|
||||
page: scopeItem.page ?? "",
|
||||
location: scopeItem.location ?? "",
|
||||
assumption_category: scopeItem.assumptionCategory ?? "",
|
||||
frame_count: scopeItem.frameCount ?? "",
|
||||
item_count: scopeItem.itemCount ?? "",
|
||||
unit_mode: scopeItem.unitMode ?? "",
|
||||
technical_spec: stringifyValue(scopeItem.technicalSpec),
|
||||
internal_comments: scopeItem.internalComments ?? "",
|
||||
external_comments: scopeItem.externalComments ?? "",
|
||||
metadata: stringifyValue(scopeItem.metadata),
|
||||
}));
|
||||
}
|
||||
|
||||
function buildDemandRows(source: EstimateExportSource) {
|
||||
const scopeItemsById = new Map(
|
||||
source.version.scopeItems.map((scopeItem) => [scopeItem.id, scopeItem]),
|
||||
);
|
||||
|
||||
return source.version.demandLines.map((line, index) => ({
|
||||
line_no: index + 1,
|
||||
line_id: line.id,
|
||||
scope_item_id: line.scopeItemId ?? "",
|
||||
scope_item_name:
|
||||
(line.scopeItemId ? scopeItemsById.get(line.scopeItemId)?.name : null) ?? "",
|
||||
role_id: line.roleId ?? "",
|
||||
resource_id: line.resourceId ?? "",
|
||||
line_type: line.lineType,
|
||||
name: line.name,
|
||||
chapter: line.chapter ?? "",
|
||||
hours: line.hours,
|
||||
days: line.days ?? "",
|
||||
fte: line.fte ?? "",
|
||||
rate_source: line.rateSource ?? "",
|
||||
cost_rate_cents: line.costRateCents,
|
||||
bill_rate_cents: line.billRateCents,
|
||||
currency: line.currency,
|
||||
cost_total_cents: line.costTotalCents,
|
||||
price_total_cents: line.priceTotalCents,
|
||||
monthly_spread: stringifyValue(toNumericRecord(line.monthlySpread)),
|
||||
staffing_attributes: stringifyValue(line.staffingAttributes),
|
||||
metadata: stringifyValue(line.metadata),
|
||||
}));
|
||||
}
|
||||
|
||||
function buildResourceRows(resourceSnapshots: ExportResourceSnapshot[]) {
|
||||
return resourceSnapshots.map((snapshot) => ({
|
||||
id: snapshot.id,
|
||||
resource_id: snapshot.resourceId ?? "",
|
||||
source_eid: snapshot.sourceEid ?? "",
|
||||
display_name: snapshot.displayName,
|
||||
chapter: snapshot.chapter ?? "",
|
||||
role_id: snapshot.roleId ?? "",
|
||||
currency: snapshot.currency,
|
||||
lcr_cents: snapshot.lcrCents,
|
||||
ucr_cents: snapshot.ucrCents,
|
||||
fte: snapshot.fte ?? "",
|
||||
location: snapshot.location ?? "",
|
||||
country: snapshot.country ?? "",
|
||||
level: snapshot.level ?? "",
|
||||
work_type: snapshot.workType ?? "",
|
||||
attributes: stringifyValue(snapshot.attributes),
|
||||
}));
|
||||
}
|
||||
|
||||
function buildMetricRows(metrics: ExportMetric[]) {
|
||||
return metrics.map((metric) => ({
|
||||
id: metric.id,
|
||||
key: metric.key,
|
||||
label: metric.label,
|
||||
metric_group: metric.metricGroup ?? "",
|
||||
value_decimal: metric.valueDecimal,
|
||||
value_cents: metric.valueCents ?? "",
|
||||
currency: metric.currency ?? "",
|
||||
metadata: stringifyValue(metric.metadata),
|
||||
}));
|
||||
}
|
||||
|
||||
function buildSapRows(
|
||||
source: EstimateExportSource,
|
||||
summary: EstimateExportSummary,
|
||||
) {
|
||||
return source.version.demandLines.map((line, index) => ({
|
||||
record_type: "ESTIMATE_LINE",
|
||||
estimate_id: summary.estimateId,
|
||||
version_number: summary.versionNumber,
|
||||
project_code: source.project?.shortCode ?? "",
|
||||
project_name: summary.projectName ?? "",
|
||||
line_no: index + 1,
|
||||
line_name: line.name,
|
||||
role_id: line.roleId ?? "",
|
||||
resource_id: line.resourceId ?? "",
|
||||
chapter: line.chapter ?? "",
|
||||
hours: line.hours,
|
||||
cost_rate_cents: line.costRateCents,
|
||||
bill_rate_cents: line.billRateCents,
|
||||
cost_total_cents: line.costTotalCents,
|
||||
price_total_cents: line.priceTotalCents,
|
||||
currency: line.currency,
|
||||
rate_source: line.rateSource ?? "",
|
||||
version_status: summary.versionStatus,
|
||||
}));
|
||||
}
|
||||
|
||||
function buildMmpRows(
|
||||
source: EstimateExportSource,
|
||||
summary: EstimateExportSummary,
|
||||
) {
|
||||
const monthKeys = Array.from(
|
||||
new Set(
|
||||
source.version.demandLines.flatMap((line) =>
|
||||
Object.keys(toNumericRecord(line.monthlySpread)),
|
||||
),
|
||||
),
|
||||
).sort();
|
||||
|
||||
return source.version.demandLines.map((line, index) => {
|
||||
const baseRow: Record<string, unknown> = {
|
||||
estimate_id: summary.estimateId,
|
||||
version_number: summary.versionNumber,
|
||||
project_id: summary.projectId ?? "",
|
||||
project_code: source.project?.shortCode ?? "",
|
||||
line_no: index + 1,
|
||||
line_name: line.name,
|
||||
role_id: line.roleId ?? "",
|
||||
resource_id: line.resourceId ?? "",
|
||||
total_hours: line.hours,
|
||||
total_cost_cents: line.costTotalCents,
|
||||
total_price_cents: line.priceTotalCents,
|
||||
currency: line.currency,
|
||||
};
|
||||
|
||||
for (const monthKey of monthKeys) {
|
||||
baseRow[`month_${monthKey}`] =
|
||||
toNumericRecord(line.monthlySpread)[monthKey] ?? 0;
|
||||
}
|
||||
|
||||
return baseRow;
|
||||
});
|
||||
}
|
||||
|
||||
function buildJsonDocument(
|
||||
source: EstimateExportSource,
|
||||
summary: EstimateExportSummary,
|
||||
) {
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
generatedAt: new Date().toISOString(),
|
||||
estimate: {
|
||||
...source.estimate,
|
||||
createdAt: source.estimate.createdAt.toISOString(),
|
||||
updatedAt: source.estimate.updatedAt.toISOString(),
|
||||
},
|
||||
project: source.project
|
||||
? {
|
||||
...source.project,
|
||||
startDate: serializeDate(source.project.startDate),
|
||||
endDate: serializeDate(source.project.endDate),
|
||||
}
|
||||
: null,
|
||||
version: {
|
||||
id: source.version.id,
|
||||
versionNumber: source.version.versionNumber,
|
||||
label: source.version.label ?? null,
|
||||
status: source.version.status,
|
||||
notes: source.version.notes ?? null,
|
||||
lockedAt: serializeDate(source.version.lockedAt),
|
||||
projectSnapshot: source.version.projectSnapshot,
|
||||
createdAt: source.version.createdAt.toISOString(),
|
||||
updatedAt: source.version.updatedAt.toISOString(),
|
||||
},
|
||||
summary,
|
||||
assumptions: source.version.assumptions.map((assumption) => ({
|
||||
...assumption,
|
||||
createdAt: assumption.createdAt.toISOString(),
|
||||
updatedAt: assumption.updatedAt.toISOString(),
|
||||
})),
|
||||
scopeItems: source.version.scopeItems.map((scopeItem) => ({
|
||||
...scopeItem,
|
||||
createdAt: scopeItem.createdAt.toISOString(),
|
||||
updatedAt: scopeItem.updatedAt.toISOString(),
|
||||
})),
|
||||
demandLines: source.version.demandLines.map((line) => ({
|
||||
...line,
|
||||
createdAt: line.createdAt.toISOString(),
|
||||
updatedAt: line.updatedAt.toISOString(),
|
||||
})),
|
||||
resourceSnapshots: source.version.resourceSnapshots.map((snapshot) => ({
|
||||
...snapshot,
|
||||
createdAt: snapshot.createdAt.toISOString(),
|
||||
updatedAt: snapshot.updatedAt.toISOString(),
|
||||
})),
|
||||
metrics: source.version.metrics.map((metric) => ({
|
||||
...metric,
|
||||
createdAt: metric.createdAt.toISOString(),
|
||||
updatedAt: metric.updatedAt.toISOString(),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
function base64ByteLength(content: string) {
|
||||
const padding = content.endsWith("==") ? 2 : content.endsWith("=") ? 1 : 0;
|
||||
return Math.floor((content.length * 3) / 4) - padding;
|
||||
}
|
||||
|
||||
function buildTextPayload(
|
||||
format: EstimateExportFormat,
|
||||
content: string,
|
||||
summary: EstimateExportSummary,
|
||||
options: {
|
||||
mimeType: string;
|
||||
fileExtension: string;
|
||||
rowCount: number;
|
||||
},
|
||||
): EstimateExportArtifactPayload {
|
||||
const lineCount = content.length === 0 ? 0 : content.split("\n").length;
|
||||
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
format,
|
||||
mimeType: options.mimeType,
|
||||
encoding: "utf8",
|
||||
fileExtension: options.fileExtension,
|
||||
generatedAt: new Date().toISOString(),
|
||||
byteLength: new TextEncoder().encode(content).length,
|
||||
rowCount: options.rowCount,
|
||||
lineCount,
|
||||
previewText: content.split("\n").slice(0, 12).join("\n"),
|
||||
content,
|
||||
summary,
|
||||
};
|
||||
}
|
||||
|
||||
function buildXlsxPayload(
|
||||
source: EstimateExportSource,
|
||||
summary: EstimateExportSummary,
|
||||
): EstimateExportArtifactPayload {
|
||||
const overviewRows = buildOverviewRows(source, summary);
|
||||
const assumptionRows = buildAssumptionRows(source.version.assumptions);
|
||||
const scopeRows = buildScopeRows(source.version.scopeItems);
|
||||
const demandRows = buildDemandRows(source);
|
||||
const resourceRows = buildResourceRows(source.version.resourceSnapshots);
|
||||
const metricRows = buildMetricRows(source.version.metrics);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
const sheets = [
|
||||
{ name: "Overview", rows: overviewRows },
|
||||
{ name: "Assumptions", rows: assumptionRows },
|
||||
{ name: "Scope", rows: scopeRows },
|
||||
{ name: "DemandLines", rows: demandRows },
|
||||
{ name: "Resources", rows: resourceRows },
|
||||
{ name: "Metrics", rows: metricRows },
|
||||
] as const;
|
||||
|
||||
for (const sheet of sheets) {
|
||||
XLSX.utils.book_append_sheet(
|
||||
workbook,
|
||||
XLSX.utils.json_to_sheet(sheet.rows),
|
||||
sheet.name,
|
||||
);
|
||||
}
|
||||
|
||||
const content = XLSX.write(workbook, {
|
||||
type: "base64",
|
||||
bookType: "xlsx",
|
||||
});
|
||||
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
format: EstimateExportFormat.XLSX,
|
||||
mimeType:
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
encoding: "base64",
|
||||
fileExtension: "xlsx",
|
||||
generatedAt: new Date().toISOString(),
|
||||
byteLength: base64ByteLength(content),
|
||||
rowCount:
|
||||
overviewRows.length +
|
||||
assumptionRows.length +
|
||||
scopeRows.length +
|
||||
demandRows.length +
|
||||
resourceRows.length +
|
||||
metricRows.length,
|
||||
lineCount: null,
|
||||
sheetNames: sheets.map((sheet) => sheet.name),
|
||||
previewText: `Sheets: ${sheets.map((sheet) => sheet.name).join(", ")}`,
|
||||
content,
|
||||
summary,
|
||||
};
|
||||
}
|
||||
|
||||
export function serializeEstimateExport(
|
||||
source: EstimateExportSource,
|
||||
format: EstimateExportFormat,
|
||||
): EstimateExportArtifactPayload {
|
||||
const summary = buildSummary(source);
|
||||
|
||||
if (format === EstimateExportFormat.JSON) {
|
||||
const content = JSON.stringify(buildJsonDocument(source, summary), null, 2);
|
||||
return buildTextPayload(format, content, summary, {
|
||||
mimeType: "application/json; charset=utf-8",
|
||||
fileExtension: "json",
|
||||
rowCount: summary.demandLineCount,
|
||||
});
|
||||
}
|
||||
|
||||
if (format === EstimateExportFormat.CSV) {
|
||||
const rows = buildDemandRows(source);
|
||||
return buildTextPayload(format, serializeDelimited(rows, ","), summary, {
|
||||
mimeType: "text/csv; charset=utf-8",
|
||||
fileExtension: "csv",
|
||||
rowCount: rows.length,
|
||||
});
|
||||
}
|
||||
|
||||
if (format === EstimateExportFormat.SAP) {
|
||||
const rows = buildSapRows(source, summary);
|
||||
return buildTextPayload(format, serializeDelimited(rows, ";"), summary, {
|
||||
mimeType: "text/plain; charset=utf-8",
|
||||
fileExtension: "sap",
|
||||
rowCount: rows.length,
|
||||
});
|
||||
}
|
||||
|
||||
if (format === EstimateExportFormat.MMP) {
|
||||
const rows = buildMmpRows(source, summary);
|
||||
return buildTextPayload(format, serializeDelimited(rows, "|"), summary, {
|
||||
mimeType: "text/plain; charset=utf-8",
|
||||
fileExtension: "mmp",
|
||||
rowCount: rows.length,
|
||||
});
|
||||
}
|
||||
|
||||
return buildXlsxPayload(source, summary);
|
||||
}
|
||||
Reference in New Issue
Block a user