Files
PowderCoatingLogix/src/PowderCoating.Infrastructure/Services/SeedDataService.ReleaseNotes.cs
T
2026-04-23 21:38:24 -04:00

90 lines
4.4 KiB
C#

using Microsoft.EntityFrameworkCore;
using PowderCoating.Core.Entities;
namespace PowderCoating.Infrastructure.Services;
public partial class SeedDataService
{
/// <summary>
/// Seeds platform-level release notes (changelog entries) that are displayed to all
/// tenants in the What's New / Release Notes section. Safe to call repeatedly —
/// each version string is checked individually and skipped if it already exists,
/// so new entries can be added to the list over time without re-inserting old ones.
/// </summary>
/// <remarks>
/// <para>
/// Unlike other seed methods, this one does NOT use <c>IgnoreQueryFilters()</c> because
/// release notes are global platform records with no <c>CompanyId</c> tenant filter, so
/// the default query already sees all rows.
/// </para>
/// <para>
/// The idempotency check is per-version (not a blanket "any rows exist?" guard) so that
/// future versions can be appended to the <c>notes</c> list and seeded incrementally.
/// </para>
/// <para>
/// This method is <c>public</c> because it is callable from the Platform Management →
/// Seed Data UI independently of company-scoped operations.
/// </para>
/// </remarks>
/// <returns>Number of new release note entries inserted, or 0 if all versions already exist.</returns>
public async Task<int> SeedReleaseNotesAsync()
{
var existingVersions = (await _context.ReleaseNotes
.Select(r => r.Version)
.ToListAsync())
.ToHashSet();
var notes = new List<ReleaseNote>
{
new()
{
Version = "2.1.0",
Title = "AI Accounting Suite, Cash Flow Forecast & Anomaly Detection",
Tag = "Feature",
IsPublished = true,
ReleasedAt = new DateTime(2026, 4, 4, 0, 0, 0, DateTimeKind.Utc),
CreatedAt = DateTime.UtcNow,
Body = """
## What's New
### AI Accounting Features
Four new AI-powered tools to save time and catch problems:
- **Receipt Scanning** Upload a photo or PDF receipt when creating a bill. AI extracts the vendor, date, invoice number, total, and line items, and attaches the file automatically.
- **Smart Account Categorisation** As you type each bill line item description, the system silently suggests the best expense account. No button to click it fills in as you work.
- **AR Follow-up Email Drafts** On the AR Aging report, click *Draft Reminder* next to any overdue customer. AI writes a professional collections email with tone that scales from gentle (30 days) to serious (60+ days).
- **Plain-English Financial Summary** In Full Analytics, click *Generate AI Summary* for a short, readable paragraph explaining what your numbers mean this period.
### Cash Flow Forecast *(New Report)*
- Projects your 30, 60, and 90-day cash position
- Factors in open AR invoices (with each customer's historical average days-to-pay), outstanding bills, and your active job pipeline
- Displays an overall outlook Strong, Moderate, Tight, or Concerning with plain-English insights per period
### Anomaly Detection *(New Report)*
- Scans your last 90 days of bills for duplicate entries, unusual amounts, and expense accounts running above their historical average
- Flags ranked by severity: Critical, Warning, Info
- Each flag includes a plain-English description and a recommended action
### Bills / Expenses Unified List
- Bills and Expenses are now combined under **Bills / Expenses** in the navigation
- Single *New* split-button to create either type
- Type filter to view all entries, bills only, or expenses only
### Other Improvements
- Bills now save as **Open** by default Record Payment is available immediately without a status change
- New **I Already Paid This** toggle on the bill create form records the bill and payment in one step
- PDF receipts are now accepted everywhere image receipts were previously supported
- Reports landing page reorganised into two clear sections: Charts & Dashboards, and Detailed Reports
"""
},
};
var toAdd = notes.Where(n => !existingVersions.Contains(n.Version)).ToList();
if (toAdd.Count == 0) return 0;
_context.ReleaseNotes.AddRange(toAdd);
await _context.SaveChangesAsync();
return toAdd.Count;
}
}