Add smoke tests for UOM conversions and enhance frontend UOM management

- Implemented smoke tests for UOM directionality, ensuring conversions are one-directional and correctly validated.
- Added tests for receiving and selling items in different UOMs, verifying correct quantity handling and error responses.
- Created a UOM conversions panel in the frontend to allow users to manage UOM conversions for items.
- Introduced hooks for allowed UOMs to optimize fetching and caching of UOM data for document line forms.
- Developed utility functions for consistent UOM formatting and conversion handling across the application.
This commit is contained in:
2026-08-10 15:12:51 +05:30
parent d37824cecc
commit 8d5a05a419
63 changed files with 1539 additions and 136 deletions
+18 -1
View File
@@ -1,6 +1,7 @@
using ERPCore.Domain.Enums;
using ERPCore.Dtos.Common;
using ERPCore.Dtos.Items;
using ERPCore.Dtos.Uoms;
using ERPCore.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;
@@ -11,8 +12,13 @@ namespace ERPCore.Controllers;
public sealed class ItemsController : ApiControllerBase
{
private readonly IItemService _items;
private readonly IUomConverter _uomConverter;
public ItemsController(IItemService items) => _items = items;
public ItemsController(IItemService items, IUomConverter uomConverter)
{
_items = items;
_uomConverter = uomConverter;
}
/// <summary>List items with optional filters and paging.</summary>
[HttpGet]
@@ -88,4 +94,15 @@ public sealed class ItemsController : ApiControllerBase
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<ItemUomConversionsDto>> UpdateUomConversions(int itemId, [FromBody] UpdateUomConversionsRequest request, CancellationToken ct)
=> Ok(await _items.UpdateUomConversionsAsync(itemId, request, ct));
/// <summary>
/// The UOMs this item may be transacted in — its base UOM plus every UOM it has a
/// conversion from, each with the factor to base. Document line forms use this to offer
/// only units that will survive posting, instead of the whole global UOM list (FR-MD-02/03).
/// </summary>
[HttpGet("{itemId:int}/uoms")]
[ProducesResponseType(typeof(IReadOnlyList<AllowedUomDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<IReadOnlyList<AllowedUomDto>>> GetAllowedUoms(int itemId, CancellationToken ct)
=> Ok(await _uomConverter.GetAllowedUomsAsync(itemId, ct));
}