Skip to content

Commit

Permalink
fix: fix csv incompatibility with entities (#33)
Browse files Browse the repository at this point in the history
* fix: add tracking-id header to transaction entity and add a migration for it

* fix: we no longer need persian-date-converter

* fix: change account and transaction
  • Loading branch information
amiralirahimii authored Sep 7, 2024
1 parent 346be34 commit 9deb06e
Show file tree
Hide file tree
Showing 15 changed files with 136 additions and 104 deletions.
24 changes: 18 additions & 6 deletions src/Application/DTOs/Account/AccountCsvModel.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
namespace Application.DTOs.Account;
using CsvHelper.Configuration.Attributes;

namespace Application.DTOs.Account;

public class AccountCsvModel
{
public long AccountID { get; set; }
public long CardID { get; set; }
public string IBAN { get; set; } = string.Empty;
[Name("AccountId", "AccountID")]
public long AccountId { get; set; }
[Name("CardId", "CardID")]
public long CardId { get; set; }
[Name("Iban", "IBAN", "Sheba")]
public string Iban { get; set; } = string.Empty;
[Name("AccountType")]
public string AccountType { get; set; } = string.Empty;
[Name("BranchTelephone")]
public string BranchTelephone { get; set; } = string.Empty;
public string BranchAdress { get; set; } = string.Empty;
[Name("BranchAddress", "BranchAdress")]
public string BranchAddress { get; set; } = string.Empty;
[Name("BranchName")]
public string BranchName { get; set; } = string.Empty;
[Name("OwnerName")]
public string OwnerName { get; set; } = string.Empty;
[Name("OwnerLastName", "OwnerFamilyName")]
public string OwnerLastName { get; set; } = string.Empty;
public long OwnerID { get; set; }
[Name("OwnerId", "OwnerID")]
public long OwnerId { get; set; }
}
5 changes: 3 additions & 2 deletions src/Application/DTOs/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ public class Result
public string Message { get; protected set; } = string.Empty;
public bool Succeed { get; protected set; }

public static Result Ok()
public static Result Ok(string message = "succeed")
{
return new Result
{
Succeed = true
Succeed = true,
Message = message
};
}

Expand Down
19 changes: 14 additions & 5 deletions src/Application/DTOs/Transaction/TransactionCsvModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ namespace Application.DTOs.Transaction;

public class TransactionCsvModel
{
public long TransactionID { get; set; }
public long SourceAcount { get; set; }
public long DestiantionAccount { get; set; }
[Name("TransactionId", "TransactionID")]
public long TransactionId { get; set; }
[Name("SourceAccount", "SourceAcount")]
public long SourceAccount { get; set; }
[Name("DestinationAccount","DestiantionAccount")]
public long DestinationAccount { get; set; }
[Name("Amount")]
public decimal Amount { get; set; }
[TypeConverter(typeof(PersianDateConverter))]
public DateTime Date { get; set; }
[Name("Date")]
public string Date { get; set; } = string.Empty;
[Name("Time")]
public string Time { get; set; } = string.Empty;
[Name("Type")]
public string Type { get; set; } = string.Empty;
[Name("TrackingId", "TrackingID")]
public long TrackingId { get; set; }
}
10 changes: 5 additions & 5 deletions src/Application/Mappers/AccountMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ public static Account ToAccount(this AccountCsvModel csvModel)
{
return new Account
{
AccountId = csvModel.AccountID,
CardId = csvModel.CardID,
Iban = csvModel.IBAN,
AccountId = csvModel.AccountId,
CardId = csvModel.CardId,
Iban = csvModel.Iban,
AccountType = csvModel.AccountType,
BranchTelephone = csvModel.BranchTelephone,
BranchAddress = csvModel.BranchAdress,
BranchAddress = csvModel.BranchAddress,
BranchName = csvModel.BranchName,
OwnerName = csvModel.OwnerName,
OwnerLastName = csvModel.OwnerLastName,
OwnerId = csvModel.OwnerID
OwnerId = csvModel.OwnerId
};
}
}
13 changes: 8 additions & 5 deletions src/Application/Mappers/TransactionMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ public static class TransactionMapper
{
public static Transaction ToTransaction(this TransactionCsvModel csvModel)
{
var date = DateOnly.Parse(csvModel.Date).ToDateTime(TimeOnly.Parse(csvModel.Time));
var utcDate = DateTime.SpecifyKind(date, DateTimeKind.Utc);
return new Transaction
{
TransactionId = csvModel.TransactionID,
SourceAccountId = csvModel.SourceAcount,
DestinationAccountId = csvModel.DestiantionAccount,
TransactionId = csvModel.TransactionId,
SourceAccountId = csvModel.SourceAccount,
DestinationAccountId = csvModel.DestinationAccount,
Amount = csvModel.Amount,
Date = csvModel.Date,
Type = csvModel.Type
Date = utcDate,
Type = csvModel.Type,
TrackingId = csvModel.TrackingId
};
}
}
39 changes: 32 additions & 7 deletions src/Application/Services/DomainService/TransactionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,50 @@ public class TransactionService : ITransactionService
{
private readonly ITransactionRepository _transactionRepository;
private readonly IFileReaderService _fileReaderService;
private readonly IAccountRepository _accountRepository;

public TransactionService(ITransactionRepository transactionRepository, IFileReaderService fileReaderService)
public TransactionService(ITransactionRepository transactionRepository, IFileReaderService fileReaderService, IAccountRepository accountRepository)
{
_transactionRepository = transactionRepository;
_fileReaderService = fileReaderService;
_accountRepository = accountRepository;
}


private async Task<List<long>> ValidateTransactionCsvModelsAsync(List<TransactionCsvModel> transactionCsvModels)
{
var invalidTransactionIds = new List<long>();
foreach (var transactionCsvModel in transactionCsvModels)
{
var sourceAccount = await _accountRepository.GetByIdAsync(transactionCsvModel.SourceAccount);
var destinationAccount = await _accountRepository.GetByIdAsync(transactionCsvModel.DestinationAccount);
bool isValidDate = DateOnly.TryParseExact(transactionCsvModel.Date, "MM/dd/yyyy", null, System.Globalization.DateTimeStyles.None, out var date);
bool isValidTime = TimeOnly.TryParse(transactionCsvModel.Time, out var time);
if(sourceAccount == null || destinationAccount == null || !isValidDate || !isValidTime)
{
invalidTransactionIds.Add(transactionCsvModel.TransactionId);
}
}
return invalidTransactionIds;
}

public async Task<Result> AddTransactionsFromCsvAsync(string filePath)
{
try
{
var transactionCsvModels = _fileReaderService.ReadFromFile<TransactionCsvModel>(filePath);
var invalidTransactionCsvModels = await ValidateTransactionCsvModelsAsync(transactionCsvModels);
var transactions = transactionCsvModels
.Where(csvModel => !invalidTransactionCsvModels.Contains(csvModel.TransactionId))
.Select(csvModel => csvModel.ToTransaction())
.ToList();

var existingTransactionsIds = await _transactionRepository.GetAllIdsAsync();
var newTransactions = transactions.Where(t => !existingTransactionsIds.Contains(t.TransactionId)).ToList();

await _transactionRepository.CreateBulkAsync(newTransactions);
return Result.Ok();
return Result.Ok(invalidTransactionCsvModels.Count == 0
? "All transactions were added successfully."
: $"Some transactions were not added because of invalid data: {string.Join(", ", invalidTransactionCsvModels)}");
}
catch (Exception ex)
{
Expand Down Expand Up @@ -77,12 +100,14 @@ public async Task<Result<List<GetTransactionsByAccountIdResponse>>> GetTransacti
AccountId = group.Key,
TransactionWithSources = group.Select(t => new TransactionCsvModel
{
TransactionID = t.TransactionId,
SourceAcount = t.SourceAccountId,
DestiantionAccount = t.DestinationAccountId,
TransactionId = t.TransactionId,
SourceAccount = t.SourceAccountId,
DestinationAccount = t.DestinationAccountId,
Amount = t.Amount,
Date = t.Date,
Date = DateOnly.FromDateTime(t.Date).ToString(),
Time = TimeOnly.FromDateTime(t.Date).ToString(),
Type = t.Type,
TrackingId = t.TrackingId
}).ToList()
};

Expand Down
34 changes: 0 additions & 34 deletions src/Application/Services/SharedService/PersianDateConverter.cs

This file was deleted.

1 change: 1 addition & 0 deletions src/Domain/Entities/Transaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ public class Transaction
public DateTime Date { get; set; }
[MaxLength(50)]
public string Type { get; set; } = String.Empty;
public long TrackingId { get; set; }
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace Infrastructure.Migrations
{
/// <inheritdoc />
public partial class accountstransactions : Migration
public partial class updatetransactionentity : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
Expand Down Expand Up @@ -86,7 +86,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
DestinationAccountId = table.Column<long>(type: "bigint", nullable: false),
Amount = table.Column<decimal>(type: "numeric", nullable: false),
Date = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Type = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false)
Type = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
TrackingId = table.Column<long>(type: "bigint", nullable: false)
},
constraints: table =>
{
Expand Down Expand Up @@ -216,9 +217,9 @@ protected override void Up(MigrationBuilder migrationBuilder)
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ "46a9f2ed-8738-448a-9ca9-3afa00eee4ff", null, "DataAdmin", "DATAADMIN" },
{ "48732a60-c9aa-4aec-9ef3-b880ab162088", null, "DataAnalyst", "DATAANALYST" },
{ "5a15c66d-6214-4dbb-a00d-10a4f7ca4cf8", null, "Admin", "ADMIN" }
{ "31f9f360-a3de-4dc3-bd7d-8f16d8da7fed", null, "DataAnalyst", "DATAANALYST" },
{ "8a0429eb-6031-4546-a06e-0a0f5ae9248c", null, "Admin", "ADMIN" },
{ "b70df7e0-cb8a-4131-bf26-3d2e52ee9834", null, "DataAdmin", "DATAADMIN" }
});

migrationBuilder.CreateIndex(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<long>("SourceAccountId")
.HasColumnType("bigint");

b.Property<long>("TrackingId")
.HasColumnType("bigint");

b.Property<string>("Type")
.IsRequired()
.HasMaxLength(50)
Expand Down Expand Up @@ -212,19 +215,19 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.HasData(
new
{
Id = "5a15c66d-6214-4dbb-a00d-10a4f7ca4cf8",
Id = "8a0429eb-6031-4546-a06e-0a0f5ae9248c",
Name = "Admin",
NormalizedName = "ADMIN"
},
new
{
Id = "46a9f2ed-8738-448a-9ca9-3afa00eee4ff",
Id = "b70df7e0-cb8a-4131-bf26-3d2e52ee9834",
Name = "DataAdmin",
NormalizedName = "DATAADMIN"
},
new
{
Id = "48732a60-c9aa-4aec-9ef3-b880ab162088",
Id = "31f9f360-a3de-4dc3-bd7d-8f16d8da7fed",
Name = "DataAnalyst",
NormalizedName = "DATAANALYST"
});
Expand Down
4 changes: 2 additions & 2 deletions src/Web/Controllers/TransactionsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ public async Task<IActionResult> UploadTransactions([FromForm] IFormFile file)
return BadRequest(errorResponse);
}

return Ok("Transactions uploaded successfully!");
return Ok(result.Message);
}

[HttpGet()]
[HttpGet]
[Authorize]
[RequiresAnyRole(Claims.Role, AppRoles.Admin, AppRoles.DataAdmin, AppRoles.DataAnalyst)]
[ProducesResponseType(200)]
Expand Down
1 change: 1 addition & 0 deletions src/Web/DTOs/Transaction/TransactionDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ public class TransactionDto
public decimal Amount { get; set; }
public DateTime Date { get; set; }
public string Type { get; set; } = String.Empty;
public long TrackingId { get; set; }
}
3 changes: 2 additions & 1 deletion src/Web/Mappers/TransactionMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public static List<TransactionDto> ToGotAllTransactionsDto(this List<Transaction
DestinationAccountId = transaction.DestinationAccountId,
Amount = transaction.Amount,
Date = transaction.Date,
Type = transaction.Type
Type = transaction.Type,
TrackingId = transaction.TrackingId
}).ToList();
}
}
Loading

0 comments on commit 9deb06e

Please sign in to comment.