/// <summary> /// High-level calculation method to get charges from the calculation logic /// and attach them to the transaction and it's lines. /// </summary> /// <param name="request">The request containing context and transaction to update.</param> /// <returns> /// Response with updated transaction. /// </returns> private static GetChargesServiceResponse CalculateCharges(GetChargesServiceRequest request) { // extract transaction we'll be populating var transaction = request.Transaction; if (request.RequestContext.GetChannelConfiguration().ChannelType == RetailChannelType.OnlineStore || request.RequestContext.GetChannelConfiguration().ChannelType == RetailChannelType.SharePointOnlineStore) { // clear all the non-manual charges ClearNonManualCharges(transaction); } // total transaction so that we have order totals and line net amounts for percentage charges and tiered fixed charges SalesTransactionTotaler.CalculateTotals(request.RequestContext, transaction); // put charges on the transaction lines // Consider calculable lines only. Ignore voided or return-by-receipt lines. foreach (var salesLine in transaction.ChargeCalculableSalesLines) { var priceChargesPerLine = CalculatePriceCharges(salesLine, request); if (priceChargesPerLine != null) { salesLine.ChargeLines.Add(priceChargesPerLine); } } // Auto-Charges are only supported for Online stores. if (request.RequestContext.GetChannelConfiguration().ChannelType == RetailChannelType.OnlineStore || request.RequestContext.GetChannelConfiguration().ChannelType == RetailChannelType.SharePointOnlineStore) { CalculateAutoCharges(request, transaction); } return(new GetChargesServiceResponse(transaction)); }
/// <summary> /// Calculates the auto charges for the transaction / sales lines. /// </summary> /// <param name="request">The request.</param> /// <param name="transaction">Current sales transaction.</param> private static void CalculateAutoCharges(GetChargesServiceRequest request, SalesTransaction transaction) { // get customer to see their markup group string customerAccount = transaction.CustomerId ?? string.Empty; string customerChargeGroup = string.Empty; if (!string.IsNullOrWhiteSpace(customerAccount)) { var getCustomerDataRequest = new GetCustomerDataRequest(customerAccount); SingleEntityDataServiceResponse <Customer> getCustomerDataResponse = request.RequestContext.Execute <SingleEntityDataServiceResponse <Customer> >(getCustomerDataRequest); var customer = getCustomerDataResponse.Entity; customerChargeGroup = (customer != null) ? customer.ChargeGroup : string.Empty; } // get delivery mode information off the transaction string deliveryMode = transaction.DeliveryMode ?? string.Empty; string deliveryModeGroup = GetDeliveryModeGroupFromCode(request.RequestContext, deliveryMode); var channelConfiguration = request.RequestContext.GetChannelConfiguration(); string currencyCode = (channelConfiguration != null) ? channelConfiguration.Currency : string.Empty; // put charges on the transaction var transactionCharges = CalculateTransactionCharges(request.RequestContext, customerAccount, customerChargeGroup, deliveryMode, deliveryModeGroup, transaction); foreach (var charge in transactionCharges) { transaction.ChargeLines.Add(charge); } // put charges on the transaction lines // Consider calculable lines only. Ignore voided or return-by-receipt lines. foreach (var salesLine in transaction.ChargeCalculableSalesLines) { // get delivery mode information off the sales line deliveryMode = string.IsNullOrEmpty(salesLine.DeliveryMode) ? (transaction.DeliveryMode ?? string.Empty) : salesLine.DeliveryMode; deliveryModeGroup = GetDeliveryModeGroupFromCode(request.RequestContext, deliveryMode); var lineCharges = CalculateLineCharges(request.RequestContext, customerAccount, customerChargeGroup, deliveryMode, deliveryModeGroup, salesLine, transaction); foreach (var charge in lineCharges) { salesLine.ChargeLines.Add(charge); } } // now that all auto charges are on the transaction, calculate their amounts CalculateAutoChargeAmounts(request.RequestContext, transaction); // convert any charge amounts not in the channel currency var transactionAutoChargeLines = transaction.ChargeLines.Where(cl => cl.ChargeType == ChargeType.AutoCharge); // Consider calculable lines only. Ignore voided or return-by-receipt lines. var lineAutoChargeLines = transaction.ChargeCalculableSalesLines.SelectMany(sl => sl.ChargeLines).Where(cl => cl.ChargeType == ChargeType.AutoCharge); var allAutoChargeLines = transactionAutoChargeLines.Concat(lineAutoChargeLines); ChargeAmountsToStoreCurrency(request.RequestContext, allAutoChargeLines, currencyCode); }
/// <summary> /// Calculates the price charges. /// </summary> /// <param name="salesLine">The sales line.</param> /// <param name="request">The request.</param> /// <returns> /// The miscellaneous charge line. /// </returns> private static Microsoft.Dynamics.Commerce.Runtime.DataModel.ChargeLine CalculatePriceCharges(SalesLine salesLine, GetChargesServiceRequest request) { // hook up with caching when it is in. var getItemsRequest = new GetItemsDataRequest(new string[] { salesLine.ItemId }); getItemsRequest.QueryResultSettings = new QueryResultSettings(new ColumnSet("ItemId", "AllocateMarkup", "PriceQty", "Markup"), PagingInfo.AllRecords); var getItemsResponse = request.RequestContext.Execute <GetItemsDataResponse>(getItemsRequest); Item itemDetails = getItemsResponse.Items.SingleOrDefault(); if (itemDetails != null && itemDetails.Markup != 0) { // there is a price charge associated with the item. decimal amount; // check type price charge if (itemDetails.AllocateMarkup) { // Per Unit markup if (!itemDetails.PriceQuantity.HasValue || itemDetails.PriceQuantity.Value == 0M) { throw new DataValidationException( DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_ValueOutOfRange, string.Format("Price quantity is set to 0 for item {0}", itemDetails.ItemId)); } amount = itemDetails.Markup / itemDetails.PriceQuantity.Value; } else { // per line markup amount = itemDetails.Markup; } // there is a price charge associated with this item. need to update the price accordingly. var priceCharge = new Microsoft.Dynamics.Commerce.Runtime.DataModel.ChargeLine { CalculatedAmount = amount, ChargeCode = string.Empty, ItemTaxGroupId = salesLine.ItemTaxGroupId, SalesTaxGroupId = salesLine.SalesTaxGroupId, ChargeType = ChargeType.PriceCharge, ModuleType = ChargeModule.Sales, }; return(priceCharge); } return(null); }