mirror of
https://github.com/bitwarden/server.git
synced 2026-06-01 01:55:55 -05:00
ci/github-code-coverage-upload
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d07a941896 |
[PM-37092] feat: Add business plan migration handler to SubscriptionUpdatedHandler (#7707)
* feat(billing): add Organization.ChangePlan extension for structural plan shape Pure helper that writes plan-derived structural columns (PlanType, Plan, Use* capability flags, UsersGetPremium, MaxCollections) without touching customer-purchase columns. Preserves the existing UseKeyConnector carve-out. Behavior-preserving extraction of the field-copy block at lines 287-310 of UpgradeOrganizationPlanCommand.UpgradePlanAsync. * refactor(billing): use Organization.ChangePlan in UpgradePlanAsync Replaces the inline structural field-copy block with a call to the new ChangePlan helper. Customer-purchase columns (Seats, MaxStorageGb, Enabled, UseSecretsManager) and the PremiumAccessAddon override on UsersGetPremium stay inline at the call site. Behavior-preserving. * feat(billing): register Teams 2020 -> current migration paths Appends Teams2020AnnualToCurrent (byte 3) and Teams2020MonthlyToCurrent (byte 4) to MigrationPathId and the MigrationPaths registry. Required for the business migration handler to resolve cohorts mapped to Teams source plans; without these entries MigrationPaths.FromId returns null and the handler no-ops on Teams orgs in Cohort A1. Snapshot tests updated. * chore(billing): inject migration cohort repositories into SubscriptionUpdatedHandler Adds IOrganizationPlanMigrationCohortRepository and IOrganizationPlanMigrationCohortAssignmentRepository as constructor dependencies in preparation for HandleScheduleTriggeredBusinessMigrationAsync. No behavior change. * feat(billing): scaffold business plan Phase-2 migration handler Adds HandleScheduleTriggeredBusinessMigrationAsync as a sibling call in HandleAsync's organization branch, gated on PM35215_BusinessPlanPriceMigration. Initial implementation short-circuits when ScheduleId is null. Locks the no-op behaviour with NoScheduleId + FeatureFlagOff tests. Full handler body lands in subsequent commits. * feat(billing): gate business migration handler on registered source price IDs Builds the source-price allowlist from MigrationPaths.All, using the seat-vs-non-seat pattern (HasNonSeatBasedPasswordManagerPlan). All four Track A 2020 plans register automatically. Skips when the previous subscription items don't include any registered 2020 source price. * feat(billing): resolve cohort via assignment row for business migration handler Reads assignment by organization id (DB is source of truth), then resolves the cohort and migration path. Stripe subscription.Metadata['migration_cohort_id'] remains stamped by PriceIncreaseScheduler for dashboard attribution but is not consulted by the handler. Skips with a warning when the assignment is missing, the cohort is missing, or MigrationPathId references an unregistered path. Idempotent: skips with info-level log when assignment.MigratedDate is already set, before any further DB reads. * feat(billing): defensive target-price sanity check for business migration After resolving the target plan from cohort.MigrationPath.ToPlan, verifies the current subscription items contain the target's PM price ID (seat-aware). Skips with a warning on mismatch to protect against operator data errors or off-path schedule transitions. * feat(billing): apply plan shape and mark assignment migrated on Phase 2 Completes HandleScheduleTriggeredBusinessMigrationAsync: loads the org, calls Organization.ChangePlan(targetPlan), persists via ReplaceAsync, and sets assignment.MigratedDate + RevisionDate before persisting the assignment. Happy-path coverage for all four Track A pairs (Teams + Enterprise, monthly + annual). Teams tests assert the UseScim flip - the load-bearing capability gain for Teams 2020 -> current. * Add more unit test * fix: add UTF-8 BOM to .cs files for editorconfig charset compliance * Add exception handle * Code refactoring * Add more unit testing * Resolve the pr comment |
||
|
|
b1395aafbe |
[PM-37083] feat: Add per-phase price resolution to UpdateOrganizationSubscriptionCommand (#7695)
* [PM-37083] feat: Add per-phase price resolution to UpdateOrganizationSubscriptionCommand Resolve source vs. target plan pricing per schedule phase so item changes target the correct phase-specific price ID. Move cohort metadata onto the schedule phases themselves to avoid Stripe normalization triggered by direct subscription metadata updates. Filter the schedule-aware update path to phases where EndDate > now, and drop the feature-flag gate on PriceIncreaseScheduler.Release so schedule existence is the gate. * Add defensive guard for source-priced single-phase migration schedules |
||
|
|
761d8d055a |
[PM-36964] Add per-org migration cohort assignment to the Admin portal (#7681)
* [PM-36949] Add OrganizationPlanMigrationCohort schema and Core domain types Add the foundation for cohort-based plan migrations: - Two tables: OrganizationPlanMigrationCohort and OrganizationPlanMigrationCohortAssignment - Two views and nine stored procedures (four CRUD on cohort, four CRUD plus ReadByOrganizationId on assignment) - Single Migrator script for MSSQL deployment - Core entities, MigrationPath value object and its registry, and bare repository interfaces under Bit.Core.Billing.Organizations.PlanMigration The cohort table holds the human-managed metadata (name, discount coupons, MigrationPathId byte) and the assignment table records each organization's position in the migration lifecycle (scheduled, migrated, churn-mitigated). Both Update SPs follow the accept-but-don't-assign pattern: immutable columns (OrganizationId, CohortId, CreatedAt) are parameters but not SET clauses. * [PM-36949] Add Dapper repositories for plan migration cohort tables OrganizationPlanMigrationCohortRepository inherits the base Repository<T, TId> CRUD methods unchanged. OrganizationPlanMigrationCohortAssignmentRepository also relies on the base for CRUD and adds GetByOrganizationIdAsync which returns at most one row (the UNIQUE constraint on OrganizationId at the database layer guarantees this). * [PM-36949] Add EF Core configurations, repositories, and provider migrations for plan migration cohort tables - EF models wrap the Core entities; the assignment model exposes nav properties for Organization and Cohort so the FK + cascade-delete is inferred by EF. - EntityTypeConfiguration classes pin ID generation to application code (ValueGeneratedNever) and declare the UNIQUE indexes plus the composite (CohortId, ScheduledAt, MigratedAt) index. - Repositories follow the OrganizationInstallationRepository template; the assignment repo adds GetByOrganizationIdAsync to mirror the SP exposed on the MSSQL side. - DatabaseContext gets two DbSet properties; auto-discovery picks up the configuration classes. - Generated migrations for MySQL, Postgres, and SQLite create matching schemas; EF truncates FK and index names on providers with 64-char identifier limits, which is consistent with the rest of the codebase. * [PM-36949] Wire up DI and add tests for plan migration cohort repositories Register both Dapper and EF Core repositories in their respective service collection extensions, following the existing AddSingleton convention in these files. Add tests: - MigrationPathIdsSnapshotTests guards the immortal byte IDs that downstream code pins on. The class- and method-level comments document why these values can never be renumbered. - MigrationPathTests covers the FromId round-trip and the null-on-unknown behavior the registry promises to callers. - OrganizationPlanMigrationCohortRepositoryTests exercises CRUD, the UNIQUE Name constraint, and verifies that ReplaceAsync ignores CreatedAt mutations (per the accept-but-don't-assign Update SP). - OrganizationPlanMigrationCohortAssignmentRepositoryTests exercises CRUD, GetByOrganizationIdAsync, the UNIQUE OrganizationId constraint, cascade-delete from both Organization and Cohort, and verifies that ReplaceAsync ignores OrganizationId, CohortId, and CreatedAt mutations. * [PM-36949] Use PlanType and MigrationPathId enums on MigrationPath Replace the byte Id with a byte-backed MigrationPathId enum and replace the string FromPlan/ToPlan fields with PlanType. Persistence is unchanged -- EF normalises enum-backed properties to their underlying type in the model snapshot, and Dapper handles enum-to-byte parameter mapping automatically. * [PM-36949] Add *.lscache to .gitignore * [PM-36949] fix: Override ReplaceAsync on EF cohort repositories for immutability parity The Dapper _Update SPs accept-but-don't-assign certain columns (CreatedAt on cohort; OrganizationId, CohortId, and CreatedAt on assignment), but the base EF Repository<T,TEntity,Guid>.ReplaceAsync uses SetValues which writes every scalar. Override on both repos and mark the immutable properties as IsModified = false so MySQL/Postgres/Sqlite match MSSQL behavior. Mirrors the existing DeviceRepository.ReplaceAsync pattern. * [PM-36949] fix: Bound cohort string columns and widen Name to 255 chars Add [MaxLength] attributes to the three cohort string properties so the EF providers (MySQL/Postgres/Sqlite) enforce the same limits as MSSQL, where the columns were already NVARCHAR-capped. Widen Name from 64 to 255 chars across MSSQL DDL, both _Create/_Update SP signatures, the Migrator script, the entity, and all three regenerated EF migrations. Coupon codes stay at 64 (Stripe IDs are short). * [PM-36949] test: Lock FromPlan and ToPlan per MigrationPath The snapshot test class doc says "byte N means a specific FromPlan -> ToPlan transition forever", but only the byte value was being asserted. A silent refactor of the registry's PlanType references would not have been caught. Add per-path FromPlan/ToPlan assertions to close the gap. * [PM-36949] chore: Apply dotnet format * [PM-36949] test: Use LaxDateTimeComparer for round-tripped DateTimes Postgres timestamp and MySQL datetime(6) store microsecond precision (6 fractional digits), but .NET DateTime is 100ns ticks (7 digits). Exact Assert.Equal fails by a single tick on round-trip. Switch the three DateTime comparisons in ReplaceAsync_UpdatesMutableColumns_AndIgnoresImmutableOnes to LaxDateTimeComparer.Default -- the same 2ms-tolerance comparer used by SendRepositoryTests and InstallationRepositoryTests for the same precision issue. * Add implementation for dropdown * Reconcile dropdown work with renamed PM-36949 schema After merging origin/main, the cohort schema now uses *Date suffixes (ScheduledDate / MigratedDate / ChurnDiscountAppliedDate / CreationDate). Rename references in the dropdown work, restore IsLocked() on the merged entity, and re-add GetManyAsync() to the cohort repository (interface + Dapper + EF) since the merge took main's pre-dropdown versions. Also remove the six superseded provider migration files (20260515*) -- the 20260518* renames from origin/main are now the only cohort migrations. * Fix UTF-8 BOM on cohort assignment unit test file * Resolve the FF and permission issue * Extract migration cohort resolution into a helper Addresses PR feedback to keep the Edit action focused: the cohort resolution/validation now lives in ResolveMigrationCohortAssignmentChangeAsync and returns a MigrationCohortAssignmentChange record. The endpoint still owns the page return. --------- Co-authored-by: Alex Morask <amorask@bitwarden.com> Co-authored-by: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com> |
||
|
|
d009a52f43 |
[PM-36949] feat: Add OrganizationPlanMigrationCohort and Assignment tables with bare repositories (#7644)
* [PM-36949] Add OrganizationPlanMigrationCohort schema and Core domain types Add the foundation for cohort-based plan migrations: - Two tables: OrganizationPlanMigrationCohort and OrganizationPlanMigrationCohortAssignment - Two views and nine stored procedures (four CRUD on cohort, four CRUD plus ReadByOrganizationId on assignment) - Single Migrator script for MSSQL deployment - Core entities, MigrationPath value object and its registry, and bare repository interfaces under Bit.Core.Billing.Organizations.PlanMigration The cohort table holds the human-managed metadata (name, discount coupons, MigrationPathId byte) and the assignment table records each organization's position in the migration lifecycle (scheduled, migrated, churn-mitigated). Both Update SPs follow the accept-but-don't-assign pattern: immutable columns (OrganizationId, CohortId, CreatedAt) are parameters but not SET clauses. * [PM-36949] Add Dapper repositories for plan migration cohort tables OrganizationPlanMigrationCohortRepository inherits the base Repository<T, TId> CRUD methods unchanged. OrganizationPlanMigrationCohortAssignmentRepository also relies on the base for CRUD and adds GetByOrganizationIdAsync which returns at most one row (the UNIQUE constraint on OrganizationId at the database layer guarantees this). * [PM-36949] Add EF Core configurations, repositories, and provider migrations for plan migration cohort tables - EF models wrap the Core entities; the assignment model exposes nav properties for Organization and Cohort so the FK + cascade-delete is inferred by EF. - EntityTypeConfiguration classes pin ID generation to application code (ValueGeneratedNever) and declare the UNIQUE indexes plus the composite (CohortId, ScheduledAt, MigratedAt) index. - Repositories follow the OrganizationInstallationRepository template; the assignment repo adds GetByOrganizationIdAsync to mirror the SP exposed on the MSSQL side. - DatabaseContext gets two DbSet properties; auto-discovery picks up the configuration classes. - Generated migrations for MySQL, Postgres, and SQLite create matching schemas; EF truncates FK and index names on providers with 64-char identifier limits, which is consistent with the rest of the codebase. * [PM-36949] Wire up DI and add tests for plan migration cohort repositories Register both Dapper and EF Core repositories in their respective service collection extensions, following the existing AddSingleton convention in these files. Add tests: - MigrationPathIdsSnapshotTests guards the immortal byte IDs that downstream code pins on. The class- and method-level comments document why these values can never be renumbered. - MigrationPathTests covers the FromId round-trip and the null-on-unknown behavior the registry promises to callers. - OrganizationPlanMigrationCohortRepositoryTests exercises CRUD, the UNIQUE Name constraint, and verifies that ReplaceAsync ignores CreatedAt mutations (per the accept-but-don't-assign Update SP). - OrganizationPlanMigrationCohortAssignmentRepositoryTests exercises CRUD, GetByOrganizationIdAsync, the UNIQUE OrganizationId constraint, cascade-delete from both Organization and Cohort, and verifies that ReplaceAsync ignores OrganizationId, CohortId, and CreatedAt mutations. * [PM-36949] Use PlanType and MigrationPathId enums on MigrationPath Replace the byte Id with a byte-backed MigrationPathId enum and replace the string FromPlan/ToPlan fields with PlanType. Persistence is unchanged -- EF normalises enum-backed properties to their underlying type in the model snapshot, and Dapper handles enum-to-byte parameter mapping automatically. * [PM-36949] Add *.lscache to .gitignore * [PM-36949] fix: Override ReplaceAsync on EF cohort repositories for immutability parity The Dapper _Update SPs accept-but-don't-assign certain columns (CreatedAt on cohort; OrganizationId, CohortId, and CreatedAt on assignment), but the base EF Repository<T,TEntity,Guid>.ReplaceAsync uses SetValues which writes every scalar. Override on both repos and mark the immutable properties as IsModified = false so MySQL/Postgres/Sqlite match MSSQL behavior. Mirrors the existing DeviceRepository.ReplaceAsync pattern. * [PM-36949] fix: Bound cohort string columns and widen Name to 255 chars Add [MaxLength] attributes to the three cohort string properties so the EF providers (MySQL/Postgres/Sqlite) enforce the same limits as MSSQL, where the columns were already NVARCHAR-capped. Widen Name from 64 to 255 chars across MSSQL DDL, both _Create/_Update SP signatures, the Migrator script, the entity, and all three regenerated EF migrations. Coupon codes stay at 64 (Stripe IDs are short). * [PM-36949] test: Lock FromPlan and ToPlan per MigrationPath The snapshot test class doc says "byte N means a specific FromPlan -> ToPlan transition forever", but only the byte value was being asserted. A silent refactor of the registry's PlanType references would not have been caught. Add per-path FromPlan/ToPlan assertions to close the gap. * [PM-36949] chore: Apply dotnet format * [PM-36949] test: Use LaxDateTimeComparer for round-tripped DateTimes Postgres timestamp and MySQL datetime(6) store microsecond precision (6 fractional digits), but .NET DateTime is 100ns ticks (7 digits). Exact Assert.Equal fails by a single tick on round-trip. Switch the three DateTime comparisons in ReplaceAsync_UpdatesMutableColumns_AndIgnoresImmutableOnes to LaxDateTimeComparer.Default -- the same 2ms-tolerance comparer used by SendRepositoryTests and InstallationRepositoryTests for the same precision issue. * [PM-36949] refactor: Rename DateTime columns to Date suffix per naming convention Addresses PR review feedback. Also tightens DATETIME2(7) / NVARCHAR(N) spacing per the SQL style guide, drops *.lscache from .gitignore (handled by #7648), and regenerates EF migrations for MySQL, Postgres, and SQLite. * Apply dotnet format to regenerated migrations * [PM-36949] chore: Align NULL/NOT NULL columns in cohort tables |