Exemple #1
0
            /// <summary>
            /// Copies the cart from the request to a different cart.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns><see cref="CopyCartResponse"/> object containing the new cart.</returns>
            protected override CopyCartResponse Process(CopyCartRequest request)
            {
                ThrowIf.Null(request, "request");

                // Loading sales transaction.
                SalesTransaction salesTransaction = CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId);

                ThrowIf.Null(salesTransaction, "salesTransaction");

                // Assigning new transaction id (cart id).
                salesTransaction.Id = CartWorkflowHelper.GenerateRandomTransactionId(this.Context);

                // Setting the cart type from the request.
                salesTransaction.CartType = request.TargetCartType;

                // Saving sales transaction.
                CartWorkflowHelper.SaveSalesTransaction(this.Context, salesTransaction);

                // Reloading sales transaction.
                salesTransaction = CartWorkflowHelper.LoadSalesTransaction(this.Context, salesTransaction.Id);

                Cart cart = CartWorkflowHelper.ConvertToCart(this.Context, salesTransaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(cart);

                return(new CopyCartResponse(cart));
            }
Exemple #2
0
            /// <summary>
            /// This method processes the AddTenderLine workflow.
            /// </summary>
            /// <param name="request">The Add tender line request.</param>
            /// <returns>The Add tender line response.</returns>
            protected override SaveTenderLineResponse Process(SaveTenderLineRequest request)
            {
                ThrowIf.Null(request, "request");

                // Get the sales transaction
                SalesTransaction salesTransaction =
                    CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId);

                if (salesTransaction == null)
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CartNotFound, request.CartId);
                }

                TenderLineBase tenderLineToProcess;

                if (request.PreprocessedTenderLine != null)
                {
                    tenderLineToProcess = request.PreprocessedTenderLine;
                }
                else if (request.TenderLine != null)
                {
                    tenderLineToProcess = request.TenderLine;
                }
                else
                {
                    throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidRequest, "Missing PreprocessedTenderLine or TenderLine");
                }

                // reason codes can be required during add/update or void
                this.AddOrUpdateReasonCodeLinesOnTransaction(request, salesTransaction);

                // Process the request.
                switch (request.OperationType)
                {
                case TenderLineOperationType.Create:
                case TenderLineOperationType.Update:
                case TenderLineOperationType.Unknown:
                    CartWorkflowHelper.AddOrUpdateTenderLine(this.Context, salesTransaction, tenderLineToProcess);
                    break;

                case TenderLineOperationType.Void:
                    CartWorkflowHelper.VoidTenderLine(this.Context, tenderLineToProcess, salesTransaction);
                    break;

                default:
                    throw new DataValidationException(
                              DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidRequest,
                              string.Format("Operation {0} is not supported on tender lines.", request.OperationType));
                }

                // Save the updated sales transaction.
                CartWorkflowHelper.SaveSalesTransaction(this.Context, salesTransaction);

                Cart cart = CartWorkflowHelper.ConvertToCart(this.Context, salesTransaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(cart);

                return(new SaveTenderLineResponse(cart));
            }
Exemple #3
0
            /// <summary>
            /// Executes the workflow to resume suspended cart.
            /// </summary>
            /// <param name="request">Instance of <see cref="ResumeCartRequest"/>.</param>
            /// <returns>Instance of <see cref="ResumeCartResponse"/>.</returns>
            protected override ResumeCartResponse Process(ResumeCartRequest request)
            {
                ThrowIf.Null(request, "request");

                var getSalesTransactionServiceRequest = new GetSalesTransactionsServiceRequest(
                    new CartSearchCriteria {
                    CartId = request.CartId
                },
                    QueryResultSettings.SingleRecord,
                    mustRemoveUnavailableProductLines: true);
                var getSalesTransactionServiceResponse = this.Context.Execute <GetSalesTransactionsServiceResponse>(getSalesTransactionServiceRequest);
                SalesTransaction transaction           = null;

                if (getSalesTransactionServiceResponse.SalesTransactions != null)
                {
                    transaction = getSalesTransactionServiceResponse.SalesTransactions.FirstOrDefault();
                }

                if (!transaction.IsSuspended)
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidStatus, request.CartId, "Cart is not suspended.");
                }

                // Resume the suspended transaction to normal state.
                transaction.EntryStatus   = TransactionStatus.Normal;
                transaction.IsSuspended   = false;
                transaction.TerminalId    = this.Context.GetTerminal().TerminalId;
                transaction.BeginDateTime = this.Context.GetNowInChannelTimeZone();
                CartWorkflowHelper.Calculate(this.Context, transaction, null);
                CartWorkflowHelper.SaveSalesTransaction(this.Context, transaction);

                if (getSalesTransactionServiceResponse.LinesWithUnavailableProducts.Any())
                {
                    // Send notification to decide if caller should be notified about discontinued products.
                    var notification = new ProductDiscontinuedFromChannelNotification(getSalesTransactionServiceResponse.LinesWithUnavailableProducts);
                    this.Context.Notify(notification);
                }

                Cart cart = CartWorkflowHelper.ConvertToCart(this.Context, transaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(cart);

                return(new ResumeCartResponse(cart));
            }
            private static Cart ConvertTransactionToCart(RequestContext context, SalesTransaction transaction, bool includeHistoricalTenderLines)
            {
                Cart cart = CartWorkflowHelper.ConvertToCart(context, transaction);

                if (cart.TenderLines.Any(t => t.IsHistorical))
                {
                    if (includeHistoricalTenderLines)
                    {
                        // Check access rights for tender line historical lines.
                        context.Execute <NullResponse>(new CheckAccessServiceRequest(RetailOperation.PaymentsHistory));
                    }
                    else
                    {
                        CartWorkflowHelper.RemoveHistoricalTenderLines(cart);
                    }
                }

                return(cart);
            }
Exemple #5
0
            /// <summary>
            /// Executes the workflow to recalculate a sales transaction and return a cart representing the transaction.
            /// </summary>
            /// <param name="request">Instance of <see cref="RecalculateOrderRequest"/>.</param>
            /// <returns>Instance of <see cref="RecalculateOrderResponse"/>.</returns>
            protected override RecalculateOrderResponse Process(RecalculateOrderRequest request)
            {
                ThrowIf.Null(request, "request");

                // Recovers transaction from database
                SalesTransaction salesTransaction = CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId);

                if (salesTransaction == null)
                {
                    throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CartNotFound, "Cart does not exist.");
                }

                // Check permissions.
                RetailOperation operation = salesTransaction.CartType == CartType.CustomerOrder ? RetailOperation.RecalculateCustomerOrder : RetailOperation.CalculateFullDiscounts;

                request.RequestContext.Execute <NullResponse>(new CheckAccessServiceRequest(operation));

                // When recalcalculating order, unlock prices so new prices and discounts are applied to the entire order.
                foreach (SalesLine salesLine in salesTransaction.SalesLines)
                {
                    salesLine.IsPriceLocked = false;
                }

                // Recalculate transaction
                CartWorkflowHelper.Calculate(this.Context, salesTransaction, requestedMode: null, discountCalculationMode: DiscountCalculationMode.CalculateAll);

                // Update order on database
                CartWorkflowHelper.SaveSalesTransaction(this.Context, salesTransaction);

                // Convert the SalesOrder into a cart object for the client
                Cart cart = CartWorkflowHelper.ConvertToCart(this.Context, salesTransaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(cart);

                // Return cart
                return(new RecalculateOrderResponse(cart));
            }
Exemple #6
0
            /// <summary>
            /// Executes the workflow to suspend cart.
            /// </summary>
            /// <param name="request">Instance of <see cref="SuspendCartRequest"/>.</param>
            /// <returns>Instance of <see cref="SuspendCartResponse"/>.</returns>
            protected override SuspendCartResponse Process(SuspendCartRequest request)
            {
                ThrowIf.Null(request, "request");

                SalesTransaction transaction = CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId);

                if (transaction.IsSuspended)
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CartNotActive, request.CartId, "Cart is already suspended.");
                }

                if (transaction.ActiveTenderLines.Any())
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CannotSuspendCartWithActiveTenderLines, request.CartId, "Cart with tender active tender lines cannot be suspended.");
                }

                if (transaction.ActiveSalesLines.Any(sl => sl.IsGiftCardLine))
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CannotSuspendCartWithActiveGiftCardSalesLines, request.CartId, "Cart with tender active gift card lines cannot be suspended.");
                }

                if (!(transaction.TerminalId ?? string.Empty).Equals(this.Context.GetTerminal().TerminalId ?? string.Empty, StringComparison.OrdinalIgnoreCase))
                {
                    // If the terminal id of the cart is not same as the context then it means that the cart is active on another terminal.
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_LoadingActiveCartFromAnotherTerminalNotAllowed, request.CartId);
                }

                // Mark the transaction suspended.
                transaction.IsSuspended = true;
                transaction.EntryStatus = TransactionStatus.OnHold;
                CartWorkflowHelper.SaveSalesTransaction(this.Context, transaction);
                Cart cart = CartWorkflowHelper.ConvertToCart(this.Context, transaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(cart);
                return(new SuspendCartResponse(cart));
            }
            /// <summary>
            /// Execute method to be overridden by each derived class.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>
            /// The response.
            /// </returns>
            protected override UpdateDeliverySpecificationsResponse Process(UpdateDeliverySpecificationsRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.NullOrWhiteSpace(request.CartId, "request.CartId");

                SalesTransaction transaction = CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId);

                if (transaction == null)
                {
                    string message = string.Format("Cart with identifer {0} was not found.", request.CartId);
                    throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_ObjectNotFound, message);
                }

                if (request.UpdateOrderLevelDeliveryOptions)
                {
                    transaction = this.UpdateOrderLevelDeliverySpecification(transaction, request.DeliverySpecification);
                }
                else
                {
                    transaction = this.UpdateLineLevelDeliveryOptions(transaction, request.LineDeliverySpecifications);
                }

                // Validate and resolve addresses.
                ShippingHelper.ValidateAndResolveAddresses(this.Context, transaction);

                // Updating the shipping information should only affect charges, taxes, amount due and totals.
                CartWorkflowHelper.Calculate(this.Context, transaction, CalculationModes.Charges | CalculationModes.Taxes | CalculationModes.AmountDue | CalculationModes.Totals);

                CartWorkflowHelper.SaveSalesTransaction(this.Context, transaction);

                Cart updatedCart = CartWorkflowHelper.ConvertToCart(this.Context, transaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(updatedCart);

                return(new UpdateDeliverySpecificationsResponse(updatedCart));
            }
            /// <summary>
            /// Saves (updating if it exists and creating a new one if it does not) the shopping cart on the request.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns><see cref="SaveCartResponse"/> object containing the cart with updated item quantities.</returns>
            protected override SaveCartResponse Process(SaveCartRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.Null(request.Cart, "request.Cart");

                var validateCustomerAccountRequest  = new GetValidatedCustomerAccountNumberServiceRequest(request.Cart.CustomerId, throwOnValidationFailure: false);
                var validateCustomerAccountResponse = this.Context.Execute <GetValidatedCustomerAccountNumberServiceResponse>(validateCustomerAccountRequest);

                if (validateCustomerAccountResponse.IsCustomerAccountNumberInContextDifferent)
                {
                    request.Cart.CustomerId = validateCustomerAccountResponse.ValidatedAccountNumber;
                }

                bool isItemSale = request.Cart.CartLines.Any(l => string.IsNullOrWhiteSpace(l.LineId) && !l.IsGiftCardLine && !l.IsVoided && l.Quantity >= 0m);

                if (string.IsNullOrWhiteSpace(request.Cart.Id))
                {
                    request.Cart.Id = CartWorkflowHelper.GenerateRandomTransactionId(this.Context);
                }

                // Copy the logic from CartService.CreateCart().
                foreach (CartLine line in request.Cart.CartLines)
                {
                    // Sets the IsReturn flag to true, when ReturnTransactionId is specified.
                    // The reason of doing so is that the IsReturn is not currently exposed on CartLine entity.
                    if (!string.IsNullOrEmpty(line.ReturnTransactionId))
                    {
                        line.LineData.IsReturnByReceipt = true;
                    }
                }

                // Get the Sales Transaction
                SalesTransaction salesTransaction = CartWorkflowHelper.LoadSalesTransaction(this.Context, request.Cart.Id);

                if (salesTransaction == null)
                {
                    // New transaction - set the default cart type to shopping if none
                    if (request.Cart.CartType == CartType.None)
                    {
                        request.Cart.CartType = CartType.Shopping;
                    }
                }

                CartWorkflowHelper.ValidateCartPermissions(salesTransaction, request.Cart, this.Context);

                if (salesTransaction == null)
                {
                    // New transaction - set the default cart type to shopping if none
                    if (request.Cart.CartType == CartType.None)
                    {
                        request.Cart.CartType = CartType.Shopping;
                    }

                    // Do not allow new transaction for blocked customer.
                    CartWorkflowHelper.ValidateCustomerAccount(this.Context, request.Cart, null);

                    // Set loyalty card from the customer number
                    CartWorkflowHelper.SetLoyaltyCardFromCustomer(this.Context, request.Cart);

                    // Set affiliations from the customer number
                    CartWorkflowHelper.AddOrUpdateAffiliationLinesFromCustomer(this.Context, null, request.Cart);

                    // If cannot find the transaction, create a new transaction.
                    salesTransaction = CartWorkflowHelper.CreateSalesTransaction(this.Context, request.Cart.Id, request.Cart.CustomerId);

                    // Set initial values on cart to be same as on transaction.
                    request.Cart.CopyPropertiesFrom(salesTransaction);

                    // Update transaction level reason code lines.
                    ReasonCodesWorkflowHelper.AddOrUpdateReasonCodeLinesOnTransaction(salesTransaction, request.Cart);

                    // Calculate required reason code lines for start of transaction.
                    ReasonCodesWorkflowHelper.CalculateRequiredReasonCodesOnTransaction(this.Context, salesTransaction, ReasonCodeSourceType.StartOfTransaction);
                }

                // If cart or the sales transaction is suspended then update is not permitted
                if (salesTransaction.IsSuspended)
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CartNotActive, request.Cart.Id);
                }

                // If the terminal id of the cart is not same as the context then it means that the cart is active on another terminal.
                GetCurrentTerminalIdDataRequest dataRequest = new GetCurrentTerminalIdDataRequest();

                if (!(salesTransaction.TerminalId ?? string.Empty).Equals(this.Context.Execute <SingleEntityDataServiceResponse <string> >(dataRequest).Entity ?? string.Empty, StringComparison.OrdinalIgnoreCase))
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_LoadingActiveCartFromAnotherTerminalNotAllowed, request.Cart.Id);
                }

                // At this point, the sales transaction is either newly created with no sales lines or just loaded from DB.
                // We are yet to add new sales lines or update existing sales lines.
                // Get the returned sales transaction if the cart contains a return line
                SalesTransaction returnTransaction = CartWorkflowHelper.LoadSalesTransactionForReturn(this.Context, request.Cart, salesTransaction, request.OperationType);

                // If customer account number is not specified on the request it should not be overriden.
                if (request.Cart.CustomerId == null)
                {
                    request.Cart.CustomerId = salesTransaction.CustomerId;
                }

                // Get the products in the cart lines
                IDictionary <long, SimpleProduct> productsByRecordId = CartWorkflowHelper.GetProductsInCartLines(this.Context, request.Cart.CartLines);

                // Validate update cart request
                CartWorkflowHelper.ValidateUpdateCartRequest(this.Context, salesTransaction, returnTransaction, request.Cart, request.IsGiftCardOperation, productsByRecordId);

                request.Cart.IsReturnByReceipt = returnTransaction != null;
                request.Cart.ReturnTransactionHasLoyaltyPayment = returnTransaction != null && returnTransaction.HasLoyaltyPayment;

                if (returnTransaction != null &&
                    !string.IsNullOrWhiteSpace(returnTransaction.LoyaltyCardId) &&
                    string.IsNullOrWhiteSpace(salesTransaction.LoyaltyCardId))
                {
                    // Set the loyalty card of the returned transaction to the current transaction
                    request.Cart.LoyaltyCardId = returnTransaction.LoyaltyCardId;
                }

                HashSet <string> newSalesLineIdSet = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

                // Perform update cart operations
                CartWorkflowHelper.PerformSaveCartOperations(this.Context, request, salesTransaction, returnTransaction, newSalesLineIdSet, productsByRecordId);

                // Sets the wharehouse id and invent location id for each line
                ItemAvailabilityHelper.SetSalesLineInventory(this.Context, salesTransaction);

                // Calculate totals and saves the sales transaction
                CartWorkflowHelper.Calculate(this.Context, salesTransaction, request.CalculationModes, isItemSale, newSalesLineIdSet);

                // Validate price on sales line after calculations
                CartWorkflowHelper.ValidateSalesLinePrice(this.Context, salesTransaction, productsByRecordId);

                // Validate the customer account deposit transaction.
                AccountDepositHelper.ValidateCustomerAccountDepositTransaction(this.Context, salesTransaction);

                // Validate return item and return transaction permissions
                CartWorkflowHelper.ValidateReturnPermission(this.Context, salesTransaction, request.Cart.CartType);

                // Calculate the required reason codes after the price calculation
                ReasonCodesWorkflowHelper.CalculateRequiredReasonCodes(this.Context, salesTransaction, ReasonCodeSourceType.None);

                CartWorkflowHelper.SaveSalesTransaction(this.Context, salesTransaction);

                Cart cart = CartWorkflowHelper.ConvertToCart(this.Context, salesTransaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(cart);

                return(new SaveCartResponse(cart));
            }
Exemple #9
0
            /// <summary>
            /// Processes the save reason code line workflow.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            protected override SaveReasonCodeLineResponse Process(SaveReasonCodeLineRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.NullOrWhiteSpace(request.CartId, "request.CartId");
                ThrowIf.Null(request.ReasonCodeLine, "request.ReasonCodeLine");

                // Get the sales transaction.
                SalesTransaction salesTransaction =
                    CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId);

                if (salesTransaction == null)
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CartNotFound, request.CartId);
                }

                // Find the reason code lines collection that the reason code line belongs.
                ICollection <ReasonCodeLine> reasonCodeLines = null;

                switch (request.ReasonCodeLineType)
                {
                case ReasonCodeLineType.Header:
                    reasonCodeLines = salesTransaction.ReasonCodeLines;
                    break;

                case ReasonCodeLineType.Sales:
                    // Consider all lines. We could add reason code to voided lines.
                    if (salesTransaction.SalesLines != null)
                    {
                        var salesLine = (from s in salesTransaction.SalesLines
                                         where s.LineId == request.ParentLineId
                                         select s).FirstOrDefault();

                        if (salesLine != null)
                        {
                            reasonCodeLines = salesLine.ReasonCodeLines;
                        }
                    }

                    break;

                case ReasonCodeLineType.Payment:
                    if (salesTransaction.TenderLines != null)
                    {
                        var tenderLine = (from t in salesTransaction.TenderLines
                                          where t.TenderLineId == request.ParentLineId
                                          select t).FirstOrDefault();

                        if (tenderLine != null)
                        {
                            reasonCodeLines = tenderLine.ReasonCodeLines;
                        }
                    }

                    break;

                default:
                    // Do nothing.
                    break;
                }

                if (reasonCodeLines == null)
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_ObjectNotFound, request.CartId, "Cannot find the requested parent line for the reason code line.");
                }

                // Add or update the reason code line.
                if (string.IsNullOrWhiteSpace(request.ReasonCodeLine.LineId))
                {
                    request.ReasonCodeLine.LineId        = Guid.NewGuid().ToString("N");
                    request.ReasonCodeLine.ParentLineId  = request.ParentLineId;
                    request.ReasonCodeLine.TransactionId = salesTransaction.Id;
                    request.ReasonCodeLine.LineType      = request.ReasonCodeLineType;

                    reasonCodeLines.Add(request.ReasonCodeLine);
                }
                else
                {
                    // Update an existing reason code line
                    var reasonCodeLineToUpdate = (from r in reasonCodeLines
                                                  where r.LineId == request.ReasonCodeLine.LineId
                                                  select r).FirstOrDefault();

                    if (reasonCodeLineToUpdate != null)
                    {
                        reasonCodeLineToUpdate.CopyPropertiesFrom(request.ReasonCodeLine);
                        reasonCodeLineToUpdate.IsChanged = true;
                    }
                }

                // Save the updated sales transaction.
                CartWorkflowHelper.SaveSalesTransaction(this.Context, salesTransaction);

                Cart cart = CartWorkflowHelper.ConvertToCart(this.Context, salesTransaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(cart);

                return(new SaveReasonCodeLineResponse(cart));
            }
            /// <summary>
            /// Executes the workflow to fetch the promotions.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            protected override GetPromotionsResponse Process(GetPromotionsRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.Null(request.CartId, "request.CartId");

                // Get the current instance of the transaction from the database.
                SalesTransaction transaction = CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId);

                if (transaction == null)
                {
                    return(new GetPromotionsResponse(null));
                }

                ThrowIf.Null(transaction, "transaction");

                // Calculate totals on the current instance of transaction.
                CartWorkflowHelper.Calculate(this.Context, transaction, CalculationModes.All);

                // The discount lines on this transaction are the discount lines that have been applied.
                SalesTransaction currentSalesTransaction = transaction.Clone <SalesTransaction>();

                Cart cart = CartWorkflowHelper.ConvertToCart(this.Context, currentSalesTransaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(cart);

                // The discount lines on the transaction are all available discount lines for the items.
                CartWorkflowHelper.LoadAllPeriodicDiscounts(this.Context, currentSalesTransaction);
                SalesTransaction tempSalesTransaction = transaction.Clone <SalesTransaction>();

                transaction = currentSalesTransaction.Clone <SalesTransaction>();

                Collection <string>            cartPromotionLines = new Collection <string>();
                Collection <CartLinePromotion> cartLinePromotions = new Collection <CartLinePromotion>();

                for (int i = 0; i < currentSalesTransaction.SalesLines.Count; i++)
                {
                    // Removing the applied discount lines, except multiple buy because a different discount level of the already applied multi buy discount can be promoted.
                    foreach (DiscountLine discountLine in currentSalesTransaction.SalesLines[i].DiscountLines)
                    {
                        tempSalesTransaction.SalesLines[i].DiscountLines.Remove(tempSalesTransaction.SalesLines[i].DiscountLines.Where(j => j.OfferId == discountLine.OfferId).SingleOrDefault());
                    }

                    // Removing the discounts that require coupon code.
                    // Removing the discount offers those were not applied (because of concurrency rules).
                    // Removing mix and match discounts (mix and match discounts are not shown as promotions).
                    List <DiscountLine> offerDiscountLines = tempSalesTransaction.SalesLines[i].DiscountLines.Where(j => (j.PeriodicDiscountType == PeriodicDiscountOfferType.Offer) || j.IsDiscountCodeRequired || (j.PeriodicDiscountType == PeriodicDiscountOfferType.MixAndMatch)).ToList();
                    foreach (DiscountLine discountLine in offerDiscountLines)
                    {
                        tempSalesTransaction.SalesLines[i].DiscountLines.Remove(discountLine);
                    }

                    PricingDataManager pricingDataManager = new PricingDataManager(this.Context);

                    // Quantity discounts.
                    // Finding all the quantity discounts that will be applied to the cart.
                    List <DiscountLine> quantityDiscountLines = tempSalesTransaction.SalesLines[i].DiscountLines.Where(j => j.PeriodicDiscountType == PeriodicDiscountOfferType.MultipleBuy).ToList();

                    // Get the multibuy discount lines for this multi buy discounts.
                    IEnumerable <QuantityDiscountLevel> multiBuyDiscountLines = pricingDataManager.GetMultipleBuyDiscountLinesByOfferIds(quantityDiscountLines.Select(j => j.OfferId));

                    foreach (DiscountLine discountLine in quantityDiscountLines)
                    {
                        GetQuantityPromotions(transaction, tempSalesTransaction, this.Context, i, discountLine, multiBuyDiscountLines);
                    }

                    // Threshhold Discounts.
                    // Finding all the threshold discounts that will be applied to the cart.
                    List <DiscountLine> thresholdDiscountLines = tempSalesTransaction.SalesLines[i].DiscountLines.Where(j => j.PeriodicDiscountType == PeriodicDiscountOfferType.Threshold).ToList();

                    // Get the tiers for this threshold discounts
                    IEnumerable <ThresholdDiscountTier> tiers = pricingDataManager.GetThresholdTiersByOfferIds(thresholdDiscountLines.Select(j => j.OfferId));

                    foreach (DiscountLine thresholdDiscount in thresholdDiscountLines)
                    {
                        GetThresholdDiscounts(transaction, tempSalesTransaction, this.Context, i, cartPromotionLines, thresholdDiscount, tiers);
                    }

                    IEnumerable <string> promotionsForCurrentLine = tempSalesTransaction.SalesLines[i].DiscountLines.Select(j => j.OfferName);
                    cartLinePromotions.Add(new CartLinePromotion(cart.CartLines[i].LineId, promotionsForCurrentLine));
                }

                CartPromotions cartPromotions = new CartPromotions(cartPromotionLines, cartLinePromotions);

                return(new GetPromotionsResponse(cartPromotions));
            }
            /// <summary>
            /// Saves the cart lines based on the request operation type.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The save cart line response.</returns>
            protected override SaveCartLinesResponse Process(SaveCartLinesRequest request)
            {
                ThrowIf.Null(request, "request");

                // Load sales transaction.
                SalesTransaction transaction = CartWorkflowHelper.LoadSalesTransaction(request.RequestContext, request.Cart.Id);

                if (transaction == null)
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CartNotFound, request.Cart.Id);
                }

                // Load return sales transaction.
                // Get the returned sales transaction if the cart contains a return line.
                SalesTransaction returnTransaction = CartWorkflowHelper.LoadSalesTransactionForReturn(request.RequestContext, request.Cart, transaction, request.OperationType);

                transaction.IsReturnByReceipt = returnTransaction != null;

                // Get the products in the cart lines
                IDictionary <long, SimpleProduct> productsByRecordId = CartWorkflowHelper.GetProductsInCartLines(this.Context, request.Cart.CartLines);

                // Validate the save cart lines request against the sales transaction.
                CartWorkflowHelper.ValidateSaveCartLinesRequest(this.Context, request, transaction, returnTransaction, productsByRecordId);

                // Process the request.
                switch (request.OperationType)
                {
                case TransactionOperationType.Create:
                    ProcessCreateCartLinesRequest(this.Context, request, transaction, returnTransaction, productsByRecordId);
                    break;

                case TransactionOperationType.Update:
                    ProcessUpdateCartLinesRequest(this.Context, request, transaction);
                    break;

                case TransactionOperationType.Delete:
                    ProcessDeleteCartLinesRequest(request, transaction);
                    break;

                case TransactionOperationType.Void:
                    ProcessVoidCartLinesRequest(this.Context, request, transaction);
                    break;

                default:
                    throw new DataValidationException(
                              DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidRequest,
                              string.Format("Operation {0} is not supported on cart lines.", request.OperationType));
                }

                // Recalculates the sales transaction after processing the request.
                RecalculateSalesTransaction(this.Context, request, transaction);

                // Validate price on sales line after calculations
                CartWorkflowHelper.ValidateSalesLinePrice(this.Context, transaction, productsByRecordId);

                // Save the sales transaction.
                CartWorkflowHelper.SaveSalesTransaction(this.Context, transaction);

                Cart cart = CartWorkflowHelper.ConvertToCart(this.Context, transaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(cart);

                return(new SaveCartLinesResponse(cart));
            }
Exemple #12
0
            /// <summary>
            /// Executes the workflow to add or delete discount codes in cart.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            protected override SaveCartResponse Process(AddOrRemoveDiscountCodesRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.Null(request.CartId, "request.CartId");
                ThrowIf.Null(request.DiscountCodes, "request.DiscountCodes");

                // Load sales transaction.
                SalesTransaction transaction = CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId);

                if (transaction == null)
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CartNotFound, request.CartId);
                }

                IEnumerable <SalesTransaction> salesTransactions = new[] { transaction };

                transaction = salesTransactions.SingleOrDefault();

                if (transaction == null)
                {
                    return(new SaveCartResponse(new Cart()));
                }

                bool update = false;

                switch (request.DiscountCodesOperation)
                {
                case DiscountCodesOperation.Add:
                    foreach (string discountCode in request.DiscountCodes)
                    {
                        if (!transaction.DiscountCodes.Contains(discountCode))
                        {
                            transaction.DiscountCodes.Add(discountCode);
                            update = true;
                        }
                    }

                    break;

                case DiscountCodesOperation.Remove:
                    foreach (string discountCode in request.DiscountCodes)
                    {
                        transaction.DiscountCodes.Remove(discountCode);
                        update = true;
                    }

                    break;

                default:
                    throw new DataValidationException(
                              DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidRequest,
                              string.Format("Invalid discount code operation value: {0}", request.DiscountCodesOperation));
                }

                if (update)
                {
                    // Calculate totals
                    CartWorkflowHelper.Calculate(this.Context, transaction, null);

                    // Save the sales transaction
                    CartWorkflowHelper.SaveSalesTransaction(this.Context, transaction);
                }

                Cart cart = CartWorkflowHelper.ConvertToCart(this.Context, transaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(cart);

                return(new SaveCartResponse(cart));
            }