Skip to content
Merged

Dev #2080

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8fe257a
AB#26878: Applicant Profile History Tab - Initial Draft
aurelio-aot Feb 27, 2026
c6cce84
AB#26878: Set font size standard for $ symbol for currencies
aurelio-aot Feb 28, 2026
3dc5b40
AB#26878: Applicant Profile Funding History Fix Bugs and Layout
aurelio-aot Feb 28, 2026
44d3ffc
bugfix/AB#31179-FailedPayments One day only UTC
JamesPasta Mar 2, 2026
c8aaadc
Merge pull request #2073 from bcgov/bugfix/AB#31179-FailedPaymentsUtc…
JamesPasta Mar 2, 2026
9fb4cc9
AB#26878: Fix bugs on Applicant Profile History Tab
aurelio-aot Mar 2, 2026
d4451a5
AB#26878: Fix bug on audit date display
aurelio-aot Mar 2, 2026
2cbca56
AB#32011 Refactor AI prompt plumbing into shared prompt components
jacobwillsmith Feb 27, 2026
743dbbb
AB#32011 Wire OpenAIService to structured prompt modules
jacobwillsmith Mar 3, 2026
af033ed
AB#26878: Set column widths to data table columns
aurelio-aot Mar 3, 2026
052c2fb
fetaure/AB#28147-Location-Data-Update This is a minor correction to c…
Stephan-McColm Mar 3, 2026
ff15ee4
Merge pull request #2076 from bcgov/feature/AB#28147-Location-Data-Up…
DarylTodosichuk Mar 3, 2026
a727e1f
feature/AB#32030-FixDuplicateState
JamesPasta Mar 3, 2026
7afdd86
feature/AB#32030-FixDuplicateState
JamesPasta Mar 3, 2026
f445205
Merge pull request #2078 from bcgov/feature/AB#32030-FixDuplicateData…
DavidBrightBcGov Mar 3, 2026
311c6e7
AB#26878: Mandatory fields on Applicant Profile - History Tab
aurelio-aot Mar 3, 2026
9cdade2
AB#26878: Update labels as per Acceptance Criteria
aurelio-aot Mar 3, 2026
87ffcea
Converted tags from pl-3 pt-3 to p-3
DavidBrightBcGov Mar 3, 2026
e391f49
Merge pull request #2079 from bcgov/bugfix/AB#31675-padding-fix
DavidBrightBcGov Mar 3, 2026
097b434
Merge pull request #2075 from bcgov/feature/AB#32011-RefactorAIPrompt…
JamesPasta Mar 3, 2026
a82daab
Merge pull request #2072 from bcgov/feature/AB#26878-ApplicantProfile…
JamesPasta Mar 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,12 @@ public async Task<List<PaymentRequest>> GetPaymentRequestsBySentToCasStatusAsync

public async Task<List<PaymentRequest>> GetPaymentRequestsByFailedsStatusAsync()
{
// LastModificationTime is stored as UTC by ABP; use UtcNow for consistent 24-hour window
var cutoff = DateTime.UtcNow.AddDays(-1);
var dbSet = await GetDbSetAsync();
return await dbSet.Where(p => p.InvoiceStatus != null
&& FailedStatusList.Contains(p.InvoiceStatus)
&& p.LastModificationTime >= DateTime.Now.AddDays(-2)).IncludeDetails().ToListAsync();
&& p.LastModificationTime >= cutoff).IncludeDetails().ToListAsync();
}

public override async Task<IQueryable<PaymentRequest>> WithDetailsAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ table.dataTable {
margin-top: 32px;
margin-left: 12px;
color: var(--bc-colors-grey-text-300);
font-size: var(--bc-font-size);
}

.unity-input-group input {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using Volo.Abp.Application.Dtos;

namespace Unity.GrantManager.ApplicantProfile;

public class AuditHistoryDto : AuditedEntityDto<Guid>
{
public Guid? ApplicantId { get; set; }
public string? AuditTrackingNumber { get; set; }
public DateTime? AuditDate { get; set; }
public string? AuditNote { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace Unity.GrantManager.ApplicantProfile;

public class CreateUpdateAuditHistoryDto
{
public Guid? ApplicantId { get; set; }
public string? AuditTrackingNumber { get; set; }
public DateTime? AuditDate { get; set; }
public string? AuditNote { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace Unity.GrantManager.ApplicantProfile;

public class CreateUpdateFundingHistoryDto
{
public Guid? ApplicantId { get; set; }
public string? GrantCategory { get; set; }
public int? FundingYear { get; set; }
public bool? RenewedFunding { get; set; }
public decimal? ApprovedAmount { get; set; }
public decimal? ReconsiderationAmount { get; set; }
public decimal? TotalGrantAmount { get; set; }
public string? FundingNotes { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace Unity.GrantManager.ApplicantProfile;

public class CreateUpdateIssueTrackingDto
{
public Guid? ApplicantId { get; set; }
public int? Year { get; set; }
public string? IssueHeading { get; set; }
public string? IssueDescription { get; set; }
public bool? Resolved { get; set; }
public string? ResolutionNote { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using Volo.Abp.Application.Dtos;

namespace Unity.GrantManager.ApplicantProfile;

public class FundingHistoryDto : AuditedEntityDto<Guid>
{
public Guid? ApplicantId { get; set; }
public string? GrantCategory { get; set; }
public int? FundingYear { get; set; }
public bool? RenewedFunding { get; set; }
public decimal? ApprovedAmount { get; set; }
public decimal? ReconsiderationAmount { get; set; }
public decimal? TotalGrantAmount { get; set; }
public string? FundingNotes { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace Unity.GrantManager.ApplicantProfile;

public interface IApplicantHistoryAppService : IApplicationService
{
Task<List<FundingHistoryDto>> GetFundingHistoryListAsync(Guid applicantId);
Task<FundingHistoryDto> GetFundingHistoryAsync(Guid id);
Task<FundingHistoryDto> CreateFundingHistoryAsync(CreateUpdateFundingHistoryDto input);
Task<FundingHistoryDto> UpdateFundingHistoryAsync(Guid id, CreateUpdateFundingHistoryDto input);
Task DeleteFundingHistoryAsync(Guid id);

Task<List<IssueTrackingDto>> GetIssueTrackingListAsync(Guid applicantId);
Task<IssueTrackingDto> GetIssueTrackingAsync(Guid id);
Task<IssueTrackingDto> CreateIssueTrackingAsync(CreateUpdateIssueTrackingDto input);
Task<IssueTrackingDto> UpdateIssueTrackingAsync(Guid id, CreateUpdateIssueTrackingDto input);
Task DeleteIssueTrackingAsync(Guid id);

Task<List<AuditHistoryDto>> GetAuditHistoryListAsync(Guid applicantId);
Task<AuditHistoryDto> GetAuditHistoryAsync(Guid id);
Task<AuditHistoryDto> CreateAuditHistoryAsync(CreateUpdateAuditHistoryDto input);
Task<AuditHistoryDto> UpdateAuditHistoryAsync(Guid id, CreateUpdateAuditHistoryDto input);
Task DeleteAuditHistoryAsync(Guid id);

Task SaveNotesAsync(Guid applicantId, SaveApplicantHistoryNotesDto input);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using Volo.Abp.Application.Dtos;

namespace Unity.GrantManager.ApplicantProfile;

public class IssueTrackingDto : AuditedEntityDto<Guid>
{
public Guid? ApplicantId { get; set; }
public int? Year { get; set; }
public string? IssueHeading { get; set; }
public string? IssueDescription { get; set; }
public bool? Resolved { get; set; }
public string? ResolutionNote { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Unity.GrantManager.ApplicantProfile;

public class SaveApplicantHistoryNotesDto
{
public string? FundingHistoryComments { get; set; }
public string? IssueTrackingComments { get; set; }
public string? AuditComments { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,23 +160,11 @@ public async Task<string> GenerateAttachmentSummaryAsync(string fileName, byte[]
{
var extractedText = await _textExtractionService.ExtractTextAsync(fileName, fileContent, contentType);

var prompt = @"ROLE
You are a professional grant analyst for the BC Government.
var prompt = $@"{AttachmentPrompts.SystemPrompt}

TASK
Produce a concise reviewer-facing summary of the provided attachment context.
{AttachmentPrompts.OutputSection}

OUTPUT
- Plain text only
- 1-2 complete sentences

RULES
- Use only the provided attachment context as evidence.
- If text content is present, summarize the actual content.
- If text content is missing or empty, provide a conservative metadata-based summary.
- Do not invent missing details.
- Keep the summary specific, concrete, and reviewer-facing.
- Return plain text only (no markdown, bullets, or JSON).";
{AttachmentPrompts.RulesSection}";

var attachmentText = string.IsNullOrWhiteSpace(extractedText) ? null : extractedText;
if (attachmentText != null)
Expand All @@ -195,7 +183,8 @@ Produce a concise reviewer-facing summary of the provided attachment context.
sizeBytes = fileContent.Length,
text = attachmentText
};
var contentToAnalyze = $"ATTACHMENT\n{JsonSerializer.Serialize(attachmentPayload, JsonLogOptions)}";
var contentToAnalyze = AttachmentPrompts.BuildUserPrompt(
JsonSerializer.Serialize(attachmentPayload, JsonLogOptions));

await LogPromptInputAsync("AttachmentSummary", prompt, contentToAnalyze);
var modelOutput = await GenerateSummaryAsync(contentToAnalyze, prompt, 150);
Expand Down Expand Up @@ -257,76 +246,13 @@ public async Task<string> AnalyzeApplicationAsync(string applicationContent, Lis
.Cast<object>()
: Enumerable.Empty<object>();

var analysisContent = $@"SCHEMA
{JsonSerializer.Serialize(schemaPayload, JsonLogOptions)}

DATA
{JsonSerializer.Serialize(dataPayload, JsonLogOptions)}

ATTACHMENTS
{JsonSerializer.Serialize(attachmentsPayload, JsonLogOptions)}

RUBRIC
{rubric}

SEVERITY
ERROR: Issue that would likely prevent the application from being approved.
WARNING: Issue that could negatively affect the application's approval.
RECOMMENDATION: Reviewer-facing improvement or follow-up consideration.

SCORE
HIGH: Application demonstrates strong evidence across most rubric areas with few or no issues.
MEDIUM: Application has some gaps or weaknesses that require reviewer attention.
LOW: Application has significant gaps or risks across key rubric areas.

OUTPUT
{{
""rating"": ""HIGH/MEDIUM/LOW"",
""warnings"": [
{{
""category"": ""Brief summary of the warning"",
""message"": ""Detailed warning message with full context and explanation""
}}
],
""errors"": [
{{
""category"": ""Brief summary of the error"",
""message"": ""Detailed error message with full context and explanation""
}}
],
""summaries"": [
{{
""category"": ""Brief summary of the recommendation"",
""message"": ""Detailed recommendation with specific actionable guidance""
}}
],
""dismissed"": []
}}
var analysisContent = AnalysisPrompts.BuildUserPrompt(
JsonSerializer.Serialize(schemaPayload, JsonLogOptions),
JsonSerializer.Serialize(dataPayload, JsonLogOptions),
JsonSerializer.Serialize(attachmentsPayload, JsonLogOptions),
rubric);

RULES
- Use only SCHEMA, DATA, ATTACHMENTS, and RUBRIC as evidence.
- Do not invent fields, documents, requirements, or facts.
- Treat missing or empty values as findings only when they weaken rubric evidence.
- Prefer material issues; avoid nitpicking.
- Each error/warning/recommendation must describe one concrete issue or consideration and why it matters.
- Use 3-6 words for category.
- Each message must be 1-2 complete sentences.
- Each message must be grounded in concrete evidence from provided inputs.
- If attachment evidence is used, reference the attachment explicitly in the message.
- Do not provide applicant-facing advice.
- Do not mention rubric section names in findings.
- If no findings exist, return empty arrays.
- rating must be HIGH, MEDIUM, or LOW.
- Return values exactly as specified in OUTPUT.
- Do not return keys outside OUTPUT.
- Return valid JSON only.
- Return plain JSON only (no markdown).";

var systemPrompt = @"ROLE
You are an expert grant analyst assistant for human reviewers.

TASK
Using SCHEMA, DATA, ATTACHMENTS, RUBRIC, SEVERITY, SCORE, OUTPUT, and RULES, return review findings.";
var systemPrompt = AnalysisPrompts.SystemPrompt;

await LogPromptInputAsync("ApplicationAnalysis", systemPrompt, analysisContent);
var rawAnalysis = await GenerateSummaryAsync(analysisContent, systemPrompt, 1000);
Expand Down Expand Up @@ -503,53 +429,12 @@ public async Task<string> GenerateScoresheetSectionAnswersAsync(string applicati
questions = sectionQuestionsPayload
};

var analysisContent = $@"DATA
{applicationContent}

ATTACHMENTS
- {attachmentSummariesText}

SECTION
{JsonSerializer.Serialize(sectionPayload, JsonLogOptions)}

RESPONSE
{{
""<question_id>"": {{
""answer"": ""<string | number>"",
""rationale"": ""<evidence-based rationale>"",
""confidence"": 85
}}
}}
var analysisContent = ScoresheetPrompts.BuildSectionUserPrompt(
applicationContent,
attachmentSummariesText,
JsonSerializer.Serialize(sectionPayload, JsonLogOptions));

RULES
- Use only DATA and ATTACHMENTS as evidence.
- Do not invent missing application details.
- Return exactly one answer object per question ID in SECTION.questions.
- Do not omit any question IDs from SECTION.questions.
- Do not add keys that are not question IDs from SECTION.questions.
- Use RESPONSE as the output contract and fill every placeholder value.
- Each answer object must include: answer, rationale, confidence.
- answer type must match question type: Number => numeric; YesNo/SelectList/Text/TextArea => string.
- For yes/no questions, answer must be exactly ""Yes"" or ""No"".
- For numeric questions, answer must be a numeric value within the allowed range.
- For select list questions, answer must be the selected availableOptions.number encoded as a string.
- For select list questions, never return option label text (for example: ""Yes"", ""No"", or ""N/A""); return the option number string.
- For text and text area questions, answer must be concise, grounded in evidence, and non-empty.
- rationale must be 1-2 complete sentences grounded in concrete DATA/ATTACHMENTS evidence.
- For every question, rationale must justify both the selected answer and confidence level based on evidence strength.
- If evidence is insufficient, choose the most conservative valid answer and state uncertainty in rationale.
- confidence must be an integer from 0 to 100.
- Confidence reflects certainty in the selected answer given available evidence, not application quality.
- Return values exactly as specified in RESPONSE.
- Do not return keys outside RESPONSE.
- Return valid JSON only.
- Return plain JSON only (no markdown).";

var systemPrompt = @"ROLE
You are an expert grant application reviewer for the BC Government.

TASK
Using DATA, ATTACHMENTS, SECTION, RESPONSE, and RULES, answer only the questions in SECTION.";
var systemPrompt = ScoresheetPrompts.SectionSystemPrompt;

await LogPromptInputAsync("ScoresheetSection", systemPrompt, analysisContent);
var modelOutput = await GenerateSummaryAsync(analysisContent, systemPrompt, 2000);
Expand Down
Loading
Loading