/// <summary> /// Populate tax summary for India. /// </summary> /// <param name="salesTransaction">The transaction.</param> /// <param name="taxSummarySettingIndia">Tax summary setting.</param> internal static void PopulateTaxSummaryForIndia(SalesTransaction salesTransaction, TaxSummarySettingIndia taxSummarySettingIndia) { if (salesTransaction == null) { throw new ArgumentNullException("salesTransaction"); } if (taxSummarySettingIndia == null) { throw new ArgumentNullException("taxSummarySettingIndia"); } if (taxSummarySettingIndia.TaxDetailsType == ReceiptTaxDetailsTypeIndia.PerTaxComponent) { IList <TaxLineIndia> indiaTaxItems = new List <TaxLineIndia>(); foreach (SalesLine saleLine in salesTransaction.ActiveSalesLines) { foreach (TaxLine taxLine in saleLine.TaxLines) { TaxLineIndia taxLineIndia = taxLine as TaxLineIndia; if (taxLineIndia != null) { indiaTaxItems.Add(taxLineIndia); } } } if (taxSummarySettingIndia.ShowTaxonTax) { salesTransaction.TaxLines.Clear(); salesTransaction.TaxLines.AddRange(BuildIndiaTaxSummaryPerComponentShowTaxonTax(indiaTaxItems)); } else { salesTransaction.TaxLines.Clear(); salesTransaction.TaxLines.AddRange(BuildIndiaTaxSummaryPerComponentNotShowTaxonTax(indiaTaxItems)); } } else if (taxSummarySettingIndia.TaxDetailsType == ReceiptTaxDetailsTypeIndia.PerLine) { salesTransaction.TaxLines.Clear(); salesTransaction.TaxLines.AddRange(BuildIndiaTaxSummaryPerLine(salesTransaction)); } }
/// <summary> /// Build tax summary line of the India receipt, with tax amounts be aggregated by "main" tax codes (which /// are not India tax on tax codes). /// </summary> /// <param name="indiaTaxItems">All tax items of the India retail transaction.</param> /// <returns>The tax summary lines of the India receipt.</returns> /// <remarks> /// In this case, the settings of <c>>"RetailStoreTable > Misc. > Receipts"</c> is as follows, /// 1) The "Tax details" option is set as "Per tax component" /// 2) The "Show tax on tax" option is turned OFF /// For example, the retail transaction has four sale line items, as follows, /// <c> /// Item ID | Price | Tax code | Formula | Tax basis | Tax rate | Tax amount /// 0001 | 100 | SERV5 | Line amount | 100.00 | 5% | 5.00 /// | | E-CSS5 | Excl.+[SERV5] | 5.00 | 5% | 0.25 /// 0002 | 100 | VAT10 | Line amount | 100.00 | 10% | 10.00 /// | | Surchg2 | Excl.+[VAT10] | 10.00 | 2% | 0.20 /// 0003 | 100 | SERV4 | Line amount | 100.00 | 4% | 4.00 /// | | E-CSS5 | Excl.+[SERV4] | 4.00 | 5% | 0.20 /// 0004 | 100 | VAT12 | Line amount | 100.00 | 12% | 12.00 /// | | Surchg2 | Excl.+[VAT12] | 12.00 | 2% | 0.24 /// And the tax summary lines will be as follows, /// Tax code | Tax basis | Tax rate | Tax amount /// SERV5 | 100.00 | 5.25% | 5.25 /// SERV4 | 100.00 | 4.20% | 4.20 /// VAT10 | 100.00 | 10.20% | 10.20 /// VAT12 | 100.00 | 12.24% | 12.24. /// </c> /// </remarks> private static IList <TaxLine> BuildIndiaTaxSummaryPerComponentNotShowTaxonTax(IList <TaxLineIndia> indiaTaxItems) { if (indiaTaxItems == null) { throw new ArgumentNullException("indiaTaxItems"); } if (indiaTaxItems.Count == 0) { throw new ArgumentException("The specified collection cannot be empty.", "indiaTaxItems"); } List <TaxLine> lines = new List <TaxLine>(); var groups = indiaTaxItems.GroupBy(x => { string taxCode = x.IsTaxOnTax ? x.TaxFormula.Split(',').First() : x.TaxCode; return(new { x.TaxGroup, taxCode }); }); foreach (var group in groups) { TaxLineIndia t = new TaxLineIndia(); t.TaxGroup = group.Key.TaxGroup; t.TaxCode = group.Key.taxCode; t.TaxBasis = group.First(x => !x.IsTaxOnTax).TaxBasis; t.Amount = group.Sum(x => x.Amount); t.Percentage = t.TaxBasis != decimal.Zero ? (100 * t.Amount / t.TaxBasis) : decimal.Zero; t.TaxComponent = group.First(x => !x.IsTaxOnTax).TaxComponent; lines.Add(t); } // Order by tax component lines = new List <TaxLine>(lines.OrderBy(x => (x as TaxLineIndia).TaxComponent)); return(lines); }
/// <summary> /// Build tax summary line of the India receipt, with tax amounts be aggregated by tax codes. /// </summary> /// <param name="indiaTaxItems">All tax items of the India retail transaction.</param> /// <returns>The tax summary lines of the India receipt.</returns> /// <remarks> /// In this case, the settings of <c>"RetailStoreTable > Misc. > Receipts"</c> is as follows, /// 1) The "Tax details" option is set as "Per tax component" /// 2) The "Show tax on tax" option is turned ON /// For example, the retail transaction has four sale line items, as follows, /// <c> /// Item ID | Price | Tax code | Formula | Tax basis | Tax rate | Tax amount /// 0001 | 100 | SERV5 | Line amount | 100.00 | 5% | 5.00 /// | | E-CSS5 | Excl.+[SERV5] | 5.00 | 5% | 0.25 /// 0002 | 100 | VAT10 | Line amount | 100.00 | 10% | 10.00 /// | | Surchg2 | Excl.+[VAT10] | 10.00 | 2% | 0.20 /// 0003 | 100 | SERV4 | Line amount | 100.00 | 4% | 4.00 /// | | E-CSS5 | Excl.+[SERV4] | 4.00 | 5% | 0.20 /// 0004 | 100 | VAT12 | Line amount | 100.00 | 12% | 12.00 /// | | Surchg2 | Excl.+[VAT12] | 12.00 | 2% | 0.24 /// And the tax summary lines will be as follows, /// Tax component | Tax code | Tax basis | Tax rate | Tax amount /// Service | SERV5 | 100.00 | 5% | 5.00 /// Service | SERV4 | 100.00 | 4% | 4.00 /// E-CSS | E-CSS5 | 9.00 | 5% | 0.45 /// VAT | VAT10 | 100.00 | 10% | 10.00 /// VAT | VAT12 | 100.00 | 12% | 12.00 /// Surcharge | Surchg2 | 22.00 | 2% | 0.44. /// </c> /// </remarks> private static IList <TaxLine> BuildIndiaTaxSummaryPerComponentShowTaxonTax(IList <TaxLineIndia> indiaTaxItems) { List <TaxLine> lines = new List <TaxLine>(); var groups = indiaTaxItems.GroupBy(x => new { x.TaxComponent, x.TaxCode }); foreach (var group in groups) { TaxLineIndia t = new TaxLineIndia(); t.TaxComponent = group.Key.TaxComponent; t.TaxCode = group.Key.TaxCode; t.Amount = group.Sum(x => x.Amount); t.Percentage = group.First().Percentage; t.TaxBasis = group.Sum(x => x.TaxBasis); t.TaxGroup = group.First().TaxGroup; lines.Add(t); } // Order by tax component lines = new List <TaxLine>(lines.OrderBy(x => (x as TaxLineIndia).TaxComponent)); return(lines); }
/// <summary> /// Build tax summary lines of the India receipt, with tax amounts be aggregated by sale line items. /// </summary> /// <param name="theTransaction">The retail transaction.</param> /// <returns>The tax summary lines of the India receipt.</returns> /// <remarks> /// In this case, the settings of <c>"RetailStoreTable > Misc > Receipts"</c> is as follows, /// 1) The "Tax details" option is set as "Per line" /// 2) The "Show tax on tax" option is set as "N/A", as it is disabled in this case /// For example, the retail transaction has four sale line items, as follows, /// <c> /// Item ID | Price | Tax code | Formula | Tax basis | Tax rate | Tax amount /// 0001 | 100 | SERV5 | Line amount | 100.00 | 5% | 5.00 /// | | E-CSS5 | Excl.+[SERV5] | 5.00 | 5% | 0.25 /// 0002 | 100 | VAT10 | Line amount | 100.00 | 10% | 10.00 /// | | Surchg2 | Excl.+[VAT10] | 10.00 | 2% | 0.20 /// 0003 | 100 | SERV4 | Line amount | 100.00 | 4% | 4.00 /// | | E-CSS5 | Excl.+[SERV4] | 4.00 | 5% | 0.20 /// 0004 | 100 | VAT12 | Line amount | 100.00 | 12% | 12.00 /// | | Surchg2 | Excl.+[VAT12] | 12.00 | 2% | 0.24 /// And the tax summary lines will be as follows, /// Tax code | Tax basis | Tax rate | Tax amount /// AA | 100.00 | 5.25% | 5.25 /// AB | 100.00 | 10.20% | 10.20 /// AC | 100.00 | 4.20% | 4.20 /// AD | 100.00 | 12.24% | 12.24 /// Tax codes are automatically named from "AA" to "AZ", ... /// </c> /// </remarks> private static IList <TaxLine> BuildIndiaTaxSummaryPerLine(SalesTransaction theTransaction) { if (theTransaction == null) { throw new ArgumentNullException("theTransaction"); } List <TaxLine> lines = new List <TaxLine>(); char code1 = TaxCodeBeginChar, code2 = TaxCodeBeginChar; foreach (SalesLine saleItem in theTransaction.ActiveSalesLines) { TaxLineIndia t = new TaxLineIndia(); t.TaxCode = string.Empty + code1 + code2; t.TaxBasis = saleItem.TaxLines.First(x => !(x as TaxLineIndia).IsTaxOnTax).TaxBasis; t.Amount = saleItem.TaxLines.Sum(x => x.Amount); t.Percentage = t.TaxBasis != decimal.Zero ? 100 * t.Amount / t.TaxBasis : decimal.Zero; lines.Add(t); // Generate tax code of the next line code2++; if (code2 > TaxCodeEndChar) { code2 = TaxCodeBeginChar; code1++; if (code1 > TaxCodeEndChar) { code1 = TaxCodeBeginChar; } } } return(lines); }
/// <summary> /// Calculates tax for this code for the line item. /// Updates the line item by adding a new Tax Item. /// </summary> /// <param name="codes">The tax codes collection.</param> /// <param name="taxCodeAmountRounder">The current, accrued totals for this tax code.</param> /// <returns>The calculated amount of tax.</returns> public override decimal CalculateTaxAmount(ReadOnlyCollection <TaxCode> codes, TaxCodeAmountRounder taxCodeAmountRounder) { if (codes == null) { return(decimal.Zero); } decimal taxAmount = decimal.Zero; this.TaxableEntity.ItemTaxGroupId = this.TaxGroup; taxAmount = this.TaxIncludedInPrice ? this.CalculateTaxIncluded(codes) : this.CalculateTaxExcluded(codes); string groupRoundingKey = string.Empty; if (this.TaxGroupRounding) { // tax codes already sorted for this taxable item. foreach (var code in codes) { groupRoundingKey += code.Code + "@:$"; } } else if (this.TaxLimitBase == TaxLimitBase.InvoiceWithoutVat) { // total tax required for whole invoice by this tax code only. groupRoundingKey = this.Code; } // rounding required for above cases and when tax is not zero (not exempted). if (taxAmount != decimal.Zero) { // Adjust tax code amount. taxAmount = taxCodeAmountRounder.Round(this.TaxContext, this, groupRoundingKey, taxAmount); } // Record amounts on line item TaxLineIndia taxLine = new TaxLineIndia(); taxLine.Amount = taxAmount; taxLine.Percentage = this.Value; taxLine.TaxCode = this.Code; taxLine.TaxGroup = this.TaxGroup; taxLine.IsExempt = this.Exempt; taxLine.IsIncludedInPrice = this.TaxIncludedInPrice; taxLine.TaxComponent = this.GetTaxComponent(); taxLine.IsTaxOnTax = this.IsTaxOnTax; foreach (string codeInFormula in this.TaxCodesInFormula) { if (!taxLine.TaxCodesInFormula.Contains(codeInFormula)) { taxLine.TaxCodesInFormula.Add(codeInFormula); } } switch (this.Formula.TaxableBasis) { case TaxableBasisIndia.MaxRetailPrice: taxLine.IsIncludedInPrice = false; break; case TaxableBasisIndia.ExclusiveLineAmount: string[] tokens = this.Formula.ParseExpression(); // Iterate through the formula if (tokens.Length > 1) { GetTaxCodeFormulaIndiaDataRequest dataRequest = new GetTaxCodeFormulaIndiaDataRequest(this.TaxGroup, tokens[1]); FormulaIndia basisFormula = this.RequestContext.Execute <SingleEntityDataServiceResponse <FormulaIndia> >(dataRequest).Entity; if (basisFormula != null && basisFormula.TaxableBasis == TaxableBasisIndia.MaxRetailPrice) { taxLine.IsIncludedInPrice = false; } } break; default: break; } taxLine.TaxBasis = this.TaxBasis; this.TaxableEntity.TaxLines.Add(taxLine); return(taxAmount); }