Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public async Task GetStatementHtml_ReturnsHtmlWithReplacedTokens() {
html.ShouldContain(this._merchant.Addresses.First().AddressLine1);
html.ShouldContain("Transactions");
html.ShouldContain("Fees");
html.ShouldContain("01/05/2025");
html.ShouldContain("02/05/2025");
html.ShouldContain("100");
html.ShouldContain("10");
html.ShouldContain("body{color:red;}");
Expand Down Expand Up @@ -131,4 +133,4 @@ public async Task GetStatementHtml_ThrowsIfMerchantContactMissing() {
await Should.ThrowAsync<InvalidOperationException>(async () => { await _builder.GetStatementHtml(merchantStatementAggregate, merchant, _cancellationToken); });
}
}
}
}
72 changes: 39 additions & 33 deletions TransactionProcessor.BusinessLogic/Services/StatementBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ public async Task<Result<String>> GetStatementHtml(MerchantStatementAggregate st
return Result.Invalid("Statement has not yet been generated");

String mainHtml = await this.FileSystem.File.ReadAllTextAsync($"{path}/Templates/Email/statement.html", cancellationToken);

var anonymousHeader = new {
List<(Int32 lineNumber, MerchantStatementLine statementLine)> statementLines = statementHeader.GetStatementLines();
mainHtml = this.ReplaceTokens(mainHtml, new {
StatementId = statementAggregate.AggregateId,
EstateName = "Demo Estate",
MerchantName = merchant.MerchantName,
Expand All @@ -79,46 +79,52 @@ public async Task<Result<String>> GetStatementHtml(MerchantStatementAggregate st
MerchantPostcode = merchant.Addresses.First().PostalCode,
MerchantContactNumber = merchant.Contacts.First().ContactPhoneNumber,
StatementDate = statementHeader.StatementDate,
};

List<(Int32 lineNumber, MerchantStatementLine statementLine)> statementLines = statementHeader.GetStatementLines();
});
mainHtml = this.ReplaceTokens(mainHtml, new {
StatementTotal = statementLines.Sum(sl => sl.statementLine.Amount),
TransactionsValue = statementLines.Where(sl => sl.statementLine.LineType == 1).Sum(sl => sl.statementLine.Amount),
TransactionFeesValue = statementLines.Where(sl => sl.statementLine.LineType == 2).Sum(sl => sl.statementLine.Amount)
});
mainHtml = mainHtml.Replace("[StatementLinesData]", await this.BuildStatementLinesHtml(path, statementLines, cancellationToken));

var anonymousFooter = new { StatementTotal = statementLines.Sum(sl => sl.statementLine.Amount), TransactionsValue = statementLines.Where(sl => sl.statementLine.LineType == 1).Sum(sl => sl.statementLine.Amount), TransactionFeesValue = statementLines.Where(sl => sl.statementLine.LineType == 2).Sum(sl => sl.statementLine.Amount) };
mainHtml = await this.AddCSSToHtml(mainHtml, "{bootstrapcss}", "bootstrap/css/bootstrap.min.css", cancellationToken);
mainHtml = await this.AddCSSToHtml(mainHtml, "{fontawesomemincss}", "fontawesome/css/fontawesome.min.css", cancellationToken);
mainHtml = await this.AddCSSToHtml(mainHtml, "{fontawesomesolidcss}", "fontawesome/css/solid.css", cancellationToken);

// Statement header class first
PropertyInfo[] statementHeaderProperties = anonymousHeader.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
return Result.Success<String>(mainHtml);
}

// Do the replaces for the transaction
foreach (PropertyInfo propertyInfo in statementHeaderProperties) {
mainHtml = mainHtml.Replace($"[{propertyInfo.Name}]", propertyInfo.GetValue(anonymousHeader)?.ToString());
private async Task<String> BuildStatementLinesHtml(IDirectoryInfo path,
List<(Int32 lineNumber, MerchantStatementLine statementLine)> statementLines,
CancellationToken cancellationToken)
{
StringBuilder lines = new StringBuilder();
String lineTemplate = await this.FileSystem.File.ReadAllTextAsync($"{path}/Templates/Email/statementline.html", cancellationToken);

foreach ((Int32 lineNumber, MerchantStatementLine statementLine) statementLineContainer in statementLines) {
String populatedLine = this.ReplaceTokens(lineTemplate, new {
StatementLineNumber = statementLineContainer.lineNumber + 1,
StatementLineDate = statementLineContainer.statementLine.DateTime.ToString("dd/MM/yyyy"),
StatementLineDescription = statementLineContainer.statementLine.Description,
StatementLineAmount = statementLineContainer.statementLine.Amount
});
lines.Append(populatedLine);
}

PropertyInfo[] statementFooterProperties = anonymousFooter.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
return lines.ToString();
}

// Do the replaces for the transaction
foreach (PropertyInfo propertyInfo in statementFooterProperties) {
mainHtml = mainHtml.Replace($"[{propertyInfo.Name}]", propertyInfo.GetValue(anonymousFooter)?.ToString());
}
private String ReplaceTokens(String html,
Object tokenSource)
{
String result = html;
PropertyInfo[] properties = tokenSource.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

StringBuilder lines = new StringBuilder();
String lineHtml = await this.FileSystem.File.ReadAllTextAsync($"{path}/Templates/Email/statementline.html", cancellationToken);
foreach ((Int32 lineNumber, MerchantStatementLine statementLine) statementLineContainer in statementHeader.GetStatementLines()) {
var anonymousLine = new { StatementLineNumber = statementLineContainer.lineNumber + 1, StatementLineDate = statementLineContainer.statementLine.DateTime.ToString("dd/MM/yyyy"), StatementLineDescription = statementLineContainer.statementLine.Description, StatementLineAmount = statementLineContainer.statementLine.Amount };
PropertyInfo[] statementLineProperties = anonymousLine.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo propertyInfo in statementLineProperties) {
lineHtml = lineHtml.Replace($"[{propertyInfo.Name}]", propertyInfo.GetValue(anonymousLine)?.ToString());
}

lines.Append(lineHtml);
foreach (PropertyInfo propertyInfo in properties) {
result = result.Replace($"[{propertyInfo.Name}]", propertyInfo.GetValue(tokenSource)?.ToString());
}

mainHtml = mainHtml.Replace("[StatementLinesData]", lines.ToString());

mainHtml = await this.AddCSSToHtml(mainHtml, "{bootstrapcss}", "bootstrap/css/bootstrap.min.css", cancellationToken);
mainHtml = await this.AddCSSToHtml(mainHtml, "{fontawesomemincss}", "fontawesome/css/fontawesome.min.css", cancellationToken);
mainHtml = await this.AddCSSToHtml(mainHtml, "{fontawesomesolidcss}", "fontawesome/css/solid.css", cancellationToken);

return Result.Success<String>(mainHtml);
return result;
}

private async Task<String> AddCSSToHtml(String html, String tag, String fileName, CancellationToken cancellationToken) {
Expand Down
Loading