Example #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));
            }
Example #2
0
            /// <summary>
            /// Creates a sales order given the cart and payment information.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            protected override SaveCustomerOrderResponse Process(SaveCustomerOrderRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.Null(request.CartId, "request.CartId");

                // Get the Sales Transaction
                SalesTransaction transaction = CustomerOrderWorkflowHelper.GetSalesTransaction(this.Context, request.CartId, request.ReceiptEmailAddress);

                // Update customer order fields before validation
                CustomerOrderWorkflowHelper.UpdateCustomerOrderFieldsOnCheckout(transaction);

                // Return validations
                switch (transaction.CustomerOrderMode)
                {
                case CustomerOrderMode.Return:
                    CustomerOrderWorkflowHelper.ValidateOrderForReturn(this.Context, transaction);
                    break;

                case CustomerOrderMode.CustomerOrderCreateOrEdit:
                case CustomerOrderMode.QuoteCreateOrEdit:
                    CustomerOrderWorkflowHelper.ValidateOrderAndQuoteCreationAndUpdate(this.Context, transaction);
                    break;

                default:
                    throw new NotSupportedException(
                              string.Format(CultureInfo.InvariantCulture, "Customer order mode {0} not supported.", transaction.CustomerOrderMode));
                }

                // Add customer order specific missing dependencies to the sales transaction
                CustomerOrderWorkflowHelper.FillMissingRequirementsForOrder(this.Context, transaction);

                // Resolve addresses
                ShippingHelper.ValidateAndResolveAddresses(this.Context, transaction);

                // Validate shipping addresses
                ShippingHelper.ValidateShippingInformation(this.Context, transaction);

                // Validate required reason code lines has been filled
                ReasonCodesWorkflowHelper.ValidateRequiredReasonCodeLinesFilled(this.Context, transaction);

                // Fill in receipt id. Receipt id will be needed if paying with credit memo.
                transaction = CustomerOrderWorkflowHelper.FillInReceiptId(this.Context, transaction, request.ReceiptNumberSequence);

                // Handle payments
                if (request.TokenizedPaymentCard != null)
                {
                    transaction = CustomerOrderWorkflowHelper.HandlePayments(this.Context, transaction, request.TokenizedPaymentCard);
                }
                else
                {
                    transaction = CustomerOrderWorkflowHelper.HandlePayments(this.Context, transaction);
                }

                // Create order through transaction service
                SalesOrder salesOrder = CustomerOrderWorkflowHelper.SaveCustomerOrder(this.Context, transaction);

                CartWorkflowHelper.TryDeleteCart(this.Context, transaction);

                return(new SaveCustomerOrderResponse(salesOrder));
            }
Example #3
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));
            }
            /// <summary>
            /// Updates the sales transaction with the quantity promotion if applicable.
            /// </summary>
            /// <param name="existingTransaction">Existing transaction.</param>
            /// <param name="tempSalesTransaction">Copy of existing transaction.</param>
            /// <param name="context">The request context.</param>
            /// <param name="salesLineIndex">The sales line under consideration.</param>
            /// <param name="discountLine">The quantity discount under consideration.</param>
            /// <param name="multiBuyDiscountLines">The multi buy discount lines.</param>
            private static void GetQuantityPromotions(SalesTransaction existingTransaction, SalesTransaction tempSalesTransaction, RequestContext context, int salesLineIndex, DiscountLine discountLine, IEnumerable <QuantityDiscountLevel> multiBuyDiscountLines)
            {
                // Get the multi buy discount lines for the current multi buy discount.
                IEnumerable <QuantityDiscountLevel> multiBuyLinesForCurrentOffer = multiBuyDiscountLines.Where(j => j.OfferId.Equals(discountLine.OfferId)).OrderBy(l => l.MinimumQuantity);

                List <SalesLine> salesLinesWithSameProduct = tempSalesTransaction.SalesLines.Where(j => j.ItemId == tempSalesTransaction.SalesLines[salesLineIndex].ItemId && j.InventoryDimensionId == tempSalesTransaction.SalesLines[salesLineIndex].InventoryDimensionId).ToList();
                decimal          totalQuantity             = salesLinesWithSameProduct.Select(j => j.Quantity).Sum();
                decimal          currentQuantity           = tempSalesTransaction.SalesLines[salesLineIndex].Quantity;

                salesLinesWithSameProduct.Remove(tempSalesTransaction.SalesLines[salesLineIndex]);
                bool neverApplied = true;

                foreach (QuantityDiscountLevel multiBuyLine in multiBuyLinesForCurrentOffer)
                {
                    // removing the quantity discounts that were not applied (because of concurrency rules).
                    if (multiBuyLine.MinimumQuantity <= totalQuantity)
                    {
                        continue;
                    }

                    // Temporarily update the current transaction with the new quantity to see if the quantity discount will be applied.
                    existingTransaction.SalesLines[salesLineIndex].Quantity = multiBuyLine.MinimumQuantity - totalQuantity + currentQuantity;

                    CartWorkflowHelper.Calculate(context, existingTransaction, CalculationModes.All);
                    DiscountLine isApplied = existingTransaction.SalesLines[salesLineIndex].DiscountLines.Where(j => j.OfferId == discountLine.OfferId).SingleOrDefault();

                    // If the quantity discount will be applied then remove the discount line from the lines with same product and get the min quantity to buy for discount.
                    if (isApplied != null && (isApplied.Amount != 0 || isApplied.Percentage != 0))
                    {
                        int toBuy = (int)(multiBuyLine.MinimumQuantity - totalQuantity);
                        if (isApplied.Amount != 0)
                        {
                            discountLine.OfferName = string.Format(CultureInfo.CurrentUICulture, Resources.MultiBuyDiscountPricePromotion, toBuy, Math.Round(isApplied.Amount, 2));
                        }
                        else
                        {
                            discountLine.OfferName = string.Format(CultureInfo.CurrentUICulture, Resources.MultiBuyDiscountPercentagePromotion, toBuy, Math.Round(isApplied.Percentage, 2));
                        }

                        neverApplied = false;
                        break;
                    }
                }

                if (neverApplied)
                {
                    tempSalesTransaction.SalesLines[salesLineIndex].DiscountLines.Remove(discountLine);
                }

                existingTransaction.SalesLines[salesLineIndex].Quantity = currentQuantity;
                CartWorkflowHelper.Calculate(context, existingTransaction, CalculationModes.All);

                foreach (SalesLine sameproductCartLine in salesLinesWithSameProduct)
                {
                    sameproductCartLine.DiscountLines.Remove(sameproductCartLine.DiscountLines.Where(k => k.OfferId == discountLine.OfferId).SingleOrDefault());
                }
            }
            /// <summary>
            /// Recalculates the sales transaction.
            /// </summary>
            /// <param name="context">The context.</param>
            /// <param name="request">The request.</param>
            /// <param name="transaction">Current transaction.</param>
            private static void RecalculateSalesTransaction(RequestContext context, SaveCartLinesRequest request, SalesTransaction transaction)
            {
                // Sets the wharehouse id and invent location id for each line
                ItemAvailabilityHelper.SetSalesLineInventory(context, transaction);

                // Calculate totals and saves the sales transaction
                CartWorkflowHelper.Calculate(context, transaction, request.CalculationModes);

                // Calculate the required reason codes after the price calculation
                ReasonCodesWorkflowHelper.CalculateRequiredReasonCodes(context, transaction, ReasonCodeSourceType.None);
            }
Example #6
0
            /// <summary>
            /// Performs the execution of the activity.
            /// </summary>
            /// <param name="context">The execution context under which the activity executes.</param>
            protected override void Execute(CodeActivityContext context)
            {
                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }

                RequestContext   requestContext = context.GetValue <RequestContext>(this.RequestContext);
                SalesTransaction transaction    = context.GetValue <SalesTransaction>(this.Transaction);

                CartWorkflowHelper.SaveSalesTransaction(requestContext, transaction);
            }
            /// <summary>
            /// Performs the execution of the activity.
            /// </summary>
            /// <param name="context">The execution context under which the activity executes.</param>
            /// <returns>Loaded sales transaction.</returns>
            protected override SalesTransaction Execute(CodeActivityContext context)
            {
                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }

                RequestContext   requestContext = context.GetValue <RequestContext>(this.RequestContext);
                string           transactionId  = context.GetValue <string>(this.TransactionId);
                SalesTransaction transaction    = CartWorkflowHelper.LoadSalesTransaction(requestContext, transactionId);

                return(transaction);
            }
         /// <summary>
         /// Executes the workflow to issue or add balance to gift card.
         /// </summary>
         /// <param name="request">Instance of <see cref="IssueOrAddToGiftCardRequest"/>.</param>
         /// <returns>Instance of <see cref="IssueOrAddToGiftCardResponse"/>.</returns>
         protected override IssueOrAddToGiftCardResponse Process(IssueOrAddToGiftCardRequest request)
         {
             ThrowIf.Null(request, "request");
 
             SalesTransaction transaction = CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId);
 
             GetGiftCardServiceResponse serviceResponse;
             GiftCardOperationType operation;
 
             if (request.ExistingGiftCard)
             {
                 // add to gift card
                 var serviceRequest = new AddToGiftCardServiceRequest(
                     request.GiftCardId,
                     request.Amount,
                     request.CurrencyCode,
                     transaction);
 
                 serviceResponse = this.Context.Execute<GetGiftCardServiceResponse>(serviceRequest);
 
                 operation = GiftCardOperationType.AddTo;
             }
             else
             {
                 // Issue new gift card
                 var serviceRequest = new IssueGiftCardServiceRequest(
                     request.GiftCardId,
                     request.Amount,
                     request.CurrencyCode,
                     transaction);
 
                 serviceResponse = this.Context.Execute<GetGiftCardServiceResponse>(serviceRequest);
 
                 operation = GiftCardOperationType.Issue;
             }
 
             CartLine giftCardLine = new CartLine
             {
                 Price = request.Amount,
                 IsGiftCardLine = true,
                 Description = request.LineDescription,
                 Comment = serviceResponse.GiftCard.Id,
                 GiftCardId = serviceResponse.GiftCard.Id,
                 GiftCardCurrencyCode = serviceResponse.GiftCard.CardCurrencyCode,
                 GiftCardOperation = operation,
                 Quantity = 1m
             };
 
             return new IssueOrAddToGiftCardResponse(giftCardLine);
         }
Example #9
0
            /// <summary>
            /// Transfer the shopping cart on the request.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns><see cref="NullResponse"/> object containing nothing.</returns>
            protected override NullResponse Process(TransferCartRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.Null(request.Cart, "request.Cart");

                // After transfering the cart, it would remain as offline till the whole transaction is done.
                request.Cart.IsCreatedOffline = true;

                // For offline cart, persist the object directly into database.
                var transaction = CartWorkflowHelper.ConvertToSalesTransaction(request.Cart);

                CartWorkflowHelper.TransferSalesTransaction(this.Context, transaction);

                return(new NullResponse());
            }
            /// <summary>
            /// Processes the create cart lines request.
            /// </summary>
            /// <param name="context">The context.</param>
            /// <param name="request">The request.</param>
            /// <param name="transaction">Current transaction.</param>
            /// <param name="returnTransaction">Return transaction.</param>
            /// <param name="productByRecordId">The mapping of products by record identifier.</param>
            private static void ProcessCreateCartLinesRequest(RequestContext context, SaveCartLinesRequest request, SalesTransaction transaction, SalesTransaction returnTransaction, IDictionary <long, SimpleProduct> productByRecordId)
            {
                // Create the new cart lines.
                var salesLines = new List <SalesLine>();

                foreach (CartLine cartLine in request.CartLines)
                {
                    var salesLine = new SalesLine();

                    if (!cartLine.LineData.IsReturnByReceipt)
                    {
                        // Creates a sales line base on the cart line
                        salesLine.CopyPropertiesFrom(cartLine.LineData);

                        // Set ItemId and VariantInventDimId of the sales line, if the cart line is constructed from listing.
                        if (cartLine.LineData.IsProductLine)
                        {
                            long          id      = cartLine.LineData.ProductId;
                            SimpleProduct product = productByRecordId[id];
                            salesLine.ItemId               = product.ItemId;
                            salesLine.ProductId            = id;
                            salesLine.InventoryDimensionId = product.InventoryDimensionId;
                            salesLine.Variant              = ProductVariant.ConvertFrom(product);
                        }
                    }
                    else
                    {
                        // Creates a sales line base on the retuned sales line
                        var returnedSalesLine = CartWorkflowHelper.GetSalesLineByNumber(returnTransaction, cartLine.LineData.ReturnLineNumber);
                        CartWorkflowHelper.SetSalesLineBasedOnReturnedSalesLine(salesLine, returnedSalesLine, returnTransaction, cartLine.LineData.Quantity);

                        // Calculate required reason code lines for return transaction.
                        ReasonCodesWorkflowHelper.CalculateRequiredReasonCodesOnSalesLine(context, transaction, salesLine, ReasonCodeSourceType.ReturnItem);
                    }

                    // Assign sales line Id. Using format 'N' to remove dashes from the GUID.
                    salesLine.LineId = Guid.NewGuid().ToString("N");

                    // Add sales lines to collection.
                    salesLines.Add(salesLine);
                }

                // Set default attributes from order header.
                CartWorkflowHelper.SetDefaultDataOnSalesLines(context, transaction, salesLines);

                // Add sales lines to transation.
                transaction.SalesLines.AddRange(salesLines);
            }
            /// <summary>
            /// Performs the execution of the activity.
            /// </summary>
            /// <param name="context">The execution context under which the activity executes.</param>
            protected override void Execute(CodeActivityContext context)
            {
                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }

                SaveCartRequest  request           = context.GetValue <SaveCartRequest>(this.Request);
                SalesTransaction transaction       = context.GetValue <SalesTransaction>(this.Transaction);
                SalesTransaction returnTransaction = context.GetValue <SalesTransaction>(this.ReturnTransaction);

                // Get products in cart
                Dictionary <long, SimpleProduct> productsByRecordId = CartWorkflowHelper.GetProductsInCartLines(request.RequestContext, request.Cart.CartLines);

                CartWorkflowHelper.PerformSaveCartOperations(request.RequestContext, request, transaction, returnTransaction, new HashSet <string>(StringComparer.OrdinalIgnoreCase), productsByRecordId);
            }
            /// <summary>
            /// Gets the transaction for custom receipts.
            /// </summary>
            /// <param name="request">The get receipt request.</param>
            /// <returns>The sales order.</returns>
            /// <remarks>
            /// This method is used to handle custom receipt. Since only sales order related receipt
            /// is using receipt designer while others are hardcoded, so we cannot support customizing receipts for
            /// NonSalesTransaction or DropAndDeclareTransaction.
            /// Here we first try to load the SalesOrder, if we cannot find it, then try to load
            /// a cart and convert it to sales order.
            /// </remarks>
            private SalesOrder GetTransactionForCustomReceipt(GetReceiptRequest request)
            {
                ReceiptRetrievalCriteria criteria = request.ReceiptRetrievalCriteria;
                string transactionId = request.TransactionId;

                SalesOrder salesOrder = null;

                if (!criteria.QueryBySalesId)
                {
                    salesOrder = this.GetTransactionByTransactionId(transactionId, false) ?? this.GetTransactionByTransactionId(transactionId, true);
                }
                else
                {
                    try
                    {
                        salesOrder = this.GetTransactionBySalesId(transactionId);
                    }
                    catch (FeatureNotSupportedException)
                    {
                        // Not able to get sales order in offline mode.
                    }
                }

                // If cannot find a sales order, then try to find a cart (suspended transaction).
                if (salesOrder == null)
                {
                    SalesTransaction salesTransaction = CartWorkflowHelper.LoadSalesTransaction(request.RequestContext, request.TransactionId);
                    if (salesTransaction != null)
                    {
                        salesOrder = new SalesOrder();

                        // Now ReceiptService only accept SalesOrder. So in order to reuse the code in ReceiptService, we need to convert
                        // SalesTransaction to SalesOrder. SalesOrder is extended from SalesTransaction, so in this case we are good. But
                        // in the future we should refactor ReceiptService to make it accept a common interface so that we can extend to
                        // other objects.
                        salesOrder.CopyFrom(salesTransaction);
                    }
                    else
                    {
                        throw new DataValidationException(
                                  DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_ObjectNotFound,
                                  string.Format("Unable to get the transaction created. ID: {0}", transactionId));
                    }
                }

                return(salesOrder);
            }
            /// <summary>
            /// Returns Sales Order by sales id and terminal id. Used to get remote orders from AX which does not have transaction id.
            /// </summary>
            /// <param name="salesId">The sales id parameter.</param>
            /// <returns>The  SalesOrder.</returns>
            private SalesOrder GetTransactionBySalesId(string salesId)
            {
                // Recall the customer order
                var realtimeRequest = new RecallCustomerOrderRealtimeRequest(salesId, isQuote: false);

                var        serviceResponse = this.Context.Execute <RecallCustomerOrderRealtimeResponse>(realtimeRequest);
                SalesOrder salesOrder      = serviceResponse.SalesOrder;

                // Channel and terminal don't come from ax
                salesOrder.ChannelId  = this.Context.GetPrincipal().ChannelId;
                salesOrder.TerminalId = this.Context.GetTerminal().TerminalId;

                // Perform order calculations (deposit, amount due, etc)
                CartWorkflowHelper.Calculate(this.Context, salesOrder, requestedMode: null);

                return(salesOrder);
            }
            /// <summary>
            /// Performs the execution of the activity.
            /// </summary>
            /// <param name="context">The execution context under which the activity executes.</param>
            protected override void Execute(CodeActivityContext context)
            {
                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }

                RequestContext   requestContext    = context.GetValue <RequestContext>(this.RequestContext);
                SaveCartRequest  request           = context.GetValue <SaveCartRequest>(this.Request);
                SalesTransaction transaction       = context.GetValue <SalesTransaction>(this.Transaction);
                SalesTransaction returnTransaction = context.GetValue <SalesTransaction>(this.ReturnTransaction);

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

                CartWorkflowHelper.ValidateUpdateCartRequest(requestContext, transaction, returnTransaction, request.Cart, false, productsByRecordId);
            }
            /// <summary>
            /// Processes the update cart lines request.
            /// </summary>
            /// <param name="context">The context.</param>
            /// <param name="request">The request.</param>
            /// <param name="transaction">Current transaction.</param>
            private static void ProcessUpdateCartLinesRequest(RequestContext context, SaveCartLinesRequest request, SalesTransaction transaction)
            {
                Dictionary <string, SalesLine> salesLinesById = transaction.SalesLines.ToDictionary(sl => sl.LineId, sl => sl);

                // Keep track of updated sales lines.
                var updatedSalesLines = new List <SalesLine>();

                // Update sales lines.
                foreach (CartLine cartLine in request.CartLines)
                {
                    var salesLine = salesLinesById[cartLine.LineId];

                    if (salesLine.Quantity != cartLine.Quantity)
                    {
                        // Validate permissions.
                        context.Execute <NullResponse>(new CheckAccessServiceRequest(RetailOperation.SetQuantity));
                    }

                    if (!salesLine.IsReturnByReceipt)
                    {
                        // Copy the properties from the cart line
                        salesLine.CopyPropertiesFrom(cartLine.LineData);

                        // we have to preserve the LineId, regardless what is set on line data
                        salesLine.LineId = cartLine.LineId;
                    }
                    else
                    {
                        // For return
                        // Keep the properties on the sales line and only copy the quantity from the cart line
                        salesLine.Quantity = cartLine.LineData.Quantity;

                        // Calculate required reason code lines for return item.
                        ReasonCodesWorkflowHelper.CalculateRequiredReasonCodesOnSalesLine(context, transaction, salesLine, ReasonCodeSourceType.ReturnItem);
                    }

                    updatedSalesLines.Add(salesLine);
                }

                // Set default attributes for the updated sales lines.
                if (updatedSalesLines.Any())
                {
                    CartWorkflowHelper.SetDefaultDataOnSalesLines(context, transaction, updatedSalesLines);
                }
            }
Example #16
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);
            }
Example #18
0
            /// <summary>
            /// Executes the workflow to validate tender line.
            /// </summary>
            /// <param name="request">Instance of <see cref="ValidateTenderLineForAddRequest"/>.</param>
            /// <returns>Instance of <see cref="NullResponse"/>.</returns>
            protected override NullResponse Process(ValidateTenderLineForAddRequest 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);
                }

                var validateRequest = new ValidateTenderLineForAddServiceRequest(salesTransaction, request.TenderLine);

                this.Context.Execute <NullResponse>(validateRequest);

                return(new NullResponse());
            }
            /// <summary>
            /// Populates the sales transaction.
            /// </summary>
            /// <param name="context">The context.</param>
            /// <param name="cartId">The cart id.</param>
            /// <param name="email">The email.</param>
            /// <param name="salesTransaction">The sales transaction.</param>
            private static void PopulateSalesTransaction(RequestContext context, string cartId, string email, out SalesTransaction salesTransaction)
            {
                salesTransaction = CartWorkflowHelper.LoadSalesTransaction(context, cartId);

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

                salesTransaction.ReceiptEmail    = email;
                salesTransaction.TransactionType = SalesTransactionType.PendingSalesOrder;

                if (string.IsNullOrEmpty(salesTransaction.ReceiptEmail))
                {
                    throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_RequiredValueNotFound, "Receipt email must be provided.");
                }

                OrderWorkflowHelper.FillTransactionWithContextData(context, salesTransaction);
            }
Example #20
0
            /// <summary>
            /// Executes the workflow to get the accepting point of card payment.
            /// </summary>
            /// <param name="request">Instance of <see cref="GetCardPaymentAcceptPointRequest"/>.</param>
            /// <returns>Instance of <see cref="GetCardPaymentAcceptPointResponse"/>.</returns>
            protected override GetCardPaymentAcceptPointResponse Process(GetCardPaymentAcceptPointRequest request)
            {
                ThrowIf.Null(request, "request");

                if (request.CartId == null)
                {
                    throw new ArgumentException("request.CartId cannot be null.");
                }

                // Find the first shipping address from the cart which is not store pickup
                // Look at the line level, if not found, then the header level.
                SalesTransaction     transaction          = CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId);
                Address              defaultAddress       = null;
                ChannelConfiguration channelConfiguration = this.Context.GetChannelConfiguration();

                foreach (var salesline in transaction.SalesLines)
                {
                    if (!string.IsNullOrWhiteSpace(salesline.DeliveryMode) &&
                        !salesline.DeliveryMode.Equals(channelConfiguration.PickupDeliveryModeCode, StringComparison.OrdinalIgnoreCase) &&
                        salesline.ShippingAddress != null)
                    {
                        defaultAddress = salesline.ShippingAddress;
                        break;
                    }
                }

                if (defaultAddress == null &&
                    !string.IsNullOrWhiteSpace(transaction.DeliveryMode) &&
                    !transaction.DeliveryMode.Equals(channelConfiguration.PickupDeliveryModeCode, StringComparison.OrdinalIgnoreCase) &&
                    transaction.ShippingAddress != null)
                {
                    defaultAddress = transaction.ShippingAddress;
                }

                // Call service to get accept point
                var serviceRequest  = new GetCardPaymentAcceptPointServiceRequest(request.CardPaymentAcceptSettings, defaultAddress, defaultAddress != null);
                var serviceResponse = this.Context.Execute <GetCardPaymentAcceptPointServiceResponse>(serviceRequest);

                return(new GetCardPaymentAcceptPointResponse(serviceResponse.CardPaymentAcceptPoint));
            }
Example #21
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));
            }
Example #22
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>
            /// Process the request.
            /// </summary>
            /// <param name="request">The request object.</param>
            /// <returns>The response object.</returns>
            protected override PickupAtStoreResponse Process(PickupAtStoreRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.Null(request.CartId, "request.CartId");

                // Get the Sales Transaction
                SalesTransaction transaction = CustomerOrderWorkflowHelper.GetSalesTransaction(this.Context, request.CartId, request.ReceiptEmailAddress);

                // Validate lines
                CustomerOrderWorkflowHelper.ValidateOrderForPickup(this.Context, transaction);

                // Fill in receipt id. Receipt id will be needed if paying with credit memo.
                transaction = CustomerOrderWorkflowHelper.FillInReceiptId(this.Context, transaction, request.ReceiptNumberSequence);

                // Handle payments
                transaction = CustomerOrderWorkflowHelper.HandlePayments(this.Context, transaction);

                // Saves the order (this will invoice the items picked up in AX)
                SalesOrder order = CustomerOrderWorkflowHelper.SaveCustomerOrder(this.Context, transaction);

                CartWorkflowHelper.TryDeleteCart(this.Context, transaction);

                return(new PickupAtStoreResponse(order));
            }
            /// <summary>
            /// Process the request.
            /// </summary>
            /// <param name="request">The request object.</param>
            /// <returns>The response object.</returns>
            protected override CancelOrderResponse Process(CancelOrderRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.Null(request.CartId, "request.CartId");

                // Get the Sales Transaction
                SalesTransaction transaction = CustomerOrderWorkflowHelper.GetSalesTransaction(this.Context, request.CartId, request.ReceiptEmailAddress);

                // Validate lines
                CustomerOrderWorkflowHelper.ValidateOrderForCancellation(this.Context, transaction);

                // Fill in receipt id. Receipt id will be needed if paying with credit memo.
                transaction = CustomerOrderWorkflowHelper.FillInReceiptId(this.Context, transaction, request.ReceiptNumberSequence);

                // Handle payments
                transaction = CustomerOrderWorkflowHelper.HandlePayments(this.Context, transaction);

                // Saves the order (this will cancel the order in the headquarters)
                SalesOrder order = CustomerOrderWorkflowHelper.SaveCustomerOrder(this.Context, transaction);

                CartWorkflowHelper.TryDeleteCart(this.Context, transaction);

                return(new CancelOrderResponse(order));
            }
            /// <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));
            }
            /// <summary>
            /// Gets the shopping cart specified by cart identifier and optionally calculates the totals on the cart.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns><see cref="GetCartResponse"/> object containing the shopping cart or a new one if the flag to create is set and no cart was found.</returns>
            protected override GetCartResponse Process(GetCartRequest request)
            {
                ThrowIf.Null(request, "request");

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

                if (validateCustomerAccountResponse.IsCustomerAccountNumberInContextDifferent)
                {
                    request.SearchCriteria.CustomerAccountNumber = validateCustomerAccountResponse.ValidatedAccountNumber;
                    request.SearchCriteria.IncludeAnonymous      = true;
                }

                if (!request.SearchCriteria.SuspendedOnly && string.IsNullOrEmpty(request.SearchCriteria.CartId) && string.IsNullOrEmpty(request.SearchCriteria.CustomerAccountNumber))
                {
                    throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidRequest, "SearchCriteria requires one of the following fields to be set: SuspendedOnly, CartId, CustomerAccountNumber.");
                }

                if (!string.IsNullOrEmpty(request.SearchCriteria.CustomerAccountNumber) && string.IsNullOrWhiteSpace(request.SearchCriteria.CartId) && !request.SearchCriteria.SuspendedOnly)
                {
                    // If the only search criteria set is that of customer account number, then anonymous carts should not be fetched.
                    request.SearchCriteria.IncludeAnonymous = false;
                }

                // User query result settings provided by caller. If not available and cart identifier is set retrieve one row, otherwise do not apply paging.
                QueryResultSettings queryResultSettings = request.QueryResultSettings ?? (string.IsNullOrEmpty(request.SearchCriteria.CartId) ? QueryResultSettings.AllRecords : QueryResultSettings.SingleRecord);
                bool removeUnassortedProducts           = !request.SearchCriteria.SuspendedOnly;

                var getCartsServiceRequest  = new GetSalesTransactionsServiceRequest(request.SearchCriteria, queryResultSettings, removeUnassortedProducts);
                var getCartsServiceResponse = this.Context.Execute <GetSalesTransactionsServiceResponse>(getCartsServiceRequest);

                PagedResult <SalesTransaction>           salesTransactions            = getCartsServiceResponse.SalesTransactions;
                IDictionary <string, IList <SalesLine> > linesWithUnavailableProducts = getCartsServiceResponse.LinesWithUnavailableProducts;

                IEnumerable <SalesTransaction> transactionWithUnassortedProducts = salesTransactions.Results.Where(t => linesWithUnavailableProducts.Keys.Contains(t.Id));

                if (removeUnassortedProducts && linesWithUnavailableProducts.Any())
                {
                    foreach (SalesTransaction transaction in transactionWithUnassortedProducts)
                    {
                        // Recalculate totals (w/o unassorted products and save cart).
                        CartWorkflowHelper.Calculate(this.Context, transaction, requestedMode: null);
                        CartWorkflowHelper.SaveSalesTransaction(this.Context, transaction);
                    }

                    if (!request.IgnoreProductDiscontinuedNotification)
                    {
                        // Send notification to decide if caller should be notified about discontinued products.
                        var notification = new ProductDiscontinuedFromChannelNotification(linesWithUnavailableProducts);
                        this.Context.Notify(notification);
                    }

                    // Reload to cart to avoid version mismatch.
                    var reloadCartsServiceRequest = new GetSalesTransactionsServiceRequest(request.SearchCriteria, queryResultSettings, mustRemoveUnavailableProductLines: false);
                    salesTransactions = this.Context.Execute <GetSalesTransactionsServiceResponse>(reloadCartsServiceRequest).SalesTransactions;
                }

                PagedResult <Cart> carts = salesTransactions.ConvertTo(transaction => ConvertTransactionToCart(this.Context, transaction, request.IncludeHistoricalTenderLines));

                return(new GetCartResponse(carts, salesTransactions));
            }
            /// <summary>
            /// Creates a sales transaction given the cart.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            protected override SaveVoidTransactionResponse Process(SaveVoidTransactionRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.Null(request.CartId, "request.CartId");

                // Get the Sales Transaction
                SalesTransaction salesTransaction = CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId, ignoreProductDiscontinuedNotification: true);

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

                if (salesTransaction.IsSuspended)
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CartNotActive, request.CartId);
                }

                // If there are unvoided non-historical Tender lines throw exception that Transaction cannot be voided.
                if (salesTransaction.TenderLines != null && salesTransaction.TenderLines.Any(l => l.TransactionStatus != TransactionStatus.Voided && l.Status != TenderLineStatus.Historical))
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_VoidTransactionContainsTenderedLines, request.CartId);
                }

                // Add or update any incoming reason codes on the transaction.
                Cart cartToBeVoided = new Cart
                {
                    Id = request.CartId
                };

                if (request.ReasonCodeLines != null)
                {
                    cartToBeVoided.ReasonCodeLines = request.ReasonCodeLines.ToList();
                }

                ReasonCodesWorkflowHelper.AddOrUpdateReasonCodeLinesOnTransaction(salesTransaction, cartToBeVoided);

                // Calculate the required reason codes on the tender line for voiding transaction.
                ReasonCodesWorkflowHelper.CalculateRequiredReasonCodesOnTransaction(this.Context, salesTransaction, ReasonCodeSourceType.VoidTransaction);

                GiftCardWorkflowHelper.VoidGiftCardSalesLines(this.Context, salesTransaction);

                // Set the Sales Transaction Status to Voided.
                salesTransaction.EntryStatus = TransactionStatus.Voided;

                // Set the transaction type to represent Cash & Carry sales.
                if (salesTransaction.TransactionType != SalesTransactionType.IncomeExpense)
                {
                    salesTransaction.TransactionType = SalesTransactionType.Sales;
                }

                // Fill in Store and Terminal information.
                OrderWorkflowHelper.FillTransactionWithContextData(this.Context, salesTransaction);

                // Create order
                var salesOrder = OrderWorkflowHelper.CreateSalesOrder(this.Context, salesTransaction);

                // We also need to delete the shopping cart.
                CartWorkflowHelper.TryDeleteCart(
                    this.Context,
                    new SalesTransaction
                {
                    Id         = request.CartId,
                    TerminalId = salesTransaction.TerminalId,
                    CustomerId = salesTransaction.CustomerId,
                });

                CartWorkflowHelper.LogAuditEntry(
                    this.Context,
                    "SaveVoidTransactionRequestHandler.Process",
                    string.Format("Transaction '{0}' voided.", request.CartId));

                return(new SaveVoidTransactionResponse(salesOrder));
            }
            /// <summary>
            /// Creates a sales transaction given the cart.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            protected override SubmitSalesTransactionResponse Process(SubmitSalesTransactionRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.Null(request.CartId, "request.CartId");

                // 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);
                }

                if (salesTransaction.IsSuspended)
                {
                    throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CartNotActive, request.CartId);
                }

                if (!(salesTransaction.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);
                }

                salesTransaction.ReceiptEmail = request.ReceiptEmail;

                // Set the transaction type to represent Cash & Carry sales by default, if it's not an IncomeExpense nor AccountDeposit transaction.
                if (salesTransaction.TransactionType != SalesTransactionType.IncomeExpense && salesTransaction.TransactionType != SalesTransactionType.CustomerAccountDeposit)
                {
                    salesTransaction.TransactionType = SalesTransactionType.Sales;
                }

                // Fill in Store and Terminal information.
                OrderWorkflowHelper.FillTransactionWithContextData(this.Context, salesTransaction);

                // Calculate required reason code for end of transaction.
                ReasonCodesWorkflowHelper.CalculateRequiredReasonCodesOnTransaction(this.Context, salesTransaction, ReasonCodeSourceType.EndOfTransaction);

                // Validate required reason code lines has been filled.
                ReasonCodesWorkflowHelper.ValidateRequiredReasonCodeLinesFilled(this.Context, salesTransaction);

                // Validate return permission.
                CartWorkflowHelper.ValidateReturnPermission(this.Context, salesTransaction, salesTransaction.CartType);

                // Fill in variant information.
                OrderWorkflowHelper.FillVariantInformation(this.Context, salesTransaction);

                // Fill in Receipt Id.
                OrderWorkflowHelper.FillInReceiptId(this.Context, salesTransaction, request.ReceiptNumberSequence);

                // Validate sales order for creation.
                OrderWorkflowHelper.ValidateContextForCreateOrder(this.Context, salesTransaction);

                // Validate payments.
                OrderWorkflowHelper.CalculateAndValidateAmountPaidForCheckout(this.Context, salesTransaction);

                salesTransaction = OrderWorkflowHelper.ProcessCheckoutPayments(this.Context, salesTransaction);

                // release/unlock gift cards on sales lines
                GiftCardWorkflowHelper.UnlockGiftCardsOnActiveSalesLines(this.Context, salesTransaction);

                // Pay Sales Invoices...
                OrderWorkflowHelper.SettleInvoiceSalesLines(this.Context, salesTransaction);

                // Create order
                var salesOrder = OrderWorkflowHelper.CreateSalesOrder(this.Context, salesTransaction);

                // We also need to delete the shopping cart.
                CartWorkflowHelper.TryDeleteCart(
                    this.Context,
                    new SalesTransaction
                {
                    Id         = salesTransaction.Id,
                    TerminalId = salesTransaction.TerminalId,
                    CustomerId = salesTransaction.CustomerId,
                });

                return(new SubmitSalesTransactionResponse(salesOrder));
            }
Example #30
0
            public void OnExecuting(Request request)
            {
                SaveCartRequest           saveCartRequest  = request as SaveCartRequest;
                SalesTransaction          salesTransaction = saveCartRequest.SalesTransaction;
                Dictionary <string, bool> checkDict        = new Dictionary <string, bool>();

                if (saveCartRequest.Cart.CartType == CartType.CustomerOrder && saveCartRequest.Cart.CustomerOrderMode == CustomerOrderMode.CustomerOrderCreateOrEdit)
                {
                    if (salesTransaction == null)
                    {
                        salesTransaction = CartWorkflowHelper.LoadSalesTransaction(saveCartRequest.RequestContext, saveCartRequest.Cart.Id, saveCartRequest.Cart.Version);
                    }

                    if (salesTransaction != null &&
                        salesTransaction.CartType == CartType.CustomerOrder && salesTransaction.CustomerOrderMode == CustomerOrderMode.CustomerOrderCreateOrEdit &&
                        (!String.IsNullOrEmpty(saveCartRequest.Cart.DeliveryMode)))
                    {
                        bool DeliveryOnhandCheck = saveCartRequest.Cart.DeliveryMode == "99" ? true : false;

                        if (DeliveryOnhandCheck == true)
                        {
                            InventoryManager inventoryManager = InventoryManager.Create(request.RequestContext.Runtime);
                            foreach (SalesLine salesLine in salesTransaction.InventorySalesLines)
                            {
                                PagingInfo  pagingInfo  = new PagingInfo(30, 0);
                                SortingInfo sortingInfo = new SortingInfo();
                                var         settings    = new QueryResultSettings(pagingInfo, sortingInfo);

                                PagedResult <OrgUnitAvailability> orgUnitAvailabilities = inventoryManager.SearchAvailableInventory(salesLine.ProductId, null, settings);
                                foreach (OrgUnitAvailability orgUnitAvailability in orgUnitAvailabilities)
                                {
                                    if (checkDict.ContainsKey(salesLine.LineId))
                                    {
                                        break;
                                    }

                                    foreach (ItemAvailability itemAvailability in orgUnitAvailability.ItemAvailabilities)
                                    {
                                        if (itemAvailability.ProductId == salesLine.ProductId &&
                                            (itemAvailability.InventoryLocationId == salesLine.InventoryLocationId || string.IsNullOrEmpty(salesLine.InventoryLocationId))
                                            //  && itemAvailability.VariantInventoryDimensionId == salesLine.InventoryDimensionId
                                            && itemAvailability.AvailableQuantity >= salesLine.Quantity)
                                        {
                                            checkDict.Add(salesLine.LineId, true);
                                            break;
                                        }
                                    }
                                }

                                if (!checkDict.ContainsKey(salesLine.LineId))
                                {
                                    checkDict.Add(salesLine.LineId, false);
                                }
                            }

                            if (checkDict.ContainsValue(false))
                            {
                                throw new CartValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidDeliveryMode, String.Format("Delivery mode {0} is not applicable since some product are out stock", salesTransaction.DeliveryMode));
                            }
                        }
                    }
                }
            }