using PayRollDAL.DTO.SAP; using System.Collections.Generic; using System.Linq; using System.Text.Json; namespace PayRollBLL.SAP.Builders { /// /// SAP Infotype 585 — Deductions (80D, 80E, 80G, etc.). /// Service: ZPY_ITDEC_DEDUCT_SRV / DeductionHeaderSet /// Source: TDECLARATIONDETAIL rows where DeclarationDetailType == 5 (Expenses). /// One SAP item per unique employee + section + particulars combination. /// public class SAP585Builder : ISapInfotypeBuilder { private const byte ExpenseType = 5; public int Infotype => 585; public string DisplayName => "Deductions (80D, 80G, etc.)"; public string EndpointPath => "/sap/opu/odata/sap/ZPY_ITDEC_DEDUCT_SRV/DeductionHeaderSet"; public string MsgNavProperty => "NAV2DEDUCTIONMSG"; public string Build(IEnumerable rows, string date, string remarks) { var items = rows .Where(r => r.DeclarationDetailId.HasValue && r.DeclarationDetailType == ExpenseType) .GroupBy(r => new { r.EmployeeCode, r.FiscalYear, r.SectionDetail, r.Particulars }) .Select(g => new Sap585Item { EmployeeID = g.Key.EmployeeCode, FiscalYear = g.Key.FiscalYear, // ConsiderActual: SAP flag — empty = use declared/approved amounts as-is ConsiderActual = string.Empty, Section = g.Key.SectionDetail, Particulars = g.Key.Particulars, Declared = SapFmt.Amount(g.Sum(r => r.DeclaredAmount)), Approved = SapFmt.Amount(g.Sum(r => r.ApprovedAmount)), Remarks = g.First().DetailRemarks, }) .ToList(); if (items.Count == 0) return string.Empty; var payload = new Sap585Payload { Date = date, Remarks = remarks, NAV2DEDUCTIONITEM = items, }; return JsonSerializer.Serialize(payload, SapJsonOptions.Plain); } } }