Пример #1
0
            /// <summary>
            /// Static entry point to calculate amount paid and due.
            /// </summary>
            /// <param name="context">The request context.</param>
            /// <param name="salesTransaction">The sales transaction.</param>
            public static void CalculateAmountPaidAndDue(RequestContext context, SalesTransaction salesTransaction)
            {
                ThrowIf.Null(context, "context");
                ThrowIf.Null(salesTransaction, "salesTransaction");

                decimal paymentRequiredAmount;

                salesTransaction.AmountPaid = SalesTransactionTotaler.GetPaymentsSum(salesTransaction.TenderLines);

                // decides what is expected to be paid for this transaction
                switch (salesTransaction.CartType)
                {
                case CartType.CustomerOrder:
                    paymentRequiredAmount = SalesTransactionTotaler.CalculateRequiredPaymentAmount(context, salesTransaction);
                    break;

                case CartType.Shopping:
                case CartType.Checkout:
                case CartType.AccountDeposit:
                    paymentRequiredAmount = salesTransaction.TotalAmount;
                    break;

                case CartType.IncomeExpense:
                    paymentRequiredAmount = salesTransaction.IncomeExpenseTotalAmount;
                    break;

                default:
                    throw new DataValidationException(
                              DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidRequest,
                              string.Format("SalesTransactionTotaler::CalculateAmountPaidAndDue: CartType '{0}' not supported.", salesTransaction.CartType));
                }

                salesTransaction.SalesPaymentDifference = paymentRequiredAmount - salesTransaction.AmountPaid;
                salesTransaction.AmountDue = paymentRequiredAmount - salesTransaction.AmountPaid;

                TenderLine lastTenderLine = null;

                if (!salesTransaction.TenderLines.IsNullOrEmpty())
                {
                    lastTenderLine = salesTransaction.ActiveTenderLines.LastOrDefault();
                }

                if (lastTenderLine != null)
                {
                    // Calculate the expected (rounded) amount due for last payment.
                    decimal amountDueBeforeLastPayment = paymentRequiredAmount - salesTransaction.ActiveTenderLines.Take(salesTransaction.ActiveTenderLines.Count - 1).Sum(t => t.Amount);
                    GetPaymentRoundedValueServiceRequest roundAmountDueBeforeLastPaymentRequest  = new GetPaymentRoundedValueServiceRequest(amountDueBeforeLastPayment, lastTenderLine.TenderTypeId, isChange: false);
                    GetRoundedValueServiceResponse       roundAmountDueBeforeLastPaymentResponse = context.Execute <GetRoundedValueServiceResponse>(roundAmountDueBeforeLastPaymentRequest);

                    // Set amont due to zero if payment amount equals to expected rounded payment amount. Otherwise another payment should be required (that could use different rounding settings).
                    if (roundAmountDueBeforeLastPaymentResponse.RoundedValue == lastTenderLine.Amount)
                    {
                        salesTransaction.AmountDue = decimal.Zero;
                    }
                }

                // When required amount is positive, amount due must be zero or negative (overtender), otherwise (e.g. for refunds or exchanges) exact amount has to refunded (zero balance).
                salesTransaction.IsRequiredAmountPaid = (paymentRequiredAmount > 0 && salesTransaction.AmountDue <= 0) ||
                                                        (paymentRequiredAmount <= 0 && salesTransaction.AmountDue == 0);
            }
            /// <summary>
            /// Round amount by tender type id.
            /// </summary>
            /// <param name="context">The request context.</param>
            /// <param name="tenderTypeId">Tender type id.</param>
            /// <param name="amount">The amount.</param>
            /// <param name="isChange">Value indicating whether this request is for change.</param>
            /// <returns>Rounded amount.</returns>
            private static decimal RoundAmountByTenderType(RequestContext context, string tenderTypeId, decimal amount, bool isChange)
            {
                ThrowIf.Null(context, "context");

                GetPaymentRoundedValueServiceRequest request  = new GetPaymentRoundedValueServiceRequest(amount, tenderTypeId, isChange);
                GetRoundedValueServiceResponse       response = context.Execute <GetRoundedValueServiceResponse>(request);

                return(response.RoundedValue);
            }
Пример #3
0
            /// <summary>
            /// Round for channel payment method.
            /// </summary>
            /// <param name="request">Service request.</param>
            /// <returns>Rounded value.</returns>
            private GetRoundedValueServiceResponse GetPaymentRoundedValue(GetPaymentRoundedValueServiceRequest request)
            {
                GetChannelTenderTypesDataRequest       dataServiceRequest = new GetChannelTenderTypesDataRequest(request.RequestContext.GetPrincipal().ChannelId, QueryResultSettings.AllRecords);
                EntityDataServiceResponse <TenderType> response           = request.RequestContext.Execute <EntityDataServiceResponse <TenderType> >(dataServiceRequest);

                TenderType tenderType = response.PagedEntityCollection.Results.SingleOrDefault(channelTenderType => string.Equals(channelTenderType.TenderTypeId, request.TenderTypeId, StringComparison.OrdinalIgnoreCase));

                RoundingMethod roundingMethod = tenderType.RoundingMethod;

                if (roundingMethod == RoundingMethod.None)
                {
                    return(new GetRoundedValueServiceResponse(request.Value));
                }

                decimal currencyUnit = tenderType.RoundOff;

                if (currencyUnit == decimal.Zero)
                {
                    currencyUnit = Rounding.DefaultRoundingValue;
                }

                decimal roundedValue;

                if (request.IsChange)
                {
                    // For change rounding up/down should be applied in opposite direction.
                    if (roundingMethod == RoundingMethod.Down)
                    {
                        roundingMethod = RoundingMethod.Up;
                    }
                    else if (roundingMethod == RoundingMethod.Up)
                    {
                        roundingMethod = RoundingMethod.Down;
                    }
                }

                // Using absolute value so payment and refund is rounded same way when rounding up or down.
                decimal absoluteAmount = Math.Abs(request.Value);

                roundedValue = Rounding.RoundToUnit(absoluteAmount, currencyUnit, roundingMethod);
                if (request.Value < 0)
                {
                    // Revert sign back to original.
                    roundedValue = decimal.Negate(roundedValue);
                }

                return(new GetRoundedValueServiceResponse(roundedValue));
            }