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;
///
/// 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.
///
public class CustomerFieldSwitchTests
{
private static CustomerService Svc(ErpDbContext db) =>
new(new Repository(db), new Repository(db), new FakeBranchConfig(),
new Repository(db), new Repository(db), new Repository(db),
new PassThroughUnitOfWork(db));
private static async Task SwitchesAsync(ErpDbContext db, Action tweak)
{
var config = new SalesConfig { ConfigId = SalesConfig.SingletonId };
tweak(config);
db.SalesConfig.Add(config);
await db.SaveChangesAsync();
}
private static CreateCustomerRequest NewCustomer(Action? 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? 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(() => 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(
() => svc.UpdateAsync(created.CustomerId, Same(stored, r => r.CreditLimit = 9999m), stored.RowVersion));
Assert.Equal(ErrorCodes.ConfigDisabled, ex.Code);
}
}