diff --git a/src/bnhtrade.Core/Logic/Validate/Format.cs b/src/bnhtrade.Core/Logic/Validate/Format.cs index 989b485..0fc5a90 100644 --- a/src/bnhtrade.Core/Logic/Validate/Format.cs +++ b/src/bnhtrade.Core/Logic/Validate/Format.cs @@ -45,6 +45,20 @@ namespace bnhtrade.Core.Logic.Validate return true; } + /// + /// Validates that a stock number string is in the format 'STK#000000' (six digits). + /// + /// + /// + public static bool StockNumber(string stockNumber) + { + if (string.IsNullOrEmpty(stockNumber)) + return false; + + // Check for exact match: STK# followed by 6 digits + return System.Text.RegularExpressions.Regex.IsMatch(stockNumber, @"^STK#\d{6}$"); + } + /// /// Checks the datetime is not default and is utc /// diff --git a/src/bnhtrade.Core/Model/Stock/StockJournal.cs b/src/bnhtrade.Core/Model/Stock/StockJournal.cs index 8627a67..d64ce43 100644 --- a/src/bnhtrade.Core/Model/Stock/StockJournal.cs +++ b/src/bnhtrade.Core/Model/Stock/StockJournal.cs @@ -1,4 +1,7 @@ -using System; +using bnhtrade.Core.Logic.Validate; +using bnhtrade.Core.Model.Account; +using FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInboundv20240320; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; @@ -9,7 +12,7 @@ namespace bnhtrade.Core.Model.Stock { public class StockJournal : IValidatableObject { - public StockJournal(int stockJournalId, StockJournalType stockJournalType, int stockId, int stockNumber, DateTime entryDate, DateTime postDate, DateTime lastModified, bool isLocked, List journalPosts) + public StockJournal(int stockJournalId, StockJournalType stockJournalType, int stockId, string stockNumber, DateTime entryDate, DateTime postDate, DateTime lastModified, bool isLocked, List journalPosts) { StockJournalId = stockJournalId; StockJournalType = stockJournalType; @@ -19,16 +22,21 @@ namespace bnhtrade.Core.Model.Stock PostDate = postDate; LastModified = lastModified; IsLocked = isLocked; - JournalPosts = journalPosts ?? throw new ArgumentNullException(nameof(journalPosts), "Journal posts cannot be null."); + StockJournalPosts = journalPosts ?? throw new ArgumentNullException(nameof(journalPosts), "Journal posts cannot be null."); } + [Required()] + [Range(1, int.MaxValue, ErrorMessage = "StockJournalId must be greater than 0.")] public int StockJournalId { get; } public StockJournalType StockJournalType { get; } + [Required()] + [Range(1, int.MaxValue, ErrorMessage = "StockId must be greater than 0.")] public int StockId { get; } - public int StockNumber { get; } + [Required(ErrorMessage = "Stock number is required.")] + public string StockNumber { get; } public DateTime EntryDate { get; } @@ -38,18 +46,17 @@ namespace bnhtrade.Core.Model.Stock public bool IsLocked { get; } - public List JournalPosts { get; } + public List StockJournalPosts { get; } - public class JournalPost + public class StockJournalPost : IValidatableObject { - public JournalPost(int journalPostId, Status status, int quantity) + public StockJournalPost(int journalPostId, Status status, int quantity) { - JournalPostId = journalPostId; + StockJournalPostId = journalPostId; Status = status; Quantity = quantity; } - - public int JournalPostId { get; } + public int StockJournalPostId { get; } [Required()] public Status Status { get; } @@ -94,12 +101,64 @@ namespace bnhtrade.Core.Model.Stock } } } + + public IEnumerable Validate(ValidationContext validationContext) + { + var validationResults = new List(); + + if (Quantity == 0) + { + validationResults.Add(new ValidationResult("Quantity cannot be zero for a journal post.", new[] { nameof(Quantity) })); + } + + return validationResults; + } } public IEnumerable Validate(ValidationContext validationContext) { - throw new NotImplementedException(); - } + var validationResults = new List(); + // dates are in UTC format + if (EntryDate.Kind != DateTimeKind.Utc || EntryDate == default(DateTime)) + { + validationResults.Add(new ValidationResult("Entry Date must be in UTC format and not a default value.", new[] { nameof(EntryDate) })); + } + if (PostDate.Kind != DateTimeKind.Utc || PostDate == default(DateTime)) + { + validationResults.Add(new ValidationResult("PostDate must be in UTC format and not a default value.", new[] { nameof(PostDate) })); + } + if (LastModified.Kind != DateTimeKind.Utc || LastModified == default(DateTime)) + { + validationResults.Add(new ValidationResult("LastModified must be in UTC format and not a default value.", new[] { nameof(LastModified) })); + } + + if (Format.StockNumber(StockNumber) == false) + { + validationResults.Add(new ValidationResult("StockNumber must be in the format 'STK#000000'.", new[] { nameof(StockNumber) })); + } + + // Validate each StockJournalPost using its own context and Validate method + int sum = 0; + for (int i = 0; i < StockJournalPosts.Count; i++) + { + sum += StockJournalPosts[i].Quantity; + + var post = StockJournalPosts[i]; + var postContext = new ValidationContext(post, validationContext, validationContext.Items); + foreach (var result in post.Validate(postContext)) + { + // Prefix property name with the index for clarity + var memberNames = result.MemberNames.Select(name => $"StockJournalPosts[{i}].{name}"); + validationResults.Add(new ValidationResult(result.ErrorMessage, memberNames)); + } + } + if (sum != 0) + { + validationResults.Add(new ValidationResult("The sum of all journal posts must equal zero.", new[] { nameof(StockJournalPosts) })); + } + + return validationResults; + } } }