/// <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> /// Validates the required reason code lines filled. /// </summary> /// <param name="requestContext">The request context.</param> /// <param name="salesTransaction">The sales transaction.</param> /// <exception cref="ConfigurationException">Required Service missing.</exception> /// <exception cref="DataValidationException">One or more reason codes required for the transaction are missing.</exception> public static void ValidateRequiredReasonCodeLinesFilled(RequestContext requestContext, SalesTransaction salesTransaction) { ThrowIf.Null(requestContext, "requestContext"); ThrowIf.Null(salesTransaction, "salesTransaction"); var serviceRequest = new CalculateRequiredReasonCodesServiceRequest(salesTransaction, ReasonCodeSourceType.None); var serviceResponse = requestContext.Execute <CalculateRequiredReasonCodesServiceResponse>(serviceRequest); ReasonCodesWorkflowHelper.ThrowIfRequiredReasonCodesMissing(serviceResponse); }
/// <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> /// Helper methods to calculates the required reason codes. /// </summary> /// <param name="requestContext">The request context.</param> /// <param name="serviceRequest">The service request.</param> /// <exception cref="ConfigurationException">Required Service missing: {0}.</exception> private static void CalculateRequiredReasonCodesHelper(RequestContext requestContext, CalculateRequiredReasonCodesServiceRequest serviceRequest) { ThrowIf.Null(serviceRequest.SalesTransaction, "serviceRequest.SalesTransaction"); // Reason codes are only calculated for retail stores and carts that are not customer orders. if ((requestContext.GetChannelConfiguration().ChannelType == RetailChannelType.RetailStore) && (serviceRequest.SalesTransaction.CartType != CartType.CustomerOrder)) { var serviceResponse = requestContext.Execute <CalculateRequiredReasonCodesServiceResponse>(serviceRequest); ReasonCodesWorkflowHelper.ThrowIfRequiredReasonCodesMissing(serviceResponse); } }
/// <summary> /// Adds or updates the reason code lines on the sales transaction. /// </summary> /// <param name="request">The save tender line request.</param> /// <param name="salesTransaction">The sales transaction.</param> private void AddOrUpdateReasonCodeLinesOnTransaction(SaveTenderLineRequest request, SalesTransaction salesTransaction) { // Add or update any incoming reason codes on the transaction. if (request.ReasonCodeLines != null && request.ReasonCodeLines.Any()) { ReasonCodesWorkflowHelper.AddOrUpdateReasonCodeLinesOnTransaction( salesTransaction, new Cart { Id = request.CartId, ReasonCodeLines = request.ReasonCodeLines.ToList() }); } }
/// <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> /// 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> /// 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)); }
/// <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> /// 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)); }
protected override CreateOrderFromCartResponse Process(CreateOrderFromCartRequest request) { ThrowIf.Null(request, "request"); ThrowIf.Null(request.CartId, "request.CartId"); List <TenderLine> tenderLines = new List <TenderLine>(); // Get the Sales Transaction. SalesTransaction salesTransaction = null; ExecutionHandler( delegate { PopulateSalesTransaction(this.Context, request.CartId, request.ReceiptEmailAddress, out salesTransaction); }, SubmitOrderOperationType.GetSalesTransaction.ToString()); // Validate sales order for creation. ExecutionHandler( delegate { OrderWorkflowHelper.ValidateContextForCreateOrder(this.Context, salesTransaction); }, SubmitOrderOperationType.ValidateContextForCreateOrder.ToString()); // Validate addresses. ExecutionHandler( delegate { ShippingHelper.ValidateAndResolveAddresses(this.Context, salesTransaction); }, SubmitOrderOperationType.ValidateAndResolveAddresses.ToString()); // Add missing dependencies to the sales transaction. ExecutionHandler( delegate { OrderWorkflowHelper.FillMissingRequirementsForOrder(this.Context, salesTransaction); }, SubmitOrderOperationType.FillMissingRequirementsForOrder.ToString()); // Validate addresses for shipping. ExecutionHandler( delegate { ShippingHelper.ValidateShippingInformation(this.Context, salesTransaction); }, SubmitOrderOperationType.ValidateShippingAddresses.ToString()); // Validate required reason code lines has been filled. ExecutionHandler( () => ReasonCodesWorkflowHelper.ValidateRequiredReasonCodeLinesFilled(this.Context, salesTransaction), SubmitOrderOperationType.ValidateReasonCodes.ToString()); // Authorize payments. ExecutionHandler( delegate { tenderLines = OrderWorkflowHelper.ProcessPendingOrderPayments(this.Context, salesTransaction, request.CartTenderLines); }, SubmitOrderOperationType.AuthorizePayments.ToString()); SalesOrder salesOrder = null; try { // Create order and add all authorization payment blobs. ExecutionHandler( delegate { salesOrder = OrderWorkflowHelper.CreateSalesOrder(this.Context, salesTransaction); }, SubmitOrderOperationType.CreateSaleOrderInCrt.ToString()); } catch (Exception ex) { try { // Cancel the payment authorizations OrderWorkflowHelper.CancelPayments(this.Context, salesTransaction, tenderLines, request.CartTenderLines); } catch (PaymentException cancelPaymentsEx) { // Inside of CancelPayments() we always wrap Exception as PaymentException. RetailLogger.Log.CrtWorkflowCancelingPaymentFailure(ex, cancelPaymentsEx); } throw; } // We also need to delete the shopping cart. CartWorkflowHelper.TryDeleteCart( this.Context, new SalesTransaction { Id = request.CartId, TerminalId = salesTransaction.TerminalId, CustomerId = salesTransaction.CustomerId, }); return(new CreateOrderFromCartResponse(salesOrder)); }
/// <summary> /// Processes the void cart lines request. /// </summary> /// <param name="context">The context.</param> /// <param name="request">The request.</param> /// <param name="salesTransaction">Sales transaction.</param> private static void ProcessVoidCartLinesRequest(RequestContext context, SaveCartLinesRequest request, SalesTransaction salesTransaction) { Dictionary <string, SalesLine> salesLinesById = salesTransaction.SalesLines.ToDictionary(sl => sl.LineId, sl => sl); // Keeps track of the enabled (unvoided) sales lines. var enabledSalesLines = new List <SalesLine>(); foreach (CartLine cartLine in request.CartLines) { var salesLine = salesLinesById[cartLine.LineId]; if (salesTransaction.CartType == CartType.CustomerOrder && salesTransaction.CustomerOrderMode != CustomerOrderMode.CustomerOrderCreateOrEdit && salesTransaction.CustomerOrderMode != CustomerOrderMode.QuoteCreateOrEdit && cartLine.IsVoided) { string errorMessage = "Cart line can be voided only at the time of CustomerOrderCreateOrEdit or QuoteCreateOrEdit."; throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidCustomerOrderModeForVoidProducts, errorMessage); } if ((cartLine.IsCustomerAccountDeposit || salesTransaction.CartType == CartType.AccountDeposit) && cartLine.IsVoided) { throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_CustomerAccountDepositCannotBeVoided, "Cart line cannot be voided for customer account deposit transaction."); } if (!cartLine.IsVoided && salesLine.IsVoided) { // Unvoid if (cartLine.IsGiftCardLine) { throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_GiftCardLineVoidReversalNotSupported, "Gift card line cannot be unvoided."); } // Unvoid the sales line. salesLine.IsVoided = false; // Unvoid the linked products' sales lines if any. if (salesLine.LineIdsLinkedProductMap.Any()) { foreach (string lineId in salesLine.LineIdsLinkedProductMap.Keys) { if (salesLinesById[lineId] != null) { salesLinesById[lineId].IsVoided = false; enabledSalesLines.Add(salesLinesById[lineId]); } else { throw new DataValidationException( DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_ObjectNotFound, string.Format("Sales line of the linked product with id : {0} was not found.", lineId)); } } } // Add the new line to the collection for attribute updates. enabledSalesLines.Add(salesLine); // Perform additional side-effect logic here (i.e. issue gift cart etc.) } else { // Process reason code lines on the cart line. ReasonCodesWorkflowHelper.AddOrUpdateReasonCodeLinesOnSalesLine(salesLine, cartLine, salesTransaction.Id); // Calculate the required reason codes for voiding sales lines. ReasonCodesWorkflowHelper.CalculateRequiredReasonCodesOnSalesLine(context, salesTransaction, salesLine, ReasonCodeSourceType.VoidItem); // Void the sales line. salesLine.IsVoided = true; // Void the linked products' sales lines if any. if (salesLine.LineIdsLinkedProductMap.Any()) { foreach (string lineId in salesLine.LineIdsLinkedProductMap.Keys) { if (salesLinesById[lineId] != null) { salesLinesById[lineId].IsVoided = true; } else { throw new DataValidationException( DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_ObjectNotFound, string.Format("Sales line of the linked product with id : {0} was not found.", lineId)); } } } // Void gift card lines. if (salesLine.IsGiftCardLine) { GiftCardWorkflowHelper.VoidGiftCardOperation(context, salesTransaction, salesLine.GiftCardId, salesLine.GiftCardCurrencyCode, salesLine.GiftCardOperation, salesLine.TotalAmount); } CartWorkflowHelper.LogAuditEntry( context, "SaveCartLinesRequestHandler.ProcessVoidCartLinesRequest", string.Format("Line item voided: {0}, #: {1}", salesLine.Description, salesLine.LineNumber)); } } // Set default attributes from order header if there are any enabled sales lines. if (enabledSalesLines.Any()) { CartWorkflowHelper.SetDefaultDataOnSalesLines(context, salesTransaction, enabledSalesLines); } }