using System.ComponentModel.DataAnnotations; using GB5Shared.DTO.Framework.Login; using Microsoft.Extensions.Logging; using MMDAL.CustomCode.MMDocument; using MMDAL.DTO.MMHead; namespace MMBLL.MMDocument { public class MMDocumentBLL : IMMDocumentBLL { private readonly IMMDocumentDAL _MMDocumentDAL; private readonly ILogger _Logger; public MMDocumentBLL(IMMDocumentDAL mmDocumentDAL, ILogger logger) { _MMDocumentDAL = mmDocumentDAL; _Logger = logger; } public async Task GetMMDocument( MMDocumentFilterDTO filter, LoginDTO login, CancellationToken ct) { ValidateFilter(filter); _Logger.LogInformation( "GetMMDocument: DocumentId {From}-{To} OUId {OUId} UserId {UserId}", filter.FromDocumentId, filter.ToDocumentId, filter.OUId, login.UserId); var heads = await _MMDocumentDAL.GetMMDocumentHeads(filter, login, ct).ConfigureAwait(false); if (heads.Count == 0) return new MMDocumentPrintResponseDTO(); var documentIds = heads.Select(h => h.DocumentId).Distinct().ToArray(); var details = await _MMDocumentDAL.GetMMDocumentDetails( documentIds, filter.IncludeB2BFields, login, ct).ConfigureAwait(false); var terms = filter.IncludeCharges ? await _MMDocumentDAL.GetTermsandConditions(documentIds, login, ct).ConfigureAwait(false) : []; var charges = filter.IncludeCharges ? await _MMDocumentDAL.GetMMDocumentCharges(documentIds, login, ct).ConfigureAwait(false) : []; var lotDetails = filter.IncludeLotDetails ? await _MMDocumentDAL.GetMMDocumentLotDetails(documentIds, login, ct).ConfigureAwait(false) : []; var schedules = filter.IncludeSchedules ? await _MMDocumentDAL.GetMMDocumentSchedules(documentIds, login, ct).ConfigureAwait(false) : []; var processes = filter.IncludeProcessDetails ? await _MMDocumentDAL.GetMMDocumentProcesses(documentIds, login, ct).ConfigureAwait(false) : []; var parameters = filter.IncludeParameters ? await _MMDocumentDAL.GetMMDocumentParameters(documentIds, login, ct).ConfigureAwait(false) : []; var addons = filter.IncludeAddons ? await _MMDocumentDAL.GetMMDocumentAddons(documentIds, login, ct).ConfigureAwait(false) : []; var packDetails = filter.IncludePackDetails ? await _MMDocumentDAL.GetMMDocumentPackDetails(documentIds, login, ct).ConfigureAwait(false) : []; var itemIds = details.Select(d => d.ItemId).Distinct().ToArray(); var itemImages = filter.IncludeItemImages && itemIds.Length > 0 ? await _MMDocumentDAL.GetMMDocumentItemImages(itemIds, login, ct).ConfigureAwait(false) : []; var voucherDetails = filter.IncludeVoucherDetails ? await _MMDocumentDAL.GetMMDocumentVoucherDetails(documentIds, login, ct).ConfigureAwait(false) : []; var billAllocations = filter.IncludeVoucherDetails ? await _MMDocumentDAL.GetMMDocumentBillAllocations(documentIds, login, ct).ConfigureAwait(false) : []; var costCenterAllocations = filter.IncludeCostCenterAllocations ? await _MMDocumentDAL.GetMMDocumentCostCenterAllocations(documentIds, login, ct).ConfigureAwait(false) : []; var itemPartyDocuments = filter.IncludeItemPartyDocument ? await _MMDocumentDAL.GetMMDocumentItemPartyDocuments(documentIds, login, ct).ConfigureAwait(false) : []; var preDocumentChain = filter.IncludePreDocumentChain ? await _MMDocumentDAL.GetMMDocumentPreDocumentChain(documentIds, login, ct).ConfigureAwait(false) : []; ComputeAmountInWords(heads); return new MMDocumentPrintResponseDTO { Heads = heads, Details = details, Charges = charges, Terms = terms, LotDetails = lotDetails, Schedules = schedules, Processes = processes, Parameters = parameters, Addons = addons, PackDetails = packDetails, ItemImages = itemImages, VoucherDetails = voucherDetails, BillAllocations = billAllocations, CostCenterAllocations = costCenterAllocations, ItemPartyDocuments = itemPartyDocuments, PreDocumentChain = preDocumentChain, }; } private static void ValidateFilter(MMDocumentFilterDTO filter) { if (filter.BizTransactionClassId == -1) throw new ValidationException("BizTransactionClassId is required."); if (filter.BizTransactionSubClassId == -1) throw new ValidationException("BizTransactionSubClassId is required."); if (filter.BizTransactionTypeId == -1) throw new ValidationException("BizTransactionTypeId is required."); if (filter.OUId == -1) throw new ValidationException("OUId is required."); if (filter.FromDocumentId == -1 && string.IsNullOrWhiteSpace(filter.FromDocumentNumber)) throw new ValidationException("At least FromDocumentId or FromDocumentNumber is required."); } private static void ComputeAmountInWords(List heads) { foreach (var h in heads) h.AmountInWords = ConvertToWords(h.DocumentValue, h.CurrencyFull, h.CurrencyDecimalName); } private static string ConvertToWords(decimal amount, string currencyFull, string decimalName) { if (amount <= 0) return string.Empty; var wholePart = (long)Math.Truncate(amount); var decimalPart = (long)Math.Round((amount - wholePart) * 100); var words = new System.Text.StringBuilder(); words.Append(string.IsNullOrEmpty(currencyFull) ? "Amount" : currencyFull); words.Append(' '); words.Append(WholeNumberToWords(wholePart)); if (decimalPart > 0) { words.Append(" and "); words.Append(WholeNumberToWords(decimalPart)); words.Append(' '); words.Append(string.IsNullOrEmpty(decimalName) ? "Cents" : decimalName); } words.Append(" Only"); return words.ToString(); } private static readonly string[] _ones = ["", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"]; private static readonly string[] _tens = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"]; private static string WholeNumberToWords(long n) { if (n == 0) return "Zero"; if (n < 0) return "Minus " + WholeNumberToWords(-n); if (n < 20) return _ones[n]; if (n < 100) return _tens[n / 10] + (n % 10 == 0 ? "" : " " + _ones[n % 10]); if (n < 1_000) return _ones[n / 100] + " Hundred" + (n % 100 == 0 ? "" : " " + WholeNumberToWords(n % 100)); if (n < 1_00_000) return WholeNumberToWords(n / 1_000) + " Thousand" + (n % 1_000 == 0 ? "" : " " + WholeNumberToWords(n % 1_000)); if (n < 1_00_00_000) return WholeNumberToWords(n / 1_00_000) + " Lakh" + (n % 1_00_000 == 0 ? "" : " " + WholeNumberToWords(n % 1_00_000)); return WholeNumberToWords(n / 1_00_00_000) + " Crore" + (n % 1_00_00_000 == 0 ? "" : " " + WholeNumberToWords(n % 1_00_00_000)); } } }