feat: add vendor optional fields and configuration hooks

- Implemented VendorOptionalFields component to handle optional vendor details (mobile, email, address) with validation.
- Created useCustomerConfig hook to load optional customer field settings from Sales configuration.
- Developed useProcurementConfig hook to manage Procurement configuration flags.
- Introduced accessConfigApi for managing access configuration settings.
- Added openingBalancesApi for handling opening balances operations.
- Created procurementConfigApi for managing procurement configuration settings.
- Implemented nav-routes for permission-based routing.
- Developed PDF generation for purchase orders with dynamic vendor and item details.
- Added purchase-order tax helpers for tax calculations and formatting.
- Defined types for opening balances and related operations.
This commit is contained in:
Dhananjaya99
2026-10-18 12:46:31 +05:30
parent c27db06880
commit e7b1f270a5
202 changed files with 99906 additions and 1894 deletions
+15 -7
View File
@@ -141,7 +141,7 @@ public class DualApprovalTests
[Fact]
public async Task SecondApproval_CanBeLimitedToRoles()
{
var h = await Harness.CreateAsync(level2Roles: "Approver");
var h = await Harness.CreateAsync(level2RoleIds: ApproverRoleId.ToString());
var id = (await h.Stock.CreateAsync(Request(-1))).AdjustmentId;
h.User.Be(ApproverA);
await h.Stock.ApproveAsync(id, null);
@@ -250,7 +250,7 @@ public class DualApprovalTests
public required AdjustmentService Stock { get; init; }
public required PriceAdjustmentService Prices { get; init; }
public static async Task<Harness> CreateAsync(int stockLevels = 2, decimal stockThreshold = 0, string? level2Roles = null)
public static async Task<Harness> CreateAsync(int stockLevels = 2, decimal stockThreshold = 0, string? level2RoleIds = null)
{
var db = new ErpDbContext(
new DbContextOptionsBuilder<ErpDbContext>().UseInMemoryDatabase(Guid.NewGuid().ToString("N"), Root).Options,
@@ -283,7 +283,7 @@ public class DualApprovalTests
db.ApprovalConfig.Add(new ApprovalConfig
{
ApprovalConfigId = ApprovalConfig.SingletonId, StockAdjustmentLevels = stockLevels,
StockAdjustmentLevel2ThresholdValue = stockThreshold, PriceAdjustmentLevels = 2, Level2RoleCodes = level2Roles
StockAdjustmentLevel2ThresholdValue = stockThreshold, PriceAdjustmentLevels = 2, Level2RoleIds = level2RoleIds
});
await db.SaveChangesAsync();
@@ -292,7 +292,7 @@ public class DualApprovalTests
var notifications = new RecordingNotifications();
var approvals = new ApprovalService(
new Repository<ApprovalConfig>(db), new Repository<DocumentApproval>(db), new Repository<User>(db),
new Repository<RolePermission>(db), user, notifications, uow);
new Repository<RolePermission>(db), new Repository<Role>(db), user, notifications, uow);
var gl = new FakeGeneralLedger();
var mutator = new RecordingMutator();
var numbers = new FakeNumberSequence();
@@ -308,8 +308,9 @@ public class DualApprovalTests
new SerialTrackingService(new Repository<Serial>(db), new Repository<SerialMovement>(db), new Repository<StockLayer>(db),
new Repository<ProductConfig>(db), user));
var prices = new PriceAdjustmentService(
new Repository<PriceAdjustment>(db), new Repository<Item>(db), new Repository<ItemPriceHistory>(db),
new Repository<User>(db), new Repository<ApprovalConfig>(db), approvals, notifications, numbers, user, uow);
new Repository<PriceAdjustment>(db), new Repository<PriceAdjustmentLine>(db), new Repository<Item>(db),
new Repository<ItemPriceHistory>(db), new Repository<User>(db), new Repository<ApprovalConfig>(db),
approvals, notifications, numbers, user, uow);
return new Harness { Db = db, User = user, Mutator = mutator, Gl = gl, Notifications = notifications, Stock = stock, Prices = prices };
}
@@ -323,7 +324,13 @@ public class DualApprovalTests
[Requester] = "Requester", [ApproverA] = "Approver", [ApproverB] = "Approver", [Clerk] = "Clerk"
};
private static readonly Dictionary<int, int> RoleIds = new()
{
[Requester] = 1, [ApproverA] = ApproverRoleId, [ApproverB] = ApproverRoleId, [Clerk] = ClerkRoleId
};
public int AuditUserId { get; private set; } = userId;
public int? RoleId { get; private set; } = RoleIds[userId];
public string? RoleCode { get; private set; } = roleCode;
public string UserId => AuditUserId.ToString();
public bool IsAuthenticated => true;
@@ -333,6 +340,7 @@ public class DualApprovalTests
public void Be(int userId)
{
AuditUserId = userId;
RoleId = RoleIds[userId];
RoleCode = Roles[userId];
}
}
@@ -368,7 +376,7 @@ public class DualApprovalTests
=> throw new NotSupportedException();
public Task<StockLedger> PostLedgerAsync(int itemId, int warehouseId, int? binId, int? batchId, int? serialId, int userId,
Direction direction, decimal qtyBase, decimal unitCost, decimal runningBalance, string sourceDocType, int sourceDocId,
DateTime createdAt, CancellationToken ct = default, decimal? valueOverride = null) => throw new NotSupportedException();
DateTime createdAt, CancellationToken ct = default, decimal? valueOverride = null, bool postGlJournal = true) => throw new NotSupportedException();
public Task<decimal> GetOnHandAsync(int itemId, int warehouseId, CancellationToken ct = default) => Task.FromResult(10m);
}