/// <summary> /// Authorizes the payment. /// </summary> /// <param name="request">The request.</param> /// <returns>A response containing the authorized tender line.</returns> private static AuthorizePaymentServiceResponse AuthorizePayment(AuthorizePaymentServiceRequest request) { if (request == null) { throw new ArgumentNullException("request"); } request.TenderLine.Status = TenderLineStatus.Committed; request.TenderLine.IsVoidable = true; // For check payments, there is no extra step needed for authorizing. return(new AuthorizePaymentServiceResponse(request.TenderLine)); }
/// <summary> /// Authorizes the payment. /// </summary> /// <param name="request">The request.</param> /// <returns>A response containing the authorized tender line.</returns> private static AuthorizePaymentServiceResponse AuthorizePayment(AuthorizePaymentServiceRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (request.TenderLine.Currency.Equals(request.RequestContext.GetChannelConfiguration().Currency, StringComparison.OrdinalIgnoreCase)) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidPaymentRequest, "Currency payment requires currency to be different from channel currency."); } request.TenderLine.Status = TenderLineStatus.Committed; request.TenderLine.IsVoidable = true; return(new AuthorizePaymentServiceResponse(request.TenderLine)); }
/// <summary> /// Authorizes the payment. /// </summary> /// <param name="request">The request.</param> /// <returns>A response containing the authorized tender line.</returns> private static AuthorizePaymentServiceResponse AuthorizePayment(AuthorizePaymentServiceRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (request.TenderLine.Amount > 0) { // Positive amount indicates credit memo payment. // Payment always uses full amount. Actual amount will be returned as part of tender line on response. string orgUnitNumber = request.RequestContext.GetOrgUnit().OrgUnitNumber; var lockRequest = new LockCreditMemoRealtimeRequest( request.TenderLine.CreditMemoId, orgUnitNumber, request.RequestContext.GetTerminal().TerminalId); CreditMemo creditMemo = request.RequestContext.Execute <SingleEntityDataServiceResponse <CreditMemo> >(lockRequest).Entity; request.TenderLine.Amount = creditMemo.Balance; request.TenderLine.Currency = creditMemo.CurrencyCode; request.TenderLine.Status = TenderLineStatus.PendingCommit; request.TenderLine.IsVoidable = true; } else { // For negative amount issue new credit memo if (!string.IsNullOrWhiteSpace(request.TenderLine.CreditMemoId)) { throw new PaymentException( PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidPaymentRequest, "Refund to existing credit memo is not allowed. To issue credit memo identifier should be left blank."); } string creditMemoId = IssueCreditMemo(request.RequestContext, decimal.Negate(request.TenderLine.Amount), request.TenderLine.Currency, request.Transaction.Id, request.Transaction.ReceiptId); request.TenderLine.CreditMemoId = creditMemoId; request.TenderLine.Status = TenderLineStatus.Committed; request.TenderLine.IsVoidable = false; } return(new AuthorizePaymentServiceResponse(request.TenderLine)); }
private static void OnAuthorizePaymentExecuting(AuthorizePaymentServiceRequest request) { // Call to get tender types (cached). var dataServiceRequest = new GetChannelTenderTypesDataRequest(request.RequestContext.GetPrincipal().ChannelId, QueryResultSettings.AllRecords); var response = request.RequestContext.Execute <EntityDataServiceResponse <TenderType> >(dataServiceRequest); TenderType tenderType = response.PagedEntityCollection.Results.Single(t => string.Equals(t.TenderTypeId, request.TenderLine.TenderTypeId, StringComparison.OrdinalIgnoreCase)); switch (tenderType.OperationType) { case RetailOperation.PayCreditMemo: if (request.TenderLine.Amount < 0) { request.RequestContext.Execute <NullResponse>(new CheckAccessServiceRequest(RetailOperation.IssueCreditMemo)); } break; default: request.RequestContext.Execute <NullResponse>(new CheckAccessServiceRequest(tenderType.OperationType)); break; } }
/// <summary> /// Authorizes the payment. /// </summary> /// <param name="request">The request.</param> /// <returns>A response containing the authorized tender line.</returns> private static AuthorizePaymentServiceResponse AuthorizePayment(AuthorizePaymentServiceRequest request) { if (request == null) { throw new ArgumentNullException("request"); } TenderType tenderType = GetTenderType(request.RequestContext, request.TenderLine.TenderTypeId); // Resolve payment service. IRequestHandler paymentService = ResolvePaymentService(request.RequestContext, request.GetType(), request.TenderLine.TenderTypeId); // Calculate amount to be authorized (some tender type like currency and credit memo do not have amount set on tender line). CalculatePaymentAmountServiceRequest calculateAmountRequest = new CalculatePaymentAmountServiceRequest(request.TenderLine); CalculatePaymentAmountServiceResponse calculateAmountResponse = request.RequestContext.Execute <CalculatePaymentAmountServiceResponse>(calculateAmountRequest, paymentService); request.TenderLine = calculateAmountResponse.TenderLine; if (!request.TenderLine.IsPreProcessed) { request.TenderLine.Amount = RoundAmountByTenderType(request.RequestContext, request.TenderLine.TenderTypeId, request.TenderLine.Amount, isChange: false); } // Update tender lines with amounts and exchange rates for channel and company currencies. CalculateTenderLineCurrencyAmounts(request.TenderLine, request.RequestContext); if (request.TenderLine.Amount == 0) { throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidAmount, "An amount of zero is not allowed on the tenderline."); } // Do amount validation. if (!request.SkipLimitValidation) { var validateRequest = new ValidateTenderLineForAddServiceRequest(request.Transaction, request.TenderLine, tenderType); request.RequestContext.Execute <NullResponse>(validateRequest); } // Check tender line status AuthorizePaymentServiceResponse response; if (request.TenderLine.Status == TenderLineStatus.PendingCommit || request.TenderLine.Status == TenderLineStatus.Committed || request.TenderLine.Status == TenderLineStatus.Voided) { // Return the tender line directly if already authorized response = new AuthorizePaymentServiceResponse(request.TenderLine); } else { // Process authorization. response = request.RequestContext.Execute <AuthorizePaymentServiceResponse>(request, paymentService); } // If we have cashback amount set on the tender line, we add it to the amount on the tender line after authorization // and set the cashback amount on the tender line to 0. This is because we do not cashback field in the // RetailTransactionPaymentTrans table. We are doing this at this point to mimic EPOS. if (response.TenderLine.CashBackAmount != 0) { CalculateAmountsWithCashBack(response.TenderLine, request.RequestContext); } return(response); }
/// <summary> /// Authorizes the payment. /// </summary> /// <param name="request">The request.</param> /// <returns>A response containing the authorized tender line.</returns> private static AuthorizePaymentServiceResponse AuthorizePayment(AuthorizePaymentServiceRequest request) { if (request == null) { throw new ArgumentNullException("request"); } TenderLine tenderLine = request.TenderLine; if (tenderLine == null) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidPaymentRequest, "Customer account payment requires tender line."); } if (string.IsNullOrWhiteSpace(tenderLine.CustomerId)) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidPaymentRequest, "Customer account payment requires CustomerId to be set on tender line."); } SalesTransaction transaction = request.Transaction; if (transaction.CartType == CartType.CustomerOrder && (transaction.CustomerOrderMode == CustomerOrderMode.CustomerOrderCreateOrEdit || transaction.CustomerOrderMode == CustomerOrderMode.Cancellation)) { throw new PaymentException( PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_CustomerAccountPaymentIsNotAllowedForCustomerOrderDepositAndCancellation, string.Format("Customer account payment cannot be used to pay customer order deposit or cancellation (current mode {0}).", transaction.CustomerOrderMode)); } if (string.IsNullOrWhiteSpace(transaction.CustomerId)) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidPaymentRequest, "Customer account payment requires CustomerId to be set on cart."); } Customer customerOnTransaction = GetCustomer(request.RequestContext, transaction.CustomerId); if (customerOnTransaction == null) { throw new PaymentException( PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidPaymentRequest, string.Format(CultureInfo.InvariantCulture, "Customer with id {0} was not found.", transaction.CustomerId)); } ValidateCustomerForPayment(customerOnTransaction); bool useInvoiceAccount = !string.IsNullOrWhiteSpace(customerOnTransaction.InvoiceAccount); string customerAccountToCharge = useInvoiceAccount ? customerOnTransaction.InvoiceAccount : customerOnTransaction.AccountNumber; if (!tenderLine.CustomerId.Equals(customerAccountToCharge, StringComparison.OrdinalIgnoreCase)) { // Someone is trying to pay with unathorized account throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_PaymentUsingUnauthorizedAccount, "Customer account payment requires its own account or matching invoice account on a tender line."); } CheckIfPaymentExceedsBalance(request.RequestContext, customerOnTransaction, useInvoiceAccount, tenderLine); // Looks like request has successfully validated tenderLine.Status = TenderLineStatus.Committed; tenderLine.IsVoidable = true; return(new AuthorizePaymentServiceResponse(tenderLine)); }
/// <summary> /// Authorizes the payment. /// This step checks whether the loyalty card has enough reward points to redeem. If yes, it decides the points /// to redeem based on redeem ranking. /// </summary> /// <param name="request">The request.</param> /// <returns>A response containing the authorized tender line.</returns> private static AuthorizePaymentServiceResponse AuthorizePayment(AuthorizePaymentServiceRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (request.TenderLine == null) { throw new ArgumentException("request.TenderLine cannot be null."); } if (request.RequestContext == null) { throw new ArgumentException("request.RequestContext cannot be null."); } if (request.Transaction == null) { throw new ArgumentException("request.Transaction cannot be null."); } // Check tender amount. if (request.TenderLine.Amount == 0m) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidPaymentRequest, "The tender amount must be greater than zero."); } // Check tender currency. if (string.IsNullOrWhiteSpace(request.TenderLine.Currency)) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidPaymentRequest, "The tender currency is missing."); } // Check if the transaction already has loyalty payments var activeTenderLines = request.Transaction.ActiveTenderLines; if (activeTenderLines != null && activeTenderLines.Any(line => !string.IsNullOrWhiteSpace(line.LoyaltyCardId))) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_NoMoreThanOneLoyaltyTender, "The transaction cannot contain more than one loyalty payment line."); } SalesOrder salesOrder = request.Transaction as SalesOrder; if (salesOrder != null && salesOrder.HasLoyaltyPayment && (salesOrder.CustomerOrderMode != CustomerOrderMode.Cancellation || salesOrder.AmountDue > decimal.Zero)) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_NoMoreThanOneLoyaltyTender, "The transaction cannot contain more than one loyalty payment line."); } // Check whether the loyalty card is valid. var getLoyaltyCardDataRequest = new GetLoyaltyCardDataRequest(request.TenderLine.LoyaltyCardId); LoyaltyCard loyaltyCard = request.RequestContext.Execute <SingleEntityDataServiceResponse <LoyaltyCard> >(getLoyaltyCardDataRequest).Entity; if (loyaltyCard == null || string.IsNullOrWhiteSpace(loyaltyCard.CardNumber)) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidLoyaltyCardNumber, "The loyalty card number does not exists."); } // Check whether the loyalty card is blocked. if (loyaltyCard.CardTenderType == LoyaltyCardTenderType.Blocked) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_BlockedLoyaltyCard, "The loyalty card is blocked."); } if (loyaltyCard.CardTenderType == LoyaltyCardTenderType.NoTender) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_NoTenderLoyaltyCard, "The loyalty card is not allowed for payment."); } // Calculate redeem trans and fill in the sales transaction. if (request.TenderLine.Amount >= 0) { LoyaltyServiceHelper.FillInLoyaltyRewardPointLinesForPayment( request.RequestContext, request.Transaction, loyaltyCard, request.TenderLine.Amount, request.TenderLine.Currency); } else { LoyaltyServiceHelper.FillInLoyaltyRewardPointLinesForRefund( request.RequestContext, request.Transaction, loyaltyCard, request.TenderLine.Amount, request.TenderLine.Currency); } // Set Card Type Id for Loyalty Card if not set by the client. if (request.TenderLine.CardTypeId == null) { string tenderTypeId = request.TenderLine.TenderTypeId; var cardTypeDataRequest = new GetCardTypeDataRequest(QueryResultSettings.AllRecords); var cardTypeInfoResponse = request.RequestContext.Execute <EntityDataServiceResponse <CardTypeInfo> >(cardTypeDataRequest); IEnumerable <CardTypeInfo> cardTypes = cardTypeInfoResponse.PagedEntityCollection.Results; CardTypeInfo loyaltyCardTypeInfo = cardTypes.FirstOrDefault(cardType => cardType.PaymentMethodId == tenderTypeId); if (loyaltyCardTypeInfo == null) { throw new ConfigurationException(ConfigurationErrors.Microsoft_Dynamics_Commerce_Runtime_ConfigurationSettingNotFound, "The loyalty card payment as a tender type card is not configured for the channel."); } request.TenderLine.CardTypeId = loyaltyCardTypeInfo.TypeId; } // Authorize. request.TenderLine.Status = TenderLineStatus.PendingCommit; request.TenderLine.IsVoidable = true; return(new AuthorizePaymentServiceResponse(request.TenderLine)); }
/// <summary> /// Authorizes the payment. /// </summary> /// <param name="request">The request.</param> /// <returns>A response containing the authorized tender line.</returns> private static AuthorizePaymentServiceResponse AuthorizePayment(AuthorizePaymentServiceRequest request) { if (request == null) { throw new ArgumentNullException("request"); } ValidateNotAlreadyAdded(request.Transaction, request.TenderLine.GiftCardId); var lockGiftCardRealtimeRequest = new LockGiftCardRealtimeRequest( request.TenderLine.GiftCardId, request.RequestContext.GetPrincipal().ChannelId, request.RequestContext.GetTerminal() == null ? string.Empty : request.RequestContext.GetTerminal().TerminalId); GiftCard giftCard = request.RequestContext.Execute <SingleEntityDataServiceResponse <GiftCard> >(lockGiftCardRealtimeRequest).Entity; GetCurrencyValueServiceResponse convertAmountToGiftCardCurrencyResponse; try { if (!request.TenderLine.Currency.Equals(request.RequestContext.GetChannelConfiguration().Currency, StringComparison.OrdinalIgnoreCase)) { throw new PaymentException( PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_GiftCardCurrencyMismatch, string.Format("Gift card payments are only supported in channel currency. Currency requested: {0}", request.TenderLine.Currency)); } convertAmountToGiftCardCurrencyResponse = ToGiftCardCurrency(request.RequestContext, request.TenderLine.Amount, giftCard.CardCurrencyCode); // Check if gift card has enough balance. if (giftCard.BalanceInCardCurrency < convertAmountToGiftCardCurrencyResponse.RoundedConvertedAmount) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_PaymentAmountExceedsGiftBalance); } } catch { try { // At this point payment failed but gift card is already locked. // Need to unlock gift card (better as void payment) so it can be used in future. var voidGiftCardPaymentRequest = new VoidGiftCardPaymentRealtimeRequest( request.TenderLine.GiftCardId, request.RequestContext.GetPrincipal().ChannelId, request.RequestContext.GetTerminal() == null ? string.Empty : request.RequestContext.GetTerminal().TerminalId); request.RequestContext.Execute <NullResponse>(voidGiftCardPaymentRequest); } catch (Exception ex) { RetailLogger.Log.CrtServicesGiftCardServiceUnlockGiftCardFailure(ex); } throw; } request.TenderLine.Currency = giftCard.CardCurrencyCode; request.TenderLine.AmountInTenderedCurrency = convertAmountToGiftCardCurrencyResponse.RoundedConvertedAmount; request.TenderLine.ExchangeRate = convertAmountToGiftCardCurrencyResponse.ExchangeRate; request.TenderLine.Status = TenderLineStatus.PendingCommit; request.TenderLine.IsVoidable = true; return(new AuthorizePaymentServiceResponse(request.TenderLine)); }