11namespace TransactionProcessor . BusinessLogic . Services
22{
33 using System ;
4+ using System . Collections . Generic ;
5+ using System . Linq ;
46 using System . Threading ;
57 using System . Threading . Tasks ;
8+ using EstateManagement . Client ;
9+ using EstateManagement . DataTransferObjects . Requests ;
10+ using EstateManagement . DataTransferObjects . Responses ;
611 using Models ;
12+ using SecurityService . Client ;
13+ using SecurityService . DataTransferObjects . Responses ;
714 using Shared . DomainDrivenDesign . EventStore ;
815 using Shared . EventStore . EventStore ;
16+ using Shared . General ;
17+ using Shared . Logger ;
918 using TransactionAggregate ;
1019
1120 /// <summary>
1423 /// <seealso cref="TransactionProcessor.BusinessLogic.Services.ITransactionDomainService" />
1524 public class TransactionDomainService : ITransactionDomainService
1625 {
26+ #region Fields
27+
28+ /// <summary>
29+ /// The aggregate repository manager
30+ /// </summary>
1731 private readonly IAggregateRepositoryManager AggregateRepositoryManager ;
1832
19- public TransactionDomainService ( IAggregateRepositoryManager aggregateRepositoryManager )
33+ /// <summary>
34+ /// The estate client
35+ /// </summary>
36+ private readonly IEstateClient EstateClient ;
37+
38+ /// <summary>
39+ /// The security service client
40+ /// </summary>
41+ private readonly ISecurityServiceClient SecurityServiceClient ;
42+
43+ #endregion
44+
45+ #region Constructors
46+
47+ /// <summary>
48+ /// Initializes a new instance of the <see cref="TransactionDomainService" /> class.
49+ /// </summary>
50+ /// <param name="aggregateRepositoryManager">The aggregate repository manager.</param>
51+ /// <param name="estateClient">The estate client.</param>
52+ /// <param name="securityServiceClient">The security service client.</param>
53+ public TransactionDomainService ( IAggregateRepositoryManager aggregateRepositoryManager ,
54+ IEstateClient estateClient ,
55+ ISecurityServiceClient securityServiceClient )
2056 {
2157 this . AggregateRepositoryManager = aggregateRepositoryManager ;
58+ this . EstateClient = estateClient ;
59+ this . SecurityServiceClient = securityServiceClient ;
2260 }
2361
62+ #endregion
63+
2464 #region Methods
2565
2666 /// <summary>
@@ -34,18 +74,36 @@ public TransactionDomainService(IAggregateRepositoryManager aggregateRepositoryM
3474 /// <param name="deviceIdentifier">The device identifier.</param>
3575 /// <param name="cancellationToken">The cancellation token.</param>
3676 /// <returns></returns>
37- public async Task < ProcessLogonTransactionResponse > ProcessLogonTransaction ( Guid transactionId , Guid estateId , Guid merchantId , DateTime transactionDateTime ,
38- String transactionNumber , String deviceIdentifier , CancellationToken cancellationToken )
77+ public async Task < ProcessLogonTransactionResponse > ProcessLogonTransaction ( Guid transactionId ,
78+ Guid estateId ,
79+ Guid merchantId ,
80+ DateTime transactionDateTime ,
81+ String transactionNumber ,
82+ String deviceIdentifier ,
83+ CancellationToken cancellationToken )
3984 {
40- IAggregateRepository < TransactionAggregate > transactionAggregateRepository = this . AggregateRepositoryManager . GetAggregateRepository < TransactionAggregate > ( estateId ) ;
41-
85+ IAggregateRepository < TransactionAggregate > transactionAggregateRepository =
86+ this . AggregateRepositoryManager . GetAggregateRepository < TransactionAggregate > ( estateId ) ;
87+
4288 TransactionAggregate transactionAggregate = await transactionAggregateRepository . GetLatestVersion ( transactionId , cancellationToken ) ;
4389 transactionAggregate . StartTransaction ( transactionDateTime , transactionNumber , "Logon" , estateId , merchantId , deviceIdentifier ) ;
4490 await transactionAggregateRepository . SaveChanges ( transactionAggregate , cancellationToken ) ;
4591
46- transactionAggregate = await transactionAggregateRepository . GetLatestVersion ( transactionId , cancellationToken ) ;
47- transactionAggregate . AuthoriseTransactionLocally ( "ABCD1234" , "0000" , "SUCCESS" ) ;
48- await transactionAggregateRepository . SaveChanges ( transactionAggregate , cancellationToken ) ;
92+ ( String responseMessage , TransactionResponseCode responseCode ) validationResult = await this . ValidateTransaction ( estateId , merchantId , deviceIdentifier , cancellationToken ) ;
93+
94+ if ( validationResult . responseCode == TransactionResponseCode . Success )
95+ {
96+ // Record the successful validation
97+ transactionAggregate = await transactionAggregateRepository . GetLatestVersion ( transactionId , cancellationToken ) ;
98+ // TODO: Generate local authcode
99+ transactionAggregate . AuthoriseTransactionLocally ( "ABCD1234" , ( ( Int32 ) validationResult . responseCode ) . ToString ( ) . PadLeft ( 4 , '0' ) , validationResult . responseMessage ) ;
100+ await transactionAggregateRepository . SaveChanges ( transactionAggregate , cancellationToken ) ;
101+ }
102+ else
103+ {
104+ // Record the failure
105+ throw new NotImplementedException ( ) ;
106+ }
49107
50108 transactionAggregate = await transactionAggregateRepository . GetLatestVersion ( transactionId , cancellationToken ) ;
51109 transactionAggregate . CompleteTransaction ( ) ;
@@ -60,7 +118,103 @@ public async Task<ProcessLogonTransactionResponse> ProcessLogonTransaction(Guid
60118 } ;
61119 }
62120
121+ /// <summary>
122+ /// Validates the transaction.
123+ /// </summary>
124+ /// <param name="estateId">The estate identifier.</param>
125+ /// <param name="merchantId">The merchant identifier.</param>
126+ /// <param name="deviceIdentifier">The device identifier.</param>
127+ /// <param name="cancellationToken">The cancellation token.</param>
128+ /// <returns></returns>
129+ /// <exception cref="TransactionProcessor.BusinessLogic.Services.TransactionValidationException">Device Identifier {deviceIdentifier} not valid for Merchant {merchant.MerchantName}</exception>
130+ private async Task < ( String responseMessage , TransactionResponseCode responseCode ) > ValidateTransaction ( Guid estateId ,
131+ Guid merchantId ,
132+ String deviceIdentifier ,
133+ CancellationToken cancellationToken )
134+ {
135+ try
136+ {
137+
138+ // Get a token to talk to the estate service
139+ String clientId = ConfigurationReader . GetValue ( "AppSettings" , "ClientId" ) ;
140+ String clientSecret = ConfigurationReader . GetValue ( "AppSettings" , "ClientSecret" ) ;
141+
142+ Logger . LogInformation ( $ "Client Id is { clientId } ") ;
143+ Logger . LogInformation ( $ "Client Secret is { clientSecret } ") ;
144+
145+ TokenResponse token = await this . SecurityServiceClient . GetToken ( clientId , clientSecret , cancellationToken ) ;
146+ Logger . LogInformation ( $ "Token is { token . AccessToken } ") ;
147+
148+ // get the merchant record and validate the device
149+ // TODO: Token
150+ MerchantResponse merchant = await this . EstateClient . GetMerchant ( token . AccessToken , estateId , merchantId , cancellationToken ) ;
151+
152+ if ( merchant . Devices == null || merchant . Devices . Any ( ) == false )
153+ {
154+ // Add the device to the merchant
155+ await this . EstateClient . AddDeviceToMerchant ( token . AccessToken ,
156+ estateId ,
157+ merchantId ,
158+ new AddMerchantDeviceRequest
159+ {
160+ DeviceIdentifier = deviceIdentifier
161+ } ,
162+ cancellationToken ) ;
163+ }
164+ else
165+ {
166+ // Validate the device
167+ KeyValuePair < Guid , String > device = merchant . Devices . SingleOrDefault ( d => d . Value == deviceIdentifier ) ;
168+
169+ if ( device . Key == Guid . Empty )
170+ {
171+ // Device not found,throw error
172+ throw new TransactionValidationException ( $ "Device Identifier { deviceIdentifier } not valid for Merchant { merchant . MerchantName } ", TransactionResponseCode . InvalidDeviceIdentifier ) ;
173+ }
174+ }
175+
176+ // If we get here everything is good
177+ return ( "SUCCESS" , TransactionResponseCode . Success ) ;
178+ }
179+ catch ( TransactionValidationException tvex )
180+ {
181+ return ( tvex . Message , tvex . ResponseCode ) ;
182+ }
183+
184+ }
63185
64186 #endregion
65187 }
188+
189+ public enum TransactionResponseCode
190+ {
191+ Success = 0 ,
192+ InvalidDeviceIdentifier = 1000
193+ }
194+
195+ public class TransactionValidationException : Exception
196+ {
197+ public TransactionResponseCode ResponseCode { get ; private set ; }
198+
199+ /// <summary>
200+ /// Initializes a new instance of the <see cref="TransactionValidationException" /> class.
201+ /// </summary>
202+ /// <param name="message">The message that describes the error.</param>
203+ /// <param name="responseCode">The response code.</param>
204+ public TransactionValidationException ( String message , TransactionResponseCode responseCode ) : this ( message , responseCode , null )
205+ {
206+
207+ }
208+
209+ /// <summary>
210+ /// Initializes a new instance of the <see cref="TransactionValidationException" /> class.
211+ /// </summary>
212+ /// <param name="message">The error message that explains the reason for the exception.</param>
213+ /// <param name="responseCode">The response code.</param>
214+ /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>
215+ public TransactionValidationException ( String message , TransactionResponseCode responseCode , Exception innerException ) : base ( message , innerException )
216+ {
217+ this . ResponseCode = responseCode ;
218+ }
219+ }
66220}
0 commit comments