private TransactionResponse ProcessVoidRequest(TransactionData transData, ITokenizedPayment payment) =>
 new TransactionResponse(
     _authorizeTokenExService.ProcessVoidRequest(
         payment.Properties[AuthorizeTokenExGateway.ProviderProfileIdPropertyName] as string,
         string.Empty,
         transData.transId),
     false);
        public TransactionResponse Process(
            IOrderGroup orderGroup,
            TransactionRequest transactionRequest,
            TransactionData transactionData,
            decimal amount,
            ITokenizedPayment payment)
        {
            switch (transactionData.type)
            {
            case TransactionType.Authorization:
                return(ProcessAuthorizeRequest(orderGroup, transactionData, payment, amount));

            case TransactionType.Capture:
                return(ProcessPriorCaptureRequest(transactionRequest, transactionData, amount));

            case TransactionType.Sale:
                return(ProcessSaleRequest(orderGroup, transactionData, payment, amount));

            case TransactionType.Credit:
                return(ProcessCreditRequest(transactionRequest, transactionData, payment, amount));

            case TransactionType.Void:
                return(ProcessVoidRequest(transactionData, payment));

            case TransactionType.CaptureOnly:
                return(ProcessCaptureOnlyRequest(transactionRequest, transactionData, payment, amount));

            default:
                throw new NotImplementedException("Not implemented TransactionType: " + transactionData.type);
            }
        }
Ejemplo n.º 3
0
 public TokenizationPaymentModel(ITokenizedPayment payment, Currency orderGroupCurrency)
     : base(payment, orderGroupCurrency)
 {
     Token           = payment.Token;
     ExpirationMonth = payment.ExpirationMonth;
     ExpirationYear  = payment.ExpirationYear;
 }
        private AuthorizeNet.Order CreatePaymentOrder(IOrderGroup orderGroup, TransactionData transactionData, ITokenizedPayment payment, decimal orderAmount)
        {
            var customer = _authorizeTokenExService.CreateCustomer(transactionData.invoiceNum, payment.BillingAddress);

            var address = Utilities.ToAuthorizeNetAddress(payment.BillingAddress);

            customer.BillingAddress = address;
            _authorizeTokenExService.UpdateCustomer(customer);

            var shippingAddress = orderGroup.Forms.First().Shipments.First().ShippingAddress;

            if (shippingAddress == null)
            {
                throw new PaymentException(PaymentException.ErrorType.ConfigurationError, "", "Shipping address was not specified.");
            }

            var paymentProfileId  = AddCreditCard(orderGroup, customer.ProfileID, payment.Token, payment.ExpirationMonth, payment.ExpirationYear);
            var shippingAddressId = AddShippingAddress(customer.ProfileID, Utilities.ToAuthorizeNetAddress(shippingAddress));

            var currency         = orderGroup.Currency;
            var market           = _marketService.GetMarket(orderGroup.MarketId);
            var merchantCurrency = _authorizeTokenExService.GetMerchantCurrency();
            var shippingTotal    = Utilities.ConvertMoney(orderGroup.GetShippingTotal(_orderGroupCalculator), merchantCurrency);
            var salesTaxTotal    = Utilities.ConvertMoney(
                new Money(orderGroup.Forms.Sum(form => form.Shipments.Sum(shipment =>
                                                                          _shippingCalculator.GetSalesTax(shipment, market, currency).Amount)), currency).Round(),
                merchantCurrency);
            var taxTotal = Utilities.ConvertMoney(orderGroup.GetTaxTotal(_orderGroupCalculator), merchantCurrency);

            var order = new AuthorizeNet.Order(customer.ProfileID, paymentProfileId, shippingAddressId)
            {
                Amount         = orderAmount - taxTotal,
                SalesTaxAmount = salesTaxTotal,
                PONumber       = transactionData.purchaseOrderNum,
                InvoiceNumber  = transactionData.invoiceNum,
                ShippingAmount = shippingTotal + (orderGroup.PricesIncludeTax ? 0 : taxTotal - salesTaxTotal)
            };

            var orderedLineItems    = orderGroup.GetAllLineItems().OrderBy(x => x.Quantity).ToList();
            var largestQuantityItem = orderedLineItems.LastOrDefault();

            var lineItemsAmount             = 0m;
            var amountWithoutLargestQtyItem = 0m;
            var settleSubTotalExclTax       = orderAmount - order.ShippingAmount - order.SalesTaxAmount;
            var isFirstLineItem             = true;
            var factor        = (decimal)Math.Pow(10, DecimalDigit);
            var roundingDelta = 1 / factor;
            var itemPriceExcludingTaxMapping = GetPriceExcludingTax(orderGroup);

            foreach (var lineItem in orderedLineItems)
            {
                var itemCode     = lineItem.Code;
                var itemQuantity = Convert.ToInt32(lineItem.Quantity);
                var displayName  = string.IsNullOrEmpty(lineItem.DisplayName) ? itemCode : lineItem.DisplayName;
                var description  = (lineItem as Mediachase.Commerce.Orders.LineItem)?.Description ?? string.Empty;

                if (lineItem.IsGift)
                {
                    itemCode    = $"Gift: {itemCode}";
                    displayName = $"Gift: {displayName}";
                    description = $"Gift: {description}";
                }

                itemCode    = Utilities.StripPreviewText(itemCode, 31);
                displayName = Utilities.StripPreviewText(displayName, 31);
                description = Utilities.StripPreviewText(description, 255);

                // Calculate unit price.
                var unitPrice = Utilities.ConvertMoney(
                    new Money(currency.Round(itemPriceExcludingTaxMapping[lineItem.LineItemId] / lineItem.Quantity, DecimalDigit), currency),
                    merchantCurrency);

                lineItemsAmount += unitPrice * lineItem.Quantity;

                if (lineItem.LineItemId != largestQuantityItem.LineItemId)
                {
                    amountWithoutLargestQtyItem = lineItemsAmount;
                }

                // In case we have Rounding Differences between rounding Total Amount (orderAmount - amount requested for settlement)
                // and rounding each lineItem unit price (amount authorized), need to recalculate unit price of item has largest quantity.
                if (lineItem.LineItemId == largestQuantityItem.LineItemId && lineItemsAmount < settleSubTotalExclTax)
                {
                    // Choose largestQuantityItem to make the unitPrice difference before and after recalculate smallest.
                    unitPrice = (settleSubTotalExclTax - amountWithoutLargestQtyItem) / largestQuantityItem.Quantity;

                    // Round up to make sure amount authorized >= requested for settlement amount.
                    unitPrice = merchantCurrency.Round(unitPrice + roundingDelta, DecimalDigit);
                }

                if (!isFirstLineItem)
                {
                    // If the lineitem price to add to the total exceed the Amount chosen
                    // for the payment. The line item price is adjusted, since it will be covered by other payment method.
                    if (unitPrice * lineItem.Quantity + order.Total > order.Amount)
                    {
                        var lineItemPrice = orderAmount - order.Total;

                        // If this is the last item, then we need to round up to make sure amount authorized >= requested for settlement amount.
                        if (lineItem.LineItemId == largestQuantityItem.LineItemId)
                        {
                            unitPrice = merchantCurrency.Round(lineItemPrice / lineItem.Quantity + roundingDelta, DecimalDigit);
                        }
                        else
                        {
                            unitPrice = merchantCurrency.Round(lineItemPrice / lineItem.Quantity, DecimalDigit);
                        }
                    }
                }

                // Note that order total calculated from authorized.net order constructor is recalculated by adding line items.
                order.AddLineItem(itemCode, displayName, description, itemQuantity, unitPrice, null);

                // We need to handle the case of first line item after being added to the order
                // since order total is recalculated when is added to the order.
                if (isFirstLineItem)
                {
                    // If with the first line item the amount chosen for the payment is exceeding
                    // the price added to the line item then should be the amount chosen.
                    if (order.Total > orderAmount)
                    {
                        // In case the order has only one line item, then we need to round up to make sure amount authorized >= requested for settlement amount.
                        if (lineItem.LineItemId == largestQuantityItem.LineItemId)
                        {
                            unitPrice = merchantCurrency.Round(settleSubTotalExclTax / lineItem.Quantity + roundingDelta, DecimalDigit);
                        }
                        else
                        {
                            unitPrice = merchantCurrency.Round(settleSubTotalExclTax / lineItem.Quantity, DecimalDigit);
                        }

                        order.RemoveLineItem(itemCode);
                        order.AddLineItem(itemCode, displayName, description, itemQuantity, unitPrice, null);
                    }
                }
                isFirstLineItem = false;
            }
            payment.Properties[AuthorizeTokenExGateway.ProviderProfileIdPropertyName] = customer.ProfileID;

            return(order);
        }
        private TransactionResponse ProcessCreditRequest(TransactionRequest transactionRequest, TransactionData transData, ITokenizedPayment payment, decimal amount)
        {
            var transactionDetail = GetTransactionDetails(transData, transactionRequest);

            if (transactionDetail.transactionStatus != AuthorizeTokenExGateway.SettledStatus)
            {
                throw new PaymentException(PaymentException.ErrorType.StatusError, "", "Refund payment requires transaction status to be settled.");
            }

            // clone the Refund method in order to set InvoiceNumber
            var request = new AuthorizeNet.APICore.createCustomerProfileTransactionRequest
            {
                transaction = new AuthorizeNet.APICore.profileTransactionType
                {
                    Item = new AuthorizeNet.APICore.profileTransRefundType
                    {
                        amount            = amount,
                        customerProfileId = payment.Properties[AuthorizeTokenExGateway.ProviderProfileIdPropertyName] as string,
                        transId           = transData.transId,
                        order             = new AuthorizeNet.APICore.orderExType
                        {
                            purchaseOrderNumber = transData.purchaseOrderNum,
                            invoiceNumber       = transData.invoiceNum
                        }
                    }
                }
            };

            return(new TransactionResponse(_authorizeTokenExService.SendRequest(request), false));
        }
        private TransactionResponse ProcessCaptureOnlyRequest(TransactionRequest transactionRequest, TransactionData transData, ITokenizedPayment payment, decimal amount)
        {
            if (IsTransactionCapturedOrSettled(transData, transactionRequest))
            {
                return(new TransactionResponse(null, true));
            }

            // clone the capture method in order to set InvoiceNumber
            var request = new AuthorizeNet.APICore.createCustomerProfileTransactionRequest
            {
                transaction = new AuthorizeNet.APICore.profileTransactionType
                {
                    Item = new AuthorizeNet.APICore.profileTransCaptureOnlyType
                    {
                        approvalCode      = transData.AuthorizationCode,
                        customerProfileId = payment.Properties[AuthorizeTokenExGateway.ProviderProfileIdPropertyName] as string,
                        amount            = amount,
                        order             = new AuthorizeNet.APICore.orderExType
                        {
                            purchaseOrderNumber = transData.purchaseOrderNum,
                            invoiceNumber       = transData.invoiceNum
                        }
                    }
                }
            };

            return(new TransactionResponse(_authorizeTokenExService.SendRequest(request), false));
        }
        private TransactionResponse ProcessSaleRequest(IOrderGroup orderGroup, TransactionData transactionData, ITokenizedPayment payment, decimal amount)
        {
            var order = CreatePaymentOrder(orderGroup, transactionData, payment, amount);

            return(new TransactionResponse(_authorizeTokenExService.AuthorizeAndCapture(order), false));
        }
        private TransactionData CreateTransactionDataForRegularTransaction(
            IOrderGroup orderGroup,
            ITokenizedPayment tokenPayment)
        {
            var transData = new TransactionData
            {
                AuthorizationCode = tokenPayment.ValidationCode,
            };

            if (string.IsNullOrEmpty(tokenPayment.TransactionType) || !Enum.TryParse(tokenPayment.TransactionType, out transData.type))
            {
                var type = Settings[PaymentOptionParameterName].Equals(TransactionType.Sale.ToString(), StringComparison.OrdinalIgnoreCase) ? TransactionType.Sale : TransactionType.Authorization;
                if (string.IsNullOrEmpty(tokenPayment.TransactionType))
                {
                    tokenPayment.TransactionType = type.ToString();
                }

                transData.type = type;
            }

            var orderForm = orderGroup.Forms.FirstOrDefault(form => form.Payments.Contains(tokenPayment));

            if (transData.type == TransactionType.Capture &&
                orderForm != null && orderForm.CapturedPaymentTotal != 0 &&
                orderForm.Payments.Count(p => p.PaymentMethodId == tokenPayment.PaymentMethodId &&
                                         p.TransactionType == TransactionType.Capture.ToString()) > 1)
            {
                // from the second capture, the transaction type must be CAPTURE_ONLY instead of PRIOR_AUTH_CAPTURE
                transData.type = TransactionType.CaptureOnly;
            }

            if (transData.type != TransactionType.Authorization)
            {
                // ProviderTransactionID might be null in site-upgrade case. Then we should get TransactionID in that case.
                transData.transId = !string.IsNullOrEmpty(tokenPayment.ProviderTransactionID) ? tokenPayment.ProviderTransactionID : tokenPayment.TransactionID;
            }

            if (orderGroup is IPurchaseOrder purchaseOrder)
            {
                transData.purchaseOrderNum = purchaseOrder.OrderNumber;

                var paymentIndex = orderGroup.Forms.SelectMany(form => form.Payments).Count();
                transData.invoiceNum = $"{transData.purchaseOrderNum}-{paymentIndex}";
            }
            else if (orderGroup is ICart)
            {
                string orderNumber;
                if (orderGroup is Cart cart)
                {
                    orderNumber            = cart.GenerateOrderNumber(cart);
                    cart.OrderNumberMethod = c => orderNumber;
                    cart.AcceptChanges();
                }
                else
                {
                    var orderNumberGenerator = ServiceLocator.Current.GetInstance <IOrderNumberGenerator>();
                    orderNumber = orderNumberGenerator.GenerateOrderNumber(orderGroup);
                    orderGroup.Properties["OrderNumber"] = orderNumber;
                }

                transData.invoiceNum = orderNumber;
            }

            return(transData);
        }
 /// <summary>
 /// Post process payment, remove token form payment.
 /// </summary>
 /// <param name="tokenPayment">Input payment, it is supposed to be a ITokenizationPayment.</param>
 private void PostProcessPayment(ITokenizedPayment tokenPayment)
 {
     tokenPayment.Token = string.Empty;
 }