public static VertexCalculateTaxRequest ToVertexCalculateTaxRequest(this OrderWorksheet order, List <OrderPromotion> promosOnOrder, string companyCode, VertexSaleMessageType type) { var itemLines = order.LineItems.Select(li => ToVertexLineItem(li)); var shippingLines = order.ShipEstimateResponse.ShipEstimates.Select(se => { var firstLi = order.LineItems.First(li => li.ID == se.ShipEstimateItems.First().LineItemID); return(ToVertexLineItem(se, firstLi.ShippingAddress)); }); return(new VertexCalculateTaxRequest() { postingDate = DateTime.Now.ToString("yyyy-MM-dd"), saleMessageType = type, transactionType = VertexTransactionType.SALE, transactionId = order.Order.ID, seller = new VertexSeller() { company = companyCode }, customer = new VertexCustomer() { customerCode = new VertexCustomerCode() { classCode = order.Order.FromUserID, value = order.Order.FromUser.Email }, }, lineItems = itemLines.Concat(shippingLines).ToList() }); }
private static IList <LineItem> HandleLineItemPromoDiscounting(OrderWorksheet order, List <OrderPromotion> promosOnOrder) { List <string> allLineItemIDsWithDiscounts = promosOnOrder .Where(promo => promo.LineItemLevel) .Select(promo => promo.LineItemID) .Distinct().ToList(); // X001, X002... List <string> allLineItemLevelPromoCodes = promosOnOrder .Where(promo => promo.LineItemLevel) .Select(promo => promo.Code) .Distinct().ToList(); // 25OFF, SAVE15... Dictionary <string, decimal> totalWeightedLineItemDiscounts = new Dictionary <string, decimal>(); foreach (string lineItemID in allLineItemIDsWithDiscounts) { // Initialize discounts at 0.00 totalWeightedLineItemDiscounts.Add(lineItemID, 0M); } // Calculate discounts one promo code at a time foreach (string promoCode in allLineItemLevelPromoCodes) { CalculateDiscountByPromoCode(promoCode, order, promosOnOrder, totalWeightedLineItemDiscounts); } foreach (string lineItemID in allLineItemIDsWithDiscounts) { LineItem lineItemToUpdate = order.LineItems.FirstOrDefault(lineItem => lineItem.ID == lineItemID); lineItemToUpdate.LineTotal = lineItemToUpdate.LineSubtotal - totalWeightedLineItemDiscounts[lineItemID]; } return(order.LineItems); }
private static void CalculateDiscountByPromoCode(string promoCode, OrderWorksheet order, List <OrderPromotion> promosOnOrder, Dictionary <string, decimal> totalWeightedLineItemDiscounts) { // Total discounted from this code for all line items decimal totalDiscountedByOrderCloud = promosOnOrder .Where(promo => promo.Code == promoCode) .Select(promo => promo.Amount) .Sum(); // Line items discounted with this code List <string> eligibleLineItemIDs = promosOnOrder .Where(promo => promo.Code == promoCode) .Select(promo => promo.LineItemID) .ToList(); // Subtotal of all of these line items before applying promo code decimal eligibleLineItemSubtotal = order.LineItems .Where(lineItem => eligibleLineItemIDs.Contains(lineItem.ID)) .Select(lineItem => lineItem.LineSubtotal) .Sum(); Dictionary <string, decimal> weightedLineItemDiscountsByPromoCode = new Dictionary <string, decimal>(); HandleWeightedDiscounting(eligibleLineItemIDs, weightedLineItemDiscountsByPromoCode, order, eligibleLineItemSubtotal, totalDiscountedByOrderCloud); foreach (string lineItemID in eligibleLineItemIDs) { totalWeightedLineItemDiscounts[lineItemID] += weightedLineItemDiscountsByPromoCode[lineItemID]; } }
public static CreateTransactionModel ToAvalaraTransationModel(this OrderWorksheet order, string companyCode, DocumentType docType) { var buyerLocationID = order.Order.BillingAddress.ID; var standardLineItems = order.LineItems.Where(li => li.Product.xp.ProductType == "Standard")?.ToList(); var poLineItemIDs = order.LineItems.Where(li => li.Product.xp.ProductType == "PurchaseOrder")?.Select(li => li?.ID)?.ToList(); var standardShipEstimates = order.ShipEstimateResponse.ShipEstimates.Where(estimate => { return(!estimate.ShipEstimateItems.Any(item => poLineItemIDs.Contains(item.LineItemID))); }); var shipingLines = standardShipEstimates.Select(shipment => { var(shipFrom, shipTo) = shipment.GetAddresses(order.LineItems); var method = shipment.GetSelectedShippingMethod(); return(method.ToLineItemModel(shipFrom, shipTo)); }); var hasResaleCert = ((int?)order.Order.BillingAddress.xp.AvalaraCertificateID != null); var exemptionNo = hasResaleCert ? buyerLocationID : null; var productLines = standardLineItems.Select(lineItem => lineItem.ToLineItemModel(lineItem.ShipFromAddress, lineItem.ShippingAddress, exemptionNo)); return(new CreateTransactionModel() { companyCode = companyCode, type = docType, customerCode = buyerLocationID, date = DateTime.Now, lines = productLines.Concat(shipingLines).ToList(), purchaseOrderNo = order.Order.ID }); }
public static CreateTransactionModel ToAvalaraTransactionModel(this OrderWorksheet order, string companyCode, DocumentType docType, List <OrderPromotion> promosOnOrder) { var buyerLocationID = order.Order.BillingAddress.ID; var standardLineItems = order.LineItems.Where(li => li.Product.xp.ProductType == "Standard")?.ToList(); var standardShipEstimates = order.ShipEstimateResponse?.ShipEstimates; var shippingLines = standardShipEstimates.Select(shipment => { var(shipFrom, shipTo) = shipment.GetAddresses(order.LineItems); return(shipment.ToLineItemModel(shipFrom, shipTo)); }); string exemptionNo = null; // can set to a resale cert id var productLines = standardLineItems.Select(lineItem => lineItem.ToLineItemModel(lineItem.ShipFromAddress, lineItem.ShippingAddress, exemptionNo)); return(new CreateTransactionModel() { companyCode = companyCode, type = docType, customerCode = buyerLocationID, date = DateTime.Now, discount = GetOrderOnlyTotalDiscount(promosOnOrder), lines = productLines.Concat(shippingLines).ToList(), purchaseOrderNo = order.Order.ID }); }
/// <summary> /// Calculates tax for an order without creating any records. Use this to display tax amount to user prior to order submit. /// </summary> public async Task <OrderTaxCalculation> CalculateEstimateAsync(OrderWorksheet orderWorksheet, List <OrderPromotion> promotions) { var orders = await CalculateTax(orderWorksheet); var orderTaxCalculation = orders.ToOrderTaxCalculation(); return(orderTaxCalculation); }
private async Task <OrderTaxCalculation> CalculateTaxAsync(OrderWorksheet orderWorksheet, List <OrderPromotion> promotions, VertexSaleMessageType type) { var request = orderWorksheet.ToVertexCalculateTaxRequest(promotions, _config.CompanyName, type); var response = await _client.CalculateTax(request); var orderTaxCalculation = response.ToOrderTaxCalculation(); return(orderTaxCalculation); }
private async Task HandleTaxTransactionCreationAsync(OrderWorksheet orderWorksheet) { var transaction = await _avalara.CreateTransactionAsync(orderWorksheet); await _oc.Orders.PatchAsync <HSOrder>(OrderDirection.Incoming, orderWorksheet.Order.ID, new PartialOrder() { TaxCost = transaction.totalTax ?? 0, // Set this again just to make sure we have the most up to date info xp = new { AvalaraTaxTransactionCode = transaction.code } }); }
public async Task <TransactionModel> GetEstimateAsync(OrderWorksheet orderWorksheet) { if (ShouldMockAvalaraResponse()) { return(CreateMockTransactionModel()); } var taxEstimate = await CreateTransactionAsync(DocumentType.SalesOrder, orderWorksheet); return(taxEstimate); }
public async Task <OrderTaxCalculation> CalculateEstimateAsync(OrderWorksheet orderWorksheet, List <OrderPromotion> promotions) { if (ShouldMockAvalaraResponse()) { return(CreateMockTransactionModel()); } var taxEstimate = await CreateTransactionAsync(DocumentType.SalesOrder, orderWorksheet, promotions); return(taxEstimate); }
public async Task <OrderTaxCalculation> CommitTransactionAsync(OrderWorksheet orderWorksheet, List <OrderPromotion> promotions) { if (ShouldMockAvalaraResponse()) { return(CreateMockTransactionModel()); } var transaction = await CreateTransactionAsync(DocumentType.SalesInvoice, orderWorksheet, promotions); return(transaction); }
public async Task <TransactionModel> CreateTransactionAsync(OrderWorksheet orderWorksheet) { if (ShouldMockAvalaraResponse()) { return(CreateMockTransactionModel()); } var transaction = await CreateTransactionAsync(DocumentType.SalesInvoice, orderWorksheet); return(transaction); }
/// <summary> /// Returns a list of TaxJarOrders because each order has a single to and from address. They therefor coorespond to OrderCloud LineItems. /// </summary> public static List <TaxJarOrder> ToTaxJarOrders(this OrderWorksheet order) { var itemLines = order.LineItems.Select(li => ToTaxJarOrders(li, order.Order.ID)); var shippingLines = order.ShipEstimateResponse.ShipEstimates.Select(se => { var firstLineItem = order.LineItems.First(li => li.ID == se.ShipEstimateItems.First().LineItemID); return(ToTaxJarOrders(se, firstLineItem, order.Order.ID)); }); return(itemLines.Concat(shippingLines).ToList()); }
private async Task HandleTaxTransactionCreationAsync(OrderWorksheet orderWorksheet) { var promotions = await _oc.Orders.ListAllPromotionsAsync(OrderDirection.All, orderWorksheet.Order.ID); var taxCalculation = await _taxCalculator.CommitTransactionAsync(orderWorksheet, promotions); await _oc.Orders.PatchAsync <HSOrder>(OrderDirection.Incoming, orderWorksheet.Order.ID, new PartialOrder() { TaxCost = taxCalculation.TotalTax, // Set this again just to make sure we have the most up to date info xp = new { ExternalTaxTransactionID = taxCalculation.ExternalTransactionID } }); }
/// <summary> /// Creates a tax transaction record in the calculating system. Use this once on purchase, payment capture, or fulfillment. /// </summary> public async Task <OrderTaxCalculation> CommitTransactionAsync(OrderWorksheet orderWorksheet, List <OrderPromotion> promotions) { var orders = await CalculateTax(orderWorksheet); foreach (var response in orders) { response.request.TransactionDate = DateTime.Now.ToString("yyyy/MM/dd"); response.request.SalesTax = response.response.TaxableAmount; } await Throttler.RunAsync(orders, 100, 8, async order => await MakeRequest(() => _client.CreateOrderAsync(order))); var orderTaxCalculation = orders.ToOrderTaxCalculation(); return(orderTaxCalculation); }
public static CreateTransactionModel ToAvalaraTransactionModel(this OrderWorksheet order, string companyCode, DocumentType docType, List <OrderPromotion> promosOnOrder) { var buyerLocationID = order.Order.BillingAddress.ID; var standardLineItems = order.LineItems.Where(li => li.Product.xp.ProductType == "Standard")?.ToList(); if (promosOnOrder.Any(promo => promo.LineItemLevel)) { order.LineItems = HandleLineItemPromoDiscounting(order, promosOnOrder); } var standardShipEstimates = order.ShipEstimateResponse?.ShipEstimates; var shippingLines = standardShipEstimates.Select(shipment => { var(shipFrom, shipTo) = shipment.GetAddresses(order.LineItems); var method = shipment.GetSelectedShippingMethod(); return(method.ToLineItemModel(shipFrom, shipTo)); }); var hasResaleCert = ((int?)order.Order.BillingAddress.xp?.AvalaraCertificateID != null); var exemptionNo = hasResaleCert ? buyerLocationID : null; var productLines = standardLineItems.Select(lineItem => lineItem.ToLineItemModel(lineItem.ShipFromAddress, lineItem.ShippingAddress, exemptionNo)); return(new CreateTransactionModel() { companyCode = companyCode, type = docType, customerCode = buyerLocationID, date = DateTime.Now, discount = GetOrderOnlyTotalDiscount(order, promosOnOrder), lines = productLines.Concat(shippingLines).ToList(), purchaseOrderNo = order.Order.ID }); }
private async Task <IEnumerable <(TaxJarOrder request, TaxResponseAttributes response)> > CalculateTax(OrderWorksheet orderWorksheet) { var orders = orderWorksheet.ToTaxJarOrders(); var responses = await Throttler.RunAsync(orders, 100, 8, async order => { var tax = await MakeRequest(() => _client.TaxForOrderAsync(order)); return(order, tax); }); return(responses); }
private async Task <TransactionModel> CreateTransactionAsync(DocumentType docType, OrderWorksheet orderWorksheet) { var standardLineItems = orderWorksheet.LineItems.Where(li => li.Product.xp.ProductType == "Standard")?.ToList(); if (standardLineItems.Any()) { try { if (ShouldMockAvalaraResponse()) { return(CreateMockTransactionModel()); } var promosOnOrder = await _oc.Orders.ListAllPromotionsAsync(OrderDirection.Incoming, orderWorksheet.Order.ID); var createTransactionModel = orderWorksheet.ToAvalaraTransactionModel(_companyCode, docType, promosOnOrder); var transaction = await _avaTax.CreateTransactionAsync("", createTransactionModel); return(transaction); } catch (AvaTaxError e) { throw new CatalystBaseException("AvalaraTaxError", e.error.error.message, e.error.error, 400); } } else { return(new TransactionModel { code = "NotTaxable", totalTax = 0 }); } }
/// <summary> /// Calculates tax for an order without creating any records. Use this to display tax amount to user prior to order submit. /// </summary> public async Task <OrderTaxCalculation> CalculateEstimateAsync(OrderWorksheet orderWorksheet, List <OrderPromotion> promotions) => await CalculateTaxAsync(orderWorksheet, promotions, VertexSaleMessageType.QUOTATION);
/// <summary> /// Creates a tax transaction record in the calculating system. Use this once on purchase, payment capture, or fulfillment. /// </summary> public async Task <OrderTaxCalculation> CommitTransactionAsync(OrderWorksheet orderWorksheet, List <OrderPromotion> promotions) => await CalculateTaxAsync(orderWorksheet, promotions, VertexSaleMessageType.INVOICE);
private static decimal GetOrderOnlyTotalDiscount(OrderWorksheet order, List <OrderPromotion> promosOnOrder) { return(promosOnOrder .Where(promo => promo.LineItemID == null && !promo.LineItemLevel) .Select(promo => promo.Amount).Sum()); }
private static void HandleWeightedDiscounting(List <string> eligibleLineItemIDs, Dictionary <string, decimal> weightedLineItemDiscountsByPromoCode, OrderWorksheet order, decimal eligibleLineItemSubtotal, decimal totalDiscountedByOrderCloud) { foreach (string lineItemID in eligibleLineItemIDs) { weightedLineItemDiscountsByPromoCode.Add(lineItemID, 0M); // Initialize discount for this promo code at 0.00 LineItem lineItem = order.LineItems.FirstOrDefault(lineItem => lineItem.ID == lineItemID); // Determine amount of promo code discount to apply to this line item and round decimal lineItemRateOfSubtotal = lineItem.LineSubtotal / eligibleLineItemSubtotal; decimal weightedDiscount = Math.Round(lineItemRateOfSubtotal * totalDiscountedByOrderCloud, 2); weightedLineItemDiscountsByPromoCode[lineItemID] += weightedDiscount; } decimal totalWeightedDiscountApplied = weightedLineItemDiscountsByPromoCode.Sum(discount => discount.Value); if (totalDiscountedByOrderCloud != totalWeightedDiscountApplied) { // If a small discrepancy occurs due to rounding, resolve it by adding/subtracting the difference to the item that was discounted the most decimal difference = totalDiscountedByOrderCloud - totalWeightedDiscountApplied; string lineItemIDToApplyDiscountDifference = weightedLineItemDiscountsByPromoCode.Aggregate((x, y) => x.Value > y.Value ? x : y).Key; weightedLineItemDiscountsByPromoCode[lineItemIDToApplyDiscountDifference] += difference; } }
public async Task <TransactionModel> CreateTransactionAsync(OrderWorksheet orderWorksheet) { var transaction = await CreateTransactionAsync(DocumentType.SalesInvoice, orderWorksheet); return(transaction); }
public async Task <TransactionModel> GetEstimateAsync(OrderWorksheet orderWorksheet) { var taxEstimate = await CreateTransactionAsync(DocumentType.SalesOrder, orderWorksheet); return(taxEstimate); }
private async Task <TransactionModel> CreateTransactionAsync(DocumentType docType, OrderWorksheet orderWorksheet) { var standardLineItems = orderWorksheet.LineItems.Where(li => li.Product.xp.ProductType == "Standard")?.ToList(); if (standardLineItems.Any()) { try { var createTransactionModel = orderWorksheet.ToAvalaraTransationModel(_companyCode, docType); var transaction = await _avaTax.CreateTransactionAsync("", createTransactionModel); return(transaction); } catch (AvaTaxError e) { throw new CatalystBaseException("AvalaraTaxError", 400, e.error.error.message, e.error.error); } } else { return(new TransactionModel { code = "NotTaxable", totalTax = 0 }); } }
private async Task <OrderTaxCalculation> CreateTransactionAsync(DocumentType docType, OrderWorksheet orderWorksheet, List <OrderPromotion> promotions) { var standardLineItems = orderWorksheet.LineItems.Where(li => li.Product.xp.ProductType == "Standard")?.ToList(); if (standardLineItems.Any()) { try { if (ShouldMockAvalaraResponse()) { return(CreateMockTransactionModel()); } var createTransactionModel = orderWorksheet.ToAvalaraTransactionModel(_companyCode, docType, promotions); var transaction = await _avaTax.CreateTransactionAsync("", createTransactionModel); return(transaction.ToOrderTaxCalculation()); } catch (AvaTaxError e) { throw new CatalystBaseException("AvalaraTaxError", e.error.error.message, e.error.error, 400); } } else { return(new OrderTaxCalculation { OrderID = orderWorksheet.Order.ID, ExternalTransactionID = "NotTaxable", TotalTax = 0 }); } }