feat: Implement Category, Item, UOM, Vendor, and Warehouse services with CRUD operations

- Added CategoryService for managing categories with listing, tree structure, and creation functionalities.
- Introduced ItemService for item management, including listing, detail retrieval, creation, updating, and status management.
- Created UomService for handling unit of measure operations, including listing and creation.
- Developed VendorService for vendor management, supporting listing, detail retrieval, creation, updating, and status management.
- Implemented WarehouseService for warehouse and bin management, including listing warehouses, creating warehouses, and managing bins within warehouses.
- Added interfaces for each service to define the contract for service implementations.
- Generated Entity Framework Core model snapshot for database migrations.
This commit is contained in:
2026-07-10 10:44:30 +05:30
parent ec94bac410
commit 057dd5aedc
54 changed files with 3437 additions and 18 deletions
+37
View File
@@ -0,0 +1,37 @@
namespace ERPCore.Common.Http;
/// <summary>
/// Encodes the PostgreSQL xmin concurrency token (a <see cref="uint"/>) as an
/// opaque, quoted HTTP ETag and parses <c>If-Match</c> values back. Round-trips
/// via base64 so the value is stable and content-type agnostic
/// (docs/11-BACKEND-PHASE1.md §1.6).
/// </summary>
public static class ETag
{
/// <summary>Quoted ETag string for a row-version token, e.g. <c>"0RsAAA=="</c>.</summary>
public static string From(uint rowVersion)
=> "\"" + Convert.ToBase64String(BitConverter.GetBytes(rowVersion)) + "\"";
/// <summary>Parse an <c>If-Match</c> header value (quoted, optionally weak) to a token.</summary>
public static bool TryParse(string? ifMatch, out uint rowVersion)
{
rowVersion = 0;
if (string.IsNullOrWhiteSpace(ifMatch)) return false;
var v = ifMatch.Trim();
if (v.StartsWith("W/", StringComparison.OrdinalIgnoreCase)) v = v[2..].Trim();
v = v.Trim('"');
try
{
var bytes = Convert.FromBase64String(v);
if (bytes.Length != sizeof(uint)) return false;
rowVersion = BitConverter.ToUInt32(bytes);
return true;
}
catch (FormatException)
{
return false;
}
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace ERPCore.Common.Http;
/// <summary>
/// Pairs a response DTO with the aggregate's current row-version so the controller
/// can emit an <c>ETag</c> header without the token leaking into the JSON body.
/// </summary>
public sealed record ETagged<T>(T Value, uint RowVersion);