diff --git a/Directory.Packages.props b/Directory.Packages.props
index 90b4e97..396b601 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -4,8 +4,8 @@
-
-
+
+
@@ -13,10 +13,10 @@
-
+
-
+
@@ -37,27 +37,22 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
diff --git a/FileProcessor.BusinessLogic.Tests/FileHandlersTests.cs b/FileProcessor.BusinessLogic.Tests/FileHandlersTests.cs
index 63aa666..bf4b3b3 100644
--- a/FileProcessor.BusinessLogic.Tests/FileHandlersTests.cs
+++ b/FileProcessor.BusinessLogic.Tests/FileHandlersTests.cs
@@ -66,17 +66,12 @@ public async Task UploadFile_WhenEventStoreAcceptanceFails_DeletesTemporaryFile(
FormFileCollection files = new() { formFile };
FormCollection formCollection = new(new Dictionary(), files);
+ DefaultHttpContext httpContext = new();
+ httpContext.Request.Form = formCollection;
await FileHandlers.UploadFile(
mediator.Instance(),
- new FileProcessor.DataTransferObjects.UploadFileRequest
- {
- FileId = TestData.FileId,
- EstateId = TestData.EstateId,
- MerchantId = TestData.MerchantId,
- UserId = TestData.UserId,
- FileProfileId = TestData.FileProfileId
- },
- formCollection,
+ CreateUploadRequest(formFile),
+ httpContext.Request,
CancellationToken.None);
Directory.GetFiles(temporaryDirectory).ShouldBeEmpty();
@@ -107,8 +102,15 @@ public async Task UploadFile_UsesUniqueTemporaryPathForRepeatedClientFilename()
IMediatorImposter mediator = new();
mediator.Send(Arg>.Any(), Arg.Any()).ReturnsAsync(Result.Success());
- await FileHandlers.UploadFile(mediator.Instance(), CreateUploadRequest(), CreateFormCollection(), CancellationToken.None);
- await FileHandlers.UploadFile(mediator.Instance(), CreateUploadRequest(), CreateFormCollection(), CancellationToken.None);
+ FormCollection firstForm = CreateFormCollection();
+ DefaultHttpContext firstContext = new();
+ firstContext.Request.Form = firstForm;
+ await FileHandlers.UploadFile(mediator.Instance(), CreateUploadRequest(firstForm.Files[0]), firstContext.Request, CancellationToken.None);
+
+ FormCollection secondForm = CreateFormCollection();
+ DefaultHttpContext secondContext = new();
+ secondContext.Request.Form = secondForm;
+ await FileHandlers.UploadFile(mediator.Instance(), CreateUploadRequest(secondForm.Files[0]), secondContext.Request, CancellationToken.None);
Directory.GetFiles(temporaryDirectory).Length.ShouldBe(2);
}
@@ -138,7 +140,10 @@ public async Task UploadFile_DoesNotUseClientFilenameCharactersInTemporaryPath()
IMediatorImposter mediator = new();
mediator.Send(Arg>.Any(), Arg.Any()).ReturnsAsync(Result.Success());
- await FileHandlers.UploadFile(mediator.Instance(), CreateUploadRequest(), CreateFormCollection("invoice:payload.csv"), CancellationToken.None);
+ FormCollection formCollection = CreateFormCollection("invoice:payload.csv");
+ DefaultHttpContext httpContext = new();
+ httpContext.Request.Form = formCollection;
+ await FileHandlers.UploadFile(mediator.Instance(), CreateUploadRequest(formCollection.Files[0]), httpContext.Request, CancellationToken.None);
string storedFileName = Path.GetFileName(Directory.GetFiles(temporaryDirectory).Single());
storedFileName.ShouldNotContain(":");
@@ -151,13 +156,14 @@ public async Task UploadFile_DoesNotUseClientFilenameCharactersInTemporaryPath()
}
}
- private static FileProcessor.DataTransferObjects.UploadFileRequest CreateUploadRequest() => new()
+ private static UploadFileForm CreateUploadRequest(IFormFile file) => new()
{
FileId = TestData.FileId,
EstateId = TestData.EstateId,
MerchantId = TestData.MerchantId,
UserId = TestData.UserId,
- FileProfileId = TestData.FileProfileId
+ FileProfileId = TestData.FileProfileId,
+ File = file
};
private static FormCollection CreateFormCollection(string fileName = "source.csv")
diff --git a/FileProcessor.BusinessLogic.Tests/MediatorTests.cs b/FileProcessor.BusinessLogic.Tests/MediatorTests.cs
index a79c670..962e11d 100644
--- a/FileProcessor.BusinessLogic.Tests/MediatorTests.cs
+++ b/FileProcessor.BusinessLogic.Tests/MediatorTests.cs
@@ -11,6 +11,8 @@
using System.Text;
using System.Threading.Tasks;
using FileProcessor.BusinessLogic.Managers;
+using FileProcessor.Bootstrapper;
+using FileProcessor.Common;
using Xunit;
namespace FileProcessor.BusinessLogic.Tests
@@ -20,6 +22,7 @@ namespace FileProcessor.BusinessLogic.Tests
using Services;
using Shared.DomainDrivenDesign.EventSourcing;
using Shared.EventStore.Aggregate;
+ using Shared.General;
public class MediatorTests
{
@@ -44,14 +47,24 @@ public async Task Mediator_Send_RequestHandled()
hostingEnvironment.ApplicationName.Getter().Returns("Test Application");
ServiceRegistry services = new ServiceRegistry();
- Startup s = new Startup(hostingEnvironment.Instance());
- Startup.Configuration = this.SetupMemoryConfiguration();
-
- this.AddTestRegistrations(services, hostingEnvironment.Instance());
- s.ConfigureContainer(services);
+ IConfigurationRoot configuration = this.SetupMemoryConfiguration();
+ ConfigurationReader.Initialise(configuration);
+
+ this.AddTestRegistrations(services, hostingEnvironment.Instance(), configuration);
+ TypeProvider.LoadDomainEventsTypeDynamically();
+ services.IncludeRegistry();
+ services.IncludeRegistry(new DomainEventHandlerRegistry(configuration));
+ services.IncludeRegistry(new RepositoryRegistry(configuration, hostingEnvironment.Instance()));
+ services.IncludeRegistry(new MiddlewareRegistry(configuration));
+ services.IncludeRegistry();
+ services.IncludeRegistry();
+ services.IncludeRegistry();
+ services.IncludeRegistry();
+
+ using Container container = new Container(services);
List errors = new List();
- IMediator mediator = Startup.Container.GetService();
+ IMediator mediator = container.GetService();
foreach (IBaseRequest baseRequest in this.Requests)
{
try
@@ -95,7 +108,8 @@ private IConfigurationRoot SetupMemoryConfiguration()
}
private void AddTestRegistrations(ServiceRegistry services,
- IWebHostEnvironment hostingEnvironment)
+ IWebHostEnvironment hostingEnvironment,
+ IConfiguration configuration)
{
services.AddLogging();
DiagnosticListener diagnosticSource = new DiagnosticListener(hostingEnvironment.ApplicationName);
@@ -103,7 +117,7 @@ private void AddTestRegistrations(ServiceRegistry services,
services.AddSingleton(diagnosticSource);
services.AddSingleton(hostingEnvironment);
services.AddSingleton(hostingEnvironment);
- services.AddSingleton(Startup.Configuration);
+ services.AddSingleton(configuration);
services.OverrideServices(s => {
s.AddSingleton();
diff --git a/FileProcessor.BusinessLogic/Services/FileProfileVersionMigrationService.cs b/FileProcessor.BusinessLogic/Services/FileProfileVersionMigrationService.cs
index 7a12b66..5c11d0e 100644
--- a/FileProcessor.BusinessLogic/Services/FileProfileVersionMigrationService.cs
+++ b/FileProcessor.BusinessLogic/Services/FileProfileVersionMigrationService.cs
@@ -1,4 +1,5 @@
-using System;
+using System;
+using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@@ -125,17 +126,31 @@ private Dictionary GetInitialVersions(List profile
private sealed record ExistingFile(Guid FileId, Guid FileProfileId);
}
+/// Summary of the file-profile version migration.
+[Description("Summary of the file-profile version migration.")]
public sealed class FileProfileVersionMigrationReport
{
+ /// Gets the number of profiles checked.
+ [Description("Number of profiles checked.")]
public Int32 ProfilesChecked { get; set; }
+ /// Gets the number of profiles that received an initial version.
+ [Description("Number of profiles that received an initial version.")]
public Int32 ProfilesWithInitialVersion { get; set; }
+ /// Gets the number of files checked.
+ [Description("Number of files checked.")]
public Int32 FilesChecked { get; set; }
+ /// Gets the number of files assigned to a profile version.
+ [Description("Number of files assigned to a profile version.")]
public Int32 FilesAssigned { get; set; }
+ /// Gets the number of files skipped by the migration.
+ [Description("Number of files skipped by the migration.")]
public Int32 FilesSkipped { get; set; }
+ /// Gets the migration failure messages.
+ [Description("Migration failure messages, if any.")]
public List Failures { get; } = new();
}
diff --git a/FileProcessor.DataTransferObjects/FileProcessor.DataTransferObjects.csproj b/FileProcessor.DataTransferObjects/FileProcessor.DataTransferObjects.csproj
index 89657bc..87ece4d 100644
--- a/FileProcessor.DataTransferObjects/FileProcessor.DataTransferObjects.csproj
+++ b/FileProcessor.DataTransferObjects/FileProcessor.DataTransferObjects.csproj
@@ -3,6 +3,7 @@
net10.0
None
+ true
diff --git a/FileProcessor.DataTransferObjects/Requests/CreateFileProfileRequest.cs b/FileProcessor.DataTransferObjects/Requests/CreateFileProfileRequest.cs
index 53639c6..4cb3b23 100644
--- a/FileProcessor.DataTransferObjects/Requests/CreateFileProfileRequest.cs
+++ b/FileProcessor.DataTransferObjects/Requests/CreateFileProfileRequest.cs
@@ -1,20 +1,37 @@
-using System;
+using System;
+using System.ComponentModel;
namespace FileProcessor.DataTransferObjects.Requests;
+/// Configuration for creating a file profile.
+[Description("Configuration for creating a file profile.")]
public class CreateFileProfileRequest
{
+ /// Gets or sets the identifier to assign to the new profile.
+ [Description("The identifier to assign to the new profile.")]
public Guid FileProfileId { get; set; }
+ /// Gets or sets the profile's display name.
+ [Description("The profile's display name.")]
public string Name { get; set; }
+ /// Gets or sets the directory from which files for this profile are collected.
+ [Description("The directory from which files for this profile are collected.")]
public string ListeningDirectory { get; set; }
+ /// Gets or sets the request or transaction type associated with files using this profile.
+ [Description("The request or transaction type associated with files using this profile.")]
public string RequestType { get; set; }
+ /// Gets or sets the operator name recorded for the profile.
+ [Description("The operator name recorded for the profile.")]
public string OperatorName { get; set; }
+ /// Gets or sets the required line ending used to separate records.
+ [Description("The required line ending used to separate records.")]
public LineTerminatorType? LineTerminator { get; set; }
+ /// Gets or sets the registered file format handler used to parse files for this profile.
+ [Description("The registered file format handler used to parse files for this profile.")]
public string FileFormatHandler { get; set; }
}
diff --git a/FileProcessor.DataTransferObjects/Requests/LineTerminatorType.cs b/FileProcessor.DataTransferObjects/Requests/LineTerminatorType.cs
index 5805298..2ff0af7 100644
--- a/FileProcessor.DataTransferObjects/Requests/LineTerminatorType.cs
+++ b/FileProcessor.DataTransferObjects/Requests/LineTerminatorType.cs
@@ -1,14 +1,23 @@
-using System;
+using System;
+using System.ComponentModel;
using System.Text.Json.Serialization;
namespace FileProcessor.DataTransferObjects.Requests;
+/// Line ending values accepted by file profile requests.
+[Description("Line ending values accepted by file profile requests.")]
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum LineTerminatorType
{
+ /// Line feed (LF, `\n`).
+ [Description("Line feed (LF, `\\n`).")]
LineFeed = 1,
+ /// Carriage return followed by line feed (CRLF, `\r\n`).
+ [Description("Carriage return followed by line feed (CRLF, `\\r\\n`).")]
CarriageReturnLineFeed = 2,
+ /// Carriage return (CR, `\r`).
+ [Description("Carriage return (CR, `\\r`).")]
CarriageReturn = 3
}
diff --git a/FileProcessor.DataTransferObjects/Requests/UpdateFileProfileRequest.cs b/FileProcessor.DataTransferObjects/Requests/UpdateFileProfileRequest.cs
index c09527c..1cbe488 100644
--- a/FileProcessor.DataTransferObjects/Requests/UpdateFileProfileRequest.cs
+++ b/FileProcessor.DataTransferObjects/Requests/UpdateFileProfileRequest.cs
@@ -1,16 +1,31 @@
+using System.ComponentModel;
namespace FileProcessor.DataTransferObjects.Requests;
+/// Configuration values to apply when updating a file profile.
+[Description("Configuration values to apply when updating a file profile.")]
public class UpdateFileProfileRequest
{
+ /// Gets or sets the profile's display name.
+ [Description("The profile's display name.")]
public string Name { get; set; }
+ /// Gets or sets the directory from which files for this profile are collected.
+ [Description("The directory from which files for this profile are collected.")]
public string ListeningDirectory { get; set; }
+ /// Gets or sets the request or transaction type associated with files using this profile.
+ [Description("The request or transaction type associated with files using this profile.")]
public string RequestType { get; set; }
+ /// Gets or sets the operator name recorded for the profile.
+ [Description("The operator name recorded for the profile.")]
public string OperatorName { get; set; }
+ /// Gets or sets the line ending used to separate records. When omitted, the profile's current value is retained.
+ [Description("The line ending used to separate records. When omitted, the profile's current value is retained.")]
public LineTerminatorType? LineTerminator { get; set; }
+ /// Gets or sets the registered file format handler used to parse files for this profile.
+ [Description("The registered file format handler used to parse files for this profile.")]
public string FileFormatHandler { get; set; }
}
diff --git a/FileProcessor.DataTransferObjects/Requests/UploadFileRequest.cs b/FileProcessor.DataTransferObjects/Requests/UploadFileRequest.cs
index 354462a..3611d92 100644
--- a/FileProcessor.DataTransferObjects/Requests/UploadFileRequest.cs
+++ b/FileProcessor.DataTransferObjects/Requests/UploadFileRequest.cs
@@ -1,22 +1,34 @@
using System;
+using System.ComponentModel;
namespace FileProcessor.DataTransferObjects
{
- ///
- ///
- ///
+ /// Metadata submitted with a file upload.
+ [Description("Metadata submitted with a file upload.")]
public class UploadFileRequest
{
+ /// Gets or sets the caller-supplied identifier for the file being uploaded.
+ [Description("The caller-supplied identifier for the file being uploaded.")]
public Guid FileId { get; set; }
+ /// Gets or sets the identifier of the estate that owns the file.
+ [Description("The identifier of the estate that owns the file.")]
public Guid EstateId { get; set; }
+ /// Gets or sets the identifier of the merchant associated with the file.
+ [Description("The identifier of the merchant associated with the file.")]
public Guid MerchantId { get; set; }
+ /// Gets or sets the identifier of the user submitting the file.
+ [Description("The identifier of the user submitting the file.")]
public Guid UserId { get; set; }
+ /// Gets or sets the identifier of the file profile used to process the file.
+ [Description("The identifier of the file profile used to process the file.")]
public Guid FileProfileId { get; set; }
+ /// Gets or sets the time the file was uploaded. If omitted or set to the minimum date value, the server uses the current local time.
+ [Description("The time the file was uploaded. If omitted or set to the minimum date value, the server uses the current local time.")]
public DateTime UploadDateTime { get; set; }
}
}
diff --git a/FileProcessor.DataTransferObjects/Responses/FileDetails.cs b/FileProcessor.DataTransferObjects/Responses/FileDetails.cs
index 3063652..ae858eb 100644
--- a/FileProcessor.DataTransferObjects/Responses/FileDetails.cs
+++ b/FileProcessor.DataTransferObjects/Responses/FileDetails.cs
@@ -1,46 +1,87 @@
namespace FileProcessor.DataTransferObjects.Responses
{
using System;
+ using System.ComponentModel;
using System.Collections.Generic;
+ /// File metadata, processing state, line results, and summary returned by file queries.
+ [Description("File metadata, processing state, line results, and summary returned by file queries.")]
public class FileDetails
{
+ /// Gets or sets the file identifier.
+ [Description("The file identifier.")]
public Guid FileId { get; set; }
+ /// Gets or sets whether processing of the file has completed.
+ [Description("Whether processing of the file has completed.")]
public Boolean ProcessingCompleted { get; set; }
+ /// Gets or sets whether the file was rejected before or during processing.
+ [Description("Whether the file was rejected before or during processing.")]
public Boolean IsRejected { get; set; }
+ /// Gets or sets the machine-readable reason code when the file was rejected.
+ [Description("The machine-readable reason code when the file was rejected.")]
public String RejectionCode { get; set; }
+ /// Gets or sets the human-readable reason when the file was rejected.
+ [Description("The human-readable reason when the file was rejected.")]
public String RejectionReason { get; set; }
+ /// Gets or sets the number of detail records observed in the uploaded file.
+ [Description("The number of detail records observed in the uploaded file.")]
public Int32 ObservedDetailRecordCount { get; set; }
+ /// Gets or sets the configured maximum number of detail records allowed.
+ [Description("The configured maximum number of detail records allowed.")]
public Int32 MaximumDetailRecordCount { get; set; }
+ /// Gets or sets the identifier of the owning estate.
+ [Description("The identifier of the owning estate.")]
public Guid EstateId { get; set; }
+ /// Gets or sets the identifier of the uploading user.
+ [Description("The identifier of the uploading user.")]
public Guid UserId { get; set; }
+ /// Gets or sets the email address of the uploading user, when available.
+ [Description("The email address of the uploading user, when available.")]
public String UserEmailAddress { get; set; }
+ /// Gets or sets the identifier of the associated merchant.
+ [Description("The identifier of the associated merchant.")]
public Guid MerchantId { get; set; }
+ /// Gets or sets the name of the associated merchant.
+ [Description("The name of the associated merchant.")]
public String MerchantName { get; set; }
+ /// Gets or sets the identifier of the file profile used to process the file.
+ [Description("The identifier of the file profile used to process the file.")]
public Guid FileProfileId { get; set; }
+ /// Gets or sets the identifier of the file profile version used to process the file.
+ [Description("The identifier of the file profile version used to process the file.")]
public Guid FileProfileVersionId { get; set; }
+ /// Gets or sets the name of the file profile used to process the file.
+ [Description("The name of the file profile used to process the file.")]
public String FileProfileName { get; set; }
+ /// Gets or sets the import log that contains this file.
+ [Description("The import log that contains this file.")]
public Guid FileImportLogId { get; set; }
+ /// Gets or sets the stored file location.
+ [Description("The stored file location.")]
public String FileLocation { get; set; }
+ /// Gets or sets the individual processing results for the file's lines.
+ [Description("The individual processing results for the file's lines.")]
public List FileLines { get; set; }
+ /// Gets or sets counts of lines by processing outcome.
+ [Description("Counts of lines by processing outcome.")]
public FileProcessingSummary ProcessingSummary { get; set; }
}
}
diff --git a/FileProcessor.DataTransferObjects/Responses/FileImportLog.cs b/FileProcessor.DataTransferObjects/Responses/FileImportLog.cs
index 7951d5d..f3521ad 100644
--- a/FileProcessor.DataTransferObjects/Responses/FileImportLog.cs
+++ b/FileProcessor.DataTransferObjects/Responses/FileImportLog.cs
@@ -1,20 +1,35 @@
namespace FileProcessor.DataTransferObjects.Responses
{
using System;
+ using System.ComponentModel;
using System.Collections.Generic;
+ /// A summary of files uploaded during one import period.
+ [Description("A summary of files uploaded during one import period.")]
public class FileImportLog
{
+ /// Gets or sets the identifier of this import log.
+ [Description("The identifier of this import log.")]
public Guid FileImportLogId { get; set; }
+ /// Gets or sets the import log timestamp.
+ [Description("The import log timestamp.")]
public DateTime ImportLogDateTime { get; set; }
+ /// Gets or sets the calendar date of the import log.
+ [Description("The calendar date of the import log.")]
public DateTime ImportLogDate { get; set; }
+ /// Gets or sets the time of day of the import log.
+ [Description("The time of day of the import log.")]
public TimeSpan ImportLogTime { get; set; }
+ /// Gets or sets the number of files in this log.
+ [Description("The number of files in this log.")]
public Int32 FileCount { get; set; }
+ /// Gets or sets the files included in this log.
+ [Description("The files included in this log.")]
public List Files { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/FileProcessor.DataTransferObjects/Responses/FileImportLogFile.cs b/FileProcessor.DataTransferObjects/Responses/FileImportLogFile.cs
index f851692..17425e7 100644
--- a/FileProcessor.DataTransferObjects/Responses/FileImportLogFile.cs
+++ b/FileProcessor.DataTransferObjects/Responses/FileImportLogFile.cs
@@ -1,28 +1,45 @@
namespace FileProcessor.DataTransferObjects.Responses
{
using System;
+ using System.ComponentModel;
+ /// File metadata contained in an import log response.
+ [Description("File metadata contained in an import log response.")]
public class FileImportLogFile
{
- #region Properties
-
+ /// Gets or sets the identifier of the uploaded file.
+ [Description("The identifier of the uploaded file.")]
public Guid FileId { get; set; }
+ /// Gets or sets the identifier of the import log containing the file.
+ [Description("The identifier of the import log containing the file.")]
public Guid FileImportLogId { get; set; }
+ /// Gets or sets the stored file path.
+ [Description("The stored file path.")]
public String FilePath { get; set; }
+ /// Gets or sets the identifier of the file profile used to process the file.
+ [Description("The identifier of the file profile used to process the file.")]
public Guid FileProfileId { get; set; }
+ /// Gets or sets the identifier of the file profile version used to process the file.
+ [Description("The identifier of the file profile version used to process the file.")]
public Guid FileProfileVersionId { get; set; }
+ /// Gets or sets when the file was uploaded.
+ [Description("When the file was uploaded.")]
public DateTime FileUploadedDateTime { get; set; }
+ /// Gets or sets the identifier of the associated merchant.
+ [Description("The identifier of the associated merchant.")]
public Guid MerchantId { get; set; }
+ /// Gets or sets the original name of the uploaded file.
+ [Description("The original name of the uploaded file.")]
public String OriginalFileName { get; set; }
+ /// Gets or sets the identifier of the user who uploaded the file.
+ [Description("The identifier of the user who uploaded the file.")]
public Guid UserId { get; set; }
-
- #endregion
}
}
diff --git a/FileProcessor.DataTransferObjects/Responses/FileImportLogList.cs b/FileProcessor.DataTransferObjects/Responses/FileImportLogList.cs
index eadb0d1..4840615 100644
--- a/FileProcessor.DataTransferObjects/Responses/FileImportLogList.cs
+++ b/FileProcessor.DataTransferObjects/Responses/FileImportLogList.cs
@@ -1,24 +1,30 @@
-namespace FileProcessor.DataTransferObjects.Responses
+using System.ComponentModel;
+namespace FileProcessor.DataTransferObjects.Responses
{
using System.Collections.Generic;
- ///
- ///
- ///
+ /// A paginated collection of file import logs.
+ [Description("A paginated collection of file import logs.")]
public class FileImportLogList
{
- #region Fields
-
+ /// Gets or sets the import logs on the current page.
+ [Description("The import logs on the current page.")]
public List FileImportLogs { get; set; }
+ /// Gets or sets the one-based current page number.
+ [Description("The one-based current page number.")]
public int PageNumber { get; set; }
+ /// Gets or sets the maximum number of results requested per page.
+ [Description("The maximum number of results requested per page.")]
public int PageSize { get; set; }
+ /// Gets or sets the total number of matching logs across all pages.
+ [Description("The total number of matching logs across all pages.")]
public int TotalCount { get; set; }
+ /// Gets or sets whether additional matching results are available on a later page.
+ [Description("Whether additional matching results are available on a later page.")]
public bool HasMore { get; set; }
-
- #endregion
}
}
diff --git a/FileProcessor.DataTransferObjects/Responses/FileLine.cs b/FileProcessor.DataTransferObjects/Responses/FileLine.cs
index 51561ad..278818c 100644
--- a/FileProcessor.DataTransferObjects/Responses/FileLine.cs
+++ b/FileProcessor.DataTransferObjects/Responses/FileLine.cs
@@ -1,27 +1,50 @@
namespace FileProcessor.DataTransferObjects.Responses
{
using System;
+ using System.ComponentModel;
using System.Collections.Generic;
+ /// Processing details for one line in an uploaded file.
+ [Description("Processing details for one line in an uploaded file.")]
public class FileLine
{
+ /// Gets or sets the original text of this line.
+ [Description("The original text of this line.")]
public String LineData { get; set; }
+ /// Gets or sets the one-based line number in the uploaded file.
+ [Description("The one-based line number in the uploaded file.")]
public Int32 LineNumber { get; set; }
+ /// Gets or sets the processing outcome for this line.
+ [Description("The processing outcome for this line.")]
public FileLineProcessingResult ProcessingResult { get; set; }
+ /// Gets or sets the transaction identifier created for this line, when available.
+ [Description("The transaction identifier created for this line, when available.")]
public Guid TransactionId { get; set; }
+ /// Gets or sets the domain event identifier produced for this line, when available.
+ [Description("The domain event identifier produced for this line, when available.")]
public Guid EventId { get; set; }
+ /// Gets or sets the rejection reason when the line was rejected.
+ [Description("The rejection reason when the line was rejected.")]
public String RejectionReason { get; set; }
+ /// Gets or sets the failure reason when processing the line failed.
+ [Description("The failure reason when processing the line failed.")]
public String FailureReason { get; set; }
+ /// Gets or sets the response code returned for the line, when available.
+ [Description("The response code returned for the line, when available.")]
public String ResponseCode { get; set; }
+ /// Gets or sets the number of dispatch attempts made for the line.
+ [Description("The number of dispatch attempts made for the line.")]
public Int32 DispatchAttemptCount { get; set; }
+ /// Gets or sets failed transaction dispatch attempts associated with the line.
+ [Description("Failed transaction dispatch attempts associated with the line.")]
public List FailedDispatchAttempts { get; set; } = new();
}
}
diff --git a/FileProcessor.DataTransferObjects/Responses/FileLineProcessingResult.cs b/FileProcessor.DataTransferObjects/Responses/FileLineProcessingResult.cs
index 4a102f4..76f63b2 100644
--- a/FileProcessor.DataTransferObjects/Responses/FileLineProcessingResult.cs
+++ b/FileProcessor.DataTransferObjects/Responses/FileLineProcessingResult.cs
@@ -1,35 +1,32 @@
-namespace FileProcessor.DataTransferObjects.Responses
+using System.ComponentModel;
+namespace FileProcessor.DataTransferObjects.Responses
{
+ /// Possible outcomes for a processed file line.
+ [Description("Possible outcomes for a processed file line.")]
public enum FileLineProcessingResult
{
- ///
- /// The unknown
- ///
+ /// The processing outcome is not known.
+ [Description("The processing outcome is not known.")]
Unknown,
- ///
- /// The not processed
- ///
+ /// The line has not been processed.
+ [Description("The line has not been processed.")]
NotProcessed,
- ///
- /// The successful
- ///
+ /// The line was processed successfully.
+ [Description("The line was processed successfully.")]
Successful,
- ///
- /// The failed
- ///
+ /// Processing the line failed.
+ [Description("Processing the line failed.")]
Failed,
- ///
- /// The ignored
- ///
+ /// The line was intentionally ignored.
+ [Description("The line was intentionally ignored.")]
Ignored,
- ///
- /// The rejected
- ///
+ /// The line or file was rejected by validation.
+ [Description("The line or file was rejected by validation.")]
Rejected
}
-}
\ No newline at end of file
+}
diff --git a/FileProcessor.DataTransferObjects/Responses/FileProcessingSummary.cs b/FileProcessor.DataTransferObjects/Responses/FileProcessingSummary.cs
index 79e3e67..c2c9ba4 100644
--- a/FileProcessor.DataTransferObjects/Responses/FileProcessingSummary.cs
+++ b/FileProcessor.DataTransferObjects/Responses/FileProcessingSummary.cs
@@ -1,19 +1,34 @@
namespace FileProcessor.DataTransferObjects.Responses
{
using System;
+ using System.ComponentModel;
+ /// Counts of file lines grouped by processing outcome.
+ [Description("Counts of file lines grouped by processing outcome.")]
public class FileProcessingSummary
{
+ /// Gets or sets the number of lines that failed during processing.
+ [Description("The number of lines that failed during processing.")]
public Int32 FailedLines { get; set; }
+ /// Gets or sets the number of lines intentionally ignored.
+ [Description("The number of lines intentionally ignored.")]
public Int32 IgnoredLines { get; set; }
+ /// Gets or sets the number of lines not processed.
+ [Description("The number of lines not processed.")]
public Int32 NotProcessedLines { get; set; }
+ /// Gets or sets the number of rejected lines.
+ [Description("The number of rejected lines.")]
public Int32 RejectedLines { get; set; }
+ /// Gets or sets the number of successfully processed lines.
+ [Description("The number of successfully processed lines.")]
public Int32 SuccessfullyProcessedLines { get; set; }
+ /// Gets or sets the total number of lines in the file.
+ [Description("The total number of lines in the file.")]
public Int32 TotalLines { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/FileProcessor.DataTransferObjects/Responses/FileProfileResponse.cs b/FileProcessor.DataTransferObjects/Responses/FileProfileResponse.cs
new file mode 100644
index 0000000..0ac1640
--- /dev/null
+++ b/FileProcessor.DataTransferObjects/Responses/FileProfileResponse.cs
@@ -0,0 +1,53 @@
+using System;
+using System.ComponentModel;
+
+namespace FileProcessor.DataTransferObjects.Responses;
+
+/// File profile configuration returned by the API.
+[Description("File profile configuration returned by the API.")]
+public class FileProfileResponse
+{
+ /// Gets or sets the identifier of the profile.
+ [Description("The identifier of the profile.")]
+ public Guid FileProfileId { get; set; }
+
+ /// Gets or sets the identifier of this profile version.
+ [Description("The identifier of this profile version.")]
+ public Guid FileProfileVersionId { get; set; }
+
+ /// Gets or sets the version number, starting at one.
+ [Description("The version number, starting at one.")]
+ public Int32 FileProfileVersion { get; set; }
+
+ /// Gets or sets the profile's display name.
+ [Description("The profile's display name.")]
+ public String Name { get; set; }
+
+ /// Gets or sets the operator name.
+ [Description("The operator name.")]
+ public String OperatorName { get; set; }
+
+ /// Gets or sets the directory from which files are collected.
+ [Description("The directory from which files are collected.")]
+ public String ListeningDirectory { get; set; }
+
+ /// Gets or sets the directory where successfully processed files are placed.
+ [Description("The directory where successfully processed files are placed.")]
+ public String ProcessedDirectory { get; set; }
+
+ /// Gets or sets the directory where failed files are placed.
+ [Description("The directory where failed files are placed.")]
+ public String FailedDirectory { get; set; }
+
+ /// Gets or sets the registered file format handler.
+ [Description("The registered file format handler.")]
+ public String FileFormatHandler { get; set; }
+
+ /// Gets or sets the request or transaction type.
+ [Description("The request or transaction type.")]
+ public String RequestType { get; set; }
+
+ /// Gets or sets the line terminator used to separate records.
+ [Description("The line terminator used to separate records.")]
+ public String LineTerminator { get; set; }
+}
diff --git a/FileProcessor.DataTransferObjects/Responses/TransactionDispatchAttempt.cs b/FileProcessor.DataTransferObjects/Responses/TransactionDispatchAttempt.cs
index f604a75..5f8d6ca 100644
--- a/FileProcessor.DataTransferObjects/Responses/TransactionDispatchAttempt.cs
+++ b/FileProcessor.DataTransferObjects/Responses/TransactionDispatchAttempt.cs
@@ -1,13 +1,22 @@
-namespace FileProcessor.DataTransferObjects.Responses
+namespace FileProcessor.DataTransferObjects.Responses
{
using System;
+ using System.ComponentModel;
+ /// Details of a failed attempt to dispatch a transaction from a file line.
+ [Description("Details of a failed attempt to dispatch a transaction from a file line.")]
public class TransactionDispatchAttempt
{
+ /// Gets or sets the transaction's position in the dispatch batch.
+ [Description("The transaction's position in the dispatch batch.")]
public Int32 TransactionNumber { get; set; }
+ /// Gets or sets the type or category of the dispatch failure.
+ [Description("The type or category of the dispatch failure.")]
public String FailureType { get; set; }
+ /// Gets or sets when the dispatch attempt occurred.
+ [Description("When the dispatch attempt occurred.")]
public DateTime AttemptedAt { get; set; }
}
}
diff --git a/FileProcessor.IntegrationTests/Common/DockerHelper.cs b/FileProcessor.IntegrationTests/Common/DockerHelper.cs
index 0d114cf..ceddffc 100644
--- a/FileProcessor.IntegrationTests/Common/DockerHelper.cs
+++ b/FileProcessor.IntegrationTests/Common/DockerHelper.cs
@@ -1,4 +1,5 @@
using DotNet.Testcontainers.Builders;
+using KurrentDB.Client;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -34,7 +35,7 @@ public class DockerHelper : global::Shared.IntegrationTesting.TestContainers.Doc
private readonly TestingContext TestingContext;
- public EventStoreProjectionManagementClient ProjectionManagementClient;
+ public KurrentDBProjectionManagementClient ProjectionManagementClient;
public IAgencyBankingClient AgencyBankingClient;
@@ -83,9 +84,9 @@ public override ContainerBuilder SetupFileProcessorContainer() {
public String AccessToken;
- protected override String GenerateEventStoreConnectionString(String userName = "admin", String password = "changeit")
+ protected override String GenerateKurrentDbConnectionString(String userName = "admin", String password = "changeit")
{
- String eventStoreAddress = $"esdb://{userName}:{password}@{this.EventStoreContainerName}:{DockerPorts.EventStoreHttpDockerPort}?tls=false&defaultDeadline=240000";
+ String eventStoreAddress = $"esdb://{userName}:{password}@{this.KurrentDbContainerName}:{DockerPorts.KurrentDbHttpDockerPort}?tls=false&defaultDeadline=240000";
return eventStoreAddress;
}
@@ -126,7 +127,7 @@ public override async Task StartContainersForScenarioRun(String scenarioName, Do
this.TestHostHttpClient.BaseAddress = new Uri($"http://127.0.0.1:{this.TestHostServicePort}");
this.AgencyBankingClient = new AgencyBankingClient(TestHostServiceBaseAddressResolver, httpClient, Serialise_CamelCase, this.Deserialise_CamelCase);
- this.ProjectionManagementClient = new EventStoreProjectionManagementClient(ConfigureEventStoreSettings());
+ this.ProjectionManagementClient = new KurrentDBProjectionManagementClient(this.ConfigureKurrentDbSettings());
SimpleResults.Result bootstrapToken = await this.SecurityServiceClient.GetToken("management-bootstrap", "management-bootstrap-secret", CancellationToken.None);
if (bootstrapToken.IsFailed || String.IsNullOrWhiteSpace(bootstrapToken.Data?.AccessToken))
diff --git a/FileProcessor.IntegrationTests/Common/GenericSteps.cs b/FileProcessor.IntegrationTests/Common/GenericSteps.cs
index 8f99710..c2df755 100644
--- a/FileProcessor.IntegrationTests/Common/GenericSteps.cs
+++ b/FileProcessor.IntegrationTests/Common/GenericSteps.cs
@@ -67,11 +67,11 @@ private DockerServices GetDockerServicesForScenario()
// the rest of the transaction-processing stack is unnecessary for these scenarios.
if (scenarioTitle.Contains("file profile", StringComparison.OrdinalIgnoreCase))
{
- return DockerServices.EventStore | DockerServices.FileProcessor | DockerServices.SecurityService |
+ return DockerServices.KurrentDb | DockerServices.FileProcessor | DockerServices.SecurityService |
DockerServices.SqlServer | DockerServices.TransactionProcessor;
}
- return DockerServices.EventStore | DockerServices.FileProcessor | DockerServices.MessagingService |
+ return DockerServices.KurrentDb | DockerServices.FileProcessor | DockerServices.MessagingService |
DockerServices.SecurityService | DockerServices.SqlServer | DockerServices.TestHost | DockerServices.TransactionProcessor;
}
diff --git a/FileProcessor.IntegrationTests/Features/FileProfile.feature.cs b/FileProcessor.IntegrationTests/Features/FileProfile.feature.cs
index 2330048..c1d7bc3 100644
--- a/FileProcessor.IntegrationTests/Features/FileProfile.feature.cs
+++ b/FileProcessor.IntegrationTests/Features/FileProfile.feature.cs
@@ -25,7 +25,7 @@ namespace FileProcessor.IntegrationTests.Features
[global::NUnit.Framework.CategoryAttribute("fileprofiles")]
public partial class FileProfileFeature
{
-
+
private global::Reqnroll.ITestRunner testRunner;
private static string[] featureTags = new string[] {
@@ -168,7 +168,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
{
return new global::Reqnroll.Formatters.RuntimeSupport.FeatureLevelCucumberMessages("Features/FileProfile.feature.ndjson", 5);
}
-
+
[global::NUnit.Framework.TestAttribute()]
[global::NUnit.Framework.DescriptionAttribute("Create, update and list file profiles")]
[global::NUnit.Framework.CategoryAttribute("PRTest")]
@@ -276,7 +276,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
}
await this.ScenarioCleanupAsync();
}
-
+
[global::NUnit.Framework.TestAttribute()]
[global::NUnit.Framework.DescriptionAttribute("Reject duplicate file profile name and request type")]
public async global::System.Threading.Tasks.Task RejectDuplicateFileProfileNameAndRequestType()
@@ -348,7 +348,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
}
await this.ScenarioCleanupAsync();
}
-
+
[global::NUnit.Framework.TestAttribute()]
[global::NUnit.Framework.DescriptionAttribute("Reject unsupported processing configuration")]
public async global::System.Threading.Tasks.Task RejectUnsupportedProcessingConfiguration()
diff --git a/FileProcessor.IntegrationTests/Features/GetFileImportDetails.feature.cs b/FileProcessor.IntegrationTests/Features/GetFileImportDetails.feature.cs
index 22ba604..f7d7433 100644
--- a/FileProcessor.IntegrationTests/Features/GetFileImportDetails.feature.cs
+++ b/FileProcessor.IntegrationTests/Features/GetFileImportDetails.feature.cs
@@ -115,66 +115,66 @@ public void ScenarioInitialize(global::Reqnroll.ScenarioInfo scenarioInfo, globa
{
#line 4
#line hidden
- global::Reqnroll.Table table10 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table11 = new global::Reqnroll.Table(new string[] {
"Name",
"DisplayName",
"Description"});
- table10.AddRow(new string[] {
+ table11.AddRow(new string[] {
"transactionProcessor",
"Transaction Processor REST Scope",
"A scope for Transaction Processor REST"});
- table10.AddRow(new string[] {
+ table11.AddRow(new string[] {
"fileProcessor",
"File Processor REST Scope",
"A scope for File Processor REST"});
#line 5
- await testRunner.GivenAsync("I create the following api scopes", ((string)(null)), table10, "Given ");
+ await testRunner.GivenAsync("I create the following api scopes", ((string)(null)), table11, "Given ");
#line hidden
- global::Reqnroll.Table table11 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table12 = new global::Reqnroll.Table(new string[] {
"Name",
"DisplayName",
"Secret",
"Scopes",
"UserClaims"});
- table11.AddRow(new string[] {
+ table12.AddRow(new string[] {
"transactionProcessor",
"Transaction Processor REST",
"Secret1",
"transactionProcessor",
"MerchantId, EstateId, role"});
- table11.AddRow(new string[] {
+ table12.AddRow(new string[] {
"fileProcessor",
"File Processor REST",
"Secret1",
"fileProcessor",
""});
#line 10
- await testRunner.GivenAsync("the following api resources exist", ((string)(null)), table11, "Given ");
+ await testRunner.GivenAsync("the following api resources exist", ((string)(null)), table12, "Given ");
#line hidden
- global::Reqnroll.Table table12 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table13 = new global::Reqnroll.Table(new string[] {
"ClientId",
"ClientName",
"Secret",
"Scopes",
"GrantTypes"});
- table12.AddRow(new string[] {
+ table13.AddRow(new string[] {
"serviceClient",
"Service Client",
"Secret1",
"transactionProcessor,fileProcessor",
"client_credentials"});
#line 15
- await testRunner.GivenAsync("the following clients exist", ((string)(null)), table12, "Given ");
+ await testRunner.GivenAsync("the following clients exist", ((string)(null)), table13, "Given ");
#line hidden
- global::Reqnroll.Table table13 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table14 = new global::Reqnroll.Table(new string[] {
"ClientId"});
- table13.AddRow(new string[] {
+ table14.AddRow(new string[] {
"serviceClient"});
#line 19
await testRunner.GivenAsync("I have a token to access the estate management and transaction processor resource" +
- "s", ((string)(null)), table13, "Given ");
+ "s", ((string)(null)), table14, "Given ");
#line hidden
- global::Reqnroll.Table table14 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table15 = new global::Reqnroll.Table(new string[] {
"Alias",
"FileProfileId",
"Name",
@@ -183,7 +183,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"OperatorName",
"LineTerminator",
"FileFormatHandler"});
- table14.AddRow(new string[] {
+ table15.AddRow(new string[] {
"Safaricom Topup",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"Safaricom Topup",
@@ -192,7 +192,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"Safaricom",
"1",
"SafaricomFileFormatHandler"});
- table14.AddRow(new string[] {
+ table15.AddRow(new string[] {
"Voucher Issue",
"8806EDBC-3ED6-406B-9E5F-A9078356BE99",
"Voucher Issue",
@@ -202,61 +202,61 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"1",
"VoucherFileFormatHandler"});
#line 23
- await testRunner.WhenAsync("I create the following file profiles", ((string)(null)), table14, "When ");
+ await testRunner.WhenAsync("I create the following file profiles", ((string)(null)), table15, "When ");
#line hidden
- global::Reqnroll.Table table15 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table16 = new global::Reqnroll.Table(new string[] {
"EstateName"});
- table15.AddRow(new string[] {
+ table16.AddRow(new string[] {
"Test Estate 1"});
#line 28
- await testRunner.GivenAsync("I have created the following estates", ((string)(null)), table15, "Given ");
+ await testRunner.GivenAsync("I have created the following estates", ((string)(null)), table16, "Given ");
#line hidden
- global::Reqnroll.Table table16 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table17 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"RequireCustomMerchantNumber",
"RequireCustomTerminalNumber"});
- table16.AddRow(new string[] {
+ table17.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"True",
"True"});
- table16.AddRow(new string[] {
+ table17.AddRow(new string[] {
"Test Estate 1",
"Voucher",
"True",
"True"});
#line 32
- await testRunner.GivenAsync("I have created the following operators", ((string)(null)), table16, "Given ");
+ await testRunner.GivenAsync("I have created the following operators", ((string)(null)), table17, "Given ");
#line hidden
- global::Reqnroll.Table table17 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table18 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName"});
- table17.AddRow(new string[] {
+ table18.AddRow(new string[] {
"Test Estate 1",
"Safaricom"});
- table17.AddRow(new string[] {
+ table18.AddRow(new string[] {
"Test Estate 1",
"Voucher"});
#line 37
- await testRunner.AndAsync("I have assigned the following operators to the estates", ((string)(null)), table17, "And ");
+ await testRunner.AndAsync("I have assigned the following operators to the estates", ((string)(null)), table18, "And ");
#line hidden
- global::Reqnroll.Table table18 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table19 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"ContractDescription"});
- table18.AddRow(new string[] {
+ table19.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"Safaricom Contract"});
- table18.AddRow(new string[] {
+ table19.AddRow(new string[] {
"Test Estate 1",
"Voucher",
"Hospital 1 Contract"});
#line 42
- await testRunner.GivenAsync("I create a contract with the following values", ((string)(null)), table18, "Given ");
+ await testRunner.GivenAsync("I create a contract with the following values", ((string)(null)), table19, "Given ");
#line hidden
- global::Reqnroll.Table table19 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table20 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"ContractDescription",
@@ -264,7 +264,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"DisplayText",
"Value",
"ProductType"});
- table19.AddRow(new string[] {
+ table20.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"Safaricom Contract",
@@ -272,7 +272,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"Custom",
"",
"MobileTopup"});
- table19.AddRow(new string[] {
+ table20.AddRow(new string[] {
"Test Estate 1",
"Voucher",
"Hospital 1 Contract",
@@ -281,9 +281,9 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"",
"Voucher"});
#line 47
- await testRunner.WhenAsync("I create the following Products", ((string)(null)), table19, "When ");
+ await testRunner.WhenAsync("I create the following Products", ((string)(null)), table20, "When ");
#line hidden
- global::Reqnroll.Table table20 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table21 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"ContractDescription",
@@ -291,7 +291,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"CalculationType",
"FeeDescription",
"Value"});
- table20.AddRow(new string[] {
+ table21.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"Safaricom Contract",
@@ -300,9 +300,9 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"Merchant Commission",
"2.50"});
#line 52
- await testRunner.WhenAsync("I add the following Transaction Fees", ((string)(null)), table20, "When ");
+ await testRunner.WhenAsync("I add the following Transaction Fees", ((string)(null)), table21, "When ");
#line hidden
- global::Reqnroll.Table table21 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table22 = new global::Reqnroll.Table(new string[] {
"MerchantName",
"AddressLine1",
"Town",
@@ -312,7 +312,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"ContactName",
"EmailAddress",
"EstateName"});
- table21.AddRow(new string[] {
+ table22.AddRow(new string[] {
"Test Merchant 1",
"Address Line 1",
"TestTown",
@@ -322,7 +322,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"Test Contact 1",
"testcontact1@merchant1.co.uk",
"Test Estate 1"});
- table21.AddRow(new string[] {
+ table22.AddRow(new string[] {
"Test Merchant 2",
"Address Line 1",
"TestTown",
@@ -333,99 +333,99 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"testcontact1@merchant2.co.uk",
"Test Estate 1"});
#line 56
- await testRunner.GivenAsync("I create the following merchants", ((string)(null)), table21, "Given ");
+ await testRunner.GivenAsync("I create the following merchants", ((string)(null)), table22, "Given ");
#line hidden
- global::Reqnroll.Table table22 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table23 = new global::Reqnroll.Table(new string[] {
"OperatorName",
"MerchantName",
"MerchantNumber",
"TerminalNumber",
"EstateName"});
- table22.AddRow(new string[] {
+ table23.AddRow(new string[] {
"Safaricom",
"Test Merchant 1",
"00000001",
"10000001",
"Test Estate 1"});
- table22.AddRow(new string[] {
+ table23.AddRow(new string[] {
"Voucher",
"Test Merchant 1",
"00000001",
"10000001",
"Test Estate 1"});
- table22.AddRow(new string[] {
+ table23.AddRow(new string[] {
"Safaricom",
"Test Merchant 2",
"00000002",
"10000002",
"Test Estate 1"});
- table22.AddRow(new string[] {
+ table23.AddRow(new string[] {
"Voucher",
"Test Merchant 2",
"00000002",
"10000002",
"Test Estate 1"});
#line 61
- await testRunner.GivenAsync("I have assigned the following operator to the merchants", ((string)(null)), table22, "Given ");
+ await testRunner.GivenAsync("I have assigned the following operator to the merchants", ((string)(null)), table23, "Given ");
#line hidden
- global::Reqnroll.Table table23 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table24 = new global::Reqnroll.Table(new string[] {
"DeviceIdentifier",
"MerchantName",
"EstateName"});
- table23.AddRow(new string[] {
+ table24.AddRow(new string[] {
"123456780",
"Test Merchant 1",
"Test Estate 1"});
- table23.AddRow(new string[] {
+ table24.AddRow(new string[] {
"123456781",
"Test Merchant 2",
"Test Estate 1"});
#line 68
- await testRunner.GivenAsync("I have assigned the following devices to the merchants", ((string)(null)), table23, "Given ");
+ await testRunner.GivenAsync("I have assigned the following devices to the merchants", ((string)(null)), table24, "Given ");
#line hidden
- global::Reqnroll.Table table24 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table25 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"ContractDescription"});
- table24.AddRow(new string[] {
+ table25.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"Safaricom Contract"});
- table24.AddRow(new string[] {
+ table25.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"Hospital 1 Contract"});
- table24.AddRow(new string[] {
+ table25.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 2",
"Safaricom Contract"});
- table24.AddRow(new string[] {
+ table25.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 2",
"Hospital 1 Contract"});
#line 73
- await testRunner.WhenAsync("I add the following contracts to the following merchants", ((string)(null)), table24, "When ");
+ await testRunner.WhenAsync("I add the following contracts to the following merchants", ((string)(null)), table25, "When ");
#line hidden
- global::Reqnroll.Table table25 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table26 = new global::Reqnroll.Table(new string[] {
"Reference",
"Amount",
"DateTime",
"MerchantName",
"EstateName"});
- table25.AddRow(new string[] {
+ table26.AddRow(new string[] {
"Deposit1",
"300.00",
"Today",
"Test Merchant 1",
"Test Estate 1"});
- table25.AddRow(new string[] {
+ table26.AddRow(new string[] {
"Deposit1",
"300.00",
"Today",
"Test Merchant 2",
"Test Estate 1"});
#line 80
- await testRunner.GivenAsync("I make the following manual merchant deposits", ((string)(null)), table25, "Given ");
+ await testRunner.GivenAsync("I make the following manual merchant deposits", ((string)(null)), table26, "Given ");
#line hidden
}
@@ -459,144 +459,144 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table26 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table27 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3"});
- table26.AddRow(new string[] {
+ table27.AddRow(new string[] {
"H",
"20210508",
""});
- table26.AddRow(new string[] {
+ table27.AddRow(new string[] {
"D",
"07777777775",
"100"});
- table26.AddRow(new string[] {
+ table27.AddRow(new string[] {
"T",
"1",
""});
#line 87
- await testRunner.GivenAsync("I have a file named \'SafarcomTopup1.txt\' with the following contents", ((string)(null)), table26, "Given ");
+ await testRunner.GivenAsync("I have a file named \'SafarcomTopup1.txt\' with the following contents", ((string)(null)), table27, "Given ");
#line hidden
- global::Reqnroll.Table table27 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table28 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId",
"UploadDateTime"});
- table27.AddRow(new string[] {
+ table28.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476",
"Today"});
#line 92
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table27, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table28, "And ");
#line hidden
- global::Reqnroll.Table table28 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table29 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3"});
- table28.AddRow(new string[] {
+ table29.AddRow(new string[] {
"H",
"20210508",
""});
- table28.AddRow(new string[] {
+ table29.AddRow(new string[] {
"D",
"07777777776",
"150"});
- table28.AddRow(new string[] {
+ table29.AddRow(new string[] {
"T",
"1",
""});
#line 96
- await testRunner.GivenAsync("I have a file named \'SafarcomTopup2.txt\' with the following contents", ((string)(null)), table28, "Given ");
+ await testRunner.GivenAsync("I have a file named \'SafarcomTopup2.txt\' with the following contents", ((string)(null)), table29, "Given ");
#line hidden
- global::Reqnroll.Table table29 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table30 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId",
"UploadDateTime"});
- table29.AddRow(new string[] {
+ table30.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 2",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476",
"Today"});
#line 101
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table29, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table30, "And ");
#line hidden
- global::Reqnroll.Table table30 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table31 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3",
"Column4"});
- table30.AddRow(new string[] {
+ table31.AddRow(new string[] {
"H",
"20210508",
"",
""});
- table30.AddRow(new string[] {
+ table31.AddRow(new string[] {
"D",
"Hospital 1",
"07777777775",
"10"});
- table30.AddRow(new string[] {
+ table31.AddRow(new string[] {
"D",
"Hospital 1",
"testrecipient1@recipient.com",
"10"});
- table30.AddRow(new string[] {
+ table31.AddRow(new string[] {
"T",
"1",
"",
""});
#line 105
- await testRunner.GivenAsync("I have a file named \'VoucherIssue1.txt\' with the following contents", ((string)(null)), table30, "Given ");
+ await testRunner.GivenAsync("I have a file named \'VoucherIssue1.txt\' with the following contents", ((string)(null)), table31, "Given ");
#line hidden
- global::Reqnroll.Table table31 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table32 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId",
"UploadDateTime"});
- table31.AddRow(new string[] {
+ table32.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"8806EDBC-3ED6-406B-9E5F-A9078356BE99",
"ABA59ABF-293D-4A6B-B81B-7007503C3476",
"Today"});
#line 111
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table31, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table32, "And ");
#line hidden
- global::Reqnroll.Table table32 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table33 = new global::Reqnroll.Table(new string[] {
"ImportLogDate",
"FileCount"});
- table32.AddRow(new string[] {
+ table33.AddRow(new string[] {
"Today",
"3"});
#line 115
await testRunner.WhenAsync("I get the \'Test Estate 1\' import logs between \'Yesterday\' and \'Today\' the followi" +
- "ng data is returned", ((string)(null)), table32, "When ");
+ "ng data is returned", ((string)(null)), table33, "When ");
#line hidden
- global::Reqnroll.Table table33 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table34 = new global::Reqnroll.Table(new string[] {
"MerchantName",
"OriginalFileName"});
- table33.AddRow(new string[] {
+ table34.AddRow(new string[] {
"Test Merchant 1",
"SafarcomTopup1.txt"});
- table33.AddRow(new string[] {
+ table34.AddRow(new string[] {
"Test Merchant 2",
"SafarcomTopup2.txt"});
- table33.AddRow(new string[] {
+ table34.AddRow(new string[] {
"Test Merchant 1",
"VoucherIssue1.txt"});
#line 119
await testRunner.WhenAsync("I get the \'Test Estate 1\' import log for \'Today\' the following file information i" +
- "s returned", ((string)(null)), table33, "When ");
+ "s returned", ((string)(null)), table34, "When ");
#line hidden
- global::Reqnroll.Table table34 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table35 = new global::Reqnroll.Table(new string[] {
"ProcessingCompleted",
"NumberOfLines",
"TotaLines",
@@ -604,7 +604,7 @@ await testRunner.WhenAsync("I get the \'Test Estate 1\' import logs between \'Ye
"IgnoredLines",
"FailedLines",
"NotProcessedLines"});
- table34.AddRow(new string[] {
+ table35.AddRow(new string[] {
"True",
"3",
"3",
@@ -614,29 +614,29 @@ await testRunner.WhenAsync("I get the \'Test Estate 1\' import logs between \'Ye
"0"});
#line 125
await testRunner.WhenAsync("I get the file \'SafarcomTopup1.txt\' for Estate \'Test Estate 1\' the following file" +
- " information is returned", ((string)(null)), table34, "When ");
+ " information is returned", ((string)(null)), table35, "When ");
#line hidden
- global::Reqnroll.Table table35 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table36 = new global::Reqnroll.Table(new string[] {
"LineNumber",
"Data",
"Result"});
- table35.AddRow(new string[] {
+ table36.AddRow(new string[] {
"1",
"H,20210508,",
"Ignored"});
- table35.AddRow(new string[] {
+ table36.AddRow(new string[] {
"2",
"D,07777777775,100",
"Successful"});
- table35.AddRow(new string[] {
+ table36.AddRow(new string[] {
"3",
"T,1,",
"Ignored"});
#line 129
await testRunner.WhenAsync("I get the file \'SafarcomTopup1.txt\' for Estate \'Test Estate 1\' the following file" +
- " lines are returned", ((string)(null)), table35, "When ");
+ " lines are returned", ((string)(null)), table36, "When ");
#line hidden
- global::Reqnroll.Table table36 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table37 = new global::Reqnroll.Table(new string[] {
"ProcessingCompleted",
"NumberOfLines",
"TotaLines",
@@ -644,7 +644,7 @@ await testRunner.WhenAsync("I get the \'Test Estate 1\' import logs between \'Ye
"IgnoredLines",
"FailedLines",
"NotProcessedLines"});
- table36.AddRow(new string[] {
+ table37.AddRow(new string[] {
"True",
"3",
"3",
@@ -654,29 +654,29 @@ await testRunner.WhenAsync("I get the \'Test Estate 1\' import logs between \'Ye
"0"});
#line 135
await testRunner.WhenAsync("I get the file \'SafarcomTopup2.txt\' for Estate \'Test Estate 1\' the following file" +
- " information is returned", ((string)(null)), table36, "When ");
+ " information is returned", ((string)(null)), table37, "When ");
#line hidden
- global::Reqnroll.Table table37 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table38 = new global::Reqnroll.Table(new string[] {
"LineNumber",
"Data",
"Result"});
- table37.AddRow(new string[] {
+ table38.AddRow(new string[] {
"1",
"H,20210508,",
"Ignored"});
- table37.AddRow(new string[] {
+ table38.AddRow(new string[] {
"2",
"D,07777777776,150",
"Successful"});
- table37.AddRow(new string[] {
+ table38.AddRow(new string[] {
"3",
"T,1,",
"Ignored"});
#line 139
await testRunner.WhenAsync("I get the file \'SafarcomTopup2.txt\' for Estate \'Test Estate 1\' the following file" +
- " lines are returned", ((string)(null)), table37, "When ");
+ " lines are returned", ((string)(null)), table38, "When ");
#line hidden
- global::Reqnroll.Table table38 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table39 = new global::Reqnroll.Table(new string[] {
"ProcessingCompleted",
"NumberOfLines",
"TotaLines",
@@ -684,7 +684,7 @@ await testRunner.WhenAsync("I get the \'Test Estate 1\' import logs between \'Ye
"IgnoredLines",
"FailedLines",
"NotProcessedLines"});
- table38.AddRow(new string[] {
+ table39.AddRow(new string[] {
"True",
"4",
"4",
@@ -694,31 +694,31 @@ await testRunner.WhenAsync("I get the \'Test Estate 1\' import logs between \'Ye
"0"});
#line 145
await testRunner.WhenAsync("I get the file \'VoucherIssue1.txt\' for Estate \'Test Estate 1\' the following file " +
- "information is returned", ((string)(null)), table38, "When ");
+ "information is returned", ((string)(null)), table39, "When ");
#line hidden
- global::Reqnroll.Table table39 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table40 = new global::Reqnroll.Table(new string[] {
"LineNumber",
"Data",
"Result"});
- table39.AddRow(new string[] {
+ table40.AddRow(new string[] {
"1",
"H,20210508,,",
"Ignored"});
- table39.AddRow(new string[] {
+ table40.AddRow(new string[] {
"2",
"D,Hospital 1,07777777775,10",
"Successful"});
- table39.AddRow(new string[] {
+ table40.AddRow(new string[] {
"3",
"D,Hospital 1,testrecipient1@recipient.com,10",
"Successful"});
- table39.AddRow(new string[] {
+ table40.AddRow(new string[] {
"4",
"T,1,,",
"Ignored"});
#line 149
await testRunner.WhenAsync("I get the file \'VoucherIssue1.txt\' for Estate \'Test Estate 1\' the following file " +
- "lines are returned", ((string)(null)), table39, "When ");
+ "lines are returned", ((string)(null)), table40, "When ");
#line hidden
}
await this.ScenarioCleanupAsync();
diff --git a/FileProcessor.IntegrationTests/Features/ProcessTopupCSV.feature.cs b/FileProcessor.IntegrationTests/Features/ProcessTopupCSV.feature.cs
index de199ad..c2bc4b8 100644
--- a/FileProcessor.IntegrationTests/Features/ProcessTopupCSV.feature.cs
+++ b/FileProcessor.IntegrationTests/Features/ProcessTopupCSV.feature.cs
@@ -1,4 +1,4 @@
-// ------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------
//
// This code was generated by Reqnroll (https://reqnroll.net/).
// Reqnroll Version:3.0.0.0
@@ -13,8 +13,8 @@
using Reqnroll;
namespace FileProcessor.IntegrationTests.Features
{
-
-
+
+
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Reqnroll", "3.0.0.0")]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::NUnit.Framework.TestFixtureAttribute()]
@@ -25,30 +25,30 @@ namespace FileProcessor.IntegrationTests.Features
[global::NUnit.Framework.CategoryAttribute("fileprofiles")]
public partial class ProcessTopupCSVFilesFeature
{
-
+
private global::Reqnroll.ITestRunner testRunner;
-
+
private static string[] featureTags = new string[] {
"base",
"shared",
"fileprofiles"};
-
+
private static global::Reqnroll.FeatureInfo featureInfo = new global::Reqnroll.FeatureInfo(new global::System.Globalization.CultureInfo("en-US"), "Features", "Process Topup CSV Files", null, global::Reqnroll.ProgrammingLanguage.CSharp, featureTags, InitializeCucumberMessages());
-
+
#line 1 "ProcessTopupCSV.feature"
#line hidden
-
+
[global::NUnit.Framework.OneTimeSetUpAttribute()]
public static async global::System.Threading.Tasks.Task FeatureSetupAsync()
{
}
-
+
[global::NUnit.Framework.OneTimeTearDownAttribute()]
public static async global::System.Threading.Tasks.Task FeatureTearDownAsync()
{
await global::Reqnroll.TestRunnerManager.ReleaseFeatureAsync(featureInfo);
}
-
+
[global::NUnit.Framework.SetUpAttribute()]
public async global::System.Threading.Tasks.Task TestInitializeAsync()
{
@@ -74,7 +74,7 @@ public partial class ProcessTopupCSVFilesFeature
}
}
}
-
+
[global::NUnit.Framework.TearDownAttribute()]
public async global::System.Threading.Tasks.Task TestTearDownAsync()
{
@@ -92,87 +92,87 @@ public partial class ProcessTopupCSVFilesFeature
testRunner = null;
}
}
-
+
public void ScenarioInitialize(global::Reqnroll.ScenarioInfo scenarioInfo, global::Reqnroll.RuleInfo ruleInfo)
{
testRunner.OnScenarioInitialize(scenarioInfo, ruleInfo);
testRunner.ScenarioContext.ScenarioContainer.RegisterInstanceAs(global::NUnit.Framework.TestContext.CurrentContext);
}
-
+
public async global::System.Threading.Tasks.Task ScenarioStartAsync()
{
await testRunner.OnScenarioStartAsync();
}
-
+
public async global::System.Threading.Tasks.Task ScenarioCleanupAsync()
{
await testRunner.CollectScenarioErrorsAsync();
}
-
+
public virtual async global::System.Threading.Tasks.Task FeatureBackgroundAsync()
{
#line 4
#line hidden
- global::Reqnroll.Table table1 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table41 = new global::Reqnroll.Table(new string[] {
"Name",
"DisplayName",
"Description"});
- table1.AddRow(new string[] {
+ table41.AddRow(new string[] {
"transactionProcessor",
"Transaction Processor REST Scope",
"A scope for Transaction Processor REST"});
- table1.AddRow(new string[] {
+ table41.AddRow(new string[] {
"fileProcessor",
"File Processor REST Scope",
"A scope for File Processor REST"});
#line 5
- await testRunner.GivenAsync("I create the following api scopes", ((string)(null)), table1, "Given ");
+ await testRunner.GivenAsync("I create the following api scopes", ((string)(null)), table41, "Given ");
#line hidden
- global::Reqnroll.Table table2 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table42 = new global::Reqnroll.Table(new string[] {
"Name",
"DisplayName",
"Secret",
"Scopes",
"UserClaims"});
- table2.AddRow(new string[] {
+ table42.AddRow(new string[] {
"transactionProcessor",
"Transaction Processor REST",
"Secret1",
"transactionProcessor",
"MerchantId, EstateId, role"});
- table2.AddRow(new string[] {
+ table42.AddRow(new string[] {
"fileProcessor",
"File Processor REST",
"Secret1",
"fileProcessor",
""});
#line 10
- await testRunner.GivenAsync("the following api resources exist", ((string)(null)), table2, "Given ");
+ await testRunner.GivenAsync("the following api resources exist", ((string)(null)), table42, "Given ");
#line hidden
- global::Reqnroll.Table table3 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table43 = new global::Reqnroll.Table(new string[] {
"ClientId",
"ClientName",
"Secret",
"Scopes",
"GrantTypes"});
- table3.AddRow(new string[] {
+ table43.AddRow(new string[] {
"serviceClient",
"Service Client",
"Secret1",
"transactionProcessor,fileProcessor",
"client_credentials"});
#line 15
- await testRunner.GivenAsync("the following clients exist", ((string)(null)), table3, "Given ");
+ await testRunner.GivenAsync("the following clients exist", ((string)(null)), table43, "Given ");
#line hidden
- global::Reqnroll.Table table4 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table44 = new global::Reqnroll.Table(new string[] {
"ClientId"});
- table4.AddRow(new string[] {
+ table44.AddRow(new string[] {
"serviceClient"});
#line 19
await testRunner.GivenAsync("I have a token to access the estate management and transaction processor resource" +
- "s", ((string)(null)), table4, "Given ");
+ "s", ((string)(null)), table44, "Given ");
#line hidden
- global::Reqnroll.Table table5 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table45 = new global::Reqnroll.Table(new string[] {
"Alias",
"FileProfileId",
"Name",
@@ -181,7 +181,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"OperatorName",
"LineTerminator",
"FileFormatHandler"});
- table5.AddRow(new string[] {
+ table45.AddRow(new string[] {
"Safaricom Topup",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"Safaricom Topup",
@@ -190,7 +190,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"Safaricom",
"1",
"SafaricomFileFormatHandler"});
- table5.AddRow(new string[] {
+ table45.AddRow(new string[] {
"Voucher Issue",
"8806EDBC-3ED6-406B-9E5F-A9078356BE99",
"Voucher Issue",
@@ -200,61 +200,61 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"1",
"VoucherFileFormatHandler"});
#line 23
- await testRunner.WhenAsync("I create the following file profiles", ((string)(null)), table5, "When ");
+ await testRunner.WhenAsync("I create the following file profiles", ((string)(null)), table45, "When ");
#line hidden
- global::Reqnroll.Table table6 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table46 = new global::Reqnroll.Table(new string[] {
"EstateName"});
- table6.AddRow(new string[] {
+ table46.AddRow(new string[] {
"Test Estate 1"});
#line 28
- await testRunner.GivenAsync("I have created the following estates", ((string)(null)), table6, "Given ");
+ await testRunner.GivenAsync("I have created the following estates", ((string)(null)), table46, "Given ");
#line hidden
- global::Reqnroll.Table table7 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table47 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"RequireCustomMerchantNumber",
"RequireCustomTerminalNumber"});
- table7.AddRow(new string[] {
+ table47.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"True",
"True"});
- table7.AddRow(new string[] {
+ table47.AddRow(new string[] {
"Test Estate 1",
"Voucher",
"True",
"True"});
#line 32
- await testRunner.GivenAsync("I have created the following operators", ((string)(null)), table7, "Given ");
+ await testRunner.GivenAsync("I have created the following operators", ((string)(null)), table47, "Given ");
#line hidden
- global::Reqnroll.Table table8 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table48 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName"});
- table8.AddRow(new string[] {
+ table48.AddRow(new string[] {
"Test Estate 1",
"Safaricom"});
- table8.AddRow(new string[] {
+ table48.AddRow(new string[] {
"Test Estate 1",
"Voucher"});
#line 37
- await testRunner.AndAsync("I have assigned the following operators to the estates", ((string)(null)), table8, "And ");
+ await testRunner.AndAsync("I have assigned the following operators to the estates", ((string)(null)), table48, "And ");
#line hidden
- global::Reqnroll.Table table9 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table49 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"ContractDescription"});
- table9.AddRow(new string[] {
+ table49.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"Safaricom Contract"});
- table9.AddRow(new string[] {
+ table49.AddRow(new string[] {
"Test Estate 1",
"Voucher",
"Hospital 1 Contract"});
#line 42
- await testRunner.GivenAsync("I create a contract with the following values", ((string)(null)), table9, "Given ");
+ await testRunner.GivenAsync("I create a contract with the following values", ((string)(null)), table49, "Given ");
#line hidden
- global::Reqnroll.Table table10 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table50 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"ContractDescription",
@@ -262,7 +262,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"DisplayText",
"Value",
"ProductType"});
- table10.AddRow(new string[] {
+ table50.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"Safaricom Contract",
@@ -270,7 +270,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"Custom",
"",
"MobileTopup"});
- table10.AddRow(new string[] {
+ table50.AddRow(new string[] {
"Test Estate 1",
"Voucher",
"Hospital 1 Contract",
@@ -279,9 +279,9 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"",
"Voucher"});
#line 47
- await testRunner.WhenAsync("I create the following Products", ((string)(null)), table10, "When ");
+ await testRunner.WhenAsync("I create the following Products", ((string)(null)), table50, "When ");
#line hidden
- global::Reqnroll.Table table11 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table51 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"ContractDescription",
@@ -289,7 +289,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"CalculationType",
"FeeDescription",
"Value"});
- table11.AddRow(new string[] {
+ table51.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"Safaricom Contract",
@@ -298,9 +298,9 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"Merchant Commission",
"2.50"});
#line 52
- await testRunner.WhenAsync("I add the following Transaction Fees", ((string)(null)), table11, "When ");
+ await testRunner.WhenAsync("I add the following Transaction Fees", ((string)(null)), table51, "When ");
#line hidden
- global::Reqnroll.Table table12 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table52 = new global::Reqnroll.Table(new string[] {
"MerchantName",
"AddressLine1",
"Town",
@@ -310,7 +310,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"ContactName",
"EmailAddress",
"EstateName"});
- table12.AddRow(new string[] {
+ table52.AddRow(new string[] {
"Test Merchant 1",
"Address Line 1",
"TestTown",
@@ -321,77 +321,77 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"testcontact1@merchant1.co.uk",
"Test Estate 1"});
#line 56
- await testRunner.GivenAsync("I create the following merchants", ((string)(null)), table12, "Given ");
+ await testRunner.GivenAsync("I create the following merchants", ((string)(null)), table52, "Given ");
#line hidden
- global::Reqnroll.Table table13 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table53 = new global::Reqnroll.Table(new string[] {
"OperatorName",
"MerchantName",
"MerchantNumber",
"TerminalNumber",
"EstateName"});
- table13.AddRow(new string[] {
+ table53.AddRow(new string[] {
"Safaricom",
"Test Merchant 1",
"00000001",
"10000001",
"Test Estate 1"});
- table13.AddRow(new string[] {
+ table53.AddRow(new string[] {
"Voucher",
"Test Merchant 1",
"00000001",
"10000001",
"Test Estate 1"});
#line 60
- await testRunner.GivenAsync("I have assigned the following operator to the merchants", ((string)(null)), table13, "Given ");
+ await testRunner.GivenAsync("I have assigned the following operator to the merchants", ((string)(null)), table53, "Given ");
#line hidden
- global::Reqnroll.Table table14 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table54 = new global::Reqnroll.Table(new string[] {
"DeviceIdentifier",
"MerchantName",
"EstateName"});
- table14.AddRow(new string[] {
+ table54.AddRow(new string[] {
"123456780",
"Test Merchant 1",
"Test Estate 1"});
#line 65
- await testRunner.GivenAsync("I have assigned the following devices to the merchants", ((string)(null)), table14, "Given ");
+ await testRunner.GivenAsync("I have assigned the following devices to the merchants", ((string)(null)), table54, "Given ");
#line hidden
- global::Reqnroll.Table table15 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table55 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"ContractDescription"});
- table15.AddRow(new string[] {
+ table55.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"Safaricom Contract"});
- table15.AddRow(new string[] {
+ table55.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"Hospital 1 Contract"});
#line 69
- await testRunner.WhenAsync("I add the following contracts to the following merchants", ((string)(null)), table15, "When ");
+ await testRunner.WhenAsync("I add the following contracts to the following merchants", ((string)(null)), table55, "When ");
#line hidden
- global::Reqnroll.Table table16 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table56 = new global::Reqnroll.Table(new string[] {
"Reference",
"Amount",
"DateTime",
"MerchantName",
"EstateName"});
- table16.AddRow(new string[] {
+ table56.AddRow(new string[] {
"Deposit1",
"300.00",
"Today",
"Test Merchant 1",
"Test Estate 1"});
#line 74
- await testRunner.GivenAsync("I make the following manual merchant deposits", ((string)(null)), table16, "Given ");
+ await testRunner.GivenAsync("I make the following manual merchant deposits", ((string)(null)), table56, "Given ");
#line hidden
}
-
+
private static global::Reqnroll.Formatters.RuntimeSupport.FeatureLevelCucumberMessages InitializeCucumberMessages()
{
return new global::Reqnroll.Formatters.RuntimeSupport.FeatureLevelCucumberMessages("Features/ProcessTopupCSV.feature.ndjson", 9);
}
-
+
[global::NUnit.Framework.TestAttribute()]
[global::NUnit.Framework.DescriptionAttribute("Process Safaricom Topup File with 1 detail row")]
public async global::System.Threading.Tasks.Task ProcessSafaricomTopupFileWith1DetailRow()
@@ -415,42 +415,42 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table17 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table57 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3"});
- table17.AddRow(new string[] {
+ table57.AddRow(new string[] {
"H",
"20210508",
""});
- table17.AddRow(new string[] {
+ table57.AddRow(new string[] {
"D",
"07777777775",
"100"});
- table17.AddRow(new string[] {
+ table57.AddRow(new string[] {
"T",
"1",
""});
#line 80
- await testRunner.GivenAsync("I have a file named \'SafarcomTopup.txt\' with the following contents", ((string)(null)), table17, "Given ");
+ await testRunner.GivenAsync("I have a file named \'SafarcomTopup.txt\' with the following contents", ((string)(null)), table57, "Given ");
#line hidden
- global::Reqnroll.Table table18 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table58 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table18.AddRow(new string[] {
+ table58.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 85
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table18, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table58, "And ");
#line hidden
}
await this.ScenarioCleanupAsync();
}
-
+
[global::NUnit.Framework.TestAttribute()]
[global::NUnit.Framework.DescriptionAttribute("Process Safaricom Topup File with 2 detail rows")]
public async global::System.Threading.Tasks.Task ProcessSafaricomTopupFileWith2DetailRows()
@@ -474,46 +474,46 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table19 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table59 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3"});
- table19.AddRow(new string[] {
+ table59.AddRow(new string[] {
"H",
"20210508",
""});
- table19.AddRow(new string[] {
+ table59.AddRow(new string[] {
"D",
"07777777775",
"100"});
- table19.AddRow(new string[] {
+ table59.AddRow(new string[] {
"D",
"07777777776",
"200"});
- table19.AddRow(new string[] {
+ table59.AddRow(new string[] {
"T",
"2",
""});
#line 92
- await testRunner.GivenAsync("I have a file named \'SafarcomTopup.txt\' with the following contents", ((string)(null)), table19, "Given ");
+ await testRunner.GivenAsync("I have a file named \'SafarcomTopup.txt\' with the following contents", ((string)(null)), table59, "Given ");
#line hidden
- global::Reqnroll.Table table20 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table60 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table20.AddRow(new string[] {
+ table60.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 98
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table20, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table60, "And ");
#line hidden
}
await this.ScenarioCleanupAsync();
}
-
+
[global::NUnit.Framework.TestAttribute()]
[global::NUnit.Framework.DescriptionAttribute("Process 2 Safaricom Topup Files")]
public async global::System.Threading.Tasks.Task Process2SafaricomTopupFiles()
@@ -537,78 +537,78 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table21 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table61 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3"});
- table21.AddRow(new string[] {
+ table61.AddRow(new string[] {
"H",
"20210508",
""});
- table21.AddRow(new string[] {
+ table61.AddRow(new string[] {
"D",
"07777777775",
"100"});
- table21.AddRow(new string[] {
+ table61.AddRow(new string[] {
"T",
"1",
""});
#line 105
- await testRunner.GivenAsync("I have a file named \'SafarcomTopup1.txt\' with the following contents", ((string)(null)), table21, "Given ");
+ await testRunner.GivenAsync("I have a file named \'SafarcomTopup1.txt\' with the following contents", ((string)(null)), table61, "Given ");
#line hidden
- global::Reqnroll.Table table22 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table62 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table22.AddRow(new string[] {
+ table62.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 110
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table22, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table62, "And ");
#line hidden
- global::Reqnroll.Table table23 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table63 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3"});
- table23.AddRow(new string[] {
+ table63.AddRow(new string[] {
"H",
"20210508",
""});
- table23.AddRow(new string[] {
+ table63.AddRow(new string[] {
"D",
"07777777776",
"150"});
- table23.AddRow(new string[] {
+ table63.AddRow(new string[] {
"D",
"07777777777",
"50"});
- table23.AddRow(new string[] {
+ table63.AddRow(new string[] {
"T",
"2",
""});
#line 114
- await testRunner.GivenAsync("I have a file named \'SafarcomTopup2.txt\' with the following contents", ((string)(null)), table23, "Given ");
+ await testRunner.GivenAsync("I have a file named \'SafarcomTopup2.txt\' with the following contents", ((string)(null)), table63, "Given ");
#line hidden
- global::Reqnroll.Table table24 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table64 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table24.AddRow(new string[] {
+ table64.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 120
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table24, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table64, "And ");
#line hidden
}
await this.ScenarioCleanupAsync();
}
-
+
[global::NUnit.Framework.TestAttribute()]
[global::NUnit.Framework.DescriptionAttribute("Process Duplicate Safaricom Topup File with 1 detail row")]
[global::NUnit.Framework.CategoryAttribute("PRTest")]
@@ -634,83 +634,82 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table25 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table65 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3"});
- table25.AddRow(new string[] {
+ table65.AddRow(new string[] {
"H",
"20210508",
""});
- table25.AddRow(new string[] {
+ table65.AddRow(new string[] {
"D",
"07777777775",
"100"});
- table25.AddRow(new string[] {
+ table65.AddRow(new string[] {
"D",
"07777777776",
"200"});
- table25.AddRow(new string[] {
+ table65.AddRow(new string[] {
"T",
"1",
""});
#line 128
- await testRunner.GivenAsync("I have a file named \'SafarcomTopup1.txt\' with the following contents", ((string)(null)), table25, "Given ");
+ await testRunner.GivenAsync("I have a file named \'SafarcomTopup1.txt\' with the following contents", ((string)(null)), table65, "Given ");
#line hidden
- global::Reqnroll.Table table26 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table66 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table26.AddRow(new string[] {
+ table66.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 134
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table26, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table66, "And ");
#line hidden
- global::Reqnroll.Table table27 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table67 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3"});
- table27.AddRow(new string[] {
+ table67.AddRow(new string[] {
"H",
"20210508",
""});
- table27.AddRow(new string[] {
+ table67.AddRow(new string[] {
"D",
"07777777775",
"100"});
- table27.AddRow(new string[] {
+ table67.AddRow(new string[] {
"D",
"07777777776",
"200"});
- table27.AddRow(new string[] {
+ table67.AddRow(new string[] {
"T",
"1",
""});
#line 140
- await testRunner.GivenAsync("I have a file named \'SafarcomTopup2.txt\' with the following contents", ((string)(null)), table27, "Given ");
+ await testRunner.GivenAsync("I have a file named \'SafarcomTopup2.txt\' with the following contents", ((string)(null)), table67, "Given ");
#line hidden
- global::Reqnroll.Table table28 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table68 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table28.AddRow(new string[] {
+ table68.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 146
- await testRunner.AndAsync("I upload this file for processing an error should be returned indicating the file" +
- " is a duplicate", ((string)(null)), table28, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table68, "And ");
#line hidden
}
await this.ScenarioCleanupAsync();
}
-
+
[global::NUnit.Framework.TestAttribute()]
[global::NUnit.Framework.DescriptionAttribute("Process Safaricom Topup File with Upload Date Time")]
public async global::System.Threading.Tasks.Task ProcessSafaricomTopupFileWithUploadDateTime()
@@ -734,77 +733,77 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table29 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table69 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3"});
- table29.AddRow(new string[] {
+ table69.AddRow(new string[] {
"H",
"20210508",
""});
- table29.AddRow(new string[] {
+ table69.AddRow(new string[] {
"D",
"07777777775",
"100"});
- table29.AddRow(new string[] {
+ table69.AddRow(new string[] {
"T",
"1",
""});
#line 152
- await testRunner.GivenAsync("I have a file named \'SafarcomTopup.txt\' with the following contents", ((string)(null)), table29, "Given ");
+ await testRunner.GivenAsync("I have a file named \'SafarcomTopup.txt\' with the following contents", ((string)(null)), table69, "Given ");
#line hidden
- global::Reqnroll.Table table30 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table70 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId",
"UploadDateTime"});
- table30.AddRow(new string[] {
+ table70.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476",
"Today"});
#line 157
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table30, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table70, "And ");
#line hidden
#line 161
await testRunner.WhenAsync("I get the import log for estate \'Test Estate 1\' the date on the import log is \'To" +
"day\'", ((string)(null)), ((global::Reqnroll.Table)(null)), "When ");
#line hidden
- global::Reqnroll.Table table31 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table71 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3"});
- table31.AddRow(new string[] {
+ table71.AddRow(new string[] {
"H",
"20210508",
""});
- table31.AddRow(new string[] {
+ table71.AddRow(new string[] {
"D",
"07777777775",
"200"});
- table31.AddRow(new string[] {
+ table71.AddRow(new string[] {
"T",
"1",
""});
#line 163
- await testRunner.GivenAsync("I have a file named \'SafarcomTopup1.txt\' with the following contents", ((string)(null)), table31, "Given ");
+ await testRunner.GivenAsync("I have a file named \'SafarcomTopup1.txt\' with the following contents", ((string)(null)), table71, "Given ");
#line hidden
- global::Reqnroll.Table table32 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table72 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId",
"UploadDateTime"});
- table32.AddRow(new string[] {
+ table72.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476",
"01/09/2021"});
#line 168
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table32, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table72, "And ");
#line hidden
#line 172
await testRunner.WhenAsync("I get the import log for estate \'Test Estate 1\' the date on the import log is \'01" +
@@ -813,7 +812,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
}
await this.ScenarioCleanupAsync();
}
-
+
[global::NUnit.Framework.TestAttribute()]
[global::NUnit.Framework.DescriptionAttribute("Upload a generated Safaricom Topup file with 1000 detail rows")]
[global::NUnit.Framework.CategoryAttribute("largefile")]
@@ -841,39 +840,39 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table33 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table73 = new global::Reqnroll.Table(new string[] {
"Reference",
"Amount",
"DateTime",
"MerchantName",
"EstateName"});
- table33.AddRow(new string[] {
+ table73.AddRow(new string[] {
"Deposit1",
"600000.00",
"Today",
"Test Merchant 1",
"Test Estate 1"});
#line 175
- await testRunner.GivenAsync("I make the following manual merchant deposits", ((string)(null)), table33, "Given ");
+ await testRunner.GivenAsync("I make the following manual merchant deposits", ((string)(null)), table73, "Given ");
#line hidden
#line 178
await testRunner.GivenAsync("I have a generated Safaricom Topup file named \'LargeSafarcomTopup.txt\' with 1000 " +
"detail rows", ((string)(null)), ((global::Reqnroll.Table)(null)), "Given ");
#line hidden
- global::Reqnroll.Table table34 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table74 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table34.AddRow(new string[] {
+ table74.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 179
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table34, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table74, "And ");
#line hidden
- global::Reqnroll.Table table35 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table75 = new global::Reqnroll.Table(new string[] {
"ProcessingCompleted",
"NumberOfLines",
"TotaLines",
@@ -881,7 +880,7 @@ await testRunner.GivenAsync("I have a generated Safaricom Topup file named \'Lar
"IgnoredLines",
"FailedLines",
"NotProcessedLines"});
- table35.AddRow(new string[] {
+ table75.AddRow(new string[] {
"True",
"1002",
"1002",
@@ -891,12 +890,12 @@ await testRunner.GivenAsync("I have a generated Safaricom Topup file named \'Lar
"0"});
#line 183
await testRunner.WhenAsync("I get the file \'LargeSafarcomTopup.txt\' for Estate \'Test Estate 1\' the following " +
- "file information is returned", ((string)(null)), table35, "When ");
+ "file information is returned", ((string)(null)), table75, "When ");
#line hidden
}
await this.ScenarioCleanupAsync();
}
-
+
[global::NUnit.Framework.TestAttribute()]
[global::NUnit.Framework.DescriptionAttribute("Reject a generated Safaricom Topup file with more than 1000 detail rows")]
[global::NUnit.Framework.CategoryAttribute("largefile")]
@@ -924,37 +923,37 @@ await testRunner.GivenAsync("I have a generated Safaricom Topup file named \'Lar
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table36 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table76 = new global::Reqnroll.Table(new string[] {
"Reference",
"Amount",
"DateTime",
"MerchantName",
"EstateName"});
- table36.AddRow(new string[] {
+ table76.AddRow(new string[] {
"Deposit1",
"600000.00",
"Today",
"Test Merchant 1",
"Test Estate 1"});
#line 189
- await testRunner.GivenAsync("I make the following manual merchant deposits", ((string)(null)), table36, "Given ");
+ await testRunner.GivenAsync("I make the following manual merchant deposits", ((string)(null)), table76, "Given ");
#line hidden
#line 192
await testRunner.GivenAsync("I have a generated Safaricom Topup file named \'OversizedSafarcomTopup.txt\' with 1" +
"001 detail rows", ((string)(null)), ((global::Reqnroll.Table)(null)), "Given ");
#line hidden
- global::Reqnroll.Table table37 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table77 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table37.AddRow(new string[] {
+ table77.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 193
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table37, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table77, "And ");
#line hidden
#line 197
await testRunner.WhenAsync("I get the file \'OversizedSafarcomTopup.txt\' for Estate \'Test Estate 1\' it is reje" +
diff --git a/FileProcessor.IntegrationTests/Features/ProcessVoucherCSV.feature.cs b/FileProcessor.IntegrationTests/Features/ProcessVoucherCSV.feature.cs
index 88e63fb..5d64d78 100644
--- a/FileProcessor.IntegrationTests/Features/ProcessVoucherCSV.feature.cs
+++ b/FileProcessor.IntegrationTests/Features/ProcessVoucherCSV.feature.cs
@@ -115,66 +115,66 @@ public void ScenarioInitialize(global::Reqnroll.ScenarioInfo scenarioInfo, globa
{
#line 4
#line hidden
- global::Reqnroll.Table table72 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table78 = new global::Reqnroll.Table(new string[] {
"Name",
"DisplayName",
"Description"});
- table72.AddRow(new string[] {
+ table78.AddRow(new string[] {
"transactionProcessor",
"Transaction Processor REST Scope",
"A scope for Transaction Processor REST"});
- table72.AddRow(new string[] {
+ table78.AddRow(new string[] {
"fileProcessor",
"File Processor REST Scope",
"A scope for File Processor REST"});
#line 5
- await testRunner.GivenAsync("I create the following api scopes", ((string)(null)), table72, "Given ");
+ await testRunner.GivenAsync("I create the following api scopes", ((string)(null)), table78, "Given ");
#line hidden
- global::Reqnroll.Table table73 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table79 = new global::Reqnroll.Table(new string[] {
"Name",
"DisplayName",
"Secret",
"Scopes",
"UserClaims"});
- table73.AddRow(new string[] {
+ table79.AddRow(new string[] {
"transactionProcessor",
"Transaction Processor REST",
"Secret1",
"transactionProcessor",
"MerchantId, EstateId, role"});
- table73.AddRow(new string[] {
+ table79.AddRow(new string[] {
"fileProcessor",
"File Processor REST",
"Secret1",
"fileProcessor",
""});
#line 10
- await testRunner.GivenAsync("the following api resources exist", ((string)(null)), table73, "Given ");
+ await testRunner.GivenAsync("the following api resources exist", ((string)(null)), table79, "Given ");
#line hidden
- global::Reqnroll.Table table74 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table80 = new global::Reqnroll.Table(new string[] {
"ClientId",
"ClientName",
"Secret",
"Scopes",
"GrantTypes"});
- table74.AddRow(new string[] {
+ table80.AddRow(new string[] {
"serviceClient",
"Service Client",
"Secret1",
"transactionProcessor,fileProcessor",
"client_credentials"});
#line 15
- await testRunner.GivenAsync("the following clients exist", ((string)(null)), table74, "Given ");
+ await testRunner.GivenAsync("the following clients exist", ((string)(null)), table80, "Given ");
#line hidden
- global::Reqnroll.Table table75 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table81 = new global::Reqnroll.Table(new string[] {
"ClientId"});
- table75.AddRow(new string[] {
+ table81.AddRow(new string[] {
"serviceClient"});
#line 19
await testRunner.GivenAsync("I have a token to access the estate management and transaction processor resource" +
- "s", ((string)(null)), table75, "Given ");
+ "s", ((string)(null)), table81, "Given ");
#line hidden
- global::Reqnroll.Table table76 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table82 = new global::Reqnroll.Table(new string[] {
"Alias",
"FileProfileId",
"Name",
@@ -183,7 +183,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"OperatorName",
"LineTerminator",
"FileFormatHandler"});
- table76.AddRow(new string[] {
+ table82.AddRow(new string[] {
"Safaricom Topup",
"B2A59ABF-293D-4A6B-B81B-7007503C3476",
"Safaricom Topup",
@@ -192,7 +192,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"Safaricom",
"1",
"SafaricomFileFormatHandler"});
- table76.AddRow(new string[] {
+ table82.AddRow(new string[] {
"Voucher Issue",
"8806EDBC-3ED6-406B-9E5F-A9078356BE99",
"Voucher Issue",
@@ -202,61 +202,61 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"1",
"VoucherFileFormatHandler"});
#line 23
- await testRunner.WhenAsync("I create the following file profiles", ((string)(null)), table76, "When ");
+ await testRunner.WhenAsync("I create the following file profiles", ((string)(null)), table82, "When ");
#line hidden
- global::Reqnroll.Table table77 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table83 = new global::Reqnroll.Table(new string[] {
"EstateName"});
- table77.AddRow(new string[] {
+ table83.AddRow(new string[] {
"Test Estate 1"});
#line 28
- await testRunner.GivenAsync("I have created the following estates", ((string)(null)), table77, "Given ");
+ await testRunner.GivenAsync("I have created the following estates", ((string)(null)), table83, "Given ");
#line hidden
- global::Reqnroll.Table table78 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table84 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"RequireCustomMerchantNumber",
"RequireCustomTerminalNumber"});
- table78.AddRow(new string[] {
+ table84.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"True",
"True"});
- table78.AddRow(new string[] {
+ table84.AddRow(new string[] {
"Test Estate 1",
"Voucher",
"True",
"True"});
#line 32
- await testRunner.GivenAsync("I have created the following operators", ((string)(null)), table78, "Given ");
+ await testRunner.GivenAsync("I have created the following operators", ((string)(null)), table84, "Given ");
#line hidden
- global::Reqnroll.Table table79 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table85 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName"});
- table79.AddRow(new string[] {
+ table85.AddRow(new string[] {
"Test Estate 1",
"Safaricom"});
- table79.AddRow(new string[] {
+ table85.AddRow(new string[] {
"Test Estate 1",
"Voucher"});
#line 37
- await testRunner.AndAsync("I have assigned the following operators to the estates", ((string)(null)), table79, "And ");
+ await testRunner.AndAsync("I have assigned the following operators to the estates", ((string)(null)), table85, "And ");
#line hidden
- global::Reqnroll.Table table80 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table86 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"ContractDescription"});
- table80.AddRow(new string[] {
+ table86.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"Safaricom Contract"});
- table80.AddRow(new string[] {
+ table86.AddRow(new string[] {
"Test Estate 1",
"Voucher",
"Hospital 1 Contract"});
#line 42
- await testRunner.GivenAsync("I create a contract with the following values", ((string)(null)), table80, "Given ");
+ await testRunner.GivenAsync("I create a contract with the following values", ((string)(null)), table86, "Given ");
#line hidden
- global::Reqnroll.Table table81 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table87 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"ContractDescription",
@@ -264,7 +264,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"DisplayText",
"Value",
"ProductType"});
- table81.AddRow(new string[] {
+ table87.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"Safaricom Contract",
@@ -272,7 +272,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"Custom",
"",
"MobileTopup"});
- table81.AddRow(new string[] {
+ table87.AddRow(new string[] {
"Test Estate 1",
"Voucher",
"Hospital 1 Contract",
@@ -281,9 +281,9 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"",
"Voucher"});
#line 47
- await testRunner.WhenAsync("I create the following Products", ((string)(null)), table81, "When ");
+ await testRunner.WhenAsync("I create the following Products", ((string)(null)), table87, "When ");
#line hidden
- global::Reqnroll.Table table82 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table88 = new global::Reqnroll.Table(new string[] {
"EstateName",
"OperatorName",
"ContractDescription",
@@ -291,7 +291,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"CalculationType",
"FeeDescription",
"Value"});
- table82.AddRow(new string[] {
+ table88.AddRow(new string[] {
"Test Estate 1",
"Safaricom",
"Safaricom Contract",
@@ -299,7 +299,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"Fixed",
"Merchant Commission",
"2.50"});
- table82.AddRow(new string[] {
+ table88.AddRow(new string[] {
"Test Estate 1",
"Voucher",
"Hospital 1 Contract",
@@ -308,9 +308,9 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"Merchant Commission",
"2.50"});
#line 52
- await testRunner.WhenAsync("I add the following Transaction Fees", ((string)(null)), table82, "When ");
+ await testRunner.WhenAsync("I add the following Transaction Fees", ((string)(null)), table88, "When ");
#line hidden
- global::Reqnroll.Table table83 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table89 = new global::Reqnroll.Table(new string[] {
"MerchantName",
"AddressLine1",
"Town",
@@ -320,7 +320,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"ContactName",
"EmailAddress",
"EstateName"});
- table83.AddRow(new string[] {
+ table89.AddRow(new string[] {
"Test Merchant 1",
"Address Line 1",
"TestTown",
@@ -331,69 +331,69 @@ await testRunner.GivenAsync("I have a token to access the estate management and
"testcontact1@merchant1.co.uk",
"Test Estate 1"});
#line 57
- await testRunner.GivenAsync("I create the following merchants", ((string)(null)), table83, "Given ");
+ await testRunner.GivenAsync("I create the following merchants", ((string)(null)), table89, "Given ");
#line hidden
- global::Reqnroll.Table table84 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table90 = new global::Reqnroll.Table(new string[] {
"OperatorName",
"MerchantName",
"MerchantNumber",
"TerminalNumber",
"EstateName"});
- table84.AddRow(new string[] {
+ table90.AddRow(new string[] {
"Safaricom",
"Test Merchant 1",
"00000001",
"10000001",
"Test Estate 1"});
- table84.AddRow(new string[] {
+ table90.AddRow(new string[] {
"Voucher",
"Test Merchant 1",
"00000001",
"10000001",
"Test Estate 1"});
#line 61
- await testRunner.GivenAsync("I have assigned the following operator to the merchants", ((string)(null)), table84, "Given ");
+ await testRunner.GivenAsync("I have assigned the following operator to the merchants", ((string)(null)), table90, "Given ");
#line hidden
- global::Reqnroll.Table table85 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table91 = new global::Reqnroll.Table(new string[] {
"DeviceIdentifier",
"MerchantName",
"EstateName"});
- table85.AddRow(new string[] {
+ table91.AddRow(new string[] {
"123456780",
"Test Merchant 1",
"Test Estate 1"});
#line 66
- await testRunner.GivenAsync("I have assigned the following devices to the merchants", ((string)(null)), table85, "Given ");
+ await testRunner.GivenAsync("I have assigned the following devices to the merchants", ((string)(null)), table91, "Given ");
#line hidden
- global::Reqnroll.Table table86 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table92 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"ContractDescription"});
- table86.AddRow(new string[] {
+ table92.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"Safaricom Contract"});
- table86.AddRow(new string[] {
+ table92.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"Hospital 1 Contract"});
#line 70
- await testRunner.WhenAsync("I add the following contracts to the following merchants", ((string)(null)), table86, "When ");
+ await testRunner.WhenAsync("I add the following contracts to the following merchants", ((string)(null)), table92, "When ");
#line hidden
- global::Reqnroll.Table table87 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table93 = new global::Reqnroll.Table(new string[] {
"Reference",
"Amount",
"DateTime",
"MerchantName",
"EstateName"});
- table87.AddRow(new string[] {
+ table93.AddRow(new string[] {
"Deposit1",
"300.00",
"Today",
"Test Merchant 1",
"Test Estate 1"});
#line 75
- await testRunner.GivenAsync("I make the following manual merchant deposits", ((string)(null)), table87, "Given ");
+ await testRunner.GivenAsync("I make the following manual merchant deposits", ((string)(null)), table93, "Given ");
#line hidden
}
@@ -425,41 +425,41 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table88 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table94 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3",
"Column4"});
- table88.AddRow(new string[] {
+ table94.AddRow(new string[] {
"H",
"20210508",
"",
""});
- table88.AddRow(new string[] {
+ table94.AddRow(new string[] {
"D",
"Hospital 1",
"testrecipient1@recipient.com",
"10"});
- table88.AddRow(new string[] {
+ table94.AddRow(new string[] {
"T",
"1",
"",
""});
#line 80
- await testRunner.GivenAsync("I have a file named \'VoucherIssue.txt\' with the following contents", ((string)(null)), table88, "Given ");
+ await testRunner.GivenAsync("I have a file named \'VoucherIssue.txt\' with the following contents", ((string)(null)), table94, "Given ");
#line hidden
- global::Reqnroll.Table table89 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table95 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table89.AddRow(new string[] {
+ table95.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"8806EDBC-3ED6-406B-9E5F-A9078356BE99",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 85
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table89, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table95, "And ");
#line hidden
}
await this.ScenarioCleanupAsync();
@@ -488,41 +488,41 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table90 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table96 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3",
"Column4"});
- table90.AddRow(new string[] {
+ table96.AddRow(new string[] {
"H",
"20210508",
"",
""});
- table90.AddRow(new string[] {
+ table96.AddRow(new string[] {
"D",
"Hospital 1",
"07777777775",
"10"});
- table90.AddRow(new string[] {
+ table96.AddRow(new string[] {
"T",
"1",
"",
""});
#line 92
- await testRunner.GivenAsync("I have a file named \'VoucherIssue.txt\' with the following contents", ((string)(null)), table90, "Given ");
+ await testRunner.GivenAsync("I have a file named \'VoucherIssue.txt\' with the following contents", ((string)(null)), table96, "Given ");
#line hidden
- global::Reqnroll.Table table91 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table97 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table91.AddRow(new string[] {
+ table97.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"8806EDBC-3ED6-406B-9E5F-A9078356BE99",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 97
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table91, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table97, "And ");
#line hidden
}
await this.ScenarioCleanupAsync();
@@ -551,46 +551,46 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table92 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table98 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3",
"Column4"});
- table92.AddRow(new string[] {
+ table98.AddRow(new string[] {
"H",
"20210508",
"",
""});
- table92.AddRow(new string[] {
+ table98.AddRow(new string[] {
"D",
"Hospital 1",
"07777777775",
"10"});
- table92.AddRow(new string[] {
+ table98.AddRow(new string[] {
"D",
"Hospital 1",
"testrecipient1@recipient.com",
"10"});
- table92.AddRow(new string[] {
+ table98.AddRow(new string[] {
"T",
"1",
"",
""});
#line 104
- await testRunner.GivenAsync("I have a file named \'VoucherIssue.txt\' with the following contents", ((string)(null)), table92, "Given ");
+ await testRunner.GivenAsync("I have a file named \'VoucherIssue.txt\' with the following contents", ((string)(null)), table98, "Given ");
#line hidden
- global::Reqnroll.Table table93 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table99 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table93.AddRow(new string[] {
+ table99.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"8806EDBC-3ED6-406B-9E5F-A9078356BE99",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 110
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table93, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table99, "And ");
#line hidden
}
await this.ScenarioCleanupAsync();
@@ -619,87 +619,87 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table94 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table100 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3",
"Column4"});
- table94.AddRow(new string[] {
+ table100.AddRow(new string[] {
"H",
"20210508",
"",
""});
- table94.AddRow(new string[] {
+ table100.AddRow(new string[] {
"D",
"Hospital 1",
"07777777775",
"10"});
- table94.AddRow(new string[] {
+ table100.AddRow(new string[] {
"D",
"Hospital 1",
"testrecipient1@recipient.com",
"10"});
- table94.AddRow(new string[] {
+ table100.AddRow(new string[] {
"T",
"1",
"",
""});
#line 117
- await testRunner.GivenAsync("I have a file named \'VoucherIssue1.txt\' with the following contents", ((string)(null)), table94, "Given ");
+ await testRunner.GivenAsync("I have a file named \'VoucherIssue1.txt\' with the following contents", ((string)(null)), table100, "Given ");
#line hidden
- global::Reqnroll.Table table95 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table101 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table95.AddRow(new string[] {
+ table101.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"8806EDBC-3ED6-406B-9E5F-A9078356BE99",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 123
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table95, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table101, "And ");
#line hidden
- global::Reqnroll.Table table96 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table102 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3",
"Column4"});
- table96.AddRow(new string[] {
+ table102.AddRow(new string[] {
"H",
"20210508",
"",
""});
- table96.AddRow(new string[] {
+ table102.AddRow(new string[] {
"D",
"Hospital 1",
"07777777775",
"20"});
- table96.AddRow(new string[] {
+ table102.AddRow(new string[] {
"D",
"Hospital 1",
"testrecipient1@recipient.com",
"20"});
- table96.AddRow(new string[] {
+ table102.AddRow(new string[] {
"T",
"1",
"",
""});
#line 127
- await testRunner.GivenAsync("I have a file named \'VoucherIssue2.txt\' with the following contents", ((string)(null)), table96, "Given ");
+ await testRunner.GivenAsync("I have a file named \'VoucherIssue2.txt\' with the following contents", ((string)(null)), table102, "Given ");
#line hidden
- global::Reqnroll.Table table97 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table103 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table97.AddRow(new string[] {
+ table103.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"8806EDBC-3ED6-406B-9E5F-A9078356BE99",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 133
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table97, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table103, "And ");
#line hidden
}
await this.ScenarioCleanupAsync();
@@ -730,88 +730,87 @@ await testRunner.GivenAsync("I have a token to access the estate management and
#line 4
await this.FeatureBackgroundAsync();
#line hidden
- global::Reqnroll.Table table98 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table104 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3",
"Column4"});
- table98.AddRow(new string[] {
+ table104.AddRow(new string[] {
"H",
"20210508",
"",
""});
- table98.AddRow(new string[] {
+ table104.AddRow(new string[] {
"D",
"Hospital 1",
"07777777775",
"10"});
- table98.AddRow(new string[] {
+ table104.AddRow(new string[] {
"D",
"Hospital 1",
"testrecipient1@recipient.com",
"20"});
- table98.AddRow(new string[] {
+ table104.AddRow(new string[] {
"T",
"1",
"",
""});
#line 141
- await testRunner.GivenAsync("I have a file named \'VoucherIssue1.txt\' with the following contents", ((string)(null)), table98, "Given ");
+ await testRunner.GivenAsync("I have a file named \'VoucherIssue1.txt\' with the following contents", ((string)(null)), table104, "Given ");
#line hidden
- global::Reqnroll.Table table99 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table105 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table99.AddRow(new string[] {
+ table105.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"8806EDBC-3ED6-406B-9E5F-A9078356BE99",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 147
- await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table99, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table105, "And ");
#line hidden
- global::Reqnroll.Table table100 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table106 = new global::Reqnroll.Table(new string[] {
"Column1",
"Column2",
"Column3",
"Column4"});
- table100.AddRow(new string[] {
+ table106.AddRow(new string[] {
"H",
"20210508",
"",
""});
- table100.AddRow(new string[] {
+ table106.AddRow(new string[] {
"D",
"Hospital 1",
"07777777775",
"10"});
- table100.AddRow(new string[] {
+ table106.AddRow(new string[] {
"D",
"Hospital 1",
"testrecipient1@recipient.com",
"20"});
- table100.AddRow(new string[] {
+ table106.AddRow(new string[] {
"T",
"1",
"",
""});
#line 153
- await testRunner.GivenAsync("I have a file named \'VoucherIssue2.txt\' with the following contents", ((string)(null)), table100, "Given ");
+ await testRunner.GivenAsync("I have a file named \'VoucherIssue2.txt\' with the following contents", ((string)(null)), table106, "Given ");
#line hidden
- global::Reqnroll.Table table101 = new global::Reqnroll.Table(new string[] {
+ global::Reqnroll.Table table107 = new global::Reqnroll.Table(new string[] {
"EstateName",
"MerchantName",
"FileProfileId",
"UserId"});
- table101.AddRow(new string[] {
+ table107.AddRow(new string[] {
"Test Estate 1",
"Test Merchant 1",
"8806EDBC-3ED6-406B-9E5F-A9078356BE99",
"ABA59ABF-293D-4A6B-B81B-7007503C3476"});
#line 160
- await testRunner.AndAsync("I upload this file for processing an error should be returned indicating the file" +
- " is a duplicate", ((string)(null)), table101, "And ");
+ await testRunner.AndAsync("I upload this file for processing", ((string)(null)), table107, "And ");
#line hidden
}
await this.ScenarioCleanupAsync();
diff --git a/FileProcessor/Bootstrapper/DomainEventHandlerRegistry.cs b/FileProcessor/Bootstrapper/DomainEventHandlerRegistry.cs
index 6a5e18a..cd459c8 100644
--- a/FileProcessor/Bootstrapper/DomainEventHandlerRegistry.cs
+++ b/FileProcessor/Bootstrapper/DomainEventHandlerRegistry.cs
@@ -19,17 +19,17 @@ public class DomainEventHandlerRegistry : ServiceRegistry
///
/// Initializes a new instance of the class.
///
- public DomainEventHandlerRegistry()
+ public DomainEventHandlerRegistry(IConfiguration configuration)
{
Dictionary eventHandlersConfiguration = new Dictionary();
- if (Startup.Configuration != null)
+ if (configuration != null)
{
- IConfigurationSection section = Startup.Configuration.GetSection("AppSettings:EventHandlerConfiguration");
+ IConfigurationSection section = configuration.GetSection("AppSettings:EventHandlerConfiguration");
if (section != null)
{
- Startup.Configuration.GetSection("AppSettings:EventHandlerConfiguration").Bind(eventHandlersConfiguration);
+ configuration.GetSection("AppSettings:EventHandlerConfiguration").Bind(eventHandlersConfiguration);
}
}
@@ -48,4 +48,4 @@ public DomainEventHandlerRegistry()
}
#endregion
-}
\ No newline at end of file
+}
diff --git a/FileProcessor/Bootstrapper/MiddlewareRegistry.cs b/FileProcessor/Bootstrapper/MiddlewareRegistry.cs
index 2c56b4e..df0b82a 100644
--- a/FileProcessor/Bootstrapper/MiddlewareRegistry.cs
+++ b/FileProcessor/Bootstrapper/MiddlewareRegistry.cs
@@ -1,6 +1,8 @@
using HealthMonitoring.Client;
using KurrentDB.Client;
using Microsoft.OpenApi;
+using Microsoft.Extensions.Configuration;
+using TransactionProcessing.ApiDefaults;
namespace FileProcessor.Bootstrapper
{
@@ -30,7 +32,7 @@ public class MiddlewareRegistry : ServiceRegistry
///
/// Initializes a new instance of the class.
///
- public MiddlewareRegistry()
+ public MiddlewareRegistry(IConfiguration configuration)
{
String eventStoreConnectionString = ConfigurationReader.GetValue("EventStoreSettings", "ConnectionString");
@@ -42,35 +44,7 @@ public MiddlewareRegistry()
failureStatus:HealthStatus.Unhealthy,
tags:new[] {"db", "eventstore"}).AddTransactionProcessorService()
.AddSecurityService(this.ApiEndpointHttpHandler);
-
- this.AddSwaggerGen(c =>
- {
- c.SwaggerDoc("v1",
- new OpenApiInfo
- {
- Title = "File Processor API",
- Version = "1.0",
- Description = "A REST Api to manage importing and processing bulk transaction files.",
- Contact = new OpenApiContact
- {
- Name = "Stuart Ferguson",
- Email = "golfhandicapping@btinternet.com"
- }
- });
- // add a custom operation filter which sets default values
-
- //Locate the XML files being generated by ASP.NET...
- var directory = new DirectoryInfo(AppContext.BaseDirectory);
- var xmlFiles = directory.GetFiles("*.xml");
-
- //... and tell Swagger to use those XML comments.
- foreach (FileInfo fileInfo in xmlFiles)
- {
- c.IncludeXmlComments(fileInfo.FullName);
- }
- });
-
-
+
this.AddAuthentication(options =>
{
options.DefaultScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
@@ -119,7 +93,12 @@ public MiddlewareRegistry()
options.MemoryBufferThreshold = 64 * 1024;
});
- this.AddHealthMonitoringRegistration(Startup.Configuration);
+ this.AddHealthMonitoringRegistration(configuration);
+
+ this.AddApiDefaults(options => {
+ options.Title = "File Processor";
+ options.Description = "API for all aspects of bulk file processing";
+ });
}
#endregion
diff --git a/FileProcessor/Bootstrapper/RepositoryRegistry.cs b/FileProcessor/Bootstrapper/RepositoryRegistry.cs
index 44a1054..5cd7a12 100644
--- a/FileProcessor/Bootstrapper/RepositoryRegistry.cs
+++ b/FileProcessor/Bootstrapper/RepositoryRegistry.cs
@@ -20,6 +20,7 @@ namespace FileProcessor.Bootstrapper;
using System;
using System.Diagnostics.CodeAnalysis;
using FileProfileAggregateRoot = FileProcessor.FileProfileAggregate.FileProfileAggregate;
+using Microsoft.AspNetCore.Hosting;
[ExcludeFromCodeCoverage]
public class RepositoryRegistry : ServiceRegistry
@@ -29,10 +30,10 @@ public class RepositoryRegistry : ServiceRegistry
///
/// Initializes a new instance of the class.
///
- public RepositoryRegistry()
+ public RepositoryRegistry(IConfiguration configuration, IWebHostEnvironment environment)
{
this.AddSingleton(typeof(IDbContextResolver<>), typeof(DbContextResolver<>));
- if (Startup.WebHostEnvironment.IsEnvironment("IntegrationTest") || Startup.Configuration.GetValue("ServiceOptions:UseInMemoryDatabase") == true)
+ if (environment.IsEnvironment("IntegrationTest") || configuration.GetValue("ServiceOptions:UseInMemoryDatabase") == true)
{
this.AddDbContext(builder => builder.UseInMemoryDatabase("TransactionProcessorReadModel"));
}
@@ -42,7 +43,7 @@ public RepositoryRegistry()
options.UseSqlServer(ConfigurationReader.GetConnectionString("TransactionProcessorReadModel")));
}
- String connectionString = Startup.Configuration.GetValue("EventStoreSettings:ConnectionString");
+ String connectionString = configuration.GetValue("EventStoreSettings:ConnectionString");
this.AddKurrentDBProjectionManagementClient(connectionString);
this.AddKurrentDBPersistentSubscriptionsClient(connectionString);
diff --git a/FileProcessor/Common/Extensions.cs b/FileProcessor/Common/Extensions.cs
index 401596c..c59fe2a 100644
--- a/FileProcessor/Common/Extensions.cs
+++ b/FileProcessor/Common/Extensions.cs
@@ -66,10 +66,13 @@ public static IServiceCollection AddInSecureEventStoreClient(
}
};
- public static void PreWarm(this IApplicationBuilder applicationBuilder){
- IFileSystem fileSystem = Startup.Container.GetInstance();
- IFileProfileDirectorySynchronizer directorySynchronizer = Startup.Container.GetInstance();
- IFileProfileDirectoryRecoveryService recoveryService = Startup.Container.GetInstance();
+ public static void PreWarm(this IApplicationBuilder applicationBuilder,
+ IFileSystem fileSystem,
+ IFileProfileDirectorySynchronizer directorySynchronizer,
+ IFileProfileDirectoryRecoveryService recoveryService,
+ IConfiguration configuration,
+ IDomainEventHandlerResolver mainEventHandlerResolver,
+ Func subscriptionRepositoryResolver){
var temporaryFileLocation = ConfigurationReader.GetValue("AppSettings", "TemporaryFileLocation");
Logger.LogInformation($"Starting up, TemporaryFileLocation is [{temporaryFileLocation}]");
@@ -90,20 +93,16 @@ public static void PreWarm(this IApplicationBuilder applicationBuilder){
TypeProvider.LoadDomainEventsTypeDynamically();
- IConfigurationSection subscriptionConfigSection = Startup.Configuration.GetSection("AppSettings:SubscriptionConfiguration");
+ IConfigurationSection subscriptionConfigSection = configuration.GetSection("AppSettings:SubscriptionConfiguration");
SubscriptionWorkersRoot subscriptionWorkersRoot = new SubscriptionWorkersRoot();
subscriptionConfigSection.Bind(subscriptionWorkersRoot);
String eventStoreConnectionString = ConfigurationReader.GetValue("EventStoreSettings", "ConnectionString");
- IDomainEventHandlerResolver mainEventHandlerResolver = Startup.Container.GetInstance("Main");
-
Dictionary eventHandlerResolvers = new Dictionary {
{"Main", mainEventHandlerResolver}
};
- Func subscriptionRepositoryResolver = Startup.Container.GetInstance>();
-
applicationBuilder.ConfigureSubscriptionService(subscriptionWorkersRoot,
eventStoreConnectionString,
eventHandlerResolvers,
diff --git a/FileProcessor/Common/ModelFactory.cs b/FileProcessor/Common/ModelFactory.cs
index 6c9d912..327ee7d 100644
--- a/FileProcessor/Common/ModelFactory.cs
+++ b/FileProcessor/Common/ModelFactory.cs
@@ -8,11 +8,35 @@ namespace FileProcessor.Common
using FileImportLogResponse = DataTransferObjects.Responses.FileImportLog;
using FileDetailsResponse = DataTransferObjects.Responses.FileDetails;
using FileLineResponse = DataTransferObjects.Responses.FileLine;
+ using FileProfileResponse = DataTransferObjects.Responses.FileProfileResponse;
public static class ModelFactory
{
#region Methods
+ public static List ConvertFrom(List fileProfiles)
+ {
+ return fileProfiles.Select(ConvertFrom).ToList();
+ }
+
+ public static FileProfileResponse ConvertFrom(Models.FileProfile fileProfile)
+ {
+ return new FileProfileResponse
+ {
+ FileProfileId = fileProfile.FileProfileId,
+ FileProfileVersionId = fileProfile.FileProfileVersionId,
+ FileProfileVersion = fileProfile.FileProfileVersion,
+ Name = fileProfile.Name,
+ OperatorName = fileProfile.OperatorName,
+ ListeningDirectory = fileProfile.ListeningDirectory,
+ ProcessedDirectory = fileProfile.ProcessedDirectory,
+ FailedDirectory = fileProfile.FailedDirectory,
+ FileFormatHandler = fileProfile.FileFormatHandler,
+ RequestType = fileProfile.RequestType,
+ LineTerminator = fileProfile.LineTerminator
+ };
+ }
+
///
/// Converts from.
///
diff --git a/FileProcessor/Endpoints/DomainEventEndpoints.cs b/FileProcessor/Endpoints/DomainEventEndpoints.cs
index e7785e9..ecfb303 100644
--- a/FileProcessor/Endpoints/DomainEventEndpoints.cs
+++ b/FileProcessor/Endpoints/DomainEventEndpoints.cs
@@ -13,7 +13,11 @@ public static class DomainEventEndpoints
public static void MapDomainEventEndpoint(this IEndpointRouteBuilder app)
{
app.MapPost(Route, DomainEventHandlers.HandleDomainEvent)
- .ExcludeFromDescription() // hides from Swagger
- .WithName("DomainEvent");
+ .WithName("DomainEvent")
+ .WithSummary("Process a domain event")
+ .WithDescription("Internal event-delivery endpoint. Send the event JSON body and identify its registered event type in the `eventType` request header. Returns 200 when all configured handlers succeed or no handlers are configured; returns 500 when one or more handlers fail.")
+ .Produces(StatusCodes.Status200OK)
+ .ProducesProblem(StatusCodes.Status500InternalServerError)
+ .WithEndpointExamples();
}
-}
\ No newline at end of file
+}
diff --git a/FileProcessor/Endpoints/FileEndpoints.cs b/FileProcessor/Endpoints/FileEndpoints.cs
index a160268..6567ed0 100644
--- a/FileProcessor/Endpoints/FileEndpoints.cs
+++ b/FileProcessor/Endpoints/FileEndpoints.cs
@@ -1,5 +1,6 @@
using System;
using FileProcessor.Handlers;
+using FileProcessor.DataTransferObjects.Responses;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
@@ -18,13 +19,27 @@ public static void MapFileEndpoints(this IEndpointRouteBuilder app)
group.MapPost("/", FileHandlers.UploadFile)
.DisableAntiforgery()
- .Accepts("multipart/form-data")
- .WithName("UploadFile");
+ .Accepts("multipart/form-data")
+ .WithName("UploadFile")
+ .WithSummary("Upload a transaction file")
+ .WithDescription("Requires authorization. Submit the upload metadata fields from `UploadFileRequest` and exactly one non-empty file as multipart form data. The file name must have a configured allowed extension and the file must be within the configured size limit. The upload time defaults to the current local time when omitted or `DateTime.MinValue`. Returns 202 Accepted with the file ID when the upload is accepted.")
+ .Produces(StatusCodes.Status202Accepted)
+ .Produces(StatusCodes.Status400BadRequest)
+ .Produces(StatusCodes.Status413PayloadTooLarge)
+ .WithEndpointExamples();
group.MapGet("/{fileId:guid}", FileHandlers.GetFile)
- .WithName("GetFile");
+ .WithName("GetFile")
+ .WithSummary("Get a file and its processing details")
+ .WithDescription("Requires authorization. Required GUID path parameter `fileId` identifies the file; required GUID query parameter `estateId` identifies the estate that owns it. Returns the file metadata, processing state, line results, and processing summary.")
+ .Produces(StatusCodes.Status200OK)
+ .WithEndpointExamples();
group.MapPost("/{fileId:guid}/lines/{lineNumber:int}/retry", FileHandlers.ReplayLine)
- .WithName("ReplayLine");
+ .WithName("ReplayLine")
+ .WithSummary("Retry a file line")
+ .WithDescription("Requires authorization. Required GUID path parameter `fileId` and integer path parameter `lineNumber` identify the file and line to replay; required GUID query parameter `estateId` identifies the owning estate. The request has no body. Returns the operation result.")
+ .Produces(StatusCodes.Status200OK)
+ .WithEndpointExamples();
}
}
diff --git a/FileProcessor/Endpoints/FileImportLogEndpoints.cs b/FileProcessor/Endpoints/FileImportLogEndpoints.cs
index f227850..029bd8c 100644
--- a/FileProcessor/Endpoints/FileImportLogEndpoints.cs
+++ b/FileProcessor/Endpoints/FileImportLogEndpoints.cs
@@ -1,5 +1,6 @@
using System;
using FileProcessor.Handlers;
+using FileProcessor.DataTransferObjects.Responses;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
@@ -17,9 +18,17 @@ public static void MapFileImportLogEndpoints(this IEndpointRouteBuilder app)
.RequireAuthorization();
group.MapGet("/", FileImportLogHandlers.GetImportLogsAsync)
- .WithName("GetImportLogs");
+ .WithName("GetImportLogs")
+ .WithSummary("List file import logs")
+ .WithDescription("Requires authorization. Query parameters: `estateId` (required), `startDate` and `endDate` (required ISO dates; end date must be on or after start date), `merchantId` (optional), `pageNumber` (defaults to 1), `pageSize` (defaults to 50; allowed range 1–200), and `descending` (defaults to false). The date range includes both calendar dates. Returns a page of import logs and pagination metadata.")
+ .Produces(StatusCodes.Status200OK)
+ .WithEndpointExamples();
group.MapGet("/{fileImportLogId:guid}", FileImportLogHandlers.GetImportLogAsync)
- .WithName("GetImportLog");
+ .WithName("GetImportLog")
+ .WithSummary("Get a file import log")
+ .WithDescription("Requires authorization. Required GUID path parameter `fileImportLogId` identifies the log; required GUID query parameter `estateId` scopes the lookup, and optional GUID query parameter `merchantId` filters its files. Returns the import log and its files.")
+ .Produces(StatusCodes.Status200OK)
+ .WithEndpointExamples();
}
-}
\ No newline at end of file
+}
diff --git a/FileProcessor/Endpoints/FileProfileEndpoints.cs b/FileProcessor/Endpoints/FileProfileEndpoints.cs
index 3897295..f9ed473 100644
--- a/FileProcessor/Endpoints/FileProfileEndpoints.cs
+++ b/FileProcessor/Endpoints/FileProfileEndpoints.cs
@@ -1,5 +1,6 @@
-using System;
+using System;
using FileProcessor.Handlers;
+using System.Collections.Generic;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
@@ -17,24 +18,52 @@ public static void MapFileProfileEndpoints(this IEndpointRouteBuilder app)
.RequireAuthorization();
group.MapGet("/", FileProfileHandlers.GetFileProfiles)
- .WithName("GetFileProfiles");
+ .WithName("GetFileProfiles")
+ .WithSummary("List file profiles")
+ .WithDescription("Requires authorization. The request has no path parameters, query parameters, or body. Returns all available file profile versions.")
+ .Produces>(StatusCodes.Status200OK)
+ .WithEndpointExamples();
group.MapGet("/{fileProfileId:guid}", FileProfileHandlers.GetFileProfile)
- .WithName("GetFileProfile");
+ .WithName("GetFileProfile")
+ .WithSummary("Get the current file profile")
+ .WithDescription("Requires authorization. Path parameter `fileProfileId` identifies the file profile. The request has no query parameters or body. Returns the current profile details.")
+ .Produces(StatusCodes.Status200OK)
+ .WithEndpointExamples();
group.MapGet("/{fileProfileId:guid}/versions", FileProfileHandlers.GetFileProfileVersions)
- .WithName("GetFileProfileVersions");
+ .WithName("GetFileProfileVersions")
+ .WithSummary("List file profile versions")
+ .WithDescription("Requires authorization. Path parameter `fileProfileId` identifies the file profile. The request has no query parameters or body. Returns the profile's versions.")
+ .Produces>(StatusCodes.Status200OK)
+ .WithEndpointExamples();
group.MapGet("/{fileProfileId:guid}/versions/{fileProfileVersionId:guid}", FileProfileHandlers.GetFileProfileVersion)
- .WithName("GetFileProfileVersion");
+ .WithName("GetFileProfileVersion")
+ .WithSummary("Get a file profile version")
+ .WithDescription("Requires authorization. Path parameters `fileProfileId` and `fileProfileVersionId` identify the profile and version. The request has no query parameters or body. Returns the selected version details.")
+ .Produces(StatusCodes.Status200OK)
+ .WithEndpointExamples();
group.MapPost("/", FileProfileHandlers.CreateFileProfile)
- .WithName("CreateFileProfile");
+ .WithName("CreateFileProfile")
+ .WithSummary("Create a file profile")
+ .WithDescription("Requires authorization. Supply a `CreateFileProfileRequest` JSON body containing the new profile identifier and configuration. The request has no path or query parameters. Returns the created profile.")
+ .Produces(StatusCodes.Status200OK)
+ .WithEndpointExamples();
group.MapPatch("/{fileProfileId:guid}", FileProfileHandlers.UpdateFileProfile)
- .WithName("UpdateFileProfile");
+ .WithName("UpdateFileProfile")
+ .WithSummary("Update a file profile")
+ .WithDescription("Requires authorization. Path parameter `fileProfileId` identifies the profile. Supply an `UpdateFileProfileRequest` JSON body with the profile configuration to apply. The request has no query parameters. Returns the updated profile.")
+ .Produces(StatusCodes.Status200OK)
+ .WithEndpointExamples();
group.MapDelete("/{fileProfileId:guid}", FileProfileHandlers.ArchiveFileProfile)
- .WithName("ArchiveFileProfile");
+ .WithName("ArchiveFileProfile")
+ .WithSummary("Archive a file profile")
+ .WithDescription("Requires authorization. Path parameter `fileProfileId` identifies the profile. The request has no query parameters or body. Returns 204 No Content when the profile is archived successfully.")
+ .Produces(StatusCodes.Status204NoContent)
+ .WithEndpointExamples();
}
}
diff --git a/FileProcessor/Endpoints/MigrationEndpoints.cs b/FileProcessor/Endpoints/MigrationEndpoints.cs
index a12ce7e..b581a05 100644
--- a/FileProcessor/Endpoints/MigrationEndpoints.cs
+++ b/FileProcessor/Endpoints/MigrationEndpoints.cs
@@ -1,5 +1,6 @@
-using System;
+using System;
using FileProcessor.Handlers;
+using FileProcessor.BusinessLogic.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
@@ -17,6 +18,10 @@ public static void MapMigrationEndpoints(this IEndpointRouteBuilder app)
.RequireAuthorization()
.RequireAuthorization(AuthorizationExtensions.PolicyNames.ClientCredentialsOnlyPolicy)
.WithTags("Migrations")
- .WithName("MigrateProfileVersions");
+ .WithName("MigrateProfileVersions")
+ .WithSummary("Migrate file profile versions")
+ .WithDescription("Requires the client-credentials-only authorization policy. The request has no path parameters, query parameters, or body. Runs the file profile version migration and returns its report.")
+ .Produces(StatusCodes.Status200OK)
+ .WithEndpointExamples();
}
}
diff --git a/FileProcessor/Endpoints/OpenApiExampleExtensions.cs b/FileProcessor/Endpoints/OpenApiExampleExtensions.cs
new file mode 100644
index 0000000..8c0b446
--- /dev/null
+++ b/FileProcessor/Endpoints/OpenApiExampleExtensions.cs
@@ -0,0 +1,488 @@
+#nullable enable
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.OpenApi;
+using Microsoft.OpenApi;
+
+namespace FileProcessor.Endpoints;
+
+/// Adds the documented request, parameter, and response examples to an endpoint.
+public static class OpenApiExampleExtensions
+{
+ private const string EstateIdParameterName = "estateId";
+ private const string FileProfileIdParameterName = "fileProfileId";
+ private const string EstateIdExampleValue = "435613ac-a468-47a3-ac4f-649d89764c22";
+ private const string FileProfileIdExampleValue = "9c89c59e-8608-47b1-b280-052a75bcf84b";
+
+ private static readonly IReadOnlyDictionary Examples = new Dictionary
+ {
+ ["DomainEvent"] = new()
+ {
+ RequestBody = """
+ {
+ "fileId": "c31f6a4b-8cd1-4d7e-9a2c-1f8a5b6d7e90",
+ "estateId": "435613ac-a468-47a3-ac4f-649d89764c22",
+ "merchantId": "ab1c99fb-1c6c-4694-9a32-b71be5d1da33",
+ "lineNumber": 1,
+ "fileLine": "D,Example Operator,01234567890,10.00",
+ "EventId": "42cae457-c061-42d0-b544-f1767d812ae5"
+ }
+ """,
+ Parameters = new Dictionary { ["eventType"] = "FileLineAddedEvent" },
+ Responses = new Dictionary
+ {
+ ["500"] = """
+ {
+ "type": "about:blank",
+ "title": "One or more event handlers failed",
+ "status": 500,
+ "eventId": "42cae457-c061-42d0-b544-f1767d812ae5",
+ "eventType": "FileLineAddedEvent",
+ "failures": [
+ { "handler": "FileDomainEventHandler", "error": "The transaction could not be processed." }
+ ]
+ }
+ """
+ }
+ },
+ ["MigrateProfileVersions"] = new()
+ {
+ Responses = new Dictionary
+ {
+ ["200"] = """
+ {
+ "profiles_checked": 12,
+ "profiles_with_initial_version": 12,
+ "files_checked": 48,
+ "files_assigned": 45,
+ "files_skipped": 3,
+ "failures": []
+ }
+ """
+ }
+ },
+ ["UploadFile"] = new()
+ {
+ RequestBody = """
+ {
+ "FileId": "c31f6a4b-8cd1-4d7e-9a2c-1f8a5b6d7e90",
+ "EstateId": "435613ac-a468-47a3-ac4f-649d89764c22",
+ "MerchantId": "ab1c99fb-1c6c-4694-9a32-b71be5d1da33",
+ "UserId": "a782891c-5c7d-45de-b002-1585a6db28df",
+ "FileProfileId": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "UploadDateTime": "2026-10-22T09:30:00Z",
+ "File": "H,Operator,Phone,Amount\nD,Example Operator,01234567890,10.00"
+ }
+ """,
+ Responses = new Dictionary
+ {
+ ["202"] = "\"c31f6a4b-8cd1-4d7e-9a2c-1f8a5b6d7e90\"",
+ ["400"] = "\"The uploaded file must not be empty.\""
+ }
+ },
+ ["GetFile"] = new()
+ {
+ Parameters = new Dictionary
+ {
+ ["fileId"] = "c31f6a4b-8cd1-4d7e-9a2c-1f8a5b6d7e90",
+ [EstateIdParameterName] = EstateIdExampleValue
+ },
+ Responses = new Dictionary
+ {
+ ["200"] = """
+ {
+ "file_id": "c31f6a4b-8cd1-4d7e-9a2c-1f8a5b6d7e90",
+ "processing_completed": true,
+ "is_rejected": false,
+ "rejection_code": null,
+ "rejection_reason": null,
+ "observed_detail_record_count": 1,
+ "maximum_detail_record_count": 1000,
+ "estate_id": "435613ac-a468-47a3-ac4f-649d89764c22",
+ "user_id": "a782891c-5c7d-45de-b002-1585a6db28df",
+ "user_email_address": "operator@example.com",
+ "merchant_id": "ab1c99fb-1c6c-4694-9a32-b71be5d1da33",
+ "merchant_name": "Example Merchant",
+ "file_profile_id": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "file_profile_version_id": "469752f8-e6f8-42c3-bff9-a79717c11d84",
+ "file_profile_name": "Voucher transactions",
+ "file_import_log_id": "9eeab611-33a4-4e31-9e84-b61d1302f743",
+ "file_location": "files/2026/10/vouchers.csv",
+ "file_lines": [
+ {
+ "line_data": "D,Example Operator,01234567890,10.00",
+ "line_number": 1,
+ "processing_result": 2,
+ "transaction_id": "cb95782a-1c7f-49bb-a96d-8cf4dbeb1f57",
+ "event_id": "42cae457-c061-42d0-b544-f1767d812ae5",
+ "rejection_reason": null,
+ "failure_reason": null,
+ "response_code": "0000",
+ "dispatch_attempt_count": 1,
+ "failed_dispatch_attempts": []
+ }
+ ],
+ "processing_summary": {
+ "failed_lines": 0,
+ "ignored_lines": 0,
+ "not_processed_lines": 0,
+ "rejected_lines": 0,
+ "successfully_processed_lines": 1,
+ "total_lines": 1
+ }
+ }
+ """
+ }
+ },
+ ["ReplayLine"] = new()
+ {
+ Parameters = new Dictionary
+ {
+ ["fileId"] = "c31f6a4b-8cd1-4d7e-9a2c-1f8a5b6d7e90",
+ [EstateIdParameterName] = EstateIdExampleValue,
+ ["lineNumber"] = 1
+ }
+ },
+ ["GetImportLogs"] = new()
+ {
+ Parameters = new Dictionary
+ {
+ [EstateIdParameterName] = EstateIdExampleValue,
+ ["startDate"] = "2026-10-21",
+ ["endDate"] = "2026-10-22",
+ ["merchantId"] = "ab1c99fb-1c6c-4694-9a32-b71be5d1da33",
+ ["pageNumber"] = 1,
+ ["pageSize"] = 50,
+ ["descending"] = true
+ },
+ Responses = new Dictionary
+ {
+ ["200"] = """
+ {
+ "file_import_logs": [
+ {
+ "file_import_log_id": "9eeab611-33a4-4e31-9e84-b61d1302f743",
+ "import_log_date_time": "2026-10-22T09:30:00Z",
+ "import_log_date": "2026-10-22T00:00:00Z",
+ "import_log_time": "09:30:00",
+ "file_count": 1,
+ "files": [
+ {
+ "file_id": "c31f6a4b-8cd1-4d7e-9a2c-1f8a5b6d7e90",
+ "file_import_log_id": "9eeab611-33a4-4e31-9e84-b61d1302f743",
+ "file_path": "files/2026/10/vouchers.csv",
+ "file_profile_id": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "file_profile_version_id": "469752f8-e6f8-42c3-bff9-a79717c11d84",
+ "file_uploaded_date_time": "2026-10-22T09:30:00Z",
+ "merchant_id": "ab1c99fb-1c6c-4694-9a32-b71be5d1da33",
+ "original_file_name": "vouchers.csv",
+ "user_id": "a782891c-5c7d-45de-b002-1585a6db28df"
+ }
+ ]
+ }
+ ],
+ "page_number": 1,
+ "page_size": 50,
+ "total_count": 1,
+ "has_more": false
+ }
+ """
+ }
+ },
+ ["GetImportLog"] = new()
+ {
+ Parameters = new Dictionary
+ {
+ ["fileImportLogId"] = "9eeab611-33a4-4e31-9e84-b61d1302f743",
+ [EstateIdParameterName] = EstateIdExampleValue,
+ ["merchantId"] = "ab1c99fb-1c6c-4694-9a32-b71be5d1da33"
+ },
+ Responses = new Dictionary
+ {
+ ["200"] = """
+ {
+ "file_import_log_id": "9eeab611-33a4-4e31-9e84-b61d1302f743",
+ "import_log_date_time": "2026-10-22T09:30:00Z",
+ "import_log_date": "2026-10-22T00:00:00Z",
+ "import_log_time": "09:30:00",
+ "file_count": 1,
+ "files": [
+ {
+ "file_id": "c31f6a4b-8cd1-4d7e-9a2c-1f8a5b6d7e90",
+ "file_import_log_id": "9eeab611-33a4-4e31-9e84-b61d1302f743",
+ "file_path": "files/2026/10/vouchers.csv",
+ "file_profile_id": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "file_profile_version_id": "469752f8-e6f8-42c3-bff9-a79717c11d84",
+ "file_uploaded_date_time": "2026-10-22T09:30:00Z",
+ "merchant_id": "ab1c99fb-1c6c-4694-9a32-b71be5d1da33",
+ "original_file_name": "vouchers.csv",
+ "user_id": "a782891c-5c7d-45de-b002-1585a6db28df"
+ }
+ ]
+ }
+ """
+ }
+ },
+ ["GetFileProfiles"] = new()
+ {
+ Responses = new Dictionary
+ {
+ ["200"] = """
+ [
+ {
+ "file_profile_id": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "file_profile_version_id": "469752f8-e6f8-42c3-bff9-a79717c11d84",
+ "file_profile_version": 1,
+ "name": "Voucher transactions",
+ "operator_name": "Example Operator",
+ "listening_directory": "files/incoming/vouchers",
+ "processed_directory": "files/incoming/vouchers/processed",
+ "failed_directory": "files/incoming/vouchers/failed",
+ "file_format_handler": "CsvFileFormatHandler",
+ "request_type": "Voucher",
+ "line_terminator": "\n"
+ }
+ ]
+ """
+ }
+ },
+ ["CreateFileProfile"] = new()
+ {
+ RequestBody = """
+ {
+ "file_profile_id": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "name": "Voucher transactions",
+ "listening_directory": "files/incoming/vouchers",
+ "request_type": "Voucher",
+ "operator_name": "Example Operator",
+ "line_terminator": "LineFeed",
+ "file_format_handler": "CsvFileFormatHandler"
+ }
+ """,
+ Responses = new Dictionary
+ {
+ ["200"] = """
+ {
+ "file_profile_id": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "file_profile_version_id": "469752f8-e6f8-42c3-bff9-a79717c11d84",
+ "file_profile_version": 1,
+ "name": "Voucher transactions",
+ "operator_name": "Example Operator",
+ "listening_directory": "files/incoming/vouchers",
+ "processed_directory": "files/incoming/vouchers/processed",
+ "failed_directory": "files/incoming/vouchers/failed",
+ "file_format_handler": "CsvFileFormatHandler",
+ "request_type": "Voucher",
+ "line_terminator": "\n"
+ }
+ """
+ }
+ },
+ ["GetFileProfile"] = new()
+ {
+ Parameters = new Dictionary { [FileProfileIdParameterName] = FileProfileIdExampleValue },
+ Responses = new Dictionary
+ {
+ ["200"] = """
+ {
+ "file_profile_id": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "file_profile_version_id": "469752f8-e6f8-42c3-bff9-a79717c11d84",
+ "file_profile_version": 1,
+ "name": "Voucher transactions",
+ "operator_name": "Example Operator",
+ "listening_directory": "files/incoming/vouchers",
+ "processed_directory": "files/incoming/vouchers/processed",
+ "failed_directory": "files/incoming/vouchers/failed",
+ "file_format_handler": "CsvFileFormatHandler",
+ "request_type": "Voucher",
+ "line_terminator": "\n"
+ }
+ """
+ }
+ },
+ ["UpdateFileProfile"] = new()
+ {
+ Parameters = new Dictionary { [FileProfileIdParameterName] = FileProfileIdExampleValue },
+ RequestBody = """
+ {
+ "name": "Voucher transactions",
+ "listening_directory": "files/incoming/vouchers",
+ "request_type": "Voucher",
+ "operator_name": "Example Operator",
+ "line_terminator": "LineFeed",
+ "file_format_handler": "CsvFileFormatHandler"
+ }
+ """,
+ Responses = new Dictionary
+ {
+ ["200"] = """
+ {
+ "file_profile_id": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "file_profile_version_id": "7738df59-9b15-44cb-8d7a-df4845bb8bd4",
+ "file_profile_version": 2,
+ "name": "Voucher transactions",
+ "operator_name": "Example Operator",
+ "listening_directory": "files/incoming/vouchers",
+ "processed_directory": "files/incoming/vouchers/processed",
+ "failed_directory": "files/incoming/vouchers/failed",
+ "file_format_handler": "CsvFileFormatHandler",
+ "request_type": "Voucher",
+ "line_terminator": "\n"
+ }
+ """
+ }
+ },
+ ["ArchiveFileProfile"] = new()
+ {
+ Parameters = new Dictionary { [FileProfileIdParameterName] = FileProfileIdExampleValue }
+ },
+ ["GetFileProfileVersions"] = new()
+ {
+ Parameters = new Dictionary { [FileProfileIdParameterName] = FileProfileIdExampleValue },
+ Responses = new Dictionary
+ {
+ ["200"] = """
+ [
+ {
+ "file_profile_id": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "file_profile_version_id": "469752f8-e6f8-42c3-bff9-a79717c11d84",
+ "file_profile_version": 1,
+ "name": "Voucher transactions",
+ "operator_name": "Example Operator",
+ "listening_directory": "files/incoming/vouchers",
+ "processed_directory": "files/incoming/vouchers/processed",
+ "failed_directory": "files/incoming/vouchers/failed",
+ "file_format_handler": "CsvFileFormatHandler",
+ "request_type": "Voucher",
+ "line_terminator": "\n"
+ },
+ {
+ "file_profile_id": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "file_profile_version_id": "7738df59-9b15-44cb-8d7a-df4845bb8bd4",
+ "file_profile_version": 2,
+ "name": "Voucher transactions",
+ "operator_name": "Example Operator",
+ "listening_directory": "files/incoming/vouchers",
+ "processed_directory": "files/incoming/vouchers/processed",
+ "failed_directory": "files/incoming/vouchers/failed",
+ "file_format_handler": "CsvFileFormatHandler",
+ "request_type": "Voucher",
+ "line_terminator": "\n"
+ }
+ ]
+ """
+ }
+ },
+ ["GetFileProfileVersion"] = new()
+ {
+ Parameters = new Dictionary
+ {
+ [FileProfileIdParameterName] = FileProfileIdExampleValue,
+ ["fileProfileVersionId"] = "7738df59-9b15-44cb-8d7a-df4845bb8bd4"
+ },
+ Responses = new Dictionary
+ {
+ ["200"] = """
+ {
+ "file_profile_id": "9c89c59e-8608-47b1-b280-052a75bcf84b",
+ "file_profile_version_id": "7738df59-9b15-44cb-8d7a-df4845bb8bd4",
+ "file_profile_version": 2,
+ "name": "Voucher transactions",
+ "operator_name": "Example Operator",
+ "listening_directory": "files/incoming/vouchers",
+ "processed_directory": "files/incoming/vouchers/processed",
+ "failed_directory": "files/incoming/vouchers/failed",
+ "file_format_handler": "CsvFileFormatHandler",
+ "request_type": "Voucher",
+ "line_terminator": "\n"
+ }
+ """
+ }
+ }
+ };
+
+ /// Attaches the examples for the endpoint's OpenAPI operation.
+ public static RouteHandlerBuilder WithEndpointExamples(this RouteHandlerBuilder builder)
+ {
+ return builder.AddOpenApiOperationTransformer((operation, _, _) => ApplyExamplesAsync(operation));
+ }
+
+ private static Task ApplyExamplesAsync(OpenApiOperation operation)
+ {
+ if (Examples.TryGetValue(operation.OperationId ?? string.Empty, out EndpointExamples? examples) == false || examples is null)
+ return Task.CompletedTask;
+
+ AddRequestBodyExample(operation, examples);
+ AddResponseExamples(operation, examples);
+ AddParameterExamples(operation, examples);
+
+ return Task.CompletedTask;
+ }
+
+ private static void AddRequestBodyExample(OpenApiOperation operation, EndpointExamples examples)
+ {
+ if (examples.RequestBody is not string requestExample || operation.RequestBody?.Content is not { } requestContent)
+ return;
+
+ foreach (OpenApiMediaType mediaType in requestContent.Values)
+ mediaType.Example = JsonNode.Parse(requestExample);
+ }
+
+ private static void AddResponseExamples(OpenApiOperation operation, EndpointExamples examples)
+ {
+ if (examples.Responses is null)
+ return;
+
+ foreach ((string statusCode, string example) in examples.Responses)
+ {
+ if (operation.Responses?.TryGetValue(statusCode, out IOpenApiResponse? response) != true || response?.Content is not { } content)
+ continue;
+
+ foreach (OpenApiMediaType mediaType in content.Values)
+ mediaType.Example = JsonNode.Parse(example);
+ }
+ }
+
+ private static void AddParameterExamples(OpenApiOperation operation, EndpointExamples examples)
+ {
+ if (examples.Parameters is null)
+ return;
+
+ AddDomainEventHeaderParameter(operation);
+
+ foreach (OpenApiParameter parameter in (operation.Parameters ?? []).OfType())
+ {
+ if (parameter.Name is string name && examples.Parameters.TryGetValue(name, out object? value) && value is not null)
+ parameter.Example = JsonSerializer.SerializeToNode(value, value.GetType());
+ }
+ }
+
+ private static void AddDomainEventHeaderParameter(OpenApiOperation operation)
+ {
+ if (operation.OperationId != "DomainEvent" || (operation.Parameters ?? []).Any(parameter => parameter.Name == "eventType"))
+ return;
+
+ operation.Parameters ??= [];
+ operation.Parameters.Add(new OpenApiParameter
+ {
+ Name = "eventType",
+ In = ParameterLocation.Header,
+ Description = "Registered event type name used to deserialize the JSON body.",
+ Required = true,
+ Schema = new OpenApiSchema { Type = JsonSchemaType.String },
+ Example = JsonValue.Create("FileLineAddedEvent")
+ });
+ }
+
+ private sealed class EndpointExamples
+ {
+ public string? RequestBody { get; init; }
+ public IReadOnlyDictionary? Responses { get; init; }
+ public IReadOnlyDictionary? Parameters { get; init; }
+ }
+}
diff --git a/FileProcessor/FileProcessor.csproj b/FileProcessor/FileProcessor.csproj
index 2c46205..1772290 100644
--- a/FileProcessor/FileProcessor.csproj
+++ b/FileProcessor/FileProcessor.csproj
@@ -24,14 +24,9 @@
-
-
-
-
-
-
+
@@ -43,4 +38,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FileProcessor/Handlers/FileHandlers.cs b/FileProcessor/Handlers/FileHandlers.cs
index bba8b42..18c05ab 100644
--- a/FileProcessor/Handlers/FileHandlers.cs
+++ b/FileProcessor/Handlers/FileHandlers.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading;
@@ -20,10 +21,11 @@ namespace FileProcessor.Handlers;
public static class FileHandlers
{
public static async Task UploadFile(IMediator mediator,
- [FromForm] UploadFileRequest request,
- [FromForm] IFormCollection formCollection,
- CancellationToken cancellationToken)
+ [FromForm, Description("Multipart form metadata and the file to upload.")] UploadFileForm request,
+ HttpRequest httpRequest,
+ CancellationToken cancellationToken)
{
+ IFormCollection formCollection = await httpRequest.ReadFormAsync(cancellationToken);
if (formCollection?.Files == null || formCollection.Files.Count != 1)
return Results.BadRequest("Exactly one file must be supplied.");
@@ -120,8 +122,8 @@ private static String SanitizeFileName(String fileName)
}
public static async Task GetFile(IMediator mediator,
- [FromRoute] Guid fileId,
- [FromQuery] Guid estateId,
+ [FromRoute, Description("GUID identifying the uploaded file.")] Guid fileId,
+ [FromQuery, Description("GUID identifying the estate that owns the file.")] Guid estateId,
CancellationToken cancellationToken)
{
FileQueries.GetFileQuery query = new(fileId, estateId);
@@ -131,9 +133,9 @@ public static async Task GetFile(IMediator mediator,
}
public static async Task ReplayLine(IMediator mediator,
- [FromRoute] Guid fileId,
- [FromQuery] Guid estateId,
- [FromRoute] Int32 lineNumber,
+ [FromRoute, Description("GUID identifying the uploaded file.")] Guid fileId,
+ [FromQuery, Description("GUID identifying the estate that owns the file.")] Guid estateId,
+ [FromRoute, Description("One-based line number to retry.")] Int32 lineNumber,
CancellationToken cancellationToken)
{
FileCommands.ReplayFileLineCommand command = new(fileId, estateId, lineNumber);
diff --git a/FileProcessor/Handlers/FileImportLogHandlers.cs b/FileProcessor/Handlers/FileImportLogHandlers.cs
index 0c9ce22..c9aff63 100644
--- a/FileProcessor/Handlers/FileImportLogHandlers.cs
+++ b/FileProcessor/Handlers/FileImportLogHandlers.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using FileProcessor.BusinessLogic.Requests;
@@ -15,13 +16,13 @@ namespace FileProcessor.Handlers;
public static class FileImportLogHandlers
{
public static async Task GetImportLogsAsync(IMediator mediator,
- [FromQuery] Guid estateId,
- [FromQuery] DateOnly startDate,
- [FromQuery] DateOnly endDate,
- [FromQuery] Guid? merchantId,
- [FromQuery] Int32 pageNumber,
- [FromQuery] Int32 pageSize,
- [FromQuery] Boolean descending,
+ [FromQuery, Description("Required estate GUID to scope the logs or log lookup.")] Guid estateId,
+ [FromQuery, Description("Required inclusive start date in ISO 8601 date format (yyyy-MM-dd). Must be on or before endDate.")] DateOnly startDate,
+ [FromQuery, Description("Required inclusive end date in ISO 8601 date format (yyyy-MM-dd). Must be on or after startDate.")] DateOnly endDate,
+ [FromQuery, Description("Optional merchant GUID used to filter logs or files.")] Guid? merchantId,
+ [FromQuery, Description("One-based page number. Defaults to 1 when omitted or zero.")] Int32 pageNumber,
+ [FromQuery, Description("Number of logs per page (1–200). Defaults to 50 when omitted or zero.")] Int32 pageSize,
+ [FromQuery, Description("Sort newest first when true; defaults to false.")] Boolean descending,
CancellationToken cancellationToken)
{
pageNumber = pageNumber == 0 ? 1 : pageNumber;
@@ -33,9 +34,9 @@ public static async Task GetImportLogsAsync(IMediator mediator,
}
public static async Task GetImportLogAsync(IMediator mediator,
- [FromRoute] Guid fileImportLogId,
- [FromQuery] Guid estateId,
- [FromQuery] Guid? merchantId,
+ [FromRoute, Description("GUID identifying the file import log.")] Guid fileImportLogId,
+ [FromQuery, Description("Required estate GUID to scope the logs or log lookup.")] Guid estateId,
+ [FromQuery, Description("Optional merchant GUID used to filter logs or files.")] Guid? merchantId,
CancellationToken cancellationToken)
{
FileQueries.GetImportLogQuery query = new(fileImportLogId, estateId, merchantId);
diff --git a/FileProcessor/Handlers/FileProfileHandlers.cs b/FileProcessor/Handlers/FileProfileHandlers.cs
index 7ad9d5e..f48a42b 100644
--- a/FileProcessor/Handlers/FileProfileHandlers.cs
+++ b/FileProcessor/Handlers/FileProfileHandlers.cs
@@ -1,7 +1,9 @@
-using System;
+using System;
+using System.ComponentModel;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using FileProcessor.Common;
using FileProcessor.BusinessLogic.Requests;
using FileProcessor.DataTransferObjects.Requests;
using MediatR;
@@ -20,38 +22,38 @@ public static async Task GetFileProfiles(IMediator mediator, Cancellati
FileProfileQueries.GetFileProfilesQuery query = new();
Result> result = await mediator.Send(query, cancellationToken);
- return ResponseFactory.FromResult(result, x => x);
+ return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom);
}
public static async Task GetFileProfile(IMediator mediator,
- [FromRoute] Guid fileProfileId,
+ [FromRoute, Description("GUID identifying the file profile.")] Guid fileProfileId,
CancellationToken cancellationToken)
{
FileProfileQueries.GetFileProfileQuery query = new(fileProfileId);
Result result = await mediator.Send(query, cancellationToken);
- return ResponseFactory.FromResult(result, x => x);
+ return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom);
}
public static async Task GetFileProfileVersions(IMediator mediator,
- [FromRoute] Guid fileProfileId,
+ [FromRoute, Description("GUID identifying the file profile.")] Guid fileProfileId,
CancellationToken cancellationToken)
{
FileProfileQueries.GetFileProfileVersionsQuery query = new(fileProfileId);
Result> result = await mediator.Send(query, cancellationToken);
- return ResponseFactory.FromResult(result, x => x);
+ return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom);
}
public static async Task GetFileProfileVersion(IMediator mediator,
- [FromRoute] Guid fileProfileId,
- [FromRoute] Guid fileProfileVersionId,
+ [FromRoute, Description("GUID identifying the file profile.")] Guid fileProfileId,
+ [FromRoute, Description("GUID identifying the requested file profile version.")] Guid fileProfileVersionId,
CancellationToken cancellationToken)
{
FileProfileQueries.GetFileProfileVersionQuery query = new(fileProfileId, fileProfileVersionId);
Result result = await mediator.Send(query, cancellationToken);
- return ResponseFactory.FromResult(result, x => x);
+ return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom);
}
public static async Task CreateFileProfile(IMediator mediator,
@@ -61,22 +63,22 @@ public static async Task CreateFileProfile(IMediator mediator,
FileProfileCommands.CreateFileProfileCommand command = new(request);
Result result = await mediator.Send(command, cancellationToken);
- return ResponseFactory.FromResult(result, x => x);
+ return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom);
}
public static async Task UpdateFileProfile(IMediator mediator,
- [FromRoute] Guid fileProfileId,
+ [FromRoute, Description("GUID identifying the file profile.")] Guid fileProfileId,
[FromBody] UpdateFileProfileRequest request,
CancellationToken cancellationToken)
{
FileProfileCommands.UpdateFileProfileCommand command = new(fileProfileId, request);
Result result = await mediator.Send(command, cancellationToken);
- return ResponseFactory.FromResult(result, x => x);
+ return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom);
}
public static async Task ArchiveFileProfile(IMediator mediator,
- [FromRoute] Guid fileProfileId,
+ [FromRoute, Description("GUID identifying the file profile.")] Guid fileProfileId,
CancellationToken cancellationToken)
{
FileProfileCommands.ArchiveFileProfileCommand command = new(fileProfileId);
diff --git a/FileProcessor/Handlers/UploadFileForm.cs b/FileProcessor/Handlers/UploadFileForm.cs
new file mode 100644
index 0000000..5f84e92
--- /dev/null
+++ b/FileProcessor/Handlers/UploadFileForm.cs
@@ -0,0 +1,14 @@
+using System.ComponentModel;
+using Microsoft.AspNetCore.Http;
+using FileProcessor.DataTransferObjects;
+
+namespace FileProcessor.Handlers;
+
+/// Multipart form fields accepted by the file upload endpoint.
+[Description("Multipart metadata and the file submitted to the upload endpoint.")]
+public sealed class UploadFileForm : UploadFileRequest
+{
+ /// The single non-empty file to upload.
+ [Description("The single non-empty file to upload.")]
+ public IFormFile File { get; set; } = default!;
+}
diff --git a/FileProcessor/Program.cs b/FileProcessor/Program.cs
index b50a377..a24c064 100644
--- a/FileProcessor/Program.cs
+++ b/FileProcessor/Program.cs
@@ -1,137 +1,190 @@
+using FileProcessor.Bootstrapper;
+using FileProcessor.Common;
+using FileProcessor.Endpoints;
+using FileProcessor.Services;
+using FileProcessor.BusinessLogic.Services;
+using Lamar;
+using Lamar.Microsoft.DependencyInjection;
+using MediatR;
+using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
+using NLog.Extensions.Logging;
+using LogManager = NLog.LogManager;
+using Sentry.Extensibility;
+using Shared.EventStore.EventHandling;
+using Shared.Extensions;
+using Shared.General;
+using Shared.Logger;
using Shared.Middleware;
-using System;
+using Shared.Serialisation;
+using Shared.DomainDrivenDesign.EventSourcing;
+using System.Diagnostics.CodeAnalysis;
using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
+using System;
+using System.IO;
+using System.Reflection;
+using NLog;
+using Logger = Shared.Logger.Logger;
+using ILogger = Microsoft.Extensions.Logging.ILogger;
+using Shared.EventStore.Aggregate;
+using Shared.EventStore.SubscriptionWorker;
+using System.IO.Abstractions;
+using TransactionProcessing.ApiDefaults;
-namespace FileProcessor
+namespace FileProcessor;
+
+[ExcludeFromCodeCoverage]
+public class Program
{
- using BusinessLogic.Managers;
- using EventStore.Client;
- using File.DomainEvents;
- using FileImportLog.DomainEvents;
- using FileProcessor.Services;
- using Lamar.Microsoft.DependencyInjection;
- using MediatR;
- using Microsoft.Extensions.DependencyInjection;
- using NLog;
- using NLog.Extensions.Logging;
- using Sentry.Extensibility;
- using Shared.EventStore.EventHandling;
- using Shared.General;
- using Shared.Logger;
- using System.Diagnostics.CodeAnalysis;
- using System.IO;
- using System.IO.Abstractions;
- using System.Net.Http;
- using System.Reflection;
-
- [ExcludeFromCodeCoverage]
- public class Program
+ public static void Main(string[] args)
{
- public static void Main(string[] args)
- {
- Program.CreateHostBuilder(args).Build().Run();
- }
+ WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
+
+ FileInfo assemblyFile = new FileInfo(Assembly.GetExecutingAssembly().Location);
+ string assemblyDirectory = assemblyFile.DirectoryName!;
+ string contentRoot = Directory.GetCurrentDirectory();
+ string nlogConfigPath = Path.Combine(contentRoot, "nlog.config");
- public static IHostBuilder CreateHostBuilder(string[] args)
+ LogManager.Setup(b =>
{
- //At this stage, we only need our hosting file for ip and ports
- FileInfo fi = new FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location);
+ b.SetupLogFactory(setup =>
+ {
+ setup.AddCallSiteHiddenAssembly(typeof(NlogLogger).Assembly);
+ setup.AddCallSiteHiddenAssembly(typeof(Shared.Logger.Logger).Assembly);
+ setup.AddCallSiteHiddenAssembly(typeof(TenantMiddleware).Assembly);
+ });
+ b.LoadConfigurationFromFile(nlogConfigPath);
+ });
- IConfigurationRoot config = new ConfigurationBuilder().SetBasePath(fi.Directory.FullName)
- .AddJsonFile("hosting.json", optional: true)
- .AddJsonFile("hosting.development.json", optional: true)
- .AddEnvironmentVariables().Build();
+ builder.Host.UseWindowsService();
+ builder.Host.UseLamar();
+ builder.Logging.AddConsole();
+ builder.Logging.AddNLog();
- String contentRoot = Directory.GetCurrentDirectory();
- String nlogConfigPath = Path.Combine(contentRoot, "nlog.config");
+ ConfigureApplicationConfiguration(builder, assemblyDirectory);
+ ConfigurationReader.Initialise((IConfigurationRoot)builder.Configuration);
+ builder.Services.AddHostedService();
- LogManager.Setup(b =>
+ builder.Host.ConfigureContainer((context, services) =>
+ {
+ TypeProvider.LoadDomainEventsTypeDynamically();
+ services.IncludeRegistry();
+ services.IncludeRegistry(new DomainEventHandlerRegistry(builder.Configuration));
+ services.IncludeRegistry(new RepositoryRegistry(builder.Configuration, builder.Environment));
+ services.IncludeRegistry(new MiddlewareRegistry(builder.Configuration));
+ services.IncludeRegistry();
+ services.IncludeRegistry();
+ services.IncludeRegistry();
+ services.IncludeRegistry();
+ });
+
+ builder.WebHost.UseConfiguration(BuildHostingConfiguration(assemblyDirectory));
+ builder.WebHost.UseKestrel();
+
+ if (builder.Configuration.GetSection("SentryConfiguration").Exists() && builder.Environment.IsDevelopment() == false)
+ {
+ IConfiguration sentryConfiguration = builder.Configuration;
+ builder.WebHost.UseSentry(options =>
{
- b.SetupLogFactory(setup =>
- {
- setup.AddCallSiteHiddenAssembly(typeof(NlogLogger).Assembly);
- setup.AddCallSiteHiddenAssembly(typeof(Shared.Logger.Logger).Assembly);
- setup.AddCallSiteHiddenAssembly(typeof(TenantMiddleware).Assembly);
- });
- b.LoadConfigurationFromFile(nlogConfigPath);
+ options.Dsn = sentryConfiguration["SentryConfiguration:Dsn"];
+ options.SendDefaultPii = true;
+ options.MaxRequestBodySize = RequestSize.Always;
+ options.CaptureBlockingCalls = ConfigurationReader.GetValueOrDefault("SentryConfiguration", "CaptureBlockingCalls", false);
+ options.IncludeActivityData = ConfigurationReader.GetValueOrDefault("SentryConfiguration", "IncludeActivityData", false);
+ options.Release = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown";
});
+ }
+
+ builder.WebHost.ConfigureKestrel(serverOptions =>
+ {
+ serverOptions.Limits.MaxRequestBodySize = UploadFileSettings.GetMaximumMultipartRequestSizeBytes();
+ });
+
+ WebApplication app = builder.Build();
+ StringSerialiser.Initialise(app.Services.GetRequiredService());
- IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args);
- hostBuilder.UseWindowsService();
- hostBuilder.UseLamar();
- hostBuilder.ConfigureLogging(logging =>
- {
- logging.AddConsole();
- logging.AddNLog();
- });
- hostBuilder.ConfigureServices((context, services) =>
+ ConfigurePipeline(app);
+ app.Run();
+ }
+
+ private static void ConfigureApplicationConfiguration(WebApplicationBuilder builder, string assemblyDirectory)
+ {
+ IWebHostEnvironment environment = builder.Environment;
+ builder.Configuration.SetBasePath(assemblyDirectory)
+ .AddJsonFile("hosting.json", optional: true)
+ .AddJsonFile($"hosting.{environment.EnvironmentName}.json", optional: true)
+ .AddJsonFile("/home/txnproc/config/appsettings.json", optional: true, reloadOnChange: true)
+ .AddJsonFile($"/home/txnproc/config/appsettings.{environment.EnvironmentName}.json", optional: true, reloadOnChange: true)
+ .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
+ .AddJsonFile($"appsettings.{environment.EnvironmentName}.json", optional: true, reloadOnChange: true)
+ .AddJsonFile("/home/txnproc/config/appsettings.local.json", optional: true, reloadOnChange: true)
+ .AddEnvironmentVariables()
+ .AddInMemoryCollection(new Dictionary
{
- services.AddHostedService();
+ ["HealthMonitoring:Service:Version"] = Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "0.0.0.0"
});
- hostBuilder.ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.ConfigureAppConfiguration((context, configBuilder) =>
- {
- var env = context.HostingEnvironment;
-
- configBuilder.SetBasePath(fi.Directory.FullName)
- .AddJsonFile("hosting.json", optional: true)
- .AddJsonFile($"hosting.{env.EnvironmentName}.json", optional: true)
- .AddJsonFile("/home/txnproc/config/appsettings.json", optional: true, reloadOnChange: true)
- .AddJsonFile($"/home/txnproc/config/appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
- .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
- .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
- .AddJsonFile($"/home/txnproc/config/appsettings.local.json", optional: true, reloadOnChange: true)
- .AddEnvironmentVariables()
- .AddInMemoryCollection(new Dictionary
- {
- ["HealthMonitoring:Service:Version"] = Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "0.0.0.0"
- });
-
- // Build a snapshot of configuration so we can use it immediately (e.g. for Sentry)
- var builtConfig = configBuilder.Build();
-
- // Keep existing static usage (if you must), and initialise the ConfigurationReader now.
- Startup.Configuration = builtConfig;
- ConfigurationReader.Initialise(Startup.Configuration);
-
- // Configure Sentry on the webBuilder using the config snapshot.
- var sentrySection = builtConfig.GetSection("SentryConfiguration");
- if (sentrySection.Exists())
- {
- // Replace the condition below if you intended to only enable Sentry in certain environments.
- if (env.IsDevelopment() == false)
- {
- webBuilder.UseSentry(o =>
- {
- o.Dsn = builtConfig["SentryConfiguration:Dsn"];
- o.SendDefaultPii = true;
- o.MaxRequestBodySize = RequestSize.Always;
- o.CaptureBlockingCalls = ConfigurationReader.GetValueOrDefault("SentryConfiguration", "CaptureBlockingCalls", false);
- o.IncludeActivityData = ConfigurationReader.GetValueOrDefault("SentryConfiguration", "IncludeActivityData", false);
- o.Release = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown";
- });
- }
- }
- });
-
- webBuilder.UseStartup();
- webBuilder.UseConfiguration(config);
- webBuilder.UseKestrel();
- webBuilder.ConfigureKestrel(serverOptions =>
- {
- serverOptions.Limits.MaxRequestBodySize = Common.UploadFileSettings.GetMaximumMultipartRequestSizeBytes();
- });
- });
-
-
- return hostBuilder;
+ }
+
+ private static IConfiguration BuildHostingConfiguration(string assemblyDirectory)
+ {
+ return new ConfigurationBuilder()
+ .SetBasePath(assemblyDirectory)
+ .AddJsonFile("hosting.json", optional: true)
+ .AddJsonFile("hosting.development.json", optional: true)
+ .AddEnvironmentVariables()
+ .Build();
+ }
+
+ private static void ConfigurePipeline(WebApplication app)
+ {
+ if (app.Environment.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
}
+
+ ILogger logger = app.Services.GetRequiredService().CreateLogger("FileProcessor");
+ Logger.Initialise(logger);
+ IConfigurationRoot configuration = (IConfigurationRoot)app.Configuration;
+ configuration.LogConfiguration(Logger.LogWarning);
+ ConfigurationReader.Initialise(configuration);
+
+ app.UseMiddleware();
+ app.AddRequestResponseLogging();
+ app.AddExceptionHandler();
+ app.UseRouting();
+ app.UseAuthentication();
+ app.UseAuthorization();
+
+ app.MapDomainEventEndpoint();
+ app.MapFileEndpoints();
+ app.MapFileImportLogEndpoints();
+ app.MapFileProfileEndpoints();
+ app.MapMigrationEndpoints();
+ // Liveness details for every registered health check.
+ app.MapHealthChecks("health", new HealthCheckOptions
+ {
+ Predicate = _ => true,
+ ResponseWriter = Shared.HealthChecks.HealthCheckMiddleware.WriteResponse
+ });
+ // Health-check payload formatted for the Health Checks UI client.
+ app.MapHealthChecks("healthui", new HealthCheckOptions
+ {
+ Predicate = _ => true,
+ ResponseWriter = HealthChecks.UI.Client.UIResponseWriter.WriteHealthCheckUIResponse
+ });
+
+ IContainer container = (IContainer)app.Services;
+ app.PreWarm(container.GetInstance(),
+ container.GetInstance(),
+ container.GetInstance(),
+ app.Configuration,
+ container.GetInstance("Main"),
+ container.GetInstance>());
+ app.UseApiDefaults();
}
}
diff --git a/FileProcessor/Startup.cs b/FileProcessor/Startup.cs
deleted file mode 100644
index 3b7e263..0000000
--- a/FileProcessor/Startup.cs
+++ /dev/null
@@ -1,151 +0,0 @@
-using FileProcessor.Endpoints;
-using ImTools;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using Shared.Serialisation;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using FileProcessor.Bootstrapper;
-using FileProcessor.Common;
-using HealthChecks.UI.Client;
-using Lamar;
-using Microsoft.AspNetCore.Diagnostics.HealthChecks;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Logging;
-using Shared.DomainDrivenDesign.EventSourcing;
-using Shared.EventStore.Aggregate;
-using Shared.Extensions;
-using Shared.General;
-using Shared.Logger;
-using Shared.Middleware;
-using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
-using ILogger = Microsoft.Extensions.Logging.ILogger;
-
-namespace FileProcessor
-{
- [ExcludeFromCodeCoverage]
- public class Startup
- {
- ///
- /// Gets or sets the configuration.
- ///
- ///
- /// The configuration.
- ///
- public static IConfigurationRoot Configuration { get; set; }
-
- ///
- /// Gets or sets the web host environment.
- ///
- ///
- /// The web host environment.
- ///
- public static IWebHostEnvironment WebHostEnvironment { get; set; }
-
- public Startup(IWebHostEnvironment webHostEnvironment)
- {
- Startup.WebHostEnvironment = webHostEnvironment;
- }
-
- public static Container Container;
-
- // This method gets called by the runtime. Use this method to add services to the container.
- // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
- public void ConfigureContainer(ServiceRegistry services)
- {
- ConfigurationReader.Initialise(Startup.Configuration);
-
- TypeProvider.LoadDomainEventsTypeDynamically();
-
- services.IncludeRegistry();
- services.IncludeRegistry();
- services.IncludeRegistry();
- services.IncludeRegistry();
- services.IncludeRegistry();
- services.IncludeRegistry();
- services.IncludeRegistry();
- services.IncludeRegistry();
-
- Startup.Container = new Container(services);
-
- Startup.ServiceProvider = services.BuildServiceProvider();
-
- var serialiser = Container.GetRequiredService();
- StringSerialiser.Initialise(serialiser);
- }
-
- public static IServiceProvider ServiceProvider { get; set; }
-
- public static void LoadDomainEventsTypeDynamically(List assemblyFilters = null)
- {
- Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
-
- List source = new List();
- foreach (string assemblyFilter in assemblyFilters)
- {
- List filteredAssemblies = assemblies.Where(a => a.FullName.Contains(assemblyFilter) == true).ToList();
- foreach (Assembly a in filteredAssemblies) {
- assemblies = assemblies.Remove(a);
- }
- }
- source.AddRange(assemblies.SelectMany((Func>)(a => (IEnumerable)a.GetTypes())));
-
- foreach (Type type in source.Where((Func)(t => t.IsSubclassOf(typeof(DomainEvent)))).OrderBy((Func)(e => e.Name)).ToList())
- TypeMap.AddType(type, type.Name);
- }
-
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory,
- IHostApplicationLifetime lifetime, IHost host)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
-
- ILogger logger = loggerFactory.CreateLogger("FileProcessor");
-
- Logger.Initialise(logger);
-
- Startup.Configuration.LogConfiguration(Logger.LogWarning);
-
- ConfigurationReader.Initialise(Startup.Configuration);
- app.UseMiddleware();
- app.AddRequestResponseLogging();
- app.AddExceptionHandler();
-
- app.UseRouting();
-
- app.UseAuthentication();
- app.UseAuthorization();
-
- app.UseEndpoints(endpoints => {
- endpoints.MapDomainEventEndpoint();
- endpoints.MapFileEndpoints();
- endpoints.MapFileImportLogEndpoints();
- endpoints.MapFileProfileEndpoints();
- endpoints.MapMigrationEndpoints();
-
- endpoints.MapHealthChecks("health", new HealthCheckOptions()
- {
- Predicate = _ => true,
- ResponseWriter = Shared.HealthChecks.HealthCheckMiddleware.WriteResponse
- });
- endpoints.MapHealthChecks("healthui", new HealthCheckOptions()
- {
- Predicate = _ => true,
- ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
- });
- });
-
- app.UseSwagger();
-
- app.UseSwaggerUI();
- app.PreWarm();
- }
- }
-}