/// <summary> /// Executes Task. /// </summary> /// <param name="request">The request.</param> /// <returns>The response.</returns> private ExecuteTaskPaymentTerminalDeviceResponse ExecuteTask(ExecuteTaskPaymentTerminalDeviceRequest request) { ThrowIf.Null(request, nameof(request)); List <CommerceProperty> commerceProperties = new List <CommerceProperty>(); ExtensionTransaction transaction; // Add/substitute 'case' matching your task and put there the business logic you need for your specific task. switch (request.Task) { case "Echo": // 1. Copying original properties into the response. commerceProperties.AddRange(request.ExtensionTransactionProperties.ExtensionProperties); // 2. Adding some new properties commerceProperties.AddRange(new CommerceProperty[] { new CommerceProperty("Key" + Guid.NewGuid(), "Value1"), new CommerceProperty("Key" + Guid.NewGuid(), "Value2") }); transaction = new ExtensionTransaction { EntityName = request.ExtensionTransactionProperties.EntityName, ExtensionProperties = commerceProperties }; break; default: throw new NotSupportedException($"The task{request.Task} is not supported"); } return(new ExecuteTaskPaymentTerminalDeviceResponse(transaction)); }
/// <summary> /// Fetch token for credit card. /// </summary> /// <param name="isManualEntry">The value indicating whether credit card should be entered manually.</param> /// <param name="extensionTransactionProperties">Optional extension transaction properties.</param> /// <returns>A task that can await until the token generation has completed.</returns> public async Task <PaymentInfo> FetchTokenAsync(bool isManualEntry, ExtensionTransaction extensionTransactionProperties) { PaymentInfo paymentInfo = new PaymentInfo(); // Get tender TenderInfo maskedTenderInfo = await this.GetTenderAsync(false); if (maskedTenderInfo == null) { return(paymentInfo); } if (this.processor == null) { this.processor = CardPaymentManager.GetPaymentProcessor(this.merchantProperties, this.paymentConnectorName); } paymentInfo.CardNumberMasked = maskedTenderInfo.CardNumber; paymentInfo.CashbackAmount = maskedTenderInfo.CashBackAmount; paymentInfo.CardType = (Microsoft.Dynamics.Commerce.HardwareStation.CardPayment.CardType)maskedTenderInfo.CardTypeId; PaymentProperty[] defaultMerchantProperties = this.merchantProperties; if (this.merchantProperties[0].Namespace.Equals(GenericNamespace.Connector) && this.merchantProperties[0].Name.Equals(ConnectorProperties.Properties)) { defaultMerchantProperties = this.merchantProperties[0].PropertyList; } // Generate card token Request request = CardPaymentManager.GetTokenRequest(defaultMerchantProperties, this.tenderInfo, this.terminalSettings.Locale, extensionTransactionProperties); Response response = this.processor.GenerateCardToken(request, null); CardPaymentManager.MapTokenResponse(response, paymentInfo); return(paymentInfo); }
/// <summary> /// Make reversal/void a payment. /// </summary> /// <param name="amount">The amount.</param> /// <param name="currency">The currency.</param> /// <param name="paymentProperties">The payment properties of the authorization response.</param> /// <param name="extensionTransactionProperties">Optional extension transaction properties.</param> /// <returns>A task that can await until the void has completed.</returns> public Task <PaymentInfo> VoidPaymentAsync(decimal amount, string currency, PaymentProperty[] paymentProperties, ExtensionTransaction extensionTransactionProperties) { if (amount < this.terminalSettings.MinimumAmountAllowed) { throw new CardPaymentException(CardPaymentException.AmountLessThanMinimumLimit, "Amount does not meet minimum amount allowed."); } if (this.processor == null) { this.processor = CardPaymentManager.GetPaymentProcessor(this.merchantProperties, this.paymentConnectorName); } if (this.terminalSettings.MaximumAmountAllowed > 0 && amount > this.terminalSettings.MaximumAmountAllowed) { throw new CardPaymentException(CardPaymentException.AmountExceedsMaximumLimit, "Amount exceeds the maximum amount allowed."); } PaymentInfo paymentInfo = new PaymentInfo(); // Handle multiple chain connectors by returning single instance used in capture. IPaymentProcessor currentProcessor = null; PaymentProperty[] currentMerchantProperties = null; CardPaymentManager.GetRequiredConnector(this.merchantProperties, paymentProperties, this.processor, out currentProcessor, out currentMerchantProperties); Request request = CardPaymentManager.GetCaptureRequest(currentMerchantProperties, paymentProperties, amount, currency, this.terminalSettings.Locale, this.isTestMode, this.terminalSettings.TerminalId, cardCache, extensionTransactionProperties); Response response = currentProcessor.Void(request); CardPaymentManager.MapVoidResponse(response, paymentInfo); return(Task.FromResult(paymentInfo)); }
/// <summary> /// Make authorization payment. /// </summary> /// <param name="amount">The amount.</param> /// <param name="currency">The currency.</param> /// <param name="voiceAuthorization">The voice approval code (optional).</param> /// <param name="isManualEntry">If manual credit card entry is required.</param> /// <param name="extensionTransactionProperties">Optional extension transaction properties.</param> /// <returns>A task that can await until the authorization has completed.</returns> public async Task <PaymentInfo> AuthorizePaymentAsync(decimal amount, string currency, string voiceAuthorization, bool isManualEntry, ExtensionTransaction extensionTransactionProperties) { if (amount < this.terminalSettings.MinimumAmountAllowed) { throw new CardPaymentException(CardPaymentException.AmountLessThanMinimumLimit, "Amount does not meet minimum amount allowed."); } if (this.terminalSettings.MaximumAmountAllowed > 0 && amount > this.terminalSettings.MaximumAmountAllowed) { throw new CardPaymentException(CardPaymentException.AmountExceedsMaximumLimit, "Amount exceeds the maximum amount allowed."); } if (this.processor == null) { this.processor = CardPaymentManager.GetPaymentProcessor(this.merchantProperties, this.paymentConnectorName); } PaymentInfo paymentInfo = new PaymentInfo(); // Get tender TenderInfo maskedTenderInfo = await this.GetTenderAsync(true); if (maskedTenderInfo == null) { return(paymentInfo); } paymentInfo.CardNumberMasked = maskedTenderInfo.CardNumber; paymentInfo.CashbackAmount = maskedTenderInfo.CashBackAmount; paymentInfo.CardType = (Microsoft.Dynamics.Commerce.HardwareStation.CardPayment.CardType)maskedTenderInfo.CardTypeId; if (paymentInfo.CashbackAmount > this.terminalSettings.DebitCashbackLimit) { throw new CardPaymentException(CardPaymentException.CashbackAmountExceedsLimit, "Cashback amount exceeds the maximum amount allowed."); } // Authorize Response response = CardPaymentManager.ChainedAuthorizationCall(this.processor, this.merchantProperties, this.tenderInfo, amount, currency, this.terminalSettings.Locale, this.isTestMode, this.terminalSettings.TerminalId, extensionTransactionProperties); Guid cardStorageKey = Guid.NewGuid(); CardPaymentManager.MapAuthorizeResponse(response, paymentInfo, cardStorageKey, this.terminalSettings.TerminalId); if (paymentInfo.IsApproved) { // Backup credit card number TemporaryCardMemoryStorage <string> cardStorage = new TemporaryCardMemoryStorage <string>(DateTime.UtcNow, this.tenderInfo.CardNumber); cardStorage.StorageInfo = paymentInfo.PaymentSdkData; cardCache.Add(cardStorageKey, cardStorage); // need signature? if (this.terminalSettings.SignatureCaptureMinimumAmount < paymentInfo.ApprovedAmount) { paymentInfo.SignatureData = await this.RequestTenderApprovalAsync(paymentInfo.ApprovedAmount); } } return(paymentInfo); }
private async Task <PaymentInfo> GetGiftCardBalanceAsync(string paymentConnectorName, string currencyCode, TenderInfo tenderInfo, ExtensionTransaction extensionTransactionProperties) { await Task.Delay(10).ConfigureAwait(false); throw new PeripheralException(PeripheralException.PaymentTerminalError, "Operation is not supported by payment terminal.", inner: null); }
private async Task <PaymentInfo> FetchTokenAsync(bool isManualEntry, ExtensionTransaction extensionTransactionProperties) { await Task.Delay(10).ConfigureAwait(false); throw new PeripheralException(PeripheralException.PaymentTerminalError, "Operation is not supported by payment terminal.", inner: null); }
private async Task <PaymentInfo> RefundPaymentAsync(decimal amount, string currency, bool isManualEntry, ExtensionTransaction extensionTransactionProperties) { return(await Task.FromResult(CreateAuthorizationSuccessPaymentInfo(amount)).ConfigureAwait(false)); }
private async Task <PaymentInfo> VoidPaymentAsync(string paymentConnectorName, decimal amount, string currency, TenderInfo tenderInfo, string paymentPropertiesXml, ExtensionTransaction extensionTransactionProperties) { ThrowIf.Null(this.merchantProperties, nameof(this.merchantProperties)); PaySdk.PaymentProperty[] properties = GetPaymentPropertiesWithInitialList(paymentConnectorName, this.merchantProperties); // Several below values are hardcoded, real implementations should take this data from real device. return(await Task.FromResult(new PaymentInfo() { CardNumberMasked = string.Empty, CardType = Microsoft.Dynamics.Commerce.HardwareStation.CardPayment.CardType.Unknown, SignatureData = string.Empty, PaymentSdkData = PaySdk.PaymentProperty.ConvertPropertyArrayToXML(properties), CashbackAmount = 0.0m, ApprovedAmount = amount, IsApproved = false, Errors = null }).ConfigureAwait(false)); }
/// <summary> /// Make refund payment. /// </summary> /// <param name="amount">The amount.</param> /// <param name="currency">The currency.</param> /// <param name="isManualEntry">If manual credit card entry is required.</param> /// <param name="extensionTransactionProperties">Optional extension transaction properties.</param> /// <returns>A task that can await until the refund has completed.</returns> public virtual async Task <PaymentInfo> RefundPaymentAsync(decimal amount, string currency, bool isManualEntry, ExtensionTransaction extensionTransactionProperties) { return(await this.Execute(async() => { return await this.paymentDevice.RefundPaymentAsync(amount, currency, isManualEntry, extensionTransactionProperties); })); }
/// <summary> /// Fetch token for credit card. /// </summary> /// <param name="isManualEntry">The value indicating whether credit card should be entered manually.</param> /// <param name="extensionTransactionProperties">Optional extension transaction properties.</param> /// <returns>A task that can await until the token generation has completed.</returns> public async Task <PaymentInfo> FetchTokenAsync(bool isManualEntry, ExtensionTransaction extensionTransactionProperties) { await Task.Delay(10); throw new System.NotImplementedException(); }
/// <summary> /// Make refund payment. /// </summary> /// <param name="amount">The amount.</param> /// <param name="currency">The currency.</param> /// <param name="isManualEntry">If manual credit card entry is required.</param> /// <param name="extensionTransactionProperties">Optional extension transaction properties.</param> /// <returns>A task that can await until the refund has completed.</returns> public async Task <PaymentInfo> RefundPaymentAsync(decimal amount, string currency, bool isManualEntry, ExtensionTransaction extensionTransactionProperties) { return(await Task.FromResult <PaymentInfo>(new PaymentInfo() { CardNumberMasked = "411111******1111", CardType = Microsoft.Dynamics.Commerce.HardwareStation.CardPayment.CardType.InternationalCreditCard, SignatureData = "AAgEAAQALP4hvpJrK/UfKvlX7ABkIfJFnxoZbaXC2vmnzYB8ItM1rBYwzRrw0IdLF3Qv89lwBfgGn5gBwKkFSoguAft6w8ZAJATwSYNMGJTlqmorxYYyN2BZvtGmroCuKygDAJoBkAyDAr46bUZ4kOFG7P9GmjcA", PaymentSdkData = "<!--- payment sdk connector payment properties for refund response -->", CashbackAmount = 0.0m, ApprovedAmount = amount, IsApproved = true, Errors = null })); }
/// <summary> /// Make reversal/void a payment. /// </summary> /// <param name="amount">The amount.</param> /// <param name="currency">The currency.</param> /// <param name="paymentProperties">The payment properties of the authorization response.</param> /// <param name="extensionTransactionProperties">Optional extension transaction properties.</param> /// <returns>A task that can await until the void has completed.</returns> public async Task <PaymentInfo> VoidPaymentAsync(decimal amount, string currency, PaymentProperty[] paymentProperties, ExtensionTransaction extensionTransactionProperties) { return(await Task.FromResult <PaymentInfo>(new PaymentInfo() { CardNumberMasked = string.Empty, CardType = Microsoft.Dynamics.Commerce.HardwareStation.CardPayment.CardType.Unknown, SignatureData = string.Empty, PaymentSdkData = "<!--- payment sdk connector payment properties for void response -->", CashbackAmount = 0.0m, ApprovedAmount = amount, IsApproved = true, Errors = null })); }
/// <summary> /// Extensibility execute method. /// </summary> /// <param name="task">The task to execute.</param> /// <param name="extensionTransactionProperties">Optional extension transaction properties.</param> /// <returns>The result of executing the task.</returns> public virtual async Task <ExtensionTransaction> ExecuteTaskAsync(string task, ExtensionTransaction extensionTransactionProperties) { IPaymentTerminalExtension extension = this.paymentDevice as IPaymentTerminalExtension; if (extension != null) { return(await extension.ExecuteTaskAsync(task, extensionTransactionProperties)); } else { return(await Task.FromResult <ExtensionTransaction>(null)); } }
/// <summary> /// Fetch token for credit card. /// </summary> /// <param name="isManualEntry">The value indicating whether credit card should be entered manually.</param> /// <param name="extensionTransactionProperties">Optional extension transaction properties.</param> /// <returns>A task that can await until the token generation has completed.</returns> public virtual async Task <PaymentInfo> FetchTokenAsync(bool isManualEntry, ExtensionTransaction extensionTransactionProperties) { return(await this.Execute(async() => { return await this.paymentDevice.FetchTokenAsync(isManualEntry, extensionTransactionProperties); })); }
/// <summary> /// Make refund payment. /// </summary> /// <param name="amount">The amount.</param> /// <param name="currency">The currency.</param> /// <param name="isManualEntry">If manual credit card entry is required.</param> /// <param name="extensionTransactionProperties">Optional extension transaction properties.</param> /// <returns>A task that can await until the refund has completed.</returns> public async Task <PaymentInfo> RefundPaymentAsync(decimal amount, string currency, bool isManualEntry, ExtensionTransaction extensionTransactionProperties) { if (amount < this.terminalSettings.MinimumAmountAllowed) { throw new CardPaymentException(CardPaymentException.AmountLessThanMinimumLimit, "Amount does not meet minimum amount allowed."); } if (this.terminalSettings.MaximumAmountAllowed > 0 && amount > this.terminalSettings.MaximumAmountAllowed) { throw new CardPaymentException(CardPaymentException.AmountExceedsMaximumLimit, "Amount exceeds the maximum amount allowed."); } if (this.processor == null) { this.processor = CardPaymentManager.GetPaymentProcessor(this.merchantProperties, this.paymentConnectorName); } PaymentInfo paymentInfo = new PaymentInfo(); // Get tender TenderInfo maskedTenderInfo = await this.GetTenderAsync(false); if (maskedTenderInfo == null) { return(paymentInfo); } paymentInfo.CardNumberMasked = maskedTenderInfo.CardNumber; paymentInfo.CashbackAmount = maskedTenderInfo.CashBackAmount; paymentInfo.CardType = (Microsoft.Dynamics.Commerce.HardwareStation.CardPayment.CardType)maskedTenderInfo.CardTypeId; if (paymentInfo.CashbackAmount > this.terminalSettings.DebitCashbackLimit) { throw new CardPaymentException(CardPaymentException.CashbackAmountExceedsLimit, "Cashback amount exceeds the maximum amount allowed."); } // Refund Response response = CardPaymentManager.ChainedRefundCall(this.processor, this.merchantProperties, this.tenderInfo, amount, currency, this.terminalSettings.Locale, this.isTestMode, this.terminalSettings.TerminalId, extensionTransactionProperties); CardPaymentManager.MapRefundResponse(response, paymentInfo); if (paymentInfo.IsApproved) { // need signature? if (this.terminalSettings.SignatureCaptureMinimumAmount < paymentInfo.ApprovedAmount) { paymentInfo.SignatureData = await this.RequestTenderApprovalAsync(paymentInfo.ApprovedAmount); } } return(paymentInfo); }
private async Task <PaymentInfo> AuthorizePaymentAsync(string paymentConnectorName, decimal amount, string currency, TenderInfo tenderInfo, ExtensionTransaction extensionTransactionProperties) { // Several below values are hardcoded, real implementations should take this data from real device. var paymentInfo = CreateAuthorizationSuccessPaymentInfo(amount); return(await Task.FromResult(paymentInfo).ConfigureAwait(false)); }
/// <summary> /// Make reversal/void a payment. /// </summary> /// <param name="amount">The amount.</param> /// <param name="currency">The currency.</param> /// <param name="paymentPropertiesXml">The payment properties of the authorization response.</param> /// <param name="extensionTransactionProperties">Optional extension transaction properties.</param> /// <returns>A task that can await until the void has completed.</returns> public virtual async Task <PaymentInfo> VoidPaymentAsync(decimal amount, string currency, string paymentPropertiesXml, ExtensionTransaction extensionTransactionProperties) { PaymentProperty[] properties = CardPaymentManager.ToLocalProperties(paymentPropertiesXml); try { return(await this.paymentDevice.VoidPaymentAsync(amount, currency, properties, extensionTransactionProperties)); } catch (PaymentException paymentException) { // When payment is already voided, treat it as success. if (paymentException.PaymentSdkErrors != null && paymentException.PaymentSdkErrors.Count == 1 && paymentException.PaymentSdkErrors[0].Code == ErrorCode.AuthorizationIsVoided) { PaymentInfo paymentInfo = new PaymentInfo(); paymentInfo.IsApproved = true; return(await Task.FromResult <PaymentInfo>(paymentInfo)); } else { throw paymentException; } } }