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