using System; using System.IO; using System.Threading; using System.Threading.Tasks; using GB5Shared.DTO.ECM; using GB5Shared.FileUpload; using GB5Shared.DTO.Framework.Login; using static GB5Shared.GB5Constant.Constant; using EntityConst = GB5Shared.GB5Constant.Constant.EntityConstant; namespace FrameworkBLL.SystemJob { /// /// Internal executor utility — called by SysJobExecutorQuartzJob when it detects /// that a report service returned a binary file response (application/pdf, xlsx, csv, etc.). /// /// Report services have no knowledge of DMS or this helper. They simply return the file /// as a standard HTTP response: /// HTTP 200 OK /// Content-Type: application/pdf /// Content-Disposition: attachment; filename="SalesReport_July2026.pdf" /// [binary body] /// /// The executor detects the binary content-type, calls UploadAsync here to store the /// file in TATTACHMENT linked to the TSYSJOB row, and writes "att:{attachmentId}" to /// TSYSJOB.RESULTLOCATION. GetSystemJobResult reads that token and streams the file /// back from DMS to the client. /// public static class SysJobAttachmentHelper { /// /// Uploads a report file to DMS linked to the given SysJob and returns "att:{attachmentId}". /// /// Injected IFileUploadBLL from the calling BLL. /// Complete file content (PDF, Excel, CSV, etc.). /// User-visible filename, e.g. "SalesReport_2026.pdf". /// MIME type, e.g. "application/pdf". /// The TSYSJOB.SYSJOBID this file belongs to. /// Caller's login — determines tenant and uploader identity. /// Cancellation token. /// "att:{attachmentId}" — store this in TSYSJOB.RESULTLOCATION. public static async Task UploadAsync( IFileUploadBLL fileUploadBLL, byte[] fileBytes, string displayFileName, string mimeType, int sysJobId, LoginDTO login, CancellationToken ct = default) { if (fileBytes is null || fileBytes.Length == 0) throw new ArgumentException("File content must not be empty.", nameof(fileBytes)); if (string.IsNullOrWhiteSpace(displayFileName)) throw new ArgumentException("Display file name must not be empty.", nameof(displayFileName)); string base64 = Convert.ToBase64String(fileBytes); var request = new FileUploadBase64RequestDTO { FileName = displayFileName, DisplayFileName = displayFileName, Base64Content = base64, ObjectId = sysJobId, ObjectTypeId = EntityConst.OBJECTSYSTEMJOB, // -1399960001 DocumentDetailId = -1, BizTransactionTypeId = -1, AttachmentType = 0, // File (not link) DocumentTypeId = -1, ClassificationMarkId = -1, SlNo = 1, Status = 1, Remarks = $"Report output for SysJob {sysJobId}", }; var result = await fileUploadBLL.FileUploadBase64Async(request, login).ConfigureAwait(false); return $"att:{result.AttachmentId}"; } /// /// Overload accepting a Stream instead of a byte array — avoids double-buffering for /// callers that already have the file as a stream (e.g. MemoryStream from QuestPDF/ClosedXML). /// The stream is read to completion; the caller is responsible for disposing it. /// public static async Task UploadAsync( IFileUploadBLL fileUploadBLL, Stream fileStream, string displayFileName, string mimeType, int sysJobId, LoginDTO login, CancellationToken ct = default) { using var ms = new MemoryStream(); await fileStream.CopyToAsync(ms, ct).ConfigureAwait(false); return await UploadAsync(fileUploadBLL, ms.ToArray(), displayFileName, mimeType, sysJobId, login, ct) .ConfigureAwait(false); } } }