using PayRollDAL.DTO.SAP; using System.Collections.Generic; using System.Linq; using System.Text.Json; namespace PayRollBLL.SAP.Builders { /// /// SAP Infotype 586 — Contributions (80C, 80CCC, 80CCD). /// Service: ZPY_IT586_CONTRIBUTIONS_SRV / IT586HeaderSet /// Source: TDECLARATIONDETAIL rows where DeclarationDetailType == 4 (Investments). /// One SAP item per unique employee + section + particulars combination. /// public class SAP586Builder : ISapInfotypeBuilder { private const byte InvestmentType = 4; public int Infotype => 586; public string DisplayName => "Contributions (80C, 80CCC, 80CCD)"; public string EndpointPath => "/sap/opu/odata/sap/ZPY_IT586_CONTRIBUTIONS_SRV/IT586HeaderSet"; public string MsgNavProperty => "NAV2IT586MESSAGE"; public string Build(IEnumerable rows, string date, string remarks) { var items = rows .Where(r => r.DeclarationDetailId.HasValue && r.DeclarationDetailType == InvestmentType) .GroupBy(r => new { r.EmployeeCode, r.FiscalYear, r.SectionDetail, r.Particulars }) .Select(g => new Sap586Item { 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 Sap586Payload { Date = date, Remarks = remarks, NAV2IT586ITEM = items, }; return JsonSerializer.Serialize(payload, SapJsonOptions.Plain); } } }