/// <summary> /// Voids the gift card operation. /// </summary> /// <param name="context">Request context.</param> /// <param name="salesTransaction">The sales transaction.</param> /// <param name="giftCardId">The identifier of the gift card to be voided.</param> /// <param name="giftCardCurrencyCode">Gift card's currency code.</param> /// <param name="giftCardOperation">The type of gift card operation(Issue or AddTo).</param> /// <param name="amount">The amount on the gift card.</param> internal static void VoidGiftCardOperation(RequestContext context, SalesTransaction salesTransaction, string giftCardId, string giftCardCurrencyCode, GiftCardOperationType giftCardOperation, decimal amount) { ThrowIf.Null(context, "context"); ThrowIf.Null(salesTransaction, "salesTransaction"); switch (giftCardOperation) { case GiftCardOperationType.AddTo: { GiftCardWorkflowHelper.VoidAddToGiftCardOperation(context, salesTransaction, giftCardId, giftCardCurrencyCode, amount); // Unlock the gift card. GiftCardWorkflowHelper.UnlockGiftCard(context, giftCardId); break; } case GiftCardOperationType.Issue: { GiftCardWorkflowHelper.VoidIssuedGiftCardOperation(context, giftCardId); // No need to unlock gift card in this case because voiding will result gift card entry being deleted. break; } default: throw new InvalidOperationException(string.Format("Gift card operation {0} is not supported.", giftCardOperation)); } }
/// <summary> /// Unlocks the gift cards that are on active sales lines. /// </summary> /// <param name="context">The context.</param> /// <param name="salesTransaction">The sales transaction.</param> internal static void UnlockGiftCardsOnActiveSalesLines(RequestContext context, SalesTransaction salesTransaction) { ThrowIf.Null(context, "context"); ThrowIf.Null(salesTransaction, "salesTransaction"); IEnumerable <SalesLine> activeGiftCardLines = salesTransaction.SalesLines.Where(l => l.IsGiftCardLine && !l.IsVoided); foreach (SalesLine line in activeGiftCardLines) { GiftCardWorkflowHelper.UnlockGiftCard(context, line.GiftCardId); } }
/// <summary> /// Voids active gift card lines on the transaction. /// </summary> /// <param name="context">The context.</param> /// <param name="salesTransaction">The sales transaction.</param> internal static void VoidGiftCardSalesLines(RequestContext context, SalesTransaction salesTransaction) { ThrowIf.Null(context, "context"); ThrowIf.Null(salesTransaction, "salesTransaction"); IEnumerable <SalesLine> activeGiftCardLines = salesTransaction.SalesLines.Where(l => l.IsGiftCardLine && !l.IsVoided); foreach (SalesLine line in activeGiftCardLines) { GiftCardWorkflowHelper.VoidGiftCardOperation(context, salesTransaction, line.GiftCardId, line.GiftCardCurrencyCode, line.GiftCardOperation, line.TotalAmount); } }
/// <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> /// 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); } }