using PayRollDAL.DTO.SAP; using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; namespace PayRollBLL.SAP.Builders { /// /// SAP Infotype 581 — HRA / Rent Paid. /// Service: ZPY_ITDEC_HRA_SRV / ITDecHRA_HeaderSet /// Source: TDECLARATIONDETAIL rows where DeclarationDetailType == 2 (Rent). /// One SAP item per rent detail record; dates formatted as dd-MMM-yyyy per SAP spec. /// public class SAP581Builder : ISapInfotypeBuilder { private const byte RentType = 2; public int Infotype => 581; public string DisplayName => "HRA / Rent Paid"; public string EndpointPath => "/sap/opu/odata/sap/ZPY_ITDEC_HRA_SRV/ITDecHRA_HeaderSet"; public string MsgNavProperty => "Nav2IT_Dec_HRA_Msg"; public string Build(IEnumerable rows, string date, string remarks) { var items = rows .Where(r => r.DeclarationDetailId.HasValue && r.DeclarationDetailType == RentType && r.DeclaredAmount != 0) .Select(r => new Sap581Item { EmployeeID = r.EmployeeCode, FiscalYear = r.FiscalYear, Particulars = r.Particulars, From = r.FromPeriod.HasValue ? r.FromPeriod.Value.ToString("dd-MMM-yyyy") : string.Empty, To = r.ToPeriod.HasValue ? r.ToPeriod.Value.ToString("dd-MMM-yyyy") : string.Empty, // IsMetro: 0 = Metro city, 1 = Non-Metro (per ITDeclarationSapDTO) Type = r.IsMetro == 0 ? "Metro" : "Non-Metro", // SAP expects monthly rent; the DB stores the annual declared/approved total. Declared = SapFmt.Amount(Math.Round(r.DeclaredAmount / 12, 2)), Approved = SapFmt.Amount(Math.Round(r.ApprovedAmount / 12, 2)), Remarks = r.DetailRemarks, LandLordName = r.ContactName, LandLordPAN = r.ContactPAN, LandLordTAN = r.ContactTAN, LandLordAddressLine1 = r.ContactAddress1, LandLordAddressLine2 = r.ContactAddress2, LandLordAddressLine3 = r.ContactAddress3, LandLordAddressLine4 = r.ContactAddress4, LandLordAddressLine5 = r.ContactAddress5, }) .ToList(); if (items.Count == 0) return string.Empty; var payload = new Sap581Payload { Date = date, Remarks = remarks, Nav2IT_Dec_HRA_Item = items, }; return JsonSerializer.Serialize(payload, SapJsonOptions.Plain); } } }