/// <summary>
        /// A Debit Return transaction returns funds to the cardholder. The transaction is generally used as a
        /// counterpart to a Debit Charge transaction that needs to be reversed. The Debit Return transaction is
        /// placed in the current open batch. If a batch is not open, this transaction create an open batch.
        /// </summary>
        /// <param name="transactionId">The gateway transaciton ID of the charge to be returned.</param>
        /// <param name="trackData">Track data read from the card by the card reader.</param>
        /// <param name="amount">Authorization amount.</param>
        /// <param name="pinBlock">PIN block.</param>
        /// <param name="allowDuplicates">Indicates whether to allow duplicate transacitons.</param>
        /// <param name="cardHolder">Card holder information.</param>
        /// <param name="encryptionData">E3 encryption data group.</param>
        /// <param name="details">Group containing additional transaction fields to be included in detail reporting.</param>
        /// <param name="clientTransactionId">Client transaction ID.</param>
        /// <returns>The Return (Authorization) results.</returns>
        public HpsAuthorization Return(int transactionId, decimal amount, string trackData, string pinBlock,
            bool allowDuplicates = false, HpsCardHolder cardHolder = null, HpsEncryptionData encryptionData = null,
            HpsTransactionDetails details = null, long? clientTransactionId = null)
        {
            HpsInputValidation.CheckAmount(amount);

            /* Build the transaction request. */
            var transaction = new PosRequestVer10Transaction
            {
                Item = new PosDebitReturnReqType
                {
                    Block1 = new DebitReturnReqBlock1Type
                    {
                        TrackData = trackData,
                        AllowDup = allowDuplicates ? booleanType.Y : booleanType.N,
                        AllowDupSpecified = true,
                        CardHolderData = cardHolder == null ? null : HydrateCardHolderData(cardHolder),
                        Amt = amount,
                        PinBlock = pinBlock,
                        EncryptionData = HydrateEncryptionData(encryptionData),
                        AdditionalTxnFields = HydrateAdditionalTxnFields(details)
                    }
                },
                ItemElementName = ItemChoiceType1.DebitReturn
            };

            var rsp = DoTransaction(transaction, clientTransactionId).Ver10;
            HpsGatewayResponseValidation.CheckResponse(rsp, ItemChoiceType2.DebitReturn);

            var returnRsp = (AuthRspStatusType)rsp.Transaction.Item;
            HpsIssuerResponseValidation.CheckResponse(rsp.Header.GatewayTxnId, returnRsp.RspCode, returnRsp.RspText);

            return HydrateAuthorization<HpsAuthorization>(rsp);
        }
        public HpsTransaction OfflineCharge(decimal amount, string currency, HpsTrackData trackData, HpsEncryptionData encryptionData = null,
            decimal gratuity = 0, decimal surcharge = 0, long? clientTransactionId = null)
        {
            HpsInputValidation.CheckAmount(amount);
            HpsInputValidation.CheckCurrency(currency);

            /* Build the transaction request. */
            var transaction = new PosRequestVer10Transaction
            {
                Item = new PosCreditOfflineSaleReqType
                {
                    Block1 = new CreditOfflineSaleReqBlock1Type
                    {
                        Amt = amount,
                        GratuityAmtInfo = gratuity,
                        GratuityAmtInfoSpecified = gratuity != 0,
                        SurchargeAmtInfo = surcharge,
                        SurchargeAmtInfoSpecified = surcharge != 0,
                        CardData = new CardDataType
                        {
                            Item = HydrateCardTrackData(trackData),
                            EncryptionData = HydrateEncryptionData(encryptionData)
                        }
                    }
                },
                ItemElementName = ItemChoiceType1.CreditOfflineSale
            };

            /* Submit the transaction. */
            var rsp = DoTransaction(transaction, clientTransactionId).Ver10;
            HpsGatewayResponseValidation.CheckResponse(rsp, ItemChoiceType2.CreditOfflineSale);

            return new HpsTransaction
            {
                Header = HydrateTransactionHeader(rsp.Header),
                TransactionId = rsp.Header.GatewayTxnId,
                ResponseCode = "00",
                ResponseText = string.Empty
            };
        }
        public HpsTransaction OfflineCharge(decimal amount, string currency, HpsCreditCard card, string offlineAuthCode, bool allowDuplicates = false,
            bool cpcRequest = false, HpsCardHolder cardHolder = null, bool requestMultiUseToken = false, HpsTransactionDetails details = null,
            HpsEncryptionData encryptionData = null, decimal gratuity = 0, decimal surcharge = 0, long? clientTransactionId = null)
        {
            HpsInputValidation.CheckAmount(amount);
            HpsInputValidation.CheckCurrency(currency);

            /* Build the transaction request. */
            var transaction = new PosRequestVer10Transaction
            {
                Item = new PosCreditOfflineSaleReqType
                {
                    Block1 = new CreditOfflineSaleReqBlock1Type
                    {
                        CardHolderData = cardHolder == null ? null : HydrateCardHolderData(cardHolder),
                        AllowDup = allowDuplicates ? booleanType.Y : booleanType.N,
                        AllowDupSpecified = true,
                        Amt = amount,
                        CPCReq = cpcRequest ? booleanType.Y : booleanType.N,
                        CPCReqSpecified = true,
                        OfflineAuthCode = offlineAuthCode,
                        GratuityAmtInfo = gratuity,
                        GratuityAmtInfoSpecified = gratuity != 0,
                        SurchargeAmtInfo = surcharge,
                        SurchargeAmtInfoSpecified = surcharge != 0,
                        CardData = new CardDataType
                        {
                            EncryptionData = HydrateEncryptionData(encryptionData),
                            TokenRequest = requestMultiUseToken ? booleanType.Y : booleanType.N,
                            Item = HydrateCardManualEntry(card)
                        },
                        AdditionalTxnFields = HydrateAdditionalTxnFields(details)
                    }
                },
                ItemElementName = ItemChoiceType1.CreditOfflineSale
            };

            /* Submit the transaction. */
            var rsp = DoTransaction(transaction, clientTransactionId).Ver10;
            HpsGatewayResponseValidation.CheckResponse(rsp, ItemChoiceType2.CreditOfflineSale);

            return new HpsTransaction
            {
                Header = HydrateTransactionHeader(rsp.Header),
                TransactionId = rsp.Header.GatewayTxnId,
                ResponseCode = "00",
                ResponseText = string.Empty
            };
        }
        public HpsCharge Charge(decimal amount, string currency, HpsTrackData trackData, HpsEncryptionData encryptionData = null,
            decimal gratuity = 0, bool allowPartialAuthorization = false, bool requestMultiUseToken = false,
            HpsDirectMarketData directMarketData = null, string emvData = "", bool allowDuplicates = false)
        {
            HpsInputValidation.CheckAmount(amount);
            HpsInputValidation.CheckCurrency(currency);

            /* Build the transaction request. */
            var transaction = new PosRequestVer10Transaction
            {
                Item = new PosCreditSaleReqType
                {
                    Block1 = new CreditSaleReqBlock1Type
                    {
                        Amt = amount,
                        GratuityAmtInfo = gratuity,
                        GratuityAmtInfoSpecified = gratuity != 0,
                        AllowPartialAuth = allowPartialAuthorization ? booleanType.Y : booleanType.N,
                        AllowPartialAuthSpecified = true,
                        AllowDup = allowDuplicates ? booleanType.Y : booleanType.N,
                        AllowDupSpecified = true,
                        CardData = new CardDataType
                        {
                            TokenRequest = requestMultiUseToken ? booleanType.Y : booleanType.N,
                            Item = HydrateCardTrackData(trackData),
                            EncryptionData = HydrateEncryptionData(encryptionData)
                        },
                        DirectMktData = HydrateDirectMktData(directMarketData),
                        EMVData = HydrateEmvData(emvData)
                    }
                },
                ItemElementName = ItemChoiceType1.CreditSale
            };

            return SubmitCharge(transaction, amount, currency);
        }
        /// <summary>
        /// The <b>credit sale</b> transaction authorizes a sale purchased with a credit card. The
        /// authorization in place in the current open batch (should auto-close for e-commerce
        /// transactions). If a batch is not open, this transaction will create an open batch.
        /// </summary>
        /// <param name="amount">The amount (in dollars).</param>
        /// <param name="currency">The currency (3-letter ISO code for currency).</param>
        /// <param name="card">The credit card information.</param>
        /// <param name="cardHolder">The card holder information (used for AVS).</param>
        /// <param name="requestMultiUseToken">Request a multi-use token.</param>
        /// <param name="descriptor">Transaction description that is concatenated to a configurable
        /// merchant DBA name. The resulting string is sent to the card issuer for the Merchant Name.</param>
        /// <param name="allowPartialAuth">Indicated whether partial authorization is supported.</param>
        /// <param name="details">The transaction details.</param>
        /// <param name="encryptionData">The encryption data.</param>
        /// <param name="gratuity">The gratuity aamount.</param>
        /// <param name="directMarketData">The direct market data.</param>
        /// <returns>The <see cref="HpsCharge"/>.</returns>
        public HpsCharge Charge(decimal amount, string currency, HpsCreditCard card, HpsCardHolder cardHolder = null,
            bool requestMultiUseToken = false, string descriptor = null, bool allowPartialAuth = false,
            HpsTransactionDetails details = null, HpsEncryptionData encryptionData = null, decimal gratuity = 0,
            HpsDirectMarketData directMarketData = null)
        {
            HpsInputValidation.CheckAmount(amount);
            HpsInputValidation.CheckCurrency(currency);

            /* Build the transaction request. */
            var transaction = new PosRequestVer10Transaction
            {
                Item = new PosCreditSaleReqType
                {
                    Block1 = new CreditSaleReqBlock1Type
                    {
                        CardHolderData = cardHolder == null ? null : HydrateCardHolderData(cardHolder),
                        AllowDup = booleanType.Y,
                        AllowDupSpecified = true,
                        AllowPartialAuth = allowPartialAuth ? booleanType.Y : booleanType.N,
                        AllowPartialAuthSpecified = true,
                        Amt = amount,
                        GratuityAmtInfo = gratuity,
                        GratuityAmtInfoSpecified = gratuity != 0,
                        CardData = new CardDataType
                        {
                            EncryptionData = HydrateEncryptionData(encryptionData),
                            TokenRequest = requestMultiUseToken ? booleanType.Y : booleanType.N,
                            Item = HydrateCardManualEntry(card)
                        },
                        AdditionalTxnFields = HydrateAdditionalTxnFields(details),
                        TxnDescriptor = descriptor,
                        DirectMktData = HydrateDirectMktData(directMarketData)
                    }
                },
                ItemElementName = ItemChoiceType1.CreditSale
            };

            /* Submit the transaction. */
            return SubmitCharge(transaction, amount, currency, (details == null) ? null : details.ClientTransactionId);
        }
        /// <summary>
        /// A <b>credit account verify</b> transaction is used to verify that the account is in good standing
        /// with the issuer. This is a zero dollar transaction with no associated authorization. Since VISA and
        /// other issuers have started assessing penalties for one dollar authorizations, this provides a way for
        /// merchants to accomplish the same task while avoiding these penalties.
        /// </summary>
        /// <param name="trackData">The CC track data.</param>
        /// <param name="encryptionData">Optional encryption data.</param>
        /// <param name="requestMultiUseToken">Request a multi-use token.</param>
        /// <param name="clientTransactionId">Optional client transaction ID.</param>
        /// <returns>The <see cref="HpsAccountVerify"/>.</returns>
        public HpsAccountVerify Verify(HpsTrackData trackData, HpsEncryptionData encryptionData = null,
            bool requestMultiUseToken = false, long? clientTransactionId = null)
        {
            var transaction = new PosRequestVer10Transaction
            {
                Item = new PosCreditAccountVerifyReqType
                {
                    Block1 = new CreditAccountVerifyBlock1Type
                    {
                        CardData = new CardDataType
                        {
                            TokenRequest = requestMultiUseToken ? booleanType.Y : booleanType.N,
                            Item = HydrateCardTrackData(trackData),
                            EncryptionData = HydrateEncryptionData(encryptionData)
                        }
                    }
                },
                ItemElementName = ItemChoiceType1.CreditAccountVerify
            };

            return SubmitVerify(transaction, clientTransactionId);
        }
        /// <summary>
        /// A Debit Charge transaction performs a sale purchased with a Debit Card. The Debit Charge is placed
        /// in the current open batch. If a batch is not open, this transaction creates an open batch.
        /// </summary>
        /// <param name="amount">Authorization amount.</param>
        /// <param name="currency">Currency type ("usd").</param>
        /// <param name="trackData">Track data read from the card by the card reader.</param>
        /// <param name="pinBlock">PIN block.</param>
        /// <param name="cashBackAmount">Contains the portion of the amount that is cash back.</param>
        /// <param name="allowDuplicates">Indicates whether to allow duplicate transactions.</param>
        /// <param name="allowPartialAuth">Indicate whether to allow partial authorization.</param>
        /// <param name="cardHolder">Card holder information.</param>
        /// <param name="encryptionData">E3 encryption data group.</param>
        /// <param name="details">Group containing additional transaction fields to be inclided in detail reporting.</param>
        /// <param name="clientTransactionId">The client transaction ID.</param>
        /// <returns>The Debit Charge result.</returns>
        public HpsAuthorization Charge(decimal amount, string currency, string trackData, string pinBlock,
            HpsEncryptionData encryptionData = null, bool allowDuplicates = false, decimal? cashBackAmount = null,
            bool allowPartialAuth = false, HpsCardHolder cardHolder = null, HpsTransactionDetails details = null,
            long? clientTransactionId = null)
        {
            HpsInputValidation.CheckAmount(amount);
            HpsInputValidation.CheckCurrency(currency);

            var transaction = new PosRequestVer10Transaction
            {
                Item = new PosDebitSaleReqType
                {
                    Block1 = new DebitSaleReqBlock1Type
                    {
                        TrackData = trackData,
                        AllowDup = allowDuplicates ? booleanType.Y : booleanType.N,
                        AllowDupSpecified = true,
                        CardHolderData = cardHolder == null ? null : HydrateCardHolderData(cardHolder),
                        Amt = amount,
                        CashbackAmtInfo = cashBackAmount.HasValue ? cashBackAmount.Value : 0,
                        CashbackAmtInfoSpecified = cashBackAmount.HasValue,
                        AllowPartialAuth = allowPartialAuth ? booleanType.Y : booleanType.N,
                        AllowPartialAuthSpecified = true,
                        PinBlock = pinBlock,
                        EncryptionData = HydrateEncryptionData(encryptionData),
                        AdditionalTxnFields = HydrateAdditionalTxnFields(details)
                    }
                },
                ItemElementName = ItemChoiceType1.DebitSale
            };

            var rsp = DoTransaction(transaction, clientTransactionId).Ver10;
            HpsGatewayResponseValidation.CheckResponse(rsp, ItemChoiceType2.DebitSale);

            var chargeResponse = (AuthRspStatusType)rsp.Transaction.Item;
            HpsIssuerResponseValidation.CheckResponse(rsp.Header.GatewayTxnId, chargeResponse.RspCode, chargeResponse.RspText);

            return HydrateAuthorization<HpsAuthorization>(rsp);
        }
        /// <summary>
        /// A Debit Reversal transaction reverses a Debit Charge or Debit Return transaction.
        /// </summary>
        /// <param name="transactionId">The gateway transaciton ID of the charge to be reversed.</param>
        /// <param name="trackData">The data read from the card by the card reader.</param>
        /// <param name="amount">Authorization amount.</param>
        /// <param name="authorizedAmount">Settlement amount or New Authorization amount after reversal occures.</param>
        /// <param name="encryptionData">E3 encryption data group.</param>
        /// <param name="details">Group containing additional transaction fields to be included in detail reporting.</param>
        /// <param name="clientTransactionId">The client transaction ID.</param>
        /// <returns>The reversal result.</returns>
        public HpsTransaction Reverse(int transactionId, decimal amount, string trackData, decimal? authorizedAmount = null,
            HpsEncryptionData encryptionData = null, HpsTransactionDetails details = null, long? clientTransactionId = null)
        {
            HpsInputValidation.CheckAmount(amount);

            /* Build the transaction request. */
            var transaction = new PosRequestVer10Transaction
            {
                Item = new PosDebitReversalReqType
                {
                    Block1 = new DebitReversalReqBlock1Type
                    {
                        GatewayTxnId = transactionId,
                        GatewayTxnIdSpecified = true,
                        TrackData = trackData,
                        Amt = amount,
                        EncryptionData = HydrateEncryptionData(encryptionData),
                        AdditionalTxnFields = HydrateAdditionalTxnFields(details)
                    }
                },
                ItemElementName = ItemChoiceType1.DebitReversal
            };

            if (authorizedAmount.HasValue)
            {
                var block = ((PosDebitReversalReqType) transaction.Item).Block1;
                block.AuthAmt = authorizedAmount.Value;
                block.AuthAmtSpecified = true;
            }

            var rsp = DoTransaction(transaction, clientTransactionId).Ver10;
            HpsGatewayResponseValidation.CheckResponse(rsp, ItemChoiceType2.DebitReversal);

            long? clientTxnId = null;
            if (rsp.Header.ClientTxnId != default(long))
                clientTxnId = rsp.Header.ClientTxnId;

            return new HpsTransaction
            {
                Header = HydrateTransactionHeader(rsp.Header),
                TransactionId = rsp.Header.GatewayTxnId,
                ClientTransactionId = clientTxnId,
                ResponseCode = "00",
                ResponseText = string.Empty
            };
        }
        /// <summary>
        /// The <b>credit return transaction</b> returns funds to the cardholder. The transaction is generally used
        /// as a counterpart to a credit card transaction that needs to be reversed, and the batch containing
        /// the original transaction has already been closed. The credit return transaction is placed in the
        /// current open batch. If a batch is not open, this transaction will create an open batch.
        /// </summary>
        /// <param name="amount">The amount (in dollars).</param>
        /// <param name="currency">The currency (3-letter ISO code for currency).</param>
        /// <param name="trackData">The card data</param>
        /// <param name="encryptionData">encryption data</param>
        /// <param name="cardHolder">The card holder information (used for AVS).</param>
        /// <param name="details">The transaction details.</param>
        /// <returns>The <see cref="HpsRefund"/>.</returns>
        public HpsRefund Refund(decimal amount, string currency, HpsTrackData trackData, HpsEncryptionData encryptionData = null,
            HpsCardHolder cardHolder = null, HpsTransactionDetails details = null)
        {
            HpsInputValidation.CheckAmount(amount);
            HpsInputValidation.CheckCurrency(currency);

            /* Build the transaction request. */
            var transaction = new PosRequestVer10Transaction
            {
                Item = new PosCreditReturnReqType
                {
                    Block1 = new CreditReturnReqBlock1Type
                    {
                        AllowDup = booleanType.Y,
                        AllowDupSpecified = true,
                        CardHolderData = cardHolder == null ? null : HydrateCardHolderData(cardHolder),
                        CardData = new CardDataType
                        {
                            Item = HydrateCardTrackData(trackData),
                            EncryptionData = HydrateEncryptionData(encryptionData)
                        },
                        Amt = amount,
                        AdditionalTxnFields = HydrateAdditionalTxnFields(details)
                    }
                },
                ItemElementName = ItemChoiceType1.CreditReturn
            };

            return SubmitRefund(transaction, (details == null) ? null : details.ClientTransactionId);
        }