Add 4 AI bookkeeping features
Feature 7: Bank Rec Auto-Match — AiSuggestMatches endpoint scores uncleared transactions vs statement ending balance; AI Auto-Match panel in Reconcile.cshtml with confidence highlights and Apply All button. Feature 8: Late Payment Prediction — PredictLatePayments endpoint scores open AR customers by risk (high/medium/low) using historical avg-days-to-pay + late rate; rendered as badge table in AR Aging view via ar-aging-ai.js. Feature 9: Natural Language Financial Queries — FinancialQuery GET page + RunFinancialQuery POST; 12-month context snapshot pre-loaded; answers grounded in real data with supporting facts, follow-up suggestions, session history, and example chips. Feature 10: Recurring Bill Detection — RunRecurringDetection scans 12 months of bills for vendor payment patterns (monthly/quarterly/annual); card grid view in Bills/RecurringDetection.cshtml with confidence badges, next-expected-date, and suggested actions. Supporting: 4 new DTO groups in AccountingAiDtos.cs, 4 method signatures in IAccountingAiService.cs, 4 implementations in AccountingAiService.cs, 4 new AiFeatures constants, 2 new Landing page AI report cards. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1136,6 +1136,68 @@ public class BillsController : Controller
|
||||
return Json(result);
|
||||
}
|
||||
|
||||
// ── AI: Recurring Bill Detection ──────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// GET page — displays the recurring bill detection tool. No data is pre-fetched here;
|
||||
/// the user triggers the scan by clicking a button which calls <see cref="RunRecurringDetection"/>.
|
||||
/// </summary>
|
||||
public IActionResult RecurringDetection() => View();
|
||||
|
||||
/// <summary>
|
||||
/// AJAX POST — loads up to 12 months of bill history for the company and passes it to
|
||||
/// Claude for recurring pattern analysis. Only posted bills (Draft/Open/Partial/Paid) are
|
||||
/// included; Voided bills are excluded so cancelled payments do not distort the pattern.
|
||||
/// Results are returned as JSON for client-side rendering in the view.
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[EnableRateLimiting(AppConstants.RateLimitPolicies.Ai)]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> RunRecurringDetection()
|
||||
{
|
||||
try
|
||||
{
|
||||
var companyId = int.TryParse(User.FindFirst("CompanyId")?.Value, out var cid) ? cid : 0;
|
||||
var cutoff = DateTime.Today.AddMonths(-12);
|
||||
|
||||
var bills = (await _unitOfWork.Bills.GetAllAsync(false, b => b.Vendor))
|
||||
.Where(b => b.Status != BillStatus.Voided && b.BillDate >= cutoff)
|
||||
.ToList();
|
||||
|
||||
if (!bills.Any())
|
||||
return Json(new RecurringBillDetectionResult
|
||||
{
|
||||
Success = true,
|
||||
Insights = new List<string> { "No bill history found in the last 12 months." }
|
||||
});
|
||||
|
||||
var companyName = (await _unitOfWork.Companies.GetByIdAsync(companyId))?.CompanyName ?? "Your Company";
|
||||
|
||||
var request = new RecurringBillDetectionRequest
|
||||
{
|
||||
CompanyName = companyName,
|
||||
Bills = bills.Select(b => new RecurringBillHistoryItem
|
||||
{
|
||||
VendorName = b.Vendor?.CompanyName ?? $"Vendor #{b.VendorId}",
|
||||
BillNumber = b.BillNumber,
|
||||
Amount = b.Total,
|
||||
DateIso = b.BillDate.ToString("yyyy-MM-dd"),
|
||||
Memo = b.Memo
|
||||
}).ToList()
|
||||
};
|
||||
|
||||
var result = await _accountingAi.DetectRecurringBillsAsync(request);
|
||||
var userId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value ?? "";
|
||||
await _usageLogger.LogAsync(companyId, userId, AppConstants.AiFeatures.RecurringBillDetection, result.Success);
|
||||
return Json(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error running recurring bill detection");
|
||||
return Json(new RecurringBillDetectionResult { Success = false, ErrorMessage = "An error occurred while analyzing bill patterns." });
|
||||
}
|
||||
}
|
||||
|
||||
// ── Receipt File Helpers ──────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user