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 @@ -2,13 +2,13 @@ namespace TransactionProcessing.MerchantFileProcessor.Configuration;

public static class FileProfileFormats
{
public const string Delimited = "delimited";
public static string Delimited { get; } = "delimited";

public const string Json = "json";
public static string Json { get; } = "json";

public static readonly HashSet<string> All = new(StringComparer.OrdinalIgnoreCase)
{
Delimited,
Json
};
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace TransactionProcessing.MerchantFileProcessor.Configuration;

public sealed class FrameworkLoggingOptions {
public const string SectionName = "FrameworkLogging";
public static string SectionName { get; } = "FrameworkLogging";

public bool EnableEfCoreCommandTrace { get; init; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace TransactionProcessing.MerchantFileProcessor.Configuration;

public sealed class MerchantProcessingOptions {
public const string SectionName = "MerchantProcessing";
public static string SectionName { get; } = "MerchantProcessing";

public AuthenticationOptions Authentication { get; init; } = new();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ namespace TransactionProcessing.MerchantFileProcessor.Configuration;

public static class TransactionFileFieldSources
{
public const string MerchantId = "merchantid";
public const string ContractId = "contractid";
public const string ProductCode = "productcode";
public const string Description = "description";
public const string Quantity = "quantity";
public const string UnitAmount = "unitamount";
public const string TotalAmount = "totalamount";
public const string Currency = "currency";
public const string TransactionDateUtc = "transactiondateutc";
public const string RecipientMobileNumber = "recipientmobilenumber";
public const string ContractIssuer = "contractissuer";
public const string ProcessingDateUtc = "processingdateutc";
public const string RecordCount = "recordcount";
public const string FileTotalAmount = "filetotalamount";
public static string MerchantId { get; } = "merchantid";
public static string ContractId { get; } = "contractid";
public static string ProductCode { get; } = "productcode";
public static string Description { get; } = "description";
public static string Quantity { get; } = "quantity";
public static string UnitAmount { get; } = "unitamount";
public static string TotalAmount { get; } = "totalamount";
public static string Currency { get; } = "currency";
public static string TransactionDateUtc { get; } = "transactiondateutc";
public static string RecipientMobileNumber { get; } = "recipientmobilenumber";
public static string ContractIssuer { get; } = "contractissuer";
public static string ProcessingDateUtc { get; } = "processingdateutc";
public static string RecordCount { get; } = "recordcount";
public static string FileTotalAmount { get; } = "filetotalamount";

public static readonly HashSet<string> All = new(StringComparer.OrdinalIgnoreCase)
{
Expand All @@ -34,4 +34,4 @@ public static class TransactionFileFieldSources
RecordCount,
FileTotalAmount
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,79 @@ public static object GetValue(FileFieldOptions field, TransactionFileContext con

var transaction = context.Transaction;

return field.Source.ToLowerInvariant() switch
{
TransactionFileFieldSources.MerchantId => context.Merchant.MerchantId,
TransactionFileFieldSources.ContractId => context.Contract.ContractId,
TransactionFileFieldSources.ContractIssuer => context.Contract.Issuer,
TransactionFileFieldSources.ProductCode => GetTransaction(transaction).ProductCode,
TransactionFileFieldSources.Description => GetTransaction(transaction).Description,
TransactionFileFieldSources.RecipientMobileNumber => GetTransaction(transaction).RecipientMobileNumber,
TransactionFileFieldSources.Quantity => ApplyFormat(GetTransaction(transaction).Quantity, field.Format),
TransactionFileFieldSources.UnitAmount => ApplyFormat(GetTransaction(transaction).UnitAmount, field.Format),
TransactionFileFieldSources.TotalAmount => ApplyFormat(GetTransaction(transaction).TotalAmount, field.Format),
TransactionFileFieldSources.Currency => GetTransaction(transaction).Currency,
TransactionFileFieldSources.TransactionDateUtc => ApplyDateFormat(GetTransaction(transaction).TransactionDateUtc, field.Format),
TransactionFileFieldSources.ProcessingDateUtc => ApplyDateFormat(context.ProcessingTimestampUtc, field.Format),
TransactionFileFieldSources.RecordCount => ApplyFormat(context.RecordCount, field.Format),
TransactionFileFieldSources.FileTotalAmount => ApplyFormat(context.FileTotalAmount, field.Format ?? "0.00"),
_ => throw new InvalidOperationException($"Unsupported field source '{field.Source}'.")
};
var source = field.Source.Trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Normalize sources before configuration validation

When a field source contains leading or trailing whitespace, every production configuration path rejects it before this normalization can run: MerchantProcessingOptionsValidator.AreFieldsValid checks the untrimmed field.Source against TransactionFileFieldSources.All, and both startup loading and SaveAsync invoke that validator. Consequently, configurations using values such as " totalAmount " still fail validation despite the new resolver behavior; trim or canonicalize the source during validation as well.

Useful? React with 👍 / 👎.


if (source.Equals(TransactionFileFieldSources.MerchantId, StringComparison.OrdinalIgnoreCase))
{
return context.Merchant.MerchantId;
}

if (source.Equals(TransactionFileFieldSources.ContractId, StringComparison.OrdinalIgnoreCase))
{
return context.Contract.ContractId;
}

if (source.Equals(TransactionFileFieldSources.ContractIssuer, StringComparison.OrdinalIgnoreCase))
{
return context.Contract.Issuer;
}

if (source.Equals(TransactionFileFieldSources.ProductCode, StringComparison.OrdinalIgnoreCase))
{
return GetTransaction(transaction).ProductCode;
}

if (source.Equals(TransactionFileFieldSources.Description, StringComparison.OrdinalIgnoreCase))
{
return GetTransaction(transaction).Description;
}

if (source.Equals(TransactionFileFieldSources.RecipientMobileNumber, StringComparison.OrdinalIgnoreCase))
{
return GetTransaction(transaction).RecipientMobileNumber;
}

if (source.Equals(TransactionFileFieldSources.Quantity, StringComparison.OrdinalIgnoreCase))
{
return ApplyFormat(GetTransaction(transaction).Quantity, field.Format);
}

if (source.Equals(TransactionFileFieldSources.UnitAmount, StringComparison.OrdinalIgnoreCase))
{
return ApplyFormat(GetTransaction(transaction).UnitAmount, field.Format);
}

if (source.Equals(TransactionFileFieldSources.TotalAmount, StringComparison.OrdinalIgnoreCase))
{
return ApplyFormat(GetTransaction(transaction).TotalAmount, field.Format);
}

if (source.Equals(TransactionFileFieldSources.Currency, StringComparison.OrdinalIgnoreCase))
{
return GetTransaction(transaction).Currency;
}

if (source.Equals(TransactionFileFieldSources.TransactionDateUtc, StringComparison.OrdinalIgnoreCase))
{
return ApplyDateFormat(GetTransaction(transaction).TransactionDateUtc, field.Format);
}

if (source.Equals(TransactionFileFieldSources.ProcessingDateUtc, StringComparison.OrdinalIgnoreCase))
{
return ApplyDateFormat(context.ProcessingTimestampUtc, field.Format);
}

if (source.Equals(TransactionFileFieldSources.RecordCount, StringComparison.OrdinalIgnoreCase))
{
return ApplyFormat(context.RecordCount, field.Format);
}

if (source.Equals(TransactionFileFieldSources.FileTotalAmount, StringComparison.OrdinalIgnoreCase))
{
return ApplyFormat(context.FileTotalAmount, field.Format ?? "0.00");
}

throw new InvalidOperationException($"Unsupported field source '{field.Source}'.");
}

private static GeneratedTransaction GetTransaction(GeneratedTransaction? transaction) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,31 +55,31 @@ Task UpdateFileStatusAsync(

public static class FileSendStatuses
{
public const string Succeeded = "Succeeded";
public static string Succeeded { get; } = "Succeeded";

public const string Failed = "Failed";
public static string Failed { get; } = "Failed";
}

public static class MerchantRunStatuses
{
public const string Succeeded = "Succeeded";
public static string Succeeded { get; } = "Succeeded";

public const string Failed = "Failed";
public static string Failed { get; } = "Failed";
}

public static class FileLineStatuses
{
public const string Unknown = "Unknown";
public static string Unknown { get; } = "Unknown";

public const string NotProcessed = "NotProcessed";
public static string NotProcessed { get; } = "NotProcessed";

public const string Successful = "Successful";
public static string Successful { get; } = "Successful";

public const string Failed = "Failed";
public static string Failed { get; } = "Failed";

public const string Ignored = "Ignored";
public static string Ignored { get; } = "Ignored";

public const string Rejected = "Rejected";
public static string Rejected { get; } = "Rejected";
}

public sealed record FileStatusPollTarget(
Expand Down
Loading