diff --git a/Adyen.EcommLibrary.Test/CloudApiPosRequestTest.cs b/Adyen.EcommLibrary.Test/CloudApiPosRequestTest.cs index 72bfbe69e..fcdd3fd0b 100644 --- a/Adyen.EcommLibrary.Test/CloudApiPosRequestTest.cs +++ b/Adyen.EcommLibrary.Test/CloudApiPosRequestTest.cs @@ -1,4 +1,5 @@ -using Adyen.EcommLibrary.Service; +using Adyen.EcommLibrary.Model.Nexo; +using Adyen.EcommLibrary.Service; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; @@ -9,13 +10,32 @@ public class CloudApiPosRequestTest : BaseTest { [TestMethod] - public void TestCloudApiRequest() + public void TestCloudApiSyncRequest() { try { //Create a mock pos payment request var paymentRequest = MockPosApiRequest.CreatePosPaymentRequest("Request"); - var client = CreateMockTestClientPosApiRequest("Mocks/pospayment-success.json"); + var client = CreateMockTestClientPosApiRequest("Mocks/terminalapi/pospayment-success.json"); + var payment = new PosPaymentCloudApi(client); + var saleToPoiResponse = payment.TerminalApiCloudSync(paymentRequest); + + Assert.IsNotNull(saleToPoiResponse); + } + catch (Exception) + { + Assert.Fail(); + } + } + + [TestMethod] + public void TestCloudApiAsyncRequest() + { + try + { + //Create a mock pos payment request + var paymentRequest = MockPosApiRequest.CreatePosPaymentRequest("Request"); + var client = CreateMockTestClientPosApiRequest("Mocks/terminalapi/pospayment-success.json"); var payment = new PosPaymentCloudApi(client); var saleToPoiResponse = payment.TerminalApiCloudAsync(paymentRequest); @@ -26,5 +46,32 @@ public void TestCloudApiRequest() Assert.Fail(); } } + + [TestMethod] + public void TestCloudApiTransactionStatusResponseSuccess() + { + var paymentRequest = MockPosApiRequest.CreatePosPaymentRequest("Request"); + var client = CreateMockTestClientPosApiRequest("Mocks/terminalapi/pospayment-transaction-status-response.json"); + var payment = new PosPaymentCloudApi(client); + var saleToPoiResponse = payment.TerminalApiCloudSync(paymentRequest); + + try + { + var transactionStatusResponse = (TransactionStatusResponse)saleToPoiResponse.MessagePayload; + var messagePayloadResponse = transactionStatusResponse.RepeatedMessageResponse.RepeatedResponseMessageBody.MessagePayload; + + Assert.IsNotNull(saleToPoiResponse); + Assert.AreEqual(saleToPoiResponse.MessageHeader.ServiceID, "35543420"); + Assert.AreEqual(saleToPoiResponse.MessageHeader.SaleID, "TOSIM_1_1_6"); + Assert.AreEqual(saleToPoiResponse.MessageHeader.POIID, "P400Plus-12345678"); + Assert.AreEqual(transactionStatusResponse.Response.Result, "Success"); + Assert.AreEqual(messagePayloadResponse.PaymentResult.PaymentInstrumentData.CardData.EntryMode[0], "ICC"); + Assert.AreEqual(messagePayloadResponse.POIData.POIReconciliationID, "1000"); + } + catch (Exception) + { + Assert.Fail(); + } + } } } diff --git a/Adyen.EcommLibrary.Test/Mocks/pospayment-cancelled.json b/Adyen.EcommLibrary.Test/Mocks/terminalapi/pospayment-cancelled.json similarity index 100% rename from Adyen.EcommLibrary.Test/Mocks/pospayment-cancelled.json rename to Adyen.EcommLibrary.Test/Mocks/terminalapi/pospayment-cancelled.json diff --git a/Adyen.EcommLibrary.Test/Mocks/pospayment-encrypted-success.json b/Adyen.EcommLibrary.Test/Mocks/terminalapi/pospayment-encrypted-success.json similarity index 100% rename from Adyen.EcommLibrary.Test/Mocks/pospayment-encrypted-success.json rename to Adyen.EcommLibrary.Test/Mocks/terminalapi/pospayment-encrypted-success.json diff --git a/Adyen.EcommLibrary.Test/Mocks/pospayment-success.json b/Adyen.EcommLibrary.Test/Mocks/terminalapi/pospayment-success.json similarity index 100% rename from Adyen.EcommLibrary.Test/Mocks/pospayment-success.json rename to Adyen.EcommLibrary.Test/Mocks/terminalapi/pospayment-success.json diff --git a/Adyen.EcommLibrary.Test/Mocks/terminalapi/pospayment-transaction-status-response.json b/Adyen.EcommLibrary.Test/Mocks/terminalapi/pospayment-transaction-status-response.json new file mode 100644 index 000000000..b33d5728b --- /dev/null +++ b/Adyen.EcommLibrary.Test/Mocks/terminalapi/pospayment-transaction-status-response.json @@ -0,0 +1,91 @@ +{ + "SaleToPOIResponse" : { + "MessageHeader" : { + "MessageCategory" : "TransactionStatus", + "ServiceID" : "35543420", + "MessageType" : "Response", + "SaleID" : "TOSIM_1_1_6", + "POIID" : "P400Plus-12345678", + "ProtocolVersion" : "3.0", + "MessageClass" : "Service" + }, + "TransactionStatusResponse" : { + "Response" : { + "Result" : "Success" + }, + "MessageReference" : { + "SaleID" : "TOSIM_1_100_6", + "ServiceID" : "05140342", + "MessageCategory" : "Payment" + }, + + "RepeatedMessageResponse" : { + "RepeatedResponseMessageBody" : { + "PaymentResponse" : { + "PaymentResult" : { + "PaymentInstrumentData" : { + "PaymentInstrumentType" : "Card", + "CardData" : { + "EntryMode" : [ + "ICC" + ], + "PaymentBrand" : "mc", + "SensitiveCardData" : { + "ExpiryDate" : "0228", + "CardSeqNumb" : "53" + }, + "CardCountryCode" : "056", + "MaskedPan" : "679999 **** 9990" + } + }, + "AuthenticationMethod" : [ + "SignatureCapture" + ], + "PaymentAcquirerData" : { + "AcquirerPOIID" : "P400Plus-275102737", + "MerchantID" : "EG_Adyen_test", + "AcquirerTransactionID" : { + "TimeStamp" : "2018-12-05T13:03:47.000Z", + "TransactionID" : "8815440150351036" + } + }, + "OnlineFlag" : true, + "PaymentType" : "Normal", + "AmountsResp" : { + "AuthorizedAmount" : 79, + "Currency" : "EUR" + }, + "MerchantOverrideFlag" : false + }, + "SaleData" : { + "SaleTransactionID" : { + "TransactionID" : "0000060001078117", + "TimeStamp" : "2018-12-05T14:03:42.000Z" + } + }, + "Response" : { + "Result" : "Success", + "AdditionalResponse" : "tid=75102737&AID=A000000004306001&transactionType=GOODS_SERVICES&backendGiftcardIndicator=false&giftcardIndicator=false&pspReference=8815440150351036&cardHolderName=TC03_MS_Approved&paymentMethodVariant=maestro&applicationPreferredName=ms%20en&offline=false&tc=9011DDEE7EA21173&mid=1000&cardHolderVerificationMethodResults=1E0000" + }, + "POIData" : { + "POITransactionID" : { + "TimeStamp" : "2018-12-05T13:03:47.000Z", + "TransactionID" : "57eT001544015027011.8815440150351036" + }, + "POIReconciliationID" : "1000" + } + } + }, + "MessageHeader" : { + "POIID" : "P400Plus-12345678", + "ProtocolVersion" : "3.0", + "MessageClass" : "Service", + "MessageCategory" : "Payment", + "ServiceID" : "35543420", + "MessageType" : "Response", + "SaleID" : "TOSIM_1_1_6" + } + } + } + } +} diff --git a/Adyen.EcommLibrary.Test/TerminalApiPosRequestTest.cs b/Adyen.EcommLibrary.Test/TerminalApiPosRequestTest.cs index 39461dded..fcf57978d 100644 --- a/Adyen.EcommLibrary.Test/TerminalApiPosRequestTest.cs +++ b/Adyen.EcommLibrary.Test/TerminalApiPosRequestTest.cs @@ -30,7 +30,7 @@ public void TestTerminalApiRequest() //encrypt the request using encryption credentials var paymentRequest = MockPosApiRequest.CreatePosPaymentRequest("Request"); //create a mock client - var client = CreateMockTestClientPosApiRequest("Mocks/pospayment-encrypted-success.json"); + var client = CreateMockTestClientPosApiRequest("Mocks/terminalapi/pospayment-encrypted-success.json"); var payment = new PosPaymentLocalApi(client); var configEndpoint = payment.Client.Config.Endpoint; var saleToPoiResponse = payment.TerminalApiLocal(paymentRequest, _encryptionCredentialDetails); diff --git a/Adyen.EcommLibrary/CloudApiSerialization/MessagePayloadSerializer.cs b/Adyen.EcommLibrary/CloudApiSerialization/MessagePayloadSerializer.cs index f78619ec4..ac3bd406e 100644 --- a/Adyen.EcommLibrary/CloudApiSerialization/MessagePayloadSerializer.cs +++ b/Adyen.EcommLibrary/CloudApiSerialization/MessagePayloadSerializer.cs @@ -1,4 +1,6 @@ using Adyen.EcommLibrary.Model.Nexo; +using Newtonsoft.Json.Linq; +using System; namespace Adyen.EcommLibrary.CloudApiSerialization { @@ -8,5 +10,6 @@ public IMessagePayload Deserialize(string messagePayloadJson) { return Converter.JSonConvertDeserializerWrapper.DeserializeObject(messagePayloadJson); } + } } diff --git a/Adyen.EcommLibrary/CloudApiSerialization/SaleToPoiMessageSerializer.cs b/Adyen.EcommLibrary/CloudApiSerialization/SaleToPoiMessageSerializer.cs index de533f382..77b7c6bbc 100644 --- a/Adyen.EcommLibrary/CloudApiSerialization/SaleToPoiMessageSerializer.cs +++ b/Adyen.EcommLibrary/CloudApiSerialization/SaleToPoiMessageSerializer.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; -using Adyen.EcommLibrary.Model.Nexo; +using Adyen.EcommLibrary.Model.Nexo; using Adyen.EcommLibrary.Security; using Newtonsoft.Json.Linq; -using Adyen.EcommLibrary.Model.Nexo.Message; namespace Adyen.EcommLibrary.CloudApiSerialization { @@ -17,34 +14,36 @@ public SaleToPoiMessageSerializer() _messageHeaderSerializer = new MessageHeaderSerializer(); _messagePayloadSerializerFactory = new MessagePayloadSerializerFactory(); } - public SaleToPOIResponse Deserialize(string saleToPoiMessageDto) { - try + //todo temporary solution until we have an improved response + if (string.Equals("ok", saleToPoiMessageDto)) { - //todo temporary solution until we have an improved response - if (string.Equals("ok", saleToPoiMessageDto)) - { - return null; - } - var saleToPoiMessageJObject = JObject.Parse(saleToPoiMessageDto); - var saleToPoiMessageRootJToken = saleToPoiMessageJObject.First; - var saleToPoiMessageWithoutRootJToken = saleToPoiMessageRootJToken.First; - var messageHeader = DeserializeMessageHeader(saleToPoiMessageWithoutRootJToken); + return null; + } + var saleToPoiMessageJObject = JObject.Parse(saleToPoiMessageDto); + var saleToPoiMessageRootJToken = saleToPoiMessageJObject.First; + var saleToPoiMessageWithoutRootJToken = saleToPoiMessageRootJToken.First; + //Messageheader + var messageHeader = DeserializeMessageHeader(saleToPoiMessageWithoutRootJToken); + //Message payload + object messagePayload = DeserializeMessagePayload(messageHeader, saleToPoiMessageWithoutRootJToken); - var messagePayload = DeserializeMessagePayload(messageHeader, saleToPoiMessageWithoutRootJToken); - var deserializedOutputMessage = new SaleToPOIResponse - { - MessageHeader = messageHeader, - MessagePayload = messagePayload - }; + var deserializedOutputMessage = new SaleToPOIResponse + { + MessageHeader = messageHeader, + MessagePayload = messagePayload + }; - return deserializedOutputMessage; - } - catch (Exception exception) + //Check and deserialize RepeatedMessageResponse. RepeatedMessageResponse is optional + if (saleToPoiMessageDto.Contains("TransactionStatusResponse") && saleToPoiMessageDto.Contains("RepeatedMessageResponse") && saleToPoiMessageDto.Contains("RepeatedResponseMessageBody")) { - throw exception; + var response = GetDeserializedRepeatedResponseMessagePayload(saleToPoiMessageWithoutRootJToken); + TransactionStatusResponse deserializedOutput = (TransactionStatusResponse)deserializedOutputMessage.MessagePayload; + deserializedOutput.RepeatedMessageResponse.RepeatedResponseMessageBody.MessagePayload = response; + deserializedOutputMessage.MessagePayload = deserializedOutput; } + return deserializedOutputMessage; } private object DeserializeMessagePayload(MessageHeader messageHeader, JToken saleToPoiMessageWithoutRootJToken) @@ -57,10 +56,19 @@ private object DeserializeMessagePayload(MessageHeader messageHeader, JToken sal return messagePayloadSerializer.Deserialize(messagePayloadJson); } + public string Serialize(SaleToPOIMessage saleToPoiMessage) + { + return Converter.JSonConvertSerializerWrapper.Serialize(saleToPoiMessage); + } + + public string Serialize(SaleToPoiMessageSecured saleToPoiMessage) + { + return Converter.JSonConvertSerializerWrapper.Serialize(saleToPoiMessage); + } + private string GetMessagePayloadJSon(JToken saleToPoiMessageWithoutRootJToken, string messageCategory, string messageType) { var messagePayloadTypedJson = saleToPoiMessageWithoutRootJToken.SelectToken(messageCategory + messageType.ToString()); - if (messagePayloadTypedJson == null) { return saleToPoiMessageWithoutRootJToken.SelectToken("MessagePayload").ToString(); @@ -70,34 +78,40 @@ private string GetMessagePayloadJSon(JToken saleToPoiMessageWithoutRootJToken, s private MessageHeader DeserializeMessageHeader(JToken saleToPoiMessageWithoutRootJObject) { var messageHeaderJson = saleToPoiMessageWithoutRootJObject.SelectToken("MessageHeader").ToString(); - var messageHeader = _messageHeaderSerializer.Deserialize(messageHeaderJson); - - return messageHeader; + return _messageHeaderSerializer.Deserialize(messageHeaderJson); } - public string Serialize(SaleToPOIMessage saleToPoiMessage) + private object GetDeserializedRepeatedResponseMessagePayload(JToken saletoPoiMessageJtoken) { - try + var repeatedMessageResponse = saletoPoiMessageJtoken.ToString(); + var repeatedMessage = saletoPoiMessageJtoken["TransactionStatusResponse"]["RepeatedMessageResponse"]["RepeatedResponseMessageBody"].ToString(); + var objMessage = JObject.Parse(repeatedMessage); + + if (repeatedMessageResponse.Contains("CardAcquisitionResponse")) { - return Converter.JSonConvertSerializerWrapper.Serialize(saleToPoiMessage); + return objMessage[repeatedMessageResponse].ToObject(); } - catch (Exception e) + if (repeatedMessageResponse.Contains("CardReaderAPDUResponse")) { - throw e; + return objMessage[repeatedMessageResponse].ToObject(); } - } - - public string Serialize(SaleToPoiMessageSecured saleToPoiMessage) - { - try + if (repeatedMessageResponse.Contains("LoyaltyResponse")) + { + return objMessage[repeatedMessageResponse].ToObject(); + } + if (repeatedMessageResponse.Contains("PaymentResponse")) { - return Converter.JSonConvertSerializerWrapper.Serialize(saleToPoiMessage); + return objMessage["PaymentResponse"].ToObject(); } - catch (Exception e) + if (repeatedMessageResponse.Contains("ReversalResponse")) { - throw e; + return objMessage[repeatedMessageResponse].ToObject(); } + if (repeatedMessageResponse.Contains("StoredValueResponse")) + { + return objMessage[repeatedMessageResponse].ToObject(); + } + return null; } - } } diff --git a/Adyen.EcommLibrary/Model/Nexo/MessageHeader.cs b/Adyen.EcommLibrary/Model/Nexo/MessageHeader.cs index 2bf04906d..5e623a8f0 100644 --- a/Adyen.EcommLibrary/Model/Nexo/MessageHeader.cs +++ b/Adyen.EcommLibrary/Model/Nexo/MessageHeader.cs @@ -7,7 +7,6 @@ [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class MessageHeader { - /// [System.Xml.Serialization.XmlAttributeAttribute()] public string ProtocolVersion; diff --git a/Adyen.EcommLibrary/Model/Nexo/RepeatedMessageResponse.cs b/Adyen.EcommLibrary/Model/Nexo/RepeatedMessageResponse.cs index 440841aaa..5477b1be4 100644 --- a/Adyen.EcommLibrary/Model/Nexo/RepeatedMessageResponse.cs +++ b/Adyen.EcommLibrary/Model/Nexo/RepeatedMessageResponse.cs @@ -1,24 +1,19 @@ -namespace Adyen.EcommLibrary.Model.Nexo +using Adyen.EcommLibrary.CloudApiSerialization; + +namespace Adyen.EcommLibrary.Model.Nexo { /// [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class RepeatedMessageResponse - { + public partial class RepeatedMessageResponse : IMessagePayload + { /// + [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] + public RepeatedResponseMessageBody RepeatedResponseMessageBody; /// [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public MessageHeader MessageHeader; - - /// - [System.Xml.Serialization.XmlElementAttribute("CardAcquisitionResponse", typeof(CardAcquisitionResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - [System.Xml.Serialization.XmlElementAttribute("CardReaderAPDUResponse", typeof(CardReaderAPDUResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - [System.Xml.Serialization.XmlElementAttribute("LoyaltyResponse", typeof(LoyaltyResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - [System.Xml.Serialization.XmlElementAttribute("PaymentResponse", typeof(PaymentResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - [System.Xml.Serialization.XmlElementAttribute("ReversalResponse", typeof(ReversalResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - [System.Xml.Serialization.XmlElementAttribute("StoredValueResponse", typeof(StoredValueResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] - public object Item; } } \ No newline at end of file diff --git a/Adyen.EcommLibrary/Model/Nexo/RepeatedResponseMessageBody.cs b/Adyen.EcommLibrary/Model/Nexo/RepeatedResponseMessageBody.cs new file mode 100644 index 000000000..2e544818f --- /dev/null +++ b/Adyen.EcommLibrary/Model/Nexo/RepeatedResponseMessageBody.cs @@ -0,0 +1,24 @@ +using Adyen.EcommLibrary.CloudApiSerialization; +using Newtonsoft.Json; +using System.Runtime.Serialization; + +namespace Adyen.EcommLibrary.Model.Nexo +{ + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] + [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] + public partial class RepeatedResponseMessageBody :IMessagePayload + { + [System.Xml.Serialization.XmlElementAttribute("CardAcquisitionResponse", typeof(CardAcquisitionResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] + [System.Xml.Serialization.XmlElementAttribute("CardReaderAPDUResponse", typeof(CardReaderAPDUResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] + [System.Xml.Serialization.XmlElementAttribute("LoyaltyResponse", typeof(LoyaltyResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] + [System.Xml.Serialization.XmlElementAttribute("PaymentResponse", typeof(PaymentResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] + [System.Xml.Serialization.XmlElementAttribute("ReversalResponse", typeof(ReversalResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] + [System.Xml.Serialization.XmlElementAttribute("StoredValueResponse", typeof(StoredValueResponse), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] + public dynamic MessagePayload; + } +} \ No newline at end of file diff --git a/Adyen.EcommLibrary/Model/Nexo/TransactionStatusResponse.cs b/Adyen.EcommLibrary/Model/Nexo/TransactionStatusResponse.cs index 32d12f964..92adeb919 100644 --- a/Adyen.EcommLibrary/Model/Nexo/TransactionStatusResponse.cs +++ b/Adyen.EcommLibrary/Model/Nexo/TransactionStatusResponse.cs @@ -9,7 +9,6 @@ namespace Adyen.EcommLibrary.Model.Nexo [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class TransactionStatusResponse : IMessagePayload { - /// [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public Response Response;