diff --git a/src/components/app/data/services/subsidies/subscriptions.js b/src/components/app/data/services/subsidies/subscriptions.js index e87ba53cda..224b158069 100644 --- a/src/components/app/data/services/subsidies/subscriptions.js +++ b/src/components/app/data/services/subsidies/subscriptions.js @@ -233,8 +233,19 @@ export async function fetchSubscriptions(enterpriseUUID) { if (customerAgreement) { subscriptionsData.customerAgreement = customerAgreement; } - subscriptionsData.subscriptionLicenses = subscriptionLicenses; subscriptionsData.showExpirationNotifications = !(customerAgreement?.disableExpirationNotifications); + + // Sort licenses within each license status by whether the associated subscription plans + // are current; current plans should be prioritized over non-current plans. + subscriptionLicenses.sort((a, b) => { + const aIsCurrent = a.subscriptionPlan.isCurrent; + const bIsCurrent = b.subscriptionPlan.isCurrent; + if (aIsCurrent && bIsCurrent) { return 0; } + return aIsCurrent ? -1 : 1; + }); + subscriptionsData.subscriptionLicenses = subscriptionLicenses; + + // Group licenses by status. subscriptionLicenses.forEach((license) => { const { subscriptionPlan, status } = license; const isUnassignedLicense = status === LICENSE_STATUS.UNASSIGNED; @@ -243,6 +254,8 @@ export async function fetchSubscriptions(enterpriseUUID) { } licensesByStatus[license.status].push(license); }); + + // Extracts a single subscription license for the user, from the ordered licenses by status. const applicableSubscriptionLicense = Object.values(licensesByStatus).flat()[0]; if (applicableSubscriptionLicense) { subscriptionsData.subscriptionLicense = applicableSubscriptionLicense; diff --git a/src/components/app/data/services/subsidies/subscriptions.test.js b/src/components/app/data/services/subsidies/subscriptions.test.js index 99dede6a16..ed181d21b2 100644 --- a/src/components/app/data/services/subsidies/subscriptions.test.js +++ b/src/components/app/data/services/subsidies/subscriptions.test.js @@ -161,6 +161,69 @@ describe('fetchSubscriptions', () => { }; expect(response).toEqual(expectedResult); }); + + it('handles learner with multiple activated licenses due to a scheduled renewal', async () => { + const mockRenewalStartDate = dayjs().add(15, 'days'); + const mockRenewalEndDate = mockRenewalStartDate.add(1, 'year'); + const mockSubscriptionLicenseRenewal = { + uuid: 'test-license-uuid-1', + status: LICENSE_STATUS.ACTIVATED, + subscriptionPlan: { + uuid: 'test-subscription-plan-uuid-1', + isActive: true, + isCurrent: false, + daysUntilExpiration: mockRenewalEndDate.diff(mockRenewalStartDate, 'days'), + startDate: mockRenewalStartDate.toISOString(), + expirationDate: mockRenewalEndDate.toISOString(), + }, + }; + const mockCurrentStartDate = mockRenewalStartDate.subtract(30, 'days'); + const mockSubscriptionLicenseCurrent = { + uuid: 'test-license-uuid-2', + status: LICENSE_STATUS.ACTIVATED, + subscriptionPlan: { + uuid: 'test-subscription-plan-uuid-2', + isActive: true, + isCurrent: true, + daysUntilExpiration: mockRenewalStartDate.diff(mockCurrentStartDate, 'days'), + startDate: mockCurrentStartDate.toISOString(), + expirationDate: mockRenewalStartDate.toISOString(), + }, + }; + const mockResponse = { + customerAgreement: { + uuid: 'test-customer-agreement-uuid', + disableExpirationNotifications: false, + }, + results: [mockSubscriptionLicenseRenewal, mockSubscriptionLicenseCurrent], + }; + const queryParams = new URLSearchParams({ + enterprise_customer_uuid: mockEnterpriseId, + include_revoked: true, + current_plans_only: false, + }); + const SUBSCRIPTIONS_URL = `${APP_CONFIG.LICENSE_MANAGER_URL}/api/v1/learner-licenses/?${queryParams.toString()}`; + axiosMock.onGet(SUBSCRIPTIONS_URL).reply(200, mockResponse); + const response = await fetchSubscriptions(mockEnterpriseId); + const expectedLicensesByStatus = { + [LICENSE_STATUS.ACTIVATED]: [], + [LICENSE_STATUS.ASSIGNED]: [], + [LICENSE_STATUS.REVOKED]: [], + }; + expectedLicensesByStatus[LICENSE_STATUS.ACTIVATED].push(mockSubscriptionLicenseCurrent); + expectedLicensesByStatus[LICENSE_STATUS.ACTIVATED].push(mockSubscriptionLicenseRenewal); + + const expectedResult = { + customerAgreement: mockResponse.customerAgreement, + licensesByStatus: expectedLicensesByStatus, + subscriptionPlan: mockSubscriptionLicenseCurrent.subscriptionPlan, + subscriptionLicense: mockSubscriptionLicenseCurrent, + subscriptionLicenses: [mockSubscriptionLicenseCurrent, mockSubscriptionLicenseRenewal], + shouldShowActivationSuccessMessage: false, + showExpirationNotifications: true, + }; + expect(response).toEqual(expectedResult); + }); }); describe('activateOrAutoApplySubscriptionLicense', () => {