/// <summary> /// Validate customer account deposit transactions. /// </summary> /// <param name="context">The request context.</param> /// <param name="salesTransaction">The sales transaction.</param> public static void ValidateCustomerAccountDepositTransaction(RequestContext context, SalesTransaction salesTransaction) { if (salesTransaction.TransactionType != SalesTransactionType.CustomerAccountDeposit && salesTransaction.CustomerAccountDepositLines.Any()) { throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CustomerAccountDepositLinesNotAllowed, "Customer account deposit lines should be present on the transaction."); } // Make sure it is a customer account deposit transaction before applying additional validation if (salesTransaction.TransactionType != SalesTransactionType.CustomerAccountDeposit) { return; } if (salesTransaction.CustomerAccountDepositLines.Any()) { context.Execute <NullResponse>(new CheckAccessServiceRequest(RetailOperation.CustomerAccountDeposit)); } // Validate that the transaction status is not set on customer account deposit lines. if (salesTransaction.CustomerAccountDepositLines.Any(customerAccountDepositLine => customerAccountDepositLine.TransactionStatus != TransactionStatus.Normal)) { throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CustomerAccountDepositLineDoesNotAllowSettingTransactionStatus, "The income/ expense line cannot have the transaction status set."); } // Check that the cart only has a single customer account deposit line. No other lines are allowed. if (salesTransaction.SalesLines.Any() || salesTransaction.CustomerAccountDepositLines.HasMultiple() || salesTransaction.IncomeExpenseLines.Any()) { throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CustomerAccountDepositMultipleCartLinesNotAllowed, "Sales lines are not allowed on a customer account deposit transaction."); } // Transaction has to have customer id if (string.IsNullOrWhiteSpace(salesTransaction.CustomerId)) { throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CustomerAccountNumberIsNotSet, "The customer id must be set for account deposit transaction."); } // Adding cashier (or) manual discounts are not allowed. if (salesTransaction.TotalManualDiscountAmount != 0 || salesTransaction.TotalManualDiscountPercentage != 0) { throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_DiscountAmountInvalidated, "The discount is not allowed in account deposit transaction."); } // Analyze deposit cart line if (salesTransaction.CustomerAccountDepositLines.Any()) { CustomerAccountDepositLine depositLine = salesTransaction.CustomerAccountDepositLines.SingleOrDefault(); // Only positive deposit is allowed. if (depositLine.Amount <= 0) { throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CustomerAccountDepositCannotBeNegative, "The customer account deposit amount must be positive."); } if (string.IsNullOrWhiteSpace(depositLine.CustomerAccount)) { throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CustomerAccountNumberIsNotSet, "The customer id must be set for account deposit transaction."); } Customer customerOnTransaction = GetCustomer(context, salesTransaction.CustomerId); bool useInvoiceAccount = !string.IsNullOrWhiteSpace(customerOnTransaction.InvoiceAccount); string customerAccountForDeposit = useInvoiceAccount ? customerOnTransaction.InvoiceAccount : customerOnTransaction.AccountNumber; if (!string.IsNullOrWhiteSpace(depositLine.CustomerAccount) && !depositLine.CustomerAccount.Equals(customerAccountForDeposit, StringComparison.OrdinalIgnoreCase)) { throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CustomerAccountMismatchBetweenTransactionAndDepositLine, "The customer account on the deposit line is different from the one on the cart."); } } }
private static void CalculateAmountDue(RequestContext context, SalesTransaction salesTransaction) { if (salesTransaction == null) { throw new ArgumentNullException("salesTransaction"); } ChannelConfiguration channelConfiguration = context.GetChannelConfiguration(); string cancellationcode = channelConfiguration.CancellationChargeCode; string currencyCode = channelConfiguration.Currency; RoundingRule roundingRule = amountToRound => RoundWithPricesRounding(context, amountToRound, currencyCode); SalesTransactionTotaler.ClearTotalAmounts(salesTransaction); salesTransaction.NumberOfItems = 0m; // initialize with header-level charges list var charges = new List <ChargeLine>(); if (salesTransaction.ChargeLines.Any()) { charges.AddRange(salesTransaction.ChargeLines); } // Calculate totals for sale items , which might also include line-level misc charge in it. foreach (SalesLine saleLineItem in salesTransaction.SalesLines) { if (saleLineItem.IsVoided == false) { // Calculate the sum of items salesTransaction.NumberOfItems += Math.Abs(saleLineItem.Quantity); // calculate the line item cost excluding charges and tax on charges. SalesLineTotaller.CalculateLine(salesTransaction, saleLineItem, roundingRule); UpdateTotalAmounts(salesTransaction, saleLineItem); } else { saleLineItem.PeriodicDiscountPossibilities.Clear(); SalesLineTotaller.CalculateLine(salesTransaction, saleLineItem, roundingRule); } saleLineItem.WasChanged = false; } // Add eligible charges on sales lines foreach (SalesLine salesLine in salesTransaction.ChargeCalculableSalesLines) { charges.AddRange(salesLine.ChargeLines); } decimal incomeExpenseTotalAmount = 0m; foreach (IncomeExpenseLine incomeExpense in salesTransaction.IncomeExpenseLines) { if (incomeExpense.AccountType != IncomeExpenseAccountType.None) { salesTransaction.NetAmountWithTax += incomeExpense.Amount; salesTransaction.NetAmountWithNoTax += incomeExpense.Amount; salesTransaction.GrossAmount += incomeExpense.Amount; salesTransaction.IncomeExpenseTotalAmount += incomeExpense.Amount; // The total is done to calculate the payment amount. incomeExpenseTotalAmount += incomeExpense.Amount; } } foreach (ChargeLine charge in charges) { AddToTaxItems(salesTransaction, charge); // Calculate tax on the charge item. CalculateTaxForCharge(charge); if (charge.ChargeCode.Equals(cancellationcode, StringComparison.OrdinalIgnoreCase) && IsSeparateTaxInCancellationCharge(context)) { salesTransaction.TaxOnCancellationCharge += charge.TaxAmount; } else { salesTransaction.TaxAmount += charge.TaxAmount; } // Later there is "TotalAmount = NetAmountWithTax + ChargeAmount", so we should add TaxAmountExclusive here salesTransaction.NetAmountWithTax += charge.TaxAmountExclusive; } salesTransaction.DiscountAmount = salesTransaction.PeriodicDiscountAmount + salesTransaction.LineDiscount + salesTransaction.TotalDiscount; salesTransaction.ChargeAmount = salesTransaction.ChargesTotal(); // Subtotal is the net amount for the transaction (which includes the discounts) and optionally the tax amount if tax inclusive salesTransaction.SubtotalAmount = roundingRule(salesTransaction.NetAmountWithNoTax + salesTransaction.TaxAmountInclusive); salesTransaction.SubtotalAmountWithoutTax = context.GetChannelConfiguration().PriceIncludesSalesTax ? salesTransaction.SubtotalAmount - salesTransaction.TaxAmount : salesTransaction.SubtotalAmount; // Net amount when saved should include charges, it should be done after Subtotal amount calc because Subtotal does not include charge amount. salesTransaction.NetAmountWithNoTax = roundingRule(salesTransaction.NetAmountWithNoTax + salesTransaction.ChargeAmount); if (salesTransaction.IncomeExpenseLines.Any()) { // Setting the total amount sames as Payment amount for Income/ expense accounts. salesTransaction.TotalAmount = incomeExpenseTotalAmount; } else if (salesTransaction.TransactionType == SalesTransactionType.CustomerAccountDeposit && salesTransaction.CustomerAccountDepositLines.Any()) { CustomerAccountDepositLine customerAccountDepositLine = salesTransaction.CustomerAccountDepositLines.SingleOrDefault(); salesTransaction.SubtotalAmountWithoutTax = customerAccountDepositLine.Amount; salesTransaction.TotalAmount = customerAccountDepositLine.Amount; } else { // NetAmountWithTax already includes the discounts salesTransaction.TotalAmount = roundingRule(salesTransaction.NetAmountWithTax + salesTransaction.ChargeAmount); } }