mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-10-28 07:41:16 +00:00
feat: scheduled report digests + per-session capacity (M33)
POST /v1/internal/jobs/reports/dispatch emails each tenant owner a trailing-window digest (bookings, revenue, per-service and per-staff breakdown) localized to the tenant locale; zero-activity tenants are skipped. Metrics cores extracted to tenant-scoped variants so the job needs no principal. PATCH /v1/catalog/class-sessions/:id sets a session's seat count with a confirmed-bookings floor — shrinking below it needs allowOverCapacity, matching the waitlist-promotion convention. Session rows gain an inline capacity editor with an overbook confirm state. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
e6f1ec38a4
commit
e680e0c2b8
14 files changed
+808
-10
No files matched your search
@@ -686,13 +686,24 @@ func (s *Service) StaffMetrics(ctx context.Context, principal domain.Principal,
|
||||
}
|
||||
return domain.StaffMetricsResponse{}, err
|
||||
}
|
||||
return s.StaffMetricsForTenant(ctx, membership.Tenant.ID, days)
|
||||
}
|
||||
|
||||
// StaffMetricsForTenant is the tenant-scoped core of StaffMetrics — used by
|
||||
// scheduled jobs that have no principal.
|
||||
func (s *Service) StaffMetricsForTenant(ctx context.Context, tenantID string, days int) (domain.StaffMetricsResponse, error) {
|
||||
if days <= 0 || days > 365 {
|
||||
days = 30
|
||||
}
|
||||
to := time.Now().UTC()
|
||||
from := to.AddDate(0, 0, -days)
|
||||
|
||||
records, err := s.repo.GetStaffMetrics(ctx, membership.Tenant.ID, from, to)
|
||||
tenant, err := s.repo.GetTenantByID(ctx, tenantID)
|
||||
if err != nil {
|
||||
return domain.StaffMetricsResponse{}, err
|
||||
}
|
||||
|
||||
records, err := s.repo.GetStaffMetrics(ctx, tenantID, from, to)
|
||||
if err != nil {
|
||||
return domain.StaffMetricsResponse{}, err
|
||||
}
|
||||
@@ -701,19 +712,19 @@ func (s *Service) StaffMetrics(ctx context.Context, principal domain.Principal,
|
||||
byStaff[rec.StaffID] = rec
|
||||
}
|
||||
|
||||
staff, err := s.repo.ListStaffByTenant(ctx, membership.Tenant.ID)
|
||||
staff, err := s.repo.ListStaffByTenant(ctx, tenantID)
|
||||
if err != nil {
|
||||
return domain.StaffMetricsResponse{}, err
|
||||
}
|
||||
rules, err := s.repo.ListAvailabilityRulesByTenant(ctx, membership.Tenant.ID)
|
||||
rules, err := s.repo.ListAvailabilityRulesByTenant(ctx, tenantID)
|
||||
if err != nil {
|
||||
return domain.StaffMetricsResponse{}, err
|
||||
}
|
||||
blockedDays, err := s.repo.ListBlockedDaysByTenant(ctx, membership.Tenant.ID, from, to)
|
||||
blockedDays, err := s.repo.ListBlockedDaysByTenant(ctx, tenantID, from, to)
|
||||
if err != nil {
|
||||
return domain.StaffMetricsResponse{}, err
|
||||
}
|
||||
loc, err := time.LoadLocation(membership.Tenant.Timezone)
|
||||
loc, err := time.LoadLocation(tenant.Timezone)
|
||||
if err != nil {
|
||||
loc = time.UTC
|
||||
}
|
||||
@@ -753,17 +764,23 @@ func (s *Service) ServiceMetrics(ctx context.Context, principal domain.Principal
|
||||
}
|
||||
return domain.ServiceMetricsResponse{}, err
|
||||
}
|
||||
return s.ServiceMetricsForTenant(ctx, membership.Tenant.ID, days)
|
||||
}
|
||||
|
||||
// ServiceMetricsForTenant is the tenant-scoped core of ServiceMetrics — used
|
||||
// by scheduled jobs that have no principal.
|
||||
func (s *Service) ServiceMetricsForTenant(ctx context.Context, tenantID string, days int) (domain.ServiceMetricsResponse, error) {
|
||||
if days <= 0 || days > 365 {
|
||||
days = 30
|
||||
}
|
||||
to := time.Now().UTC()
|
||||
from := to.AddDate(0, 0, -days)
|
||||
|
||||
bookingsList, err := s.repo.ListBookingsByTenantBetween(ctx, membership.Tenant.ID, from, to)
|
||||
bookingsList, err := s.repo.ListBookingsByTenantBetween(ctx, tenantID, from, to)
|
||||
if err != nil {
|
||||
return domain.ServiceMetricsResponse{}, err
|
||||
}
|
||||
services, err := s.repo.ListServicesByTenant(ctx, membership.Tenant.ID)
|
||||
services, err := s.repo.ListServicesByTenant(ctx, tenantID)
|
||||
if err != nil {
|
||||
return domain.ServiceMetricsResponse{}, err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user