ui bug fixers

This commit is contained in:
2026-10-07 10:28:29 +05:30
committed by ImanThiyanga
parent 0d3f2fba14
commit 3abcfa6e6f
37 changed files with 1852 additions and 542 deletions
@@ -65,4 +65,15 @@ public sealed class VendorsController : ApiControllerBase
await _vendors.SetStatusAsync(vendorId, request.Status, ct);
return NoContent();
}
[HttpDelete("{vendorId:int}")]
[Authorize(Policy = NavPolicies.Prefix + "vendors" + NavPolicies.ActionSeparator + NavPolicies.DeleteAction)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<IActionResult> Delete(int vendorId, CancellationToken ct)
{
await _vendors.DeleteAsync(vendorId, ct);
return NoContent();
}
}
@@ -31,6 +31,8 @@ public sealed class CreatePurchaseInvoicePaymentRequest
[Range(0.01, double.MaxValue)] public decimal Amount { get; set; }
[Required] public long GlBankAccountId { get; set; }
[StringLength(100)] public string? Reference { get; set; }
/// <summary>When the vendor was paid; also the GL entry date. Omitted ⇒ today. Never in the future.</summary>
public DateOnly? PaymentDate { get; set; }
}
public sealed class CreatePurchaseInvoiceRequest
@@ -13,4 +13,5 @@ public interface IVendorService
Task<ETagged<VendorDto>> CreateAsync(CreateVendorRequest request, CancellationToken ct = default);
Task<ETagged<VendorDto>> UpdateAsync(int vendorId, UpdateVendorRequest request, uint expectedRowVersion, CancellationToken ct = default);
Task SetStatusAsync(int vendorId, EntityStatus status, CancellationToken ct = default);
Task DeleteAsync(int vendorId, CancellationToken ct = default);
}
@@ -59,6 +59,7 @@ public sealed class PurchaseInvoicePaymentService : IPurchaseInvoicePaymentServi
var actor = _currentUser.AuditUserId;
var now = DateTime.UtcNow;
var (paymentDay, paymentDate) = ResolvePaymentDate(request.PaymentDate, now);
var payment = await _uow.ExecuteInTransactionAsync(async token =>
{
@@ -82,7 +83,7 @@ public sealed class PurchaseInvoicePaymentService : IPurchaseInvoicePaymentServi
{
PurchaseInvoiceId = invoice.PurchaseInvoiceId,
Amount = request.Amount,
PaymentDate = now,
PaymentDate = paymentDate,
GlBankAccountId = account.AccountId,
BankAccountName = account.AccountName,
Reference = request.Reference,
@@ -101,6 +102,21 @@ public sealed class PurchaseInvoicePaymentService : IPurchaseInvoicePaymentServi
return Map(payment);
}
/// <summary>
/// The payment's calendar day (also the GL entry date) and the timestamp stored on it — same
/// rule as <see cref="SalesInvoicePaymentService"/>. Omitted ⇒ today. One day of slack on
/// "future": the client sends its local date, which runs ahead of UTC for users east of it.
/// Today keeps the actual time of entry; a back-dated payment is stamped at that day's start.
/// </summary>
private static (DateOnly Day, DateTime Stamp) ResolvePaymentDate(DateOnly? requested, DateTime now)
{
var today = DateOnly.FromDateTime(now);
var day = requested ?? today;
if (day > today.AddDays(1))
throw new DomainException(ErrorCodes.Validation, "Payment date cannot be in the future.", 400);
return (day, day >= today ? now : day.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc));
}
public async Task<IReadOnlyList<PurchaseInvoicePaymentDto>> ListAsync(int purchaseInvoiceId, CancellationToken ct = default)
{
if (!await _invoices.Query().AnyAsync(i => i.PurchaseInvoiceId == purchaseInvoiceId, ct))
@@ -66,7 +66,11 @@ public sealed class RequisitionService : IRequisitionService
{
await EnsureItemsExistAsync(request.Lines.Select(l => l.ItemId), ct);
var actor = _currentUser.AuditUserId;
var branchId = await _branchConfig.ResolveBranchIdAsync(request.BranchId, ct);
// Branch is optional on a requisition: an unset one falls back to the default branch
// rather than being rejected (this also covers reorder-alert requisitions, which carry none).
var branchId = request.BranchId > 0
? await _branchConfig.ResolveBranchIdAsync(request.BranchId, ct)
: await _branchConfig.ResolveDefaultBranchIdAsync(ct);
var req = await _uow.ExecuteInTransactionAsync(async token =>
{
+20
View File
@@ -120,6 +120,26 @@ public sealed class VendorService : IVendorService
await _uow.SaveChangesAsync(ct);
}
/// <summary>
/// Hard delete. Every FK to vendors (POs, GRNs, invoices, returns, quotations, item
/// default vendor) is Restrict, so a vendor in use is refused with 409 — deactivate it instead.
/// </summary>
public async Task DeleteAsync(int vendorId, CancellationToken ct = default)
{
var vendor = await _vendors.GetByIdAsync(vendorId, ct)
?? throw new NotFoundException($"Vendor {vendorId} was not found.");
_vendors.Remove(vendor);
try
{
await _uow.SaveChangesAsync(ct);
}
catch (DbUpdateException)
{
throw new DomainException(ErrorCodes.MasterInUse, "This vendor is used by purchase documents or items and cannot be deleted. Deactivate it instead.", 409);
}
}
private static VendorDto Map(Vendor v) => new(
v.VendorId, v.Code, v.Name, v.Terms, v.TaxReg, v.Currency, v.Status, v.BranchId, v.CreatedAt, v.UpdatedAt);
}
@@ -10,5 +10,8 @@
},
"AuthHex": {
"BaseUrl": "http://localhost:5011"
},
"GeneralLedgerService": {
"BaseUrl": "http://localhost:5200/api/v1/"
}
}