Split QueryStatus.Accepted into ProAccepted/ClientAccepted

Distinguish the two parties' acceptances: ProAccepted (provider) and
ClientAccepted (client) replace the single Accepted value for new
acceptances. Accepted=2 is retained as a legacy value so existing DB rows
keep their integer mapping.

- FrontOfficeApiController.AcceptQuery sets status by ActorRole
- BillingController provider-ongoing filters match the new values
- FrontOfficeController (MVC) dashboard counts use ProAccepted||Accepted
- PostIt: IsOngoingStatus, GetStatusRank (client-accepted ranks first for
  the pro), and status-badge switches (P/C glyphs) handle the new values
- Tests assert ProAccepted (provider) vs ClientAccepted (client)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
Paul Schneider 2026-09-21 17:33:32 +01:00
commit 827fe6b41f
Signed by: notazof
GPG key ID: AD4B9B545FBD7D12
8 changed files with 62 additions and 19 deletions

View file

@ -171,5 +171,9 @@ public partial class BillingQueriesPageViewModel : ViewModelBase, IActionStatusV
}
private static bool IsOngoingStatus(QueryStatus status)
=> status is QueryStatus.Inserted or QueryStatus.Accepted or QueryStatus.InProgress;
=> status is QueryStatus.Inserted
or QueryStatus.Accepted
or QueryStatus.ProAccepted
or QueryStatus.ClientAccepted
or QueryStatus.InProgress;
}

View file

@ -166,6 +166,8 @@ public partial class BillingQueryDetailsPageViewModel : ViewModelBase, IActionSt
=> status switch
{
QueryStatus.Accepted => "#E6F7EC",
QueryStatus.ProAccepted => "#E6F7EC",
QueryStatus.ClientAccepted => "#E1F5FE",
QueryStatus.InProgress => "#FFF4D6",
QueryStatus.Rejected => "#FDECEA",
QueryStatus.Failed => "#ECEFF1",
@ -177,6 +179,8 @@ public partial class BillingQueryDetailsPageViewModel : ViewModelBase, IActionSt
=> status switch
{
QueryStatus.Accepted => "#2E7D32",
QueryStatus.ProAccepted => "#2E7D32",
QueryStatus.ClientAccepted => "#1565C0",
QueryStatus.InProgress => "#B26A00",
QueryStatus.Rejected => "#C62828",
QueryStatus.Failed => "#607D8B",
@ -188,6 +192,8 @@ public partial class BillingQueryDetailsPageViewModel : ViewModelBase, IActionSt
=> status switch
{
QueryStatus.Accepted => "#1B5E20",
QueryStatus.ProAccepted => "#1B5E20",
QueryStatus.ClientAccepted => "#0D47A1",
QueryStatus.InProgress => "#7A4A00",
QueryStatus.Rejected => "#8E0000",
QueryStatus.Failed => "#37474F",
@ -199,6 +205,8 @@ public partial class BillingQueryDetailsPageViewModel : ViewModelBase, IActionSt
=> status switch
{
QueryStatus.Accepted => "OK",
QueryStatus.ProAccepted => "P",
QueryStatus.ClientAccepted => "C",
QueryStatus.InProgress => "~",
QueryStatus.Rejected => "!",
QueryStatus.Failed => "X",

View file

@ -344,11 +344,13 @@ public partial class ProviderOngoingRequestsPageViewModel : ViewModelBase, IActi
=> status switch
{
QueryStatus.InProgress => 0,
QueryStatus.Accepted => 1,
QueryStatus.Inserted => 2,
QueryStatus.Success => 3,
QueryStatus.Rejected => 4,
QueryStatus.Failed => 5,
QueryStatus.ClientAccepted => 1,
QueryStatus.ProAccepted => 2,
QueryStatus.Accepted => 2,
QueryStatus.Inserted => 3,
QueryStatus.Success => 4,
QueryStatus.Rejected => 5,
QueryStatus.Failed => 6,
_ => 99,
};

View file

@ -5,15 +5,28 @@ namespace Yavsc
/// should be associated to any
/// client user query to a provider user or
/// other external entity.
///
/// <para>
/// Acceptance is split by party: <see cref="ProAccepted"/> when the
/// provider accepts the client's request (and produces/submits the
/// estimate), <see cref="ClientAccepted"/> when the client accepts
/// the provider's estimate. <see cref="Accepted"/> is the legacy
/// single-value kept for rows written before the split; new writes
/// use the party-specific values. Its integer value (2) is stable
/// so existing rows still deserialize.
/// </para>
/// </summary>
public enum QueryStatus: int
{
Inserted,
Rejected,
Accepted,
InProgress,
Inserted = 0,
Rejected = 1,
Accepted = 2,
InProgress = 3,
// final states
Failed,
Success
Failed = 4,
Success = 5,
// party-specific acceptance (see summary)
ProAccepted = 6,
ClientAccepted = 7,
}
}

View file

@ -127,7 +127,8 @@ public sealed class FrontOfficeApiControllerTests : IClassFixture<ApiWebServerFi
var assertDb = assertScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
var updated = assertDb.RdvQueries.Single(q => q.Id == queryId);
Assert.Equal(QueryStatus.Accepted, updated.Status);
// Default caller is "alice" (the provider) → ProAccepted.
Assert.Equal(QueryStatus.ProAccepted, updated.Status);
}
[Fact]
@ -146,7 +147,7 @@ public sealed class FrontOfficeApiControllerTests : IClassFixture<ApiWebServerFi
using var assertScope = _fixture.Services.CreateScope();
var assertDb = assertScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
Assert.Equal(QueryStatus.Accepted, assertDb.RdvQueries.Single(q => q.Id == queryId).Status);
Assert.Equal(QueryStatus.ProAccepted, assertDb.RdvQueries.Single(q => q.Id == queryId).Status);
var estimate = assertDb.Estimates.Single(e => e.Id == estimateId);
Assert.True(estimate.ProviderValidationDate != default);
@ -173,7 +174,7 @@ public sealed class FrontOfficeApiControllerTests : IClassFixture<ApiWebServerFi
using var assertScope = _fixture.Services.CreateScope();
var assertDb = assertScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
Assert.Equal(QueryStatus.Accepted, assertDb.RdvQueries.Single(q => q.Id == queryId).Status);
Assert.Equal(QueryStatus.ClientAccepted, assertDb.RdvQueries.Single(q => q.Id == queryId).Status);
var estimate = assertDb.Estimates.Single(e => e.Id == estimateId);
Assert.True(estimate.ClientValidationDate != default);

View file

@ -157,6 +157,8 @@ namespace Yavsc.ApiControllers
.Where(q => allowedActivityCodes.Contains(q.ActivityCode))
.Where(q => q.Status == QueryStatus.Inserted
|| q.Status == QueryStatus.Accepted
|| q.Status == QueryStatus.ProAccepted
|| q.Status == QueryStatus.ClientAccepted
|| q.Status == QueryStatus.InProgress)
.Cast<NominativeServiceCommand>()
.ToList()
@ -169,6 +171,8 @@ namespace Yavsc.ApiControllers
.Where(q => allowedActivityCodes.Contains(q.ActivityCode))
.Where(q => q.Status == QueryStatus.Inserted
|| q.Status == QueryStatus.Accepted
|| q.Status == QueryStatus.ProAccepted
|| q.Status == QueryStatus.ClientAccepted
|| q.Status == QueryStatus.InProgress)
.Cast<NominativeServiceCommand>()
.ToList()
@ -181,6 +185,8 @@ namespace Yavsc.ApiControllers
.Where(q => allowedActivityCodes.Contains(q.ActivityCode))
.Where(q => q.Status == QueryStatus.Inserted
|| q.Status == QueryStatus.Accepted
|| q.Status == QueryStatus.ProAccepted
|| q.Status == QueryStatus.ClientAccepted
|| q.Status == QueryStatus.InProgress)
.Cast<NominativeServiceCommand>()
.ToList()

View file

@ -100,7 +100,16 @@ namespace Yavsc.ApiControllers
estimate.ClientValidationDate = DateTime.UtcNow;
}
query.Status = QueryStatus.Accepted;
// The party-specific status records who accepted: the
// provider (ProAccepted) or the client (ClientAccepted).
// An admin accepting (neither party) falls back to the
// legacy generic Accepted.
query.Status = role switch
{
ActorRole.Provider => QueryStatus.ProAccepted,
ActorRole.Client => QueryStatus.ClientAccepted,
_ => QueryStatus.Accepted,
};
try
{

View file

@ -46,9 +46,9 @@ namespace Yavsc.Controllers
{
EstimateToProduceCount = _context.RdvQueries.Where(c => c.PerformerId == uid && c.EventDate > now && c.Status == QueryStatus.Inserted
&& c.ValidationDate == null && !_context.Estimates.Any(e => e.CommandId == c.Id)).Count(),
EstimateToHonorAsProCount = _context.RdvQueries.Where(c => c.PerformerId == uid && c.EventDate > now && c.Status == QueryStatus.Accepted
EstimateToHonorAsProCount = _context.RdvQueries.Where(c => c.PerformerId == uid && c.EventDate > now && (c.Status == QueryStatus.ProAccepted || c.Status == QueryStatus.Accepted)
&& c.ValidationDate == null && _context.Estimates.Any(e => e.CommandId == c.Id )).Count(),
EstimateToSignAsCliCount = _context.Estimates.Where(e => e.ClientId == uid && e.Query.Status == QueryStatus.Accepted).Count(),
EstimateToSignAsCliCount = _context.Estimates.Where(e => e.ClientId == uid && (e.Query.Status == QueryStatus.ProAccepted || e.Query.Status == QueryStatus.Accepted)).Count(),
BillToSignAsCliCount = 0,
NewPayementsCount = 0