From 35a287017932331da575dbe61b42a7127c662a00 Mon Sep 17 00:00:00 2001 From: yurii Date: Mon, 7 Sep 2026 18:08:24 +0100 Subject: [PATCH] added confirm transaction endpoint --- Client.cs | 18 ++++---- ClientApp.cs | 121 ++++++++++++--------------------------------------- 2 files changed, 39 insertions(+), 100 deletions(-) diff --git a/Client.cs b/Client.cs index 6636235..2499ab6 100644 --- a/Client.cs +++ b/Client.cs @@ -318,7 +318,7 @@ namespace Creditcall.ChipDna.Client PerformStartTransaction("250", ""); break; case "C": - PerformConfirmTransaction("", out TransactionConfirmation confirmation); + PerformConfirmTransaction("", ""); break; case "V": PerformVoidTransaction(""); @@ -642,19 +642,23 @@ namespace Creditcall.ChipDna.Client } } - public void PerformConfirmTransaction(string reference, out TransactionConfirmation confirmation) + public Dictionary PerformConfirmTransaction(string reference, string amount) { - confirmation = new TransactionConfirmation(); - + var confirmationResult = new Dictionary(); var parameters = new ParameterSet(); parameters.Add(ParameterKeys.Reference, reference); + parameters.Add(ParameterKeys.Amount, amount); parameters.Add(GetExtraParams("ConfirmTransaction")); var response = chipDnaClientLib.ConfirmTransaction(parameters); + var responseParameter = response.ToList(); + responseParameter.ForEach(parameter => + { + confirmationResult.Add(parameter.Key, parameter.Value); + }); string receipt, result; if (response.GetValue(ParameterKeys.TransactionResult, out result)) { Console.WriteLine("Confirmed Transaction Result: {0}", result); - confirmation.Result = result; } if (response.GetValue(ParameterKeys.ReceiptDataMerchant, out receipt)) { @@ -663,21 +667,19 @@ namespace Creditcall.ChipDna.Client if (response.GetValue(ParameterKeys.ReceiptDataCardholder, out receipt)) { PrintReceiptData(ReceiptData.GetReceiptDataFromXml(receipt)); - confirmation.ReceiptDataCardholder = receipt; } string errors; if (response.GetValue(ParameterKeys.Errors, out errors)) { Console.WriteLine(ErrorsString("ConfirmTransaction Errors", errors)); - confirmation.Errors = errors; } string errorDescription; if (response.GetValue(ParameterKeys.ErrorDescription, out errorDescription)) { Console.WriteLine("ErrorDescription: {0}", errorDescription); - confirmation.ErrorDescription = errorDescription; } + return confirmationResult; } private void DoUpdateTransaction() diff --git a/ClientApp.cs b/ClientApp.cs index 26578ee..fc4b145 100644 --- a/ClientApp.cs +++ b/ClientApp.cs @@ -73,7 +73,7 @@ namespace Creditcall.ChipDna.Client { HttpListener listener = new HttpListener(); listener.Prefixes.Add("http://127.0.0.1:18181/start-transaction/"); - listener.Prefixes.Add("http://127.0.0.1:18181/start-and-confirm-transaction/"); + listener.Prefixes.Add("http://127.0.0.1:18181/confirm-transaction/"); listener.Prefixes.Add("http://127.0.0.1:18181/transaction-information/"); listener.Prefixes.Add("http://127.0.0.1:18181/void-transaction/"); listener.Prefixes.Add("http://127.0.0.1:18181/chipdna-status/"); @@ -81,7 +81,7 @@ namespace Creditcall.ChipDna.Client Console.WriteLine("Listening on:"); Console.WriteLine(" http://127.0.0.1:18181/start-transaction/"); - Console.WriteLine(" http://127.0.0.1:18181/start-and-confirm-transaction/"); + Console.WriteLine(" http://127.0.0.1:18181/confirm-transaction/"); Console.WriteLine(" http://127.0.0.1:18181/transaction-information/"); Console.WriteLine(" http://127.0.0.1:18181/void-transaction/"); Console.WriteLine(" http://127.0.0.1:18181/chipdna-status/"); @@ -105,9 +105,9 @@ namespace Creditcall.ChipDna.Client { HandleStartTransaction(context); - } else if (rawUrl.StartsWith("/start-and-confirm-transaction", StringComparison.OrdinalIgnoreCase)) + } else if (rawUrl.StartsWith("/confirm-transaction", StringComparison.OrdinalIgnoreCase)) { - HandleStartAndConfirmTransaction(context); + HandleConfirmTransaction(context); } else if (rawUrl.StartsWith("/transaction-information", StringComparison.OrdinalIgnoreCase)) { @@ -120,7 +120,8 @@ namespace Creditcall.ChipDna.Client else if (rawUrl.StartsWith("/chipdna-status", StringComparison.OrdinalIgnoreCase)) { HandleGetStatus(context); - } + } + else { context.Response.StatusCode = 404; context.Response.Close(); @@ -212,105 +213,34 @@ namespace Creditcall.ChipDna.Client } } - private static void HandleStartAndConfirmTransaction(HttpListenerContext context) + private static void HandleConfirmTransaction(HttpListenerContext context) { try { - var serializer = new XmlSerializer(typeof(TransactionPayload)); - TransactionPayload payload = (TransactionPayload)serializer.Deserialize(context.Request.InputStream); + var serializer = new XmlSerializer(typeof(ConfirmTransactionRequest)); + ConfirmTransactionRequest payload = (ConfirmTransactionRequest)serializer.Deserialize(context.Request.InputStream); - Console.WriteLine($"Received start transaction: Amount={payload.Amount}, Type={payload.TransactionType}"); + Console.WriteLine($"Received confirm transaction: Amount={payload.Amount}, TransactionReference={payload.TransactionReference}"); - client.TransactionCompletionSource = new TaskCompletionSource>(); + var confirmationResult = client.PerformConfirmTransaction(payload.TransactionReference, payload.Amount); - // start transaction (non-blocking) - client.PerformStartTransaction(payload.Amount, payload.TransactionType); - - // Wait for completion with timeout - var task = client.TransactionCompletionSource.Task; - if (!task.Wait(TimeSpan.FromSeconds(transactionTimeoutSeconds))) - { - // timeout - var errorMap = new Dictionary - { - { ParameterKeys.TransactionResult, "TIMEOUT" }, - { ParameterKeys.Errors, "Transaction timed out waiting for device response" } - }; - - var wrappedTimeout = new SerializableKeyValueList(errorMap); - context.Response.ContentType = "application/xml"; - new XmlSerializer(typeof(SerializableKeyValueList)).Serialize(context.Response.OutputStream, wrappedTimeout); - return; - } - - // Task completed — handle possible exception - Dictionary transactionResult; - try - { - transactionResult = task.Result; // safe now, Wait returned - } - catch (AggregateException agg) - { - var first = agg.Flatten().InnerExceptions[0]; - var errMap = new Dictionary - { - { ParameterKeys.TransactionResult, "ERROR" }, - { ParameterKeys.Errors, $"Transaction task faulted: {first.Message}" } - }; - var wrapped = new SerializableKeyValueList(errMap); - context.Response.ContentType = "application/xml"; - new XmlSerializer(typeof(SerializableKeyValueList)).Serialize(context.Response.OutputStream, wrapped); - return; - } - - // If it's a SALE and approved, call ConfirmTransaction and attach its XML - transactionResult.TryGetValue(ParameterKeys.TransactionType, out string txType); - transactionResult.TryGetValue(ParameterKeys.TransactionResult, out string txResult); - transactionResult.TryGetValue(ParameterKeys.Reference, out string txReference); - - if (!string.IsNullOrEmpty(txType) && txType.Equals("SALE", StringComparison.OrdinalIgnoreCase) && - !string.IsNullOrEmpty(txResult) && txResult.Equals("APPROVED", StringComparison.OrdinalIgnoreCase) && - !string.IsNullOrEmpty(txReference)) - { - try - { - TransactionConfirmation confirmation; - client.PerformConfirmTransaction(txReference, out confirmation); - - // Keep original fields, but also add confirmation-prefixed fields - transactionResult["CONFIRM_RESULT"] = confirmation?.Result ?? ""; - transactionResult["CONFIRM_ERRORS"] = confirmation?.Errors ?? ""; - if (!string.IsNullOrEmpty(confirmation.ErrorDescription)) - { - transactionResult["CONFIRM_ERRORS"] = $"{confirmation.Errors} {confirmation.ErrorDescription}"; - } - if (!string.IsNullOrEmpty(confirmation?.ReceiptDataCardholder)) - { - transactionResult[ParameterKeys.ReceiptDataCardholder] = confirmation.ReceiptDataCardholder; - } - - // XML (omit declaration so it can be embedded) - var xml = SerializeToXml(confirmation, omitXmlDeclaration: true); - transactionResult["TRANSACTION_CONFIRMATION"] = xml; - } - catch (Exception ex) - { - // preserve original transaction result but add an error key - transactionResult["CONFIRM_RESULT"] = "ERROR"; - transactionResult["CONFIRM_ERRORS"] = $"ConfirmTransaction failed: {ex.Message}"; - } - } - - // Return the final key/value list as before var responseSerializer = new XmlSerializer(typeof(SerializableKeyValueList)); context.Response.ContentType = "application/xml"; - var wrappedResult = new SerializableKeyValueList(transactionResult); + var wrappedResult = new SerializableKeyValueList(confirmationResult); responseSerializer.Serialize(context.Response.OutputStream, wrappedResult); } catch (Exception ex) { - Console.WriteLine("Error in start-and-confirm-transaction: " + ex.Message); - context.Response.StatusCode = 500; + var errorMap = new Dictionary + { + { ParameterKeys.TransactionResult, "ERROR" }, + { ParameterKeys.Errors, $"ConfirmTransaction failed: {ex.Message}" } + }; + + var responseSerializer = new XmlSerializer(typeof(SerializableKeyValueList)); + context.Response.ContentType = "application/xml"; + var wrappedResult = new SerializableKeyValueList(errorMap); + responseSerializer.Serialize(context.Response.OutputStream, wrappedResult); } finally { @@ -491,4 +421,11 @@ namespace Creditcall.ChipDna.Client public string TransactionReference { get; set; } } + [XmlRoot("ConfirmTransactionRequest")] + public class ConfirmTransactionRequest + { + public string Amount { get; set; } + public string TransactionReference { get; set; } + } + }