namespace GB5Shared.DocumentMerge; /// /// Result of a document merge — the merged file's bytes plus enough metadata for a caller to /// save it (e.g. via the ECM/TATTACHMENT pattern) or stream it back in an HTTP response. /// public class DocumentMergeResultDTO { public byte[] Content { get; set; } = System.Array.Empty(); public string ContentType { get; set; } = string.Empty; public string FileName { get; set; } = string.Empty; } /// /// Shared, module-independent Word/Excel template merge engine (plan: "Document Generation /// Engine — shared foundation, not Correspondence-specific"). Consumers (Correspondence today; /// a future Sales/CRM quotation generator later) own their own template storage and data /// assembly — this service only knows how to merge bytes + field values into a finished /// document. It never touches TATTACHMENT/ECM or any DB table directly (GB5Shared must not /// depend on FrameworkDAL/FrameworkBLL) — callers load template bytes and pass them in. /// public interface IDocumentMergeService { /// /// Merges a .docx or .xlsx template (detected from 's /// extension) against (flat placeholder values, ##FieldName##) and /// (named repeating-row datasets — each key is the repeat-region /// name used in the template via a ##REPEAT:Name## marker row/table-row, each value is the /// list of per-row field dictionaries). Conditional blocks (##IF:Field##...##ENDIF##) and /// image fields (##IMG:Field## with a byte[] value in ) are /// resolved automatically by whichever engine handles the file type. /// Task MergeAsync( byte[] templateBytes, string templateFileName, IReadOnlyDictionary fields, IReadOnlyDictionary>>? tables = null, CancellationToken ct = default); } /// /// Facade that dispatches to or /// based on the template's file extension. /// public sealed class DocumentMergeService( IWordMergeEngine _wordEngine, IExcelMergeEngine _excelEngine ) : IDocumentMergeService { public async Task MergeAsync( byte[] templateBytes, string templateFileName, IReadOnlyDictionary fields, IReadOnlyDictionary>>? tables = null, CancellationToken ct = default) { if (templateBytes is null || templateBytes.Length == 0) throw new ArgumentException("Template bytes cannot be empty.", nameof(templateBytes)); var ext = Path.GetExtension(templateFileName).ToLowerInvariant(); return ext switch { ".docx" => await _wordEngine.MergeAsync(templateBytes, fields, tables, ct).ConfigureAwait(false), ".xlsx" => await _excelEngine.MergeAsync(templateBytes, fields, tables, ct).ConfigureAwait(false), _ => throw new NotSupportedException( $"Unsupported template file type '{ext}'. Only .docx and .xlsx templates are supported.") }; } }