Demo data realism + invoice resend via SMS on any status
Seed data fixes: - Fix EF interceptor: no longer overwrites explicitly-set CreatedAt on Added entities — root cause of all "same month" chart issues - Customer seeder: generates 15 customers/month from Jan → current month; keeps 10 commercial anchors in deterministic order for job seeder index map - Invoice seeder: historical range bumped from 2→8 paid invoices/month so P&L shows consistent profit (~$5,200 collected vs ~$4,200 monthly expenses) - Month -1 bumped to 7 paid invoices to stay above expenses - Jobs: set UpdatedAt to historical event date so analytics don't need null fallback - Analytics (ReportsController): use CompletedDate ?? UpdatedAt ?? CreatedAt for revenue chart grouping; fixes empty Revenue Trend charts on Overview/Revenue tabs - SeedDataService: inject IAccountBalanceService; auto-recalculate account balances after seeding; patch checking/savings opening balances unconditionally on reset - Customer list: sort by CompanyName ?? ContactLastName so individuals and commercial accounts interleave instead of appearing as two blocks Invoice resend: - ResendInvoice action now accepts sendEmail + sendSms parameters; SMS-only resend no longer requires an email address on file - Ensures PublicViewToken exists before SMS so the view link is always valid - canResend in Details view now allows Paid invoices (removed != Paid guard) - Resend button shows channel-choice modal when customer has both email + SMS, direct SMS button when SMS only, or email button when email only - New #resendChannelModal mirrors the Send channel modal but posts to ResendInvoice - resendInvoice() JS updated to pass sendEmail/sendSms query params Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -183,6 +183,23 @@ public partial class SeedDataService
|
||||
}
|
||||
}
|
||||
|
||||
// ── Months −12 through −4: 8 paid invoices per month ────────────────
|
||||
// 8 × avg ~$650 = ~$5,200/month collected revenue, which exceeds the seeded
|
||||
// ~$4,200/month in operating expenses, so the P&L chart shows a consistent profit.
|
||||
// Payment methods and tax rates alternate for variety in the ledger.
|
||||
var histMethods = new[] { PaymentMethod.BankTransferACH, PaymentMethod.Check, PaymentMethod.CreditDebitCard, PaymentMethod.Cash };
|
||||
for (int monthBack = 12; monthBack >= 4; monthBack--)
|
||||
{
|
||||
for (int inv = 0; inv < 8; inv++)
|
||||
{
|
||||
var daysAgo = monthBack * 30 + 25 - (inv * 3);
|
||||
var taxPct = (monthBack + inv) % 2 == 0 ? 7.5m : 0m;
|
||||
var method = histMethods[(monthBack * 8 + inv) % histMethods.Length];
|
||||
var chkRef = method == PaymentMethod.Check ? $"CHK-{9000 + monthBack * 8 + inv:D4}" : null;
|
||||
await Inv(InvoiceStatus.Paid, daysAgo, 30, taxPct, "Net 30", "Thank you for your business!", method, chkRef);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Month −3 (6 paid) ─────────────────────────────────────────────────
|
||||
await Inv(InvoiceStatus.Paid, 88, 30, 0m, "Net 30", "Thank you for your business!", PaymentMethod.BankTransferACH);
|
||||
await Inv(InvoiceStatus.Paid, 84, 30, 7.5m, "Net 30", "Thank you for your business!", PaymentMethod.Check, "CHK-1041");
|
||||
@@ -201,12 +218,15 @@ public partial class SeedDataService
|
||||
await Inv(InvoiceStatus.PartiallyPaid, 40, 30, 0m, "Net 30", "50% deposit received — balance due.", PaymentMethod.Check, "CHK-1053");
|
||||
await Inv(InvoiceStatus.PartiallyPaid, 37, 30, 7.5m, "Net 30", "Deposit on file — balance due on pickup.", PaymentMethod.BankTransferACH);
|
||||
|
||||
// ── Month −1 (5 paid + 2 partial + 2 sent) ───────────────────────────
|
||||
await Inv(InvoiceStatus.Paid, 32, 30, 0m, "Net 30", "Thank you!", PaymentMethod.BankTransferACH);
|
||||
await Inv(InvoiceStatus.Paid, 28, 30, 7.5m, "Net 30", "Thank you for your business!", PaymentMethod.Check, "CHK-1056");
|
||||
await Inv(InvoiceStatus.Paid, 24, 14, 0m, "Net 14", "Thank you!", PaymentMethod.Cash);
|
||||
await Inv(InvoiceStatus.Paid, 20, 30, 7.5m, "Net 30", "Thank you for your business!", PaymentMethod.BankTransferACH);
|
||||
await Inv(InvoiceStatus.Paid, 16, 30, 0m, "Net 30", "Thank you!", PaymentMethod.CreditDebitCard);
|
||||
// ── Month −1 (7 paid + 2 partial + 2 sent) ───────────────────────────
|
||||
// 7 paid × avg ~$650 + 2 partial × 50% × avg ~$650 ≈ $5,200 collected — above expenses.
|
||||
await Inv(InvoiceStatus.Paid, 35, 30, 0m, "Net 30", "Thank you for your business!", PaymentMethod.BankTransferACH);
|
||||
await Inv(InvoiceStatus.Paid, 32, 30, 7.5m, "Net 30", "Thank you!", PaymentMethod.Check, "CHK-1054");
|
||||
await Inv(InvoiceStatus.Paid, 28, 30, 0m, "Net 30", "Thank you for your business!", PaymentMethod.BankTransferACH);
|
||||
await Inv(InvoiceStatus.Paid, 24, 14, 7.5m, "Net 14", "Thank you!", PaymentMethod.Cash);
|
||||
await Inv(InvoiceStatus.Paid, 20, 30, 0m, "Net 30", "Thank you for your business!", PaymentMethod.BankTransferACH);
|
||||
await Inv(InvoiceStatus.Paid, 18, 30, 7.5m, "Net 30", "Thank you!", PaymentMethod.CreditDebitCard);
|
||||
await Inv(InvoiceStatus.Paid, 16, 30, 0m, "Net 30", "Thank you for your business!", PaymentMethod.Check, "CHK-1058");
|
||||
await Inv(InvoiceStatus.PartiallyPaid, 14, 30, 7.5m, "Net 30", "50% deposit received.", PaymentMethod.Check, "CHK-1060");
|
||||
await Inv(InvoiceStatus.PartiallyPaid, 11, 30, 0m, "Net 30", "50% deposit — balance due on completion.", PaymentMethod.BankTransferACH);
|
||||
await Inv(InvoiceStatus.Sent, 9, 30, 7.5m, "Net 30", "Payment due within 30 days.");
|
||||
|
||||
Reference in New Issue
Block a user