e7b1f270a5
- 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.
159 lines
6.7 KiB
C#
159 lines
6.7 KiB
C#
using ERPCore.Domain.Entities;
|
|
using ERPCore.Dtos.Customers;
|
|
using ERPCore.Infra.Persistence;
|
|
using ERPCore.Repositories;
|
|
using ERPCore.Services;
|
|
using ERPCore.System.Errors;
|
|
using ERPCore.Tests.TestSupport;
|
|
using static ERPCore.Tests.TestSupport.BankDepositTestSupport;
|
|
|
|
namespace ERPCore.Tests;
|
|
|
|
/// <summary>
|
|
/// Sales Configuration decides which optional customer fields exist (phone, email, address, city, country, credit limit,
|
|
/// credit days). The forms hide a switched-off field; the server refuses a new value for it and keeps what is stored.
|
|
/// </summary>
|
|
public class CustomerFieldSwitchTests
|
|
{
|
|
private static CustomerService Svc(ErpDbContext db) =>
|
|
new(new Repository<Customer>(db), new Repository<Warehouse>(db), new FakeBranchConfig(),
|
|
new Repository<SalesConfig>(db), new Repository<SalesInvoice>(db), new Repository<SalesInvoicePayment>(db),
|
|
new PassThroughUnitOfWork(db));
|
|
|
|
private static async Task SwitchesAsync(ErpDbContext db, Action<SalesConfig> tweak)
|
|
{
|
|
var config = new SalesConfig { ConfigId = SalesConfig.SingletonId };
|
|
tweak(config);
|
|
db.SalesConfig.Add(config);
|
|
await db.SaveChangesAsync();
|
|
}
|
|
|
|
private static CreateCustomerRequest NewCustomer(Action<CreateCustomerRequest>? tweak = null)
|
|
{
|
|
var request = new CreateCustomerRequest { CustomerCode = "C-1", Name = "Nimal Perera", BranchId = Branch1 };
|
|
tweak?.Invoke(request);
|
|
return request;
|
|
}
|
|
|
|
private static UpdateCustomerRequest Same(Customer c, Action<UpdateCustomerRequest>? tweak = null)
|
|
{
|
|
var request = new UpdateCustomerRequest
|
|
{
|
|
CustomerCode = c.CustomerCode, CustomerType = c.CustomerType, Name = c.Name, DisplayName = c.DisplayName,
|
|
Phone = c.Phone, Email = c.Email, AddressLine1 = c.AddressLine1, AddressLine2 = c.AddressLine2,
|
|
City = c.City, Country = c.Country, TaxRegistrationNo = c.TaxRegistrationNo,
|
|
CreditLimit = c.CreditLimit, CreditDays = c.CreditDays, BranchId = c.BranchId
|
|
};
|
|
tweak?.Invoke(request);
|
|
return request;
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EveryFieldIsOn_WhenNothingIsConfigured_SoExistingBehaviourIsUnchanged()
|
|
{
|
|
await using var db = CreateContext(); // no sales_config row at all
|
|
|
|
var created = (await Svc(db).CreateAsync(NewCustomer(r =>
|
|
{
|
|
r.Phone = "0771234567"; r.Email = "a@b.lk"; r.AddressLine1 = "No. 12"; r.City = "Colombo";
|
|
r.Country = "Sri Lanka"; r.CreditLimit = 5000m; r.CreditDays = 30;
|
|
}))).Value;
|
|
|
|
Assert.Equal(("0771234567", "a@b.lk", "No. 12", "Colombo", "Sri Lanka"), (created.Phone, created.Email, created.AddressLine1, created.City, created.Country));
|
|
Assert.Equal((5000m, 30), (created.CreditLimit, created.CreditDays));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("phone")]
|
|
[InlineData("email")]
|
|
[InlineData("address")]
|
|
[InlineData("city")]
|
|
[InlineData("country")]
|
|
[InlineData("creditLimit")]
|
|
[InlineData("creditDays")]
|
|
public async Task Create_ANewValueForASwitchedOffField_IsRefused(string field)
|
|
{
|
|
await using var db = CreateContext();
|
|
await SwitchesAsync(db, c =>
|
|
{
|
|
c.CustomerPhoneEnabled = field != "phone";
|
|
c.CustomerEmailEnabled = field != "email";
|
|
c.CustomerAddressEnabled = field != "address";
|
|
c.CustomerCityEnabled = field != "city";
|
|
c.CustomerCountryEnabled = field != "country";
|
|
c.CustomerCreditLimitEnabled = field != "creditLimit";
|
|
c.CustomerCreditDaysEnabled = field != "creditDays";
|
|
});
|
|
|
|
var ex = await Assert.ThrowsAsync<DomainException>(() => Svc(db).CreateAsync(NewCustomer(r =>
|
|
{
|
|
switch (field)
|
|
{
|
|
case "phone": r.Phone = "0771234567"; break;
|
|
case "email": r.Email = "a@b.lk"; break;
|
|
case "address": r.AddressLine2 = "Wellawatte"; break;
|
|
case "city": r.City = "Colombo"; break;
|
|
case "country": r.Country = "Sri Lanka"; break;
|
|
case "creditLimit": r.CreditLimit = 100m; break;
|
|
default: r.CreditDays = 7; break;
|
|
}
|
|
})));
|
|
|
|
Assert.Equal(ErrorCodes.ConfigDisabled, ex.Code);
|
|
Assert.Equal(422, ex.StatusCode);
|
|
Assert.Empty(db.Customers.Where(c => c.CustomerCode == "C-1"));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Create_WithTheSwitchedOffFieldsLeftBlank_Works()
|
|
{
|
|
await using var db = CreateContext();
|
|
await SwitchesAsync(db, c =>
|
|
{
|
|
c.CustomerPhoneEnabled = c.CustomerEmailEnabled = c.CustomerAddressEnabled = false;
|
|
c.CustomerCityEnabled = c.CustomerCountryEnabled = false;
|
|
c.CustomerCreditLimitEnabled = c.CustomerCreditDaysEnabled = false;
|
|
});
|
|
|
|
var created = (await Svc(db).CreateAsync(NewCustomer())).Value;
|
|
|
|
Assert.Equal("Nimal Perera", created.Name);
|
|
Assert.Null(created.Phone);
|
|
Assert.Equal((0m, 0), (created.CreditLimit, created.CreditDays));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Update_KeepsAStoredValueWhoseFieldWasSwitchedOff_EvenWhenTheFormSendsItBlank()
|
|
{
|
|
await using var db = CreateContext();
|
|
var svc = Svc(db);
|
|
var created = (await svc.CreateAsync(NewCustomer(r => { r.Phone = "0771234567"; r.CreditLimit = 5000m; r.CreditDays = 30; }))).Value;
|
|
|
|
await SwitchesAsync(db, c => { c.CustomerPhoneEnabled = false; c.CustomerCreditLimitEnabled = false; c.CustomerCreditDaysEnabled = false; });
|
|
var stored = db.Customers.Single(c => c.CustomerId == created.CustomerId);
|
|
|
|
// The edit form no longer has the fields, so it sends blanks / zeros.
|
|
var updated = (await svc.UpdateAsync(created.CustomerId,
|
|
Same(stored, r => { r.Name = "Nimal P."; r.Phone = null; r.CreditLimit = 0m; r.CreditDays = 0; }), stored.RowVersion)).Value;
|
|
|
|
Assert.Equal("Nimal P.", updated.Name);
|
|
Assert.Equal("0771234567", updated.Phone);
|
|
Assert.Equal((5000m, 30), (updated.CreditLimit, updated.CreditDays));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Update_ADifferentValueForASwitchedOffField_IsRefused()
|
|
{
|
|
await using var db = CreateContext();
|
|
var svc = Svc(db);
|
|
var created = (await svc.CreateAsync(NewCustomer(r => r.CreditLimit = 5000m))).Value;
|
|
await SwitchesAsync(db, c => c.CustomerCreditLimitEnabled = false);
|
|
var stored = db.Customers.Single(c => c.CustomerId == created.CustomerId);
|
|
|
|
var ex = await Assert.ThrowsAsync<DomainException>(
|
|
() => svc.UpdateAsync(created.CustomerId, Same(stored, r => r.CreditLimit = 9999m), stored.RowVersion));
|
|
|
|
Assert.Equal(ErrorCodes.ConfigDisabled, ex.Code);
|
|
}
|
|
}
|