async Task BuildLineItem(IList <BillLineItem> container, BillRequest request, BillRequestLineItem item) { // No stage 2 payments if (request.Type == BillType.Stage2 && (item.Scheme == Scheme.Endorsement || item.SubScheme == SubScheme.Canteen || item.SubScheme == SubScheme.ShortTerm)) { return; } var codes = await GetCertFeeCodes(request.ReferenceDate, item.Scheme, item.SubScheme); var code = codes.Count() == 1 ? codes.First() : codes.FirstOrDefault(e => ConditionEvaluator.Evaluate(item.Area, e.Conditions?.ToArray())); if (code == null) { return; } if (request.Type == BillType.Stage1) { await Stage1CertFee(container, code, item); } else if (request.Type == BillType.Stage2) { await Stage2CertFee(request.RequestType, container, code, item); } }
async Task Stage1CertFee(IList <BillLineItem> container, TransactionCode code, BillRequestLineItem item) { var duration = item.SubScheme == SubScheme.ShortTerm ? (item.ExpiresOn - item.StartsFrom).Days + 1 : BillingUtils.CalculateNoOfMonths(item.StartsFrom.Date, item.ExpiresOn.Date); var factor = await _context.Stage1Factor(); // Full payment for stage 1 if (item.Scheme == Scheme.Endorsement || item.SubScheme == SubScheme.Canteen || item.SubScheme == SubScheme.ShortTerm) { factor = 1M; } // Short term billed per 7 days else if (item.SubScheme == SubScheme.ShortTerm) { factor = Math.Ceiling(duration / 7M); } else { factor = Math.Min(factor, duration / 12M); } // For case where the pro-rated value is less than stage 1 expected factor. factor = Math.Min(duration / 12, factor); var unitPrice = code.GetLatestPriceAmount(); var gst = await _context.GST(); var qty = factor; var fee = qty * unitPrice; var gstAmount = fee * gst; var section = BillingUtils.LineItemSection(BillType.Stage1); var yearPrefix = duration > 12 ? " - Year 1" : ""; string prorateText = duration < 12 ? $" ({duration} of 12 months)" : ""; container.Add(new BillLineItem { SectionIndex = section.Item1, Section = section.Item2, Qty = qty, CodeID = code.ID, Code = code.Code, Descr = $"{code.Text}{yearPrefix}{prorateText}", UnitPrice = code.GetLatestPriceAmount(), Amount = decimal.Round(fee, 2), GSTAmount = decimal.Round(gstAmount, 2), GST = gst, WillRecord = true }); }
async Task Stage2CertFee(BillRequestType requestType, IList <BillLineItem> container, TransactionCode code, BillRequestLineItem item) { var totalDuration = BillingUtils.CalculateNoOfMonths(item.StartsFrom.Date, item.ExpiresOn.Date); var stage1Factor = await _context.Stage1Factor(); var prorate = Math.Round(totalDuration / 12M, 2); // No stage 2 payment for prorated application whose factor is less than stage 1 payment. if (prorate < stage1Factor && requestType != BillRequestType.Renewal) { return; } var section = BillingUtils.LineItemSection(BillType.Stage2); decimal factor; int i = 0; var duration = (decimal)totalDuration; do { prorate = Math.Min(Math.Round(duration / 12M, 2), 1M); // First year factor. Renewal will only have stage 2 payment. if (i == 0 && requestType != BillRequestType.Renewal) { factor = Math.Max(Math.Min( 1M - stage1Factor, prorate - stage1Factor), 0); } else { factor = Math.Min(1M, prorate); } if (factor == 0M) { break; } var unitPrice = code.GetLatestPriceAmount(); var gst = await _context.GST(); var qty = factor; var fee = qty * unitPrice; var gstAmount = fee * gst; var yearPrefix = totalDuration > 12 ? $" - Year {i + 1}" : ""; var prorateText = duration < 12 ? $" ({(int)duration} of 12 months)" : ""; container.Add(new BillLineItem { SectionIndex = section.Item1, Section = section.Item2, Qty = qty, CodeID = code.ID, Code = code.Code, Descr = $"{code.Text}{yearPrefix}{prorateText}", UnitPrice = code.GetLatestPriceAmount(), Amount = decimal.Round(fee, 2), GSTAmount = decimal.Round(gstAmount, 2), GST = gst, WillRecord = true }); duration -= 12; i++; } while (duration > 0); }