diff --git a/api/Controllers/TransfersController.cs b/api/Controllers/TransfersController.cs index 18ac7ff..7998fb1 100644 --- a/api/Controllers/TransfersController.cs +++ b/api/Controllers/TransfersController.cs @@ -39,6 +39,42 @@ public IActionResult Create([FromBody] TransferRequestCreate req) }); } + [HttpPut("{transferId}")] + public IActionResult Update(Guid transferId, [FromBody] TransferRequestUpdate req) + { + // transfer exists + if (!_transferProvider.TransferExists(transferId)) + return NotFound(new { message = $"Transfer not found for id {transferId}" }); + + + // check if transfer is completed + if (_transferProvider.IsTransferCompleted(transferId)) + return Conflict(new { message = $"This transfer has already been completed. Updates to a completed transfer are not allowed." }); + + + Transfer? updatedTransfer = _transferProvider.Update(transferId, req); + return Ok(new + { + message = "Transfer updated!", + created_transfer = new TransferResponse + { + Id = updatedTransfer.Id, + Reference = updatedTransfer.Reference, + TransferFromId = updatedTransfer.TransferFromId, + TransferToId = updatedTransfer.TransferToId, + TransferStatus = updatedTransfer.TransferStatus.ToString(), + Items = updatedTransfer.TransferItems?.Select(ti => new TransferItemDTO() + { + ItemId = ti.ItemId, + Amount = ti.Amount, + }).ToList(), + CreatedAt = updatedTransfer.CreatedAt, + UpdatedAt = updatedTransfer.UpdatedAt, + } + }); + } + + [HttpDelete("{transferId}")] public IActionResult Delete(Guid transferId) { @@ -66,7 +102,7 @@ public IActionResult Delete(Guid transferId) }); } - [HttpPut("{transferId}")] + [HttpPut("{transferId}/commit")] public IActionResult CommitTransfer(Guid transferId) { Transfer? commitedTransfer = _transferProvider.CommitTransfer(transferId); diff --git a/api/DTOs/TransferDTO.cs b/api/DTOs/TransferDTO.cs index 52962cb..b600d6a 100644 --- a/api/DTOs/TransferDTO.cs +++ b/api/DTOs/TransferDTO.cs @@ -17,6 +17,26 @@ public class TransferRequestCreate : BaseDTO public List? Items { get; set; } } +[ApiExplorerSettings(IgnoreApi = true)] +public class TransferRequestUpdate : BaseDTO +{ + [JsonPropertyName("reference")] + public string? Reference { get; set; } + + [JsonPropertyName("transfer_from_id")] + public Guid? TransferFromId { get; set; } + + [JsonPropertyName("transfer_to_id")] + public Guid? TransferToId { get; set; } + + [JsonPropertyName("transfer_status")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public TransferStatus TransferStatus { get; set; } + + [JsonPropertyName("items")] + public List? Items { get; set; } +} + public class TransferItemDTO() { public Guid? ItemId { get; set; } diff --git a/api/Program.cs b/api/Program.cs index 9873e76..56a47ce 100644 --- a/api/Program.cs +++ b/api/Program.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; +using System.Text.Json.Serialization; var builder = WebApplication.CreateBuilder(args); @@ -133,7 +134,8 @@ -builder.Services.AddControllers(); +builder.Services.AddControllers().AddJsonOptions(options => + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())); ; var app = builder.Build(); diff --git a/api/REST/Transfers.rest b/api/REST/Transfers.rest index 2d5dc81..9f5e130 100644 --- a/api/REST/Transfers.rest +++ b/api/REST/Transfers.rest @@ -30,11 +30,29 @@ Content-Type: application/json } ### +### UPDATE TRANSFER +PUT http://localhost:5000/api/transfers/586f80b3-c631-4160-be01-7ecc7e3777a6 +Content-Type: application/json + +{ + "transfer_from_id": "5aeb7004-fd10-4dab-82f3-05216ff3df4d", + "transfer_to_id": "5aeb7004-fd10-4dab-82f3-05216ff3df7c", + "reference": "TST-0273", + "transfer_status": "Processing", + "items": [ + { + "itemId": "d91369f6-af0a-4b45-9b23-ec263a6f2556", + "amount": 50 + } + ] +} +### + ### DELETE TRANSFER DELETE http://localhost:5000/api/transfers/7fcf22de-edd6-423c-a371-a4e9cc9d0f1b Content-Type: application/json ### COMMIT TRANSFER -PUT http://localhost:5000/api/transfers/7fcf22de-edd6-423c-a371-a4e9cc9d0f1b +PUT http://localhost:5000/api/transfers/7fcf22de-edd6-423c-a371-a4e9cc9d0f1b/commit Content-Type: application/json ### \ No newline at end of file diff --git a/api/abstracts/BaseModel.cs b/api/abstracts/BaseModel.cs index 007046e..294e08b 100644 --- a/api/abstracts/BaseModel.cs +++ b/api/abstracts/BaseModel.cs @@ -19,8 +19,9 @@ public BaseModel(bool newInstance = false, bool isUpdate = false) public virtual void SetTimeStamps() { - CreatedAt = DateTime.UtcNow; - UpdatedAt = DateTime.UtcNow; + DateTime now = DateTime.UtcNow; + CreatedAt = now; + UpdatedAt = now; } public virtual void SetUpdatedAt() diff --git a/api/providers/TransfersProvider.cs b/api/providers/TransfersProvider.cs index ad7c19d..70d07f4 100644 --- a/api/providers/TransfersProvider.cs +++ b/api/providers/TransfersProvider.cs @@ -49,6 +49,32 @@ public TransferProvider(AppDbContext db, IValidator validator, Locatio return newTransfer; } + public override Transfer? Update(Guid id, BaseDTO updatedValues) + { + TransferRequestUpdate? req = updatedValues as TransferRequestUpdate; + if (req == null) throw new ApiFlowException("Could not process update transfer request. Update failed."); + + Transfer? foundTransfer = GetById(id); + if (foundTransfer == null) throw new ApiFlowException("Could not update transfer.", StatusCodes.Status404NotFound); + + foundTransfer.Reference = req.Reference; + foundTransfer.TransferFromId = req.TransferFromId; + foundTransfer.TransferToId = req.TransferToId; + foundTransfer.TransferStatus = req.TransferStatus; + _db.TransferItems.RemoveRange(foundTransfer.TransferItems); + foundTransfer.TransferItems = req.Items?.Select(reqItem => new TransferItem(newInstance: true) + { + Id = Guid.NewGuid(), + ItemId = reqItem.ItemId, + Amount = reqItem.Amount + }).ToList(); + + ValidateModel(foundTransfer); + SaveToDBOrFail(); + + return foundTransfer; + } + public override Transfer? Delete(Guid id) { Transfer? foundTransfer = GetById(id); @@ -167,5 +193,8 @@ public TransferProvider(AppDbContext db, IValidator validator, Locatio return _itemsProvider.GetById((Guid)itemId); } + public bool IsTransferCompleted(Guid transferId) => _db.Transfers.Any(t => t.Id == transferId && t.TransferStatus == TransferStatus.Completed); + public bool TransferExists(Guid transferId) => _db.Transfers.Any(t => t.Id == transferId); + protected override void ValidateModel(Transfer model) => _transferValidator.ValidateAndThrow(model); } \ No newline at end of file