[PM-39236]: Add RenewalNotificationSentDate column + repository method#8031
[PM-39236]: Add RenewalNotificationSentDate column + repository method#8031sbrown-livefront wants to merge 22 commits into
Conversation
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE Reviewed the addition of the nullable Code Review DetailsNo new findings. The change is consistent across all four providers:
All issues raised in earlier review threads (view refresh, |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8031 +/- ##
===========================================
+ Coverage 14.96% 66.85% +51.89%
===========================================
Files 1389 2293 +904
Lines 60360 99966 +39606
Branches 4793 9019 +4226
===========================================
+ Hits 9030 66831 +57801
+ Misses 51175 30866 -20309
- Partials 155 2269 +2114 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…nt stored procedure
kdenney
left a comment
There was a problem hiding this comment.
Thanks for answering my question; looks good to me. Nice job!
There was a problem hiding this comment.
Pull request overview
Adds a nullable RenewalNotificationSentDate field to OrganizationPlanMigrationCohortAssignment across schema/migrations, and introduces a repository query to fetch cohort assignments eligible for renewal-invoice notifications within a configurable expiration window.
Changes:
- Added
RenewalNotificationSentDatecolumn plus backfill-from-ScheduledDatein migrations (MSSQL script + EF migrations for SQLite/Postgres/MySQL). - Added
GetSendInvoiceCandidatesInWindowAsync(minDays, maxDays)to repository interface and implemented it for both Dapper (new stored proc) and EF Core. - Added multi-provider integration tests covering inclusion/exclusion criteria for the new candidate-selection query.
Reviewed changes
Copilot reviewed 16 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| util/SqliteMigrations/Migrations/DatabaseContextModelSnapshot.cs | Adds RenewalNotificationSentDate to SQLite EF snapshot. |
| util/SqliteMigrations/Migrations/20260717173646_AddRenewalNotificationSentDateToOrganizationPlanMigrationCohortAssignment.Designer.cs | SQLite migration designer reflecting the new column. |
| util/SqliteMigrations/Migrations/20260717173646_AddRenewalNotificationSentDateToOrganizationPlanMigrationCohortAssignment.cs | SQLite EF migration adding column + backfill SQL. |
| util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs | Adds RenewalNotificationSentDate to Postgres EF snapshot. |
| util/PostgresMigrations/Migrations/20260717173652_AddRenewalNotificationSentDateToOrganizationPlanMigrationCohortAssignment.Designer.cs | Postgres migration designer reflecting the new column. |
| util/PostgresMigrations/Migrations/20260717173652_AddRenewalNotificationSentDateToOrganizationPlanMigrationCohortAssignment.cs | Postgres EF migration adding column + backfill SQL. |
| util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs | Adds RenewalNotificationSentDate to MySQL EF snapshot. |
| util/MySqlMigrations/Migrations/20260717173659_AddRenewalNotificationSentDateToOrganizationPlanMigrationCohortAssignment.cs | MySQL EF migration adding column + backfill SQL. |
| util/Migrator/DbScripts/2026-07-17_00_AddRenewalNotificationSentDateToOrganizationPlanMigrationCohortAssignment.sql | MSSQL migration script: adds column, refreshes SELECT * view, backfills, updates create/update procs, adds read-many proc. |
| src/Sql/dbo/Billing/Tables/OrganizationPlanMigrationCohortAssignment.sql | SSDT table definition updated to include the new nullable column. |
| src/Sql/dbo/Billing/Stored Procedures/OrganizationPlanMigrationCohortAssignment_Create.sql | SSDT create proc updated to accept/persist RenewalNotificationSentDate. |
| src/Sql/dbo/Billing/Stored Procedures/OrganizationPlanMigrationCohortAssignment_Update.sql | SSDT update proc updated to accept/persist RenewalNotificationSentDate. |
| src/Sql/dbo/Billing/Stored Procedures/OrganizationPlanMigrationCohortAssignment_ReadManyByExpirationDateRange.sql | New stored proc to select invoice-notification candidates by expiration window. |
| src/Core/Billing/Organizations/PlanMigration/Entities/OrganizationPlanMigrationCohortAssignment.cs | Core entity updated with RenewalNotificationSentDate. |
| src/Core/Billing/Organizations/PlanMigration/Repositories/IOrganizationPlanMigrationCohortAssignmentRepository.cs | Interface extended with GetSendInvoiceCandidatesInWindowAsync. |
| src/Infrastructure.Dapper/Billing/Repositories/OrganizationPlanMigrationCohortAssignmentRepository.cs | Dapper implementation added for the new candidate query. |
| src/Infrastructure.EntityFramework/Billing/Repositories/OrganizationPlanMigrationCohortAssignmentRepository.cs | EF implementation added for the new candidate query (needs fix per comments). |
| test/Infrastructure.IntegrationTest/Billing/Repositories/OrganizationPlanMigrationCohortAssignmentRepositoryTests.cs | New integration tests for the candidate-selection query and edge cases. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-39236
📔 Objective
Adds the nullable
RenewalNotificationSentDatecolumn toOrganizationPlanMigrationCohortAssignmentand a repository method to select the organizations that are candidates for a renewal-invoice notification.Schema (both ORM tracks)
RenewalNotificationSentDate DATETIME2(7)column onOrganizationPlanMigrationCohortAssignment— added to the entity, the SSDT table, the Dapper_Create/_Updatestored procedures, and generated for EF Core (PostgreSQL, MySQL, SQLite).RenewalNotificationSentDate = ScheduledDatewhereScheduledDate IS NOT NULL, so organizations already processed via thecharge_automaticallypath read as notified rather than incomplete. The EF migrations perform the equivalent backfill for the other three providers.OrganizationPlanMigrationCohortAssignmentView(sp_refreshview) after theALTER TABLE, since thatSELECT *view (and the read procs built on it) caches its column list and would otherwise not surface the new column.Repository method
GetSendInvoiceCandidatesInWindowAsync(int minDays, int maxDays)onIOrganizationPlanMigrationCohortAssignmentRepository, implemented in both Dapper (newOrganizationPlanMigrationCohortAssignment_ReadManyByExpirationDateRangestored procedure) and EF Core.MigratedDate IS NULL, the assignment is not-yet-complete (ScheduledDate IS NULL OR RenewalNotificationSentDate IS NULL), the organization has non-nullGatewayCustomerId/GatewaySubscriptionId, andExpirationDatefalls within[now + minDays, now + maxDays].Tests
[DatabaseData]integration tests (run against all four providers) covering the happy path plus each exclusion clause: inactive cohort, migrated assignment, scheduled-but-not-notified (included) vs. scheduled-and-notified (excluded), missing gateway identifiers, and expiration before/after the window and null.