diff --git a/api/lib/application/sup-organization-learners/index.js b/api/lib/application/sup-organization-learners/index.js deleted file mode 100644 index ec1ce66d964..00000000000 --- a/api/lib/application/sup-organization-learners/index.js +++ /dev/null @@ -1,46 +0,0 @@ -import JoiDate from '@joi/date'; -import BaseJoi from 'joi'; -const Joi = BaseJoi.extend(JoiDate); - -import { sendJsonApiError, UnprocessableEntityError } from '../../../src/shared/application/http-errors.js'; -import { supOrganizationLearnerController } from './sup-organization-learner-controller.js'; - -const register = async function (server) { - server.route([ - { - method: 'POST', - path: '/api/sup-organization-learners/association', - config: { - handler: supOrganizationLearnerController.reconcileSupOrganizationLearner, - validate: { - options: { - allowUnknown: false, - }, - payload: Joi.object({ - data: { - attributes: { - 'student-number': Joi.string().empty(Joi.string().regex(/^\s*$/)).required(), - 'first-name': Joi.string().empty(Joi.string().regex(/^\s*$/)).required(), - 'last-name': Joi.string().empty(Joi.string().regex(/^\s*$/)).required(), - birthdate: Joi.date().format('YYYY-MM-DD').required(), - 'campaign-code': Joi.string().empty(Joi.string().regex(/^\s*$/)).required(), - }, - type: 'sup-organization-learners', - }, - }), - failAction: (request, h) => { - return sendJsonApiError(new UnprocessableEntityError('Un des champs saisis n’est pas valide.'), h); - }, - }, - notes: [ - '- **Cette route est restreinte aux utilisateurs authentifiés**\n' + - '- Elle réconcilie l’utilisateur à l’inscription d’un étudiant dans cette organisation', - ], - tags: ['api', 'sup-organization-learner'], - }, - }, - ]); -}; - -const name = 'sup-organization-learners-api'; -export { name, register }; diff --git a/api/lib/application/sup-organization-learners/sup-organization-learner-controller.js b/api/lib/application/sup-organization-learners/sup-organization-learner-controller.js deleted file mode 100644 index 836f8a9246f..00000000000 --- a/api/lib/application/sup-organization-learners/sup-organization-learner-controller.js +++ /dev/null @@ -1,24 +0,0 @@ -import { usecases } from '../../domain/usecases/index.js'; - -const reconcileSupOrganizationLearner = async function (request, h) { - const userId = request.auth.credentials.userId; - const payload = request.payload.data.attributes; - - const campaignCode = payload['campaign-code']; - - const reconciliationInfo = { - userId, - studentNumber: payload['student-number'], - firstName: payload['first-name'], - lastName: payload['last-name'], - birthdate: payload['birthdate'], - }; - - await usecases.reconcileSupOrganizationLearner({ campaignCode, reconciliationInfo }); - - return h.response(null).code(204); -}; - -const supOrganizationLearnerController = { reconcileSupOrganizationLearner }; - -export { supOrganizationLearnerController }; diff --git a/api/lib/domain/usecases/create-user-and-reconcile-to-organization-learner-from-external-user.js b/api/lib/domain/usecases/create-user-and-reconcile-to-organization-learner-from-external-user.js index 2e72f83cc66..5128c05f154 100644 --- a/api/lib/domain/usecases/create-user-and-reconcile-to-organization-learner-from-external-user.js +++ b/api/lib/domain/usecases/create-user-and-reconcile-to-organization-learner-from-external-user.js @@ -24,6 +24,7 @@ const createUserAndReconcileToOrganizationLearnerFromExternalUser = async functi userLoginRepository, userToCreateRepository, organizationLearnerRepository, + prescriptionOrganizationLearnerRepository, studentRepository, }) { const campaign = await campaignRepository.getByCode(campaignCode); @@ -102,7 +103,7 @@ const createUserAndReconcileToOrganizationLearnerFromExternalUser = async functi userId: reconciliationUserId, identityProvider, }); - const organizationLearner = await organizationLearnerRepository.reconcileUserToOrganizationLearner({ + const organizationLearner = await prescriptionOrganizationLearnerRepository.reconcileUserToOrganizationLearner({ userId: reconciliationUserId, organizationLearnerId: matchedOrganizationLearner.id, }); diff --git a/api/lib/domain/usecases/index.js b/api/lib/domain/usecases/index.js index b87ffa2189e..ab16d204ff9 100644 --- a/api/lib/domain/usecases/index.js +++ b/api/lib/domain/usecases/index.js @@ -75,7 +75,7 @@ import * as campaignParticipationBCRepository from '../../../src/prescription/ca import * as campaignProfileRepository from '../../../src/prescription/campaign-participation/infrastructure/repositories/campaign-profile-repository.js'; import { participationCompletedJobRepository } from '../../../src/prescription/campaign-participation/infrastructure/repositories/jobs/participation-completed-job-repository.js'; import * as poleEmploiSendingRepository from '../../../src/prescription/campaign-participation/infrastructure/repositories/pole-emploi-sending-repository.js'; -import * as supOrganizationLearnerRepository from '../../../src/prescription/learner-management/infrastructure/repositories/sup-organization-learner-repository.js'; +import * as prescriptionOrganizationLearnerRepository from '../../../src/prescription/learner-management/infrastructure/repositories/organization-learner-repository.js'; import * as organizationLearnerActivityRepository from '../../../src/prescription/organization-learner/infrastructure/repositories/organization-learner-activity-repository.js'; import * as registrationOrganizationLearnerRepository from '../../../src/prescription/organization-learner/infrastructure/repositories/registration-organization-learner-repository.js'; import * as targetProfileSummaryForAdminRepository from '../../../src/prescription/target-profile/infrastructure/repositories/target-profile-summary-for-admin-repository.js'; @@ -296,6 +296,7 @@ const dependencies = { placementProfileService, poleEmploiNotifier: requirePoleEmploiNotifier(), poleEmploiSendingRepository, + prescriptionOrganizationLearnerRepository, refreshTokenRepository, registrationOrganizationLearnerRepository, resetPasswordDemandRepository, @@ -318,7 +319,6 @@ const dependencies = { stageRepository, studentRepository, supervisorAccessRepository, - supOrganizationLearnerRepository, tagRepository, targetProfileRepository, targetProfileShareRepository, diff --git a/api/lib/domain/usecases/reconcile-sco-organization-learner-manually.js b/api/lib/domain/usecases/reconcile-sco-organization-learner-manually.js index 431ec62d88a..382b99f3d5a 100644 --- a/api/lib/domain/usecases/reconcile-sco-organization-learner-manually.js +++ b/api/lib/domain/usecases/reconcile-sco-organization-learner-manually.js @@ -15,6 +15,7 @@ const reconcileScoOrganizationLearnerManually = async function ({ withReconciliation, campaignRepository, organizationLearnerRepository, + prescriptionOrganizationLearnerRepository, registrationOrganizationLearnerRepository, studentRepository, userRepository, @@ -53,7 +54,7 @@ const reconcileScoOrganizationLearnerManually = async function ({ }); if (withReconciliation) { - return organizationLearnerRepository.reconcileUserToOrganizationLearner({ + return prescriptionOrganizationLearnerRepository.reconcileUserToOrganizationLearner({ userId: reconciliationInfo.id, organizationLearnerId: organizationLearnerOfUserAccessingCampaign.id, }); diff --git a/api/lib/infrastructure/repositories/organization-learner-repository.js b/api/lib/infrastructure/repositories/organization-learner-repository.js index 8ff39991712..d5e8d7f4318 100644 --- a/api/lib/infrastructure/repositories/organization-learner-repository.js +++ b/api/lib/infrastructure/repositories/organization-learner-repository.js @@ -4,7 +4,6 @@ import { NotFoundError, OrganizationLearnerCertificabilityNotUpdatedError, OrganizationLearnerNotFound, - UserCouldNotBeReconciledError, UserNotFoundError, } from '../../../src/shared/domain/errors.js'; import { OrganizationLearner } from '../../../src/shared/domain/models/OrganizationLearner.js'; @@ -134,21 +133,6 @@ const findByOrganizationIdAndBirthdate = async function ({ organizationId, birth return rawOrganizationLearners.map((rawOrganizationLearner) => new OrganizationLearner(rawOrganizationLearner)); }; -const reconcileUserToOrganizationLearner = async function ({ userId, organizationLearnerId }) { - try { - const knexConn = DomainTransaction.getConnection(); - const [rawOrganizationLearner] = await knexConn('organization-learners') - .where({ id: organizationLearnerId }) - .where('isDisabled', false) - .update({ userId, updatedAt: knex.fn.now() }) - .returning('*'); - if (!rawOrganizationLearner) throw new Error(); - return new OrganizationLearner(rawOrganizationLearner); - } catch (error) { - throw new UserCouldNotBeReconciledError(); - } -}; - const dissociateAllStudentsByUserId = async function ({ userId }) { const knexConn = DomainTransaction.getConnection(); await _queryBuilderDissociation(knexConn) @@ -377,7 +361,6 @@ export { get, getLatestOrganizationLearner, isActive, - reconcileUserToOrganizationLearner, updateCertificability, updateUserIdWhereNull, }; diff --git a/api/lib/routes.js b/api/lib/routes.js index e2f6df7fe5e..73ccb3b893b 100644 --- a/api/lib/routes.js +++ b/api/lib/routes.js @@ -13,7 +13,6 @@ import * as organizations from './application/organizations/index.js'; import * as passwords from './application/passwords/index.js'; import * as scoOrganizationLearners from './application/sco-organization-learners/index.js'; import * as sessions from './application/sessions/index.js'; -import * as supOrganizationLearners from './application/sup-organization-learners/index.js'; import * as tags from './application/tags/index.js'; import * as targetProfiles from './application/target-profiles/index.js'; import * as userOrgaSettings from './application/user-orga-settings/index.js'; @@ -33,7 +32,6 @@ const routes = [ organizations, passwords, scoOrganizationLearners, - supOrganizationLearners, sessions, tags, targetProfiles, diff --git a/api/src/prescription/learner-management/application/sup-organization-management-controller.js b/api/src/prescription/learner-management/application/sup-organization-management-controller.js index 434c1cc35f1..707cde1140a 100644 --- a/api/src/prescription/learner-management/application/sup-organization-management-controller.js +++ b/api/src/prescription/learner-management/application/sup-organization-management-controller.js @@ -108,11 +108,31 @@ const updateStudentNumber = async function (request, h) { return h.response().code(204); }; +const reconcileSupOrganizationLearner = async function (request, h) { + const userId = request.auth.credentials.userId; + const payload = request.payload.data.attributes; + + const campaignCode = payload['campaign-code']; + + const reconciliationInfo = { + userId, + studentNumber: payload['student-number'], + firstName: payload['first-name'], + lastName: payload['last-name'], + birthdate: payload['birthdate'], + }; + + await usecases.reconcileSupOrganizationLearner({ campaignCode, reconciliationInfo }); + + return h.response(null).code(204); +}; + const supOrganizationManagementController = { getOrganizationLearnersCsvTemplate, importSupOrganizationLearners, replaceSupOrganizationLearners, updateStudentNumber, + reconcileSupOrganizationLearner, }; export { supOrganizationManagementController }; diff --git a/api/src/prescription/learner-management/application/sup-organization-management-route.js b/api/src/prescription/learner-management/application/sup-organization-management-route.js index e385e1feeff..0df666aef47 100644 --- a/api/src/prescription/learner-management/application/sup-organization-management-route.js +++ b/api/src/prescription/learner-management/application/sup-organization-management-route.js @@ -18,6 +18,38 @@ const ERRORS = { const register = async function (server) { server.route([ + { + method: 'POST', + path: '/api/sup-organization-learners/association', + config: { + handler: supOrganizationManagementController.reconcileSupOrganizationLearner, + validate: { + options: { + allowUnknown: false, + }, + payload: Joi.object({ + data: { + attributes: { + 'student-number': Joi.string().empty(Joi.string().regex(/^\s*$/)).required(), + 'first-name': Joi.string().empty(Joi.string().regex(/^\s*$/)).required(), + 'last-name': Joi.string().empty(Joi.string().regex(/^\s*$/)).required(), + birthdate: Joi.date().format('YYYY-MM-DD').required(), + 'campaign-code': Joi.string().empty(Joi.string().regex(/^\s*$/)).required(), + }, + type: 'sup-organization-learners', + }, + }), + failAction: (request, h) => { + return sendJsonApiError(new UnprocessableEntityError('Un des champs saisis n’est pas valide.'), h); + }, + }, + notes: [ + '- **Cette route est restreinte aux utilisateurs authentifiés**\n' + + '- Elle réconcilie l’utilisateur à l’inscription d’un étudiant dans cette organisation', + ], + tags: ['api', 'sup-organization-learner'], + }, + }, { method: 'POST', path: '/api/organizations/{organizationId}/sup-organization-learners/replace-csv', diff --git a/api/lib/domain/usecases/reconcile-sup-organization-learner.js b/api/src/prescription/learner-management/domain/usecases/reconcile-sup-organization-learner.js similarity index 92% rename from api/lib/domain/usecases/reconcile-sup-organization-learner.js rename to api/src/prescription/learner-management/domain/usecases/reconcile-sup-organization-learner.js index 88af731e59b..0f7655160c7 100644 --- a/api/lib/domain/usecases/reconcile-sup-organization-learner.js +++ b/api/src/prescription/learner-management/domain/usecases/reconcile-sup-organization-learner.js @@ -1,4 +1,4 @@ -import { NotFoundError } from '../../../src/shared/domain/errors.js'; +import { NotFoundError } from '../../../../shared/domain/errors.js'; const reconcileSupOrganizationLearner = async function ({ campaignCode, diff --git a/api/src/prescription/learner-management/infrastructure/repositories/organization-learner-repository.js b/api/src/prescription/learner-management/infrastructure/repositories/organization-learner-repository.js index 35407e0cac0..c5da1bc0b34 100644 --- a/api/src/prescription/learner-management/infrastructure/repositories/organization-learner-repository.js +++ b/api/src/prescription/learner-management/infrastructure/repositories/organization-learner-repository.js @@ -222,6 +222,21 @@ const findOrganizationLearnerIdsByOrganizationId = function ({ organizationId }) return knexConnection('view-active-organization-learners').where({ organizationId }).select('id').pluck('id'); }; +const reconcileUserToOrganizationLearner = async function ({ userId, organizationLearnerId }) { + try { + const knexConn = DomainTransaction.getConnection(); + const [rawOrganizationLearner] = await knexConn('organization-learners') + .where({ id: organizationLearnerId }) + .where('isDisabled', false) + .update({ userId, updatedAt: knexConn.fn.now() }) + .returning('*'); + if (!rawOrganizationLearner) throw new Error(); + return new OrganizationLearner(rawOrganizationLearner); + } catch (error) { + throw new UserCouldNotBeReconciledError(); + } +}; + export { addOrUpdateOrganizationOfOrganizationLearners, disableAllOrganizationLearnersInOrganization, @@ -233,6 +248,7 @@ export { findOrganizationLearnerIdsByOrganizationId, getOrganizationLearnerForAdmin, reconcileUserByNationalStudentIdAndOrganizationId, + reconcileUserToOrganizationLearner, removeByIds, saveCommonOrganizationLearners, update, diff --git a/api/tests/acceptance/application/sup-organization-learners/sup-organization-learner-controller_test.js b/api/tests/acceptance/application/sup-organization-learners/sup-organization-learner-controller_test.js index 02f3770f7ba..4d3a3a6caad 100644 --- a/api/tests/acceptance/application/sup-organization-learners/sup-organization-learner-controller_test.js +++ b/api/tests/acceptance/application/sup-organization-learners/sup-organization-learner-controller_test.js @@ -13,57 +13,6 @@ describe('Acceptance | Controller | sup-organization-learners', function () { server = await createServer(); }); - describe('POST /api/sup-organization-learners/association', function () { - let organization; - let campaign; - let options; - let user; - - beforeEach(async function () { - // given - options = { - method: 'POST', - url: '/api/sup-organization-learners/association', - headers: {}, - payload: {}, - }; - - user = databaseBuilder.factory.buildUser(); - organization = databaseBuilder.factory.buildOrganization(); - campaign = databaseBuilder.factory.buildCampaign({ organizationId: organization.id }); - databaseBuilder.factory.buildOrganizationLearner({ - firstName: 'Jean', - lastName: 'Michel', - birthdate: new Date('2010-01-01'), - studentNumber: '12345', - organizationId: organization.id, - userId: null, - }); - - await databaseBuilder.commit(); - }); - - it('should return an 204 status after updating higher organization learner', async function () { - // given - options.headers.authorization = generateValidRequestAuthorizationHeader(user.id); - options.payload.data = { - attributes: { - 'student-number': '12345', - 'first-name': 'Jean', - 'last-name': 'Michel', - birthdate: '2010-01-01', - 'campaign-code': campaign.code, - }, - type: 'sup-organization-learners', - }; - - // when - const response = await server.inject(options); - // then - expect(response.statusCode).to.equal(204); - }); - }); - describe('PATCH /api/organizations/id/sup-organization-learners/organizationLearnerId', function () { let organizationId; const studentNumber = '54321'; diff --git a/api/tests/integration/application/sup-organization-learners/index_test.js b/api/tests/integration/application/sup-organization-learners/index_test.js deleted file mode 100644 index 9f2102316fb..00000000000 --- a/api/tests/integration/application/sup-organization-learners/index_test.js +++ /dev/null @@ -1,230 +0,0 @@ -import * as moduleUnderTest from '../../../../lib/application/sup-organization-learners/index.js'; -import { supOrganizationLearnerController } from '../../../../lib/application/sup-organization-learners/sup-organization-learner-controller.js'; -import { expect, HttpTestServer, sinon } from '../../../test-helper.js'; - -describe('Integration | Application | Route | sup-organization-learners', function () { - let httpTestServer; - - beforeEach(async function () { - sinon - .stub(supOrganizationLearnerController, 'reconcileSupOrganizationLearner') - .callsFake((request, h) => h.response('ok').code(204)); - - httpTestServer = new HttpTestServer(); - await httpTestServer.register(moduleUnderTest); - }); - - describe('POST /api/sup-organization-learners/association', function () { - const method = 'POST'; - const url = '/api/sup-organization-learners/association'; - - context('User association with studentNumber, firstName, lastName, birthdate and campaignCode', function () { - it('should succeed', async function () { - // given - const payload = { - data: { - attributes: { - 'student-number': 'F001', - 'first-name': 'Robert', - 'last-name': 'Smith', - birthdate: '2012-12-12', - 'campaign-code': 'RESTRICTD', - }, - }, - }; - - // when - const response = await httpTestServer.request(method, url, payload); - - // then - expect(response.statusCode).to.equal(204); - }); - - it('should succeed when there is a space', async function () { - // given - const payload = { - data: { - attributes: { - 'student-number': 'F001 ', - 'first-name': 'Robert ', - 'last-name': 'Smith ', - birthdate: '2012-12-12', - 'campaign-code': 'RESTRICTD', - }, - }, - }; - - // when - const response = await httpTestServer.request(method, url, payload); - - // then - expect(response.statusCode).to.equal(204); - expect(response.request.payload.data.attributes['first-name']).to.equal('Robert '); - }); - - it('should return an error when there is no payload', async function () { - // when - const response = await httpTestServer.request(method, url); - - // then - expect(response.statusCode).to.equal(422); - }); - - it('should return an error when there is an invalid student number attribute in the payload', async function () { - // given - const INVALID_STUDENT_NUMBER = ' '; - const payload = { - data: { - attributes: { - 'student-number': INVALID_STUDENT_NUMBER, - 'first-name': 'Robert', - 'last-name': 'Smith', - birthdate: '2012-12-12', - 'campaign-code': 'RESTRICTD', - }, - }, - }; - - // when - const response = await httpTestServer.request(method, url, payload); - - // then - expect(response.statusCode).to.equal(422); - }); - - it('should return an error when there is an invalid first name attribute in the payload', async function () { - // given - const INVALID_FIRSTNAME = ' '; - const payload = { - data: { - attributes: { - 'student-number': 'F001', - 'first-name': INVALID_FIRSTNAME, - 'last-name': 'Smith', - birthdate: '2012-12-12', - 'campaign-code': 'RESTRICTD', - }, - }, - }; - - // when - const response = await httpTestServer.request(method, url, payload); - - // then - expect(response.statusCode).to.equal(422); - }); - - it('should return an error when there is an invalid last name attribute in the payload', async function () { - // given - const INVALID_LASTNAME = ''; - const payload = { - data: { - attributes: { - 'student-number': 'F001', - 'first-name': 'Robert', - 'last-name': INVALID_LASTNAME, - birthdate: '2012-12-12', - 'campaign-code': 'RESTRICTD', - }, - }, - }; - - // when - const response = await httpTestServer.request(method, url, payload); - - // then - expect(response.statusCode).to.equal(422); - }); - - it('should return an error when there is an invalid a birthdate attribute (with space) in the payload', async function () { - // given - const INVALID_BIRTHDATE = '2012- 12-12'; - - // when - const payload = { - data: { - attributes: { - 'student-number': 'F001', - 'first-name': 'Robert', - 'last-name': 'Smith', - birthdate: INVALID_BIRTHDATE, - 'campaign-code': 'RESTRICTD', - }, - }, - }; - - // when - const response = await httpTestServer.request(method, url, payload); - - // then - expect(response.statusCode).to.equal(422); - }); - - it('should return an error when there is an invalid birthdate attribute (with extra zeros) in the payload', async function () { - // given - const INVALID_BIRTHDATE = '2012-012-12'; - const payload = { - data: { - attributes: { - 'student-number': 'F001', - 'first-name': 'Robert', - 'last-name': 'Smith', - birthdate: INVALID_BIRTHDATE, - 'campaign-code': 'RESTRICTD', - }, - }, - }; - - // when - const response = await httpTestServer.request(method, url, payload); - - // then - expect(response.statusCode).to.equal(422); - }); - - it('should return an error when there is an invalid birthdate attribute (not a proper date) in the payload', async function () { - // given - const INVALID_BIRTHDATE = '1999-99-99'; - const payload = { - data: { - attributes: { - 'student-number': 'F001', - 'first-name': 'Robert', - 'last-name': 'Smith', - birthdate: INVALID_BIRTHDATE, - 'campaign-code': 'RESTRICTD', - }, - }, - }; - - // when - const response = await httpTestServer.request(method, url, payload); - - // then - expect(response.statusCode).to.equal(422); - }); - - it('should return an error when there is an invalid campaign code attribute in the payload', async function () { - // given - const INVALID_CAMPAIGNCODE = ''; - const payload = { - data: { - attributes: { - 'student-number': 'F001', - 'first-name': 'Robert', - 'last-name': 'Smith', - birthdate: '2012-12-12', - 'campaign-code': INVALID_CAMPAIGNCODE, - }, - }, - }; - - // when - const response = await httpTestServer.request(method, url, payload); - - // then - expect(response.statusCode).to.equal(422); - }); - }); - }); -}); diff --git a/api/tests/integration/domain/usecases/create-user-and-reconcile-to-organization-learner-from-external-user_test.js b/api/tests/integration/domain/usecases/create-user-and-reconcile-to-organization-learner-from-external-user_test.js index d0cb1d2cc1c..27317e34ca7 100644 --- a/api/tests/integration/domain/usecases/create-user-and-reconcile-to-organization-learner-from-external-user_test.js +++ b/api/tests/integration/domain/usecases/create-user-and-reconcile-to-organization-learner-from-external-user_test.js @@ -1,13 +1,5 @@ -import * as obfuscationService from '../../../../lib/domain/services/obfuscation-service.js'; -import * as userReconciliationService from '../../../../lib/domain/services/user-reconciliation-service.js'; -import { createUserAndReconcileToOrganizationLearnerFromExternalUser as createUserAndReconcileToOrganizationLearnerByExternalUser } from '../../../../lib/domain/usecases/create-user-and-reconcile-to-organization-learner-from-external-user.js'; -import * as campaignRepository from '../../../../lib/infrastructure/repositories/campaign-repository.js'; -import * as organizationLearnerRepository from '../../../../lib/infrastructure/repositories/organization-learner-repository.js'; -import * as studentRepository from '../../../../lib/infrastructure/repositories/student-repository.js'; +import { usecases } from '../../../../lib/domain/usecases/index.js'; import { NON_OIDC_IDENTITY_PROVIDERS } from '../../../../src/identity-access-management/domain/constants/identity-providers.js'; -import * as authenticationMethodRepository from '../../../../src/identity-access-management/infrastructure/repositories/authentication-method.repository.js'; -import * as userRepository from '../../../../src/identity-access-management/infrastructure/repositories/user.repository.js'; -import { userToCreateRepository } from '../../../../src/identity-access-management/infrastructure/repositories/user-to-create.repository.js'; import { CampaignCodeError, NotFoundError, @@ -15,17 +7,14 @@ import { OrganizationLearnerAlreadyLinkedToUserError, } from '../../../../src/shared/domain/errors.js'; import { tokenService } from '../../../../src/shared/domain/services/token-service.js'; -import * as userService from '../../../../src/shared/domain/services/user-service.js'; -import * as userLoginRepository from '../../../../src/shared/infrastructure/repositories/user-login-repository.js'; import { catchErr, databaseBuilder, expect, knex } from '../../../test-helper.js'; describe('Integration | UseCases | create-user-and-reconcile-to-organization-learner-from-external-user', function () { context('When there is no campaign with the given code', function () { it('should throw a campaign code error', async function () { // when - const error = await catchErr(createUserAndReconcileToOrganizationLearnerByExternalUser)({ + const error = await catchErr(usecases.createUserAndReconcileToOrganizationLearnerFromExternalUser)({ campaignCode: 'NOTEXIST', - campaignRepository, }); // then @@ -51,11 +40,10 @@ describe('Integration | UseCases | create-user-and-reconcile-to-organization-lea const token = tokenService.createIdTokenForUserReconciliation(externalUser); // when - const error = await catchErr(createUserAndReconcileToOrganizationLearnerByExternalUser)({ + const error = await catchErr(usecases.createUserAndReconcileToOrganizationLearnerFromExternalUser)({ campaignCode, token, tokenService, - campaignRepository, }); // then @@ -74,11 +62,9 @@ describe('Integration | UseCases | create-user-and-reconcile-to-organization-lea const token = tokenService.createIdTokenForUserReconciliation(externalUser); // when - const error = await catchErr(createUserAndReconcileToOrganizationLearnerByExternalUser)({ + const error = await catchErr(usecases.createUserAndReconcileToOrganizationLearnerFromExternalUser)({ campaignCode, token, - tokenService, - campaignRepository, }); // then @@ -97,11 +83,9 @@ describe('Integration | UseCases | create-user-and-reconcile-to-organization-lea const token = tokenService.createIdTokenForUserReconciliation(externalUser); // when - const error = await catchErr(createUserAndReconcileToOrganizationLearnerByExternalUser)({ + const error = await catchErr(usecases.createUserAndReconcileToOrganizationLearnerFromExternalUser)({ campaignCode, token, - tokenService, - campaignRepository, }); // then @@ -131,14 +115,10 @@ describe('Integration | UseCases | create-user-and-reconcile-to-organization-lea const birthdate = '2008-01-01'; // when - const error = await catchErr(createUserAndReconcileToOrganizationLearnerByExternalUser)({ + const error = await catchErr(usecases.createUserAndReconcileToOrganizationLearnerFromExternalUser)({ birthdate, campaignCode, token, - campaignRepository, - tokenService, - userReconciliationService, - organizationLearnerRepository, }); // then @@ -178,21 +158,11 @@ describe('Integration | UseCases | create-user-and-reconcile-to-organization-lea const usersBefore = await knex('users'); // when - await createUserAndReconcileToOrganizationLearnerByExternalUser({ + await usecases.createUserAndReconcileToOrganizationLearnerFromExternalUser({ birthdate: organizationLearner.birthdate, campaignCode, - campaignRepository, token, - obfuscationService, tokenService, - userReconciliationService, - userService, - authenticationMethodRepository, - organizationLearnerRepository, - studentRepository, - userRepository, - userLoginRepository, - userToCreateRepository, }); // then @@ -220,17 +190,10 @@ describe('Integration | UseCases | create-user-and-reconcile-to-organization-lea await databaseBuilder.commit(); // when - const error = await catchErr(createUserAndReconcileToOrganizationLearnerByExternalUser)({ + const error = await catchErr(usecases.createUserAndReconcileToOrganizationLearnerFromExternalUser)({ birthdate: organizationLearner.birthdate, campaignCode, token, - obfuscationService, - tokenService, - userReconciliationService, - campaignRepository, - organizationLearnerRepository, - userRepository, - userLoginRepository, }); // then @@ -273,19 +236,10 @@ describe('Integration | UseCases | create-user-and-reconcile-to-organization-lea await databaseBuilder.commit(); // when - await createUserAndReconcileToOrganizationLearnerByExternalUser({ + await usecases.createUserAndReconcileToOrganizationLearnerFromExternalUser({ campaignCode, token, birthdate: organizationLearner.birthdate, - obfuscationService, - tokenService, - userReconciliationService, - authenticationMethodRepository, - campaignRepository, - organizationLearnerRepository, - studentRepository, - userRepository, - userLoginRepository, }); // then @@ -334,19 +288,10 @@ describe('Integration | UseCases | create-user-and-reconcile-to-organization-lea await databaseBuilder.commit(); // when - await createUserAndReconcileToOrganizationLearnerByExternalUser({ + await usecases.createUserAndReconcileToOrganizationLearnerFromExternalUser({ campaignCode, token, birthdate: organizationLearner.birthdate, - obfuscationService, - tokenService, - userReconciliationService, - authenticationMethodRepository, - campaignRepository, - organizationLearnerRepository, - studentRepository, - userRepository, - userLoginRepository, }); // then @@ -388,18 +333,10 @@ describe('Integration | UseCases | create-user-and-reconcile-to-organization-lea const usersBefore = await knex('users'); // when - await createUserAndReconcileToOrganizationLearnerByExternalUser({ + await usecases.createUserAndReconcileToOrganizationLearnerFromExternalUser({ birthdate: organizationLearner.birthdate, campaignCode, token, - obfuscationService, - tokenService, - userReconciliationService, - campaignRepository, - organizationLearnerRepository, - studentRepository, - userRepository, - userLoginRepository, }); // then diff --git a/api/tests/integration/infrastructure/repositories/organization-learner-repository_test.js b/api/tests/integration/infrastructure/repositories/organization-learner-repository_test.js index e2d8e503c40..958d2f593be 100644 --- a/api/tests/integration/infrastructure/repositories/organization-learner-repository_test.js +++ b/api/tests/integration/infrastructure/repositories/organization-learner-repository_test.js @@ -8,7 +8,6 @@ import { NotFoundError, OrganizationLearnerCertificabilityNotUpdatedError, OrganizationLearnerNotFound, - UserCouldNotBeReconciledError, UserNotFoundError, } from '../../../../src/shared/domain/errors.js'; import { OrganizationLearner } from '../../../../src/shared/domain/models/index.js'; @@ -704,86 +703,6 @@ describe('Integration ¨| Infrastructure | Repository | organization-learner-rep }); }); - describe('#reconcileUserToOrganizationLearner', function () { - let organization; - let organizationLearner; - let user; - let initialDate; - - beforeEach(async function () { - initialDate = new Date('2023-01-01'); - organization = databaseBuilder.factory.buildOrganization(); - organizationLearner = databaseBuilder.factory.buildOrganizationLearner({ - organizationId: organization.id, - userId: null, - firstName: 'Steeve', - lastName: 'Roger', - updatedAt: initialDate, - }); - user = databaseBuilder.factory.buildUser({ firstName: 'Steeve', lastName: 'Roger' }); - await databaseBuilder.commit(); - }); - - it('should save association between user and organizationLearner', async function () { - // when - const organizationLearnerPatched = await organizationLearnerRepository.reconcileUserToOrganizationLearner({ - userId: user.id, - organizationLearnerId: organizationLearner.id, - }); - - // then - expect(organizationLearnerPatched).to.be.instanceof(OrganizationLearner); - expect(organizationLearnerPatched.updatedAt).to.be.above(initialDate); - expect(organizationLearnerPatched.userId).to.equal(user.id); - }); - - it('should return an error when we don’t find the organizationLearner to update', async function () { - // given - const fakeStudentId = 1; - - // when - const error = await catchErr(organizationLearnerRepository.reconcileUserToOrganizationLearner)({ - userId: user.id, - organizationLearnerId: fakeStudentId, - }); - - // then - expect(error).to.be.instanceOf(UserCouldNotBeReconciledError); - }); - - it('should return an error when the userId to link don’t match a user', async function () { - // given - const fakeUserId = 1; - - // when - const error = await catchErr(organizationLearnerRepository.reconcileUserToOrganizationLearner)({ - userId: fakeUserId, - organizationLearnerId: organizationLearner.id, - }); - - // then - expect(error).to.be.instanceOf(UserCouldNotBeReconciledError); - }); - - it('should return an error when the organization learner is disabled', async function () { - // given - const disabledOrganizationLearner = databaseBuilder.factory.buildOrganizationLearner({ - organizationId: organization.id, - userId: null, - isDisabled: true, - }); - - // when - const error = await catchErr(organizationLearnerRepository.reconcileUserToOrganizationLearner)({ - userId: user.id, - organizationLearnerId: disabledOrganizationLearner.id, - }); - - // then - expect(error).to.be.instanceOf(UserCouldNotBeReconciledError); - }); - }); - describe('#get', function () { let organizationLearnerId; diff --git a/api/tests/prescription/learner-management/acceptance/application/sup-organization-management-route_test.js b/api/tests/prescription/learner-management/acceptance/application/sup-organization-management-route_test.js index 4641a718092..44735ac0765 100644 --- a/api/tests/prescription/learner-management/acceptance/application/sup-organization-management-route_test.js +++ b/api/tests/prescription/learner-management/acceptance/application/sup-organization-management-route_test.js @@ -20,7 +20,58 @@ describe('Acceptance | Application | organization-controller-sup-organization-le server = await createServer(); }); - describe('POST organizations/{organizationId}/sup-organization-learners/import-csv', function () { + describe('POST /api/sup-organization-learners/association', function () { + let organization; + let campaign; + let options; + let user; + + beforeEach(async function () { + // given + options = { + method: 'POST', + url: '/api/sup-organization-learners/association', + headers: {}, + payload: {}, + }; + + user = databaseBuilder.factory.buildUser(); + organization = databaseBuilder.factory.buildOrganization(); + campaign = databaseBuilder.factory.buildCampaign({ organizationId: organization.id }); + databaseBuilder.factory.buildOrganizationLearner({ + firstName: 'Jean', + lastName: 'Michel', + birthdate: new Date('2010-01-01'), + studentNumber: '12345', + organizationId: organization.id, + userId: null, + }); + + await databaseBuilder.commit(); + }); + + it('should return an 204 status after updating higher organization learner', async function () { + // given + options.headers.authorization = generateValidRequestAuthorizationHeader(user.id); + options.payload.data = { + attributes: { + 'student-number': '12345', + 'first-name': 'Jean', + 'last-name': 'Michel', + birthdate: '2010-01-01', + 'campaign-code': campaign.code, + }, + type: 'sup-organization-learners', + }; + + // when + const response = await server.inject(options); + // then + expect(response.statusCode).to.equal(204); + }); + }); + + describe('POST organizations/{organizationId/sup-organization-learners/import-csv', function () { let connectedUser; beforeEach(async function () { diff --git a/api/tests/prescription/learner-management/integration/application/sup-organization-management-routes_test.js b/api/tests/prescription/learner-management/integration/application/sup-organization-management-routes_test.js index d5c35ed8bf3..c9b5233c387 100644 --- a/api/tests/prescription/learner-management/integration/application/sup-organization-management-routes_test.js +++ b/api/tests/prescription/learner-management/integration/application/sup-organization-management-routes_test.js @@ -7,6 +7,10 @@ describe('Integration | Application | Route | sup-organization-learners', functi let httpTestServer; beforeEach(async function () { + sinon + .stub(supOrganizationManagementController, 'reconcileSupOrganizationLearner') + .callsFake((request, h) => h.response('ok').code(204)); + sinon .stub(securityPreHandlers, 'checkUserIsAdminInSUPOrganizationManagingStudents') .callsFake((request, h) => h.response(true)); @@ -134,4 +138,218 @@ describe('Integration | Application | Route | sup-organization-learners', functi }); }); }); + + describe('POST /api/sup-organization-learners/association', function () { + const method = 'POST'; + const url = '/api/sup-organization-learners/association'; + + context('User association with studentNumber, firstName, lastName, birthdate and campaignCode', function () { + it('should succeed', async function () { + // given + const payload = { + data: { + attributes: { + 'student-number': 'F001', + 'first-name': 'Robert', + 'last-name': 'Smith', + birthdate: '2012-12-12', + 'campaign-code': 'RESTRICTD', + }, + }, + }; + + // when + const response = await httpTestServer.request(method, url, payload); + + // then + expect(response.statusCode).to.equal(204); + }); + + it('should succeed when there is a space', async function () { + // given + const payload = { + data: { + attributes: { + 'student-number': 'F001 ', + 'first-name': 'Robert ', + 'last-name': 'Smith ', + birthdate: '2012-12-12', + 'campaign-code': 'RESTRICTD', + }, + }, + }; + + // when + const response = await httpTestServer.request(method, url, payload); + + // then + expect(response.statusCode).to.equal(204); + expect(response.request.payload.data.attributes['first-name']).to.equal('Robert '); + }); + + it('should return an error when there is no payload', async function () { + // when + const response = await httpTestServer.request(method, url); + + // then + expect(response.statusCode).to.equal(422); + }); + + it('should return an error when there is an invalid student number attribute in the payload', async function () { + // given + const INVALID_STUDENT_NUMBER = ' '; + const payload = { + data: { + attributes: { + 'student-number': INVALID_STUDENT_NUMBER, + 'first-name': 'Robert', + 'last-name': 'Smith', + birthdate: '2012-12-12', + 'campaign-code': 'RESTRICTD', + }, + }, + }; + + // when + const response = await httpTestServer.request(method, url, payload); + + // then + expect(response.statusCode).to.equal(422); + }); + + it('should return an error when there is an invalid first name attribute in the payload', async function () { + // given + const INVALID_FIRSTNAME = ' '; + const payload = { + data: { + attributes: { + 'student-number': 'F001', + 'first-name': INVALID_FIRSTNAME, + 'last-name': 'Smith', + birthdate: '2012-12-12', + 'campaign-code': 'RESTRICTD', + }, + }, + }; + + // when + const response = await httpTestServer.request(method, url, payload); + + // then + expect(response.statusCode).to.equal(422); + }); + + it('should return an error when there is an invalid last name attribute in the payload', async function () { + // given + const INVALID_LASTNAME = ''; + const payload = { + data: { + attributes: { + 'student-number': 'F001', + 'first-name': 'Robert', + 'last-name': INVALID_LASTNAME, + birthdate: '2012-12-12', + 'campaign-code': 'RESTRICTD', + }, + }, + }; + + // when + const response = await httpTestServer.request(method, url, payload); + + // then + expect(response.statusCode).to.equal(422); + }); + + it('should return an error when there is an invalid a birthdate attribute (with space) in the payload', async function () { + // given + const INVALID_BIRTHDATE = '2012- 12-12'; + + // when + const payload = { + data: { + attributes: { + 'student-number': 'F001', + 'first-name': 'Robert', + 'last-name': 'Smith', + birthdate: INVALID_BIRTHDATE, + 'campaign-code': 'RESTRICTD', + }, + }, + }; + + // when + const response = await httpTestServer.request(method, url, payload); + + // then + expect(response.statusCode).to.equal(422); + }); + + it('should return an error when there is an invalid birthdate attribute (with extra zeros) in the payload', async function () { + // given + const INVALID_BIRTHDATE = '2012-012-12'; + const payload = { + data: { + attributes: { + 'student-number': 'F001', + 'first-name': 'Robert', + 'last-name': 'Smith', + birthdate: INVALID_BIRTHDATE, + 'campaign-code': 'RESTRICTD', + }, + }, + }; + + // when + const response = await httpTestServer.request(method, url, payload); + + // then + expect(response.statusCode).to.equal(422); + }); + + it('should return an error when there is an invalid birthdate attribute (not a proper date) in the payload', async function () { + // given + const INVALID_BIRTHDATE = '1999-99-99'; + const payload = { + data: { + attributes: { + 'student-number': 'F001', + 'first-name': 'Robert', + 'last-name': 'Smith', + birthdate: INVALID_BIRTHDATE, + 'campaign-code': 'RESTRICTD', + }, + }, + }; + + // when + const response = await httpTestServer.request(method, url, payload); + + // then + expect(response.statusCode).to.equal(422); + }); + + it('should return an error when there is an invalid campaign code attribute in the payload', async function () { + // given + const INVALID_CAMPAIGNCODE = ''; + const payload = { + data: { + attributes: { + 'student-number': 'F001', + 'first-name': 'Robert', + 'last-name': 'Smith', + birthdate: '2012-12-12', + 'campaign-code': INVALID_CAMPAIGNCODE, + }, + }, + }; + + // when + const response = await httpTestServer.request(method, url, payload); + + // then + expect(response.statusCode).to.equal(422); + }); + }); + }); }); diff --git a/api/tests/integration/domain/usecases/reconcile-sup-organization-learner_test.js b/api/tests/prescription/learner-management/integration/domain/usecases/reconcile-sup-organization-learner_test.js similarity index 70% rename from api/tests/integration/domain/usecases/reconcile-sup-organization-learner_test.js rename to api/tests/prescription/learner-management/integration/domain/usecases/reconcile-sup-organization-learner_test.js index ce784c23065..21f5240a38b 100644 --- a/api/tests/integration/domain/usecases/reconcile-sup-organization-learner_test.js +++ b/api/tests/prescription/learner-management/integration/domain/usecases/reconcile-sup-organization-learner_test.js @@ -1,10 +1,9 @@ -import * as userReconciliationService from '../../../../lib/domain/services/user-reconciliation-service.js'; -import { reconcileSupOrganizationLearner } from '../../../../lib/domain/usecases/reconcile-sup-organization-learner.js'; -import * as campaignRepository from '../../../../lib/infrastructure/repositories/campaign-repository.js'; -import * as organizationLearnerRepository from '../../../../lib/infrastructure/repositories/organization-learner-repository.js'; -import * as supOrganizationLearnerRepository from '../../../../src/prescription/learner-management/infrastructure/repositories/sup-organization-learner-repository.js'; -import { NotFoundError, OrganizationLearnerAlreadyLinkedToUserError } from '../../../../src/shared/domain/errors.js'; -import { catchErr, databaseBuilder, expect, knex } from '../../../test-helper.js'; +import { usecases } from '../../../../../../src/prescription/learner-management/domain/usecases/index.js'; +import { + NotFoundError, + OrganizationLearnerAlreadyLinkedToUserError, +} from '../../../../../../src/shared/domain/errors.js'; +import { catchErr, databaseBuilder, expect, knex } from '../../../../../test-helper.js'; describe('Integration | UseCases | reconcile-sup-organization-learner', function () { let userId; @@ -14,10 +13,9 @@ describe('Integration | UseCases | reconcile-sup-organization-learner', function context('When there is no campaign with the given code', function () { it('should throw a campaign code error', async function () { // when - const error = await catchErr(reconcileSupOrganizationLearner)({ + const error = await catchErr(usecases.reconcileSupOrganizationLearner)({ campaignCode: 'NOTEXIST', reconciliationInfo: {}, - campaignRepository, }); // then @@ -54,13 +52,9 @@ describe('Integration | UseCases | reconcile-sup-organization-learner', function await databaseBuilder.commit(); // when - const error = await catchErr(reconcileSupOrganizationLearner)({ + const error = await catchErr(usecases.reconcileSupOrganizationLearner)({ campaignCode, reconciliationInfo, - campaignRepository, - supOrganizationLearnerRepository, - organizationLearnerRepository, - userReconciliationService, }); // then @@ -89,13 +83,9 @@ describe('Integration | UseCases | reconcile-sup-organization-learner', function await databaseBuilder.commit(); // when - await reconcileSupOrganizationLearner({ + await usecases.reconcileSupOrganizationLearner({ campaignCode, reconciliationInfo, - campaignRepository, - supOrganizationLearnerRepository, - organizationLearnerRepository, - userReconciliationService, }); // then @@ -124,13 +114,9 @@ describe('Integration | UseCases | reconcile-sup-organization-learner', function await databaseBuilder.commit(); // when - const error = await catchErr(reconcileSupOrganizationLearner)({ + const error = await catchErr(usecases.reconcileSupOrganizationLearner)({ campaignCode, reconciliationInfo, - campaignRepository, - supOrganizationLearnerRepository, - organizationLearnerRepository, - userReconciliationService, }); // then diff --git a/api/tests/prescription/learner-management/integration/infrastructure/repositories/organization-learner-repository_test.js b/api/tests/prescription/learner-management/integration/infrastructure/repositories/organization-learner-repository_test.js index 2bca67e76ce..3b678f83287 100644 --- a/api/tests/prescription/learner-management/integration/infrastructure/repositories/organization-learner-repository_test.js +++ b/api/tests/prescription/learner-management/integration/infrastructure/repositories/organization-learner-repository_test.js @@ -13,6 +13,7 @@ import { findOrganizationLearnerIdsByOrganizationId, getOrganizationLearnerForAdmin, reconcileUserByNationalStudentIdAndOrganizationId, + reconcileUserToOrganizationLearner, removeByIds, saveCommonOrganizationLearners, update, @@ -1748,4 +1749,84 @@ describe('Integration | Repository | Organization Learner Management | Organizat expect(results).to.deep.equal([organizationLearnerId]); }); }); + + describe('#reconcileUserToOrganizationLearner', function () { + let organization; + let organizationLearner; + let user; + let initialDate; + + beforeEach(async function () { + initialDate = new Date('2023-01-01'); + organization = databaseBuilder.factory.buildOrganization(); + organizationLearner = databaseBuilder.factory.buildOrganizationLearner({ + organizationId: organization.id, + userId: null, + firstName: 'Steeve', + lastName: 'Roger', + updatedAt: initialDate, + }); + user = databaseBuilder.factory.buildUser({ firstName: 'Steeve', lastName: 'Roger' }); + await databaseBuilder.commit(); + }); + + it('should save association between user and organizationLearner', async function () { + // when + const organizationLearnerPatched = await reconcileUserToOrganizationLearner({ + userId: user.id, + organizationLearnerId: organizationLearner.id, + }); + + // then + expect(organizationLearnerPatched).to.be.instanceof(OrganizationLearner); + expect(organizationLearnerPatched.updatedAt).to.be.above(initialDate); + expect(organizationLearnerPatched.userId).to.equal(user.id); + }); + + it('should return an error when we don’t find the organizationLearner to update', async function () { + // given + const fakeStudentId = 1; + + // when + const error = await catchErr(reconcileUserToOrganizationLearner)({ + userId: user.id, + organizationLearnerId: fakeStudentId, + }); + + // then + expect(error).to.be.instanceOf(UserCouldNotBeReconciledError); + }); + + it('should return an error when the userId to link don’t match a user', async function () { + // given + const fakeUserId = 1; + + // when + const error = await catchErr(reconcileUserToOrganizationLearner)({ + userId: fakeUserId, + organizationLearnerId: organizationLearner.id, + }); + + // then + expect(error).to.be.instanceOf(UserCouldNotBeReconciledError); + }); + + it('should return an error when the organization learner is disabled', async function () { + // given + const disabledOrganizationLearner = databaseBuilder.factory.buildOrganizationLearner({ + organizationId: organization.id, + userId: null, + isDisabled: true, + }); + + // when + const error = await catchErr(reconcileUserToOrganizationLearner)({ + userId: user.id, + organizationLearnerId: disabledOrganizationLearner.id, + }); + + // then + expect(error).to.be.instanceOf(UserCouldNotBeReconciledError); + }); + }); }); diff --git a/api/tests/unit/domain/usecases/reconcile-sco-organization-learner-manually_test.js b/api/tests/unit/domain/usecases/reconcile-sco-organization-learner-manually_test.js index 183e5cc8c9b..5cba799a59e 100644 --- a/api/tests/unit/domain/usecases/reconcile-sco-organization-learner-manually_test.js +++ b/api/tests/unit/domain/usecases/reconcile-sco-organization-learner-manually_test.js @@ -13,6 +13,7 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio let campaignRepository; let organizationLearnerRepository; + let prescriptionOrganizationLearnerRepository; let registrationOrganizationLearnerRepository; let userReconciliationService; @@ -35,9 +36,11 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio getByCode: sinon.stub(), }; organizationLearnerRepository = { - reconcileUserToOrganizationLearner: sinon.stub(), findByUserId: sinon.stub(), }; + prescriptionOrganizationLearnerRepository = { + reconcileUserToOrganizationLearner: sinon.stub(), + }; registrationOrganizationLearnerRepository = { findOneByUserIdAndOrganizationId: sinon.stub(), }; @@ -194,7 +197,9 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio userReconciliationService.assertStudentHasAnAlreadyReconciledAccount.resolves(); registrationOrganizationLearnerRepository.findOneByUserIdAndOrganizationId.resolves(); organizationLearnerRepository.findByUserId.withArgs({ userId: 1 }).resolves([previousOrganizationLearner]); - organizationLearnerRepository.reconcileUserToOrganizationLearner.resolves(currentOrganizationLearner); + prescriptionOrganizationLearnerRepository.reconcileUserToOrganizationLearner.resolves( + currentOrganizationLearner, + ); // when await usecases.reconcileScoOrganizationLearnerManually({ @@ -204,11 +209,14 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio campaignRepository, userReconciliationService, organizationLearnerRepository, + prescriptionOrganizationLearnerRepository, registrationOrganizationLearnerRepository, }); // then - expect(organizationLearnerRepository.reconcileUserToOrganizationLearner).to.have.been.calledOnceWithExactly({ + expect( + prescriptionOrganizationLearnerRepository.reconcileUserToOrganizationLearner, + ).to.have.been.calledOnceWithExactly({ userId: reconciliationInfo.id, organizationLearnerId: currentOrganizationLearner.id, }); @@ -304,7 +312,9 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio userReconciliationService.assertStudentHasAnAlreadyReconciledAccount.resolves(); registrationOrganizationLearnerRepository.findOneByUserIdAndOrganizationId.resolves(); organizationLearnerRepository.findByUserId.withArgs({ userId: 1 }).resolves([previousOrganizationLearner]); - organizationLearnerRepository.reconcileUserToOrganizationLearner.resolves(currentOrganizationLearner); + prescriptionOrganizationLearnerRepository.reconcileUserToOrganizationLearner.resolves( + currentOrganizationLearner, + ); // when await usecases.reconcileScoOrganizationLearnerManually({ @@ -314,11 +324,14 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio campaignRepository, userReconciliationService, organizationLearnerRepository, + prescriptionOrganizationLearnerRepository, registrationOrganizationLearnerRepository, }); // then - expect(organizationLearnerRepository.reconcileUserToOrganizationLearner).to.have.been.calledOnceWithExactly({ + expect( + prescriptionOrganizationLearnerRepository.reconcileUserToOrganizationLearner, + ).to.have.been.calledOnceWithExactly({ userId: reconciliationInfo.id, organizationLearnerId: currentOrganizationLearner.id, }); @@ -359,7 +372,9 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio userReconciliationService.assertStudentHasAnAlreadyReconciledAccount.resolves(); registrationOrganizationLearnerRepository.findOneByUserIdAndOrganizationId.resolves(); organizationLearnerRepository.findByUserId.withArgs({ userId: 1 }).resolves([previousOrganizationLearner]); - organizationLearnerRepository.reconcileUserToOrganizationLearner.resolves(currentOrganizationLearner); + prescriptionOrganizationLearnerRepository.reconcileUserToOrganizationLearner.resolves( + currentOrganizationLearner, + ); // when await usecases.reconcileScoOrganizationLearnerManually({ @@ -369,11 +384,14 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio campaignRepository, userReconciliationService, organizationLearnerRepository, + prescriptionOrganizationLearnerRepository, registrationOrganizationLearnerRepository, }); // then - expect(organizationLearnerRepository.reconcileUserToOrganizationLearner).to.have.been.calledOnceWithExactly({ + expect( + prescriptionOrganizationLearnerRepository.reconcileUserToOrganizationLearner, + ).to.have.been.calledOnceWithExactly({ userId: reconciliationInfo.id, organizationLearnerId: currentOrganizationLearner.id, }); @@ -495,16 +513,17 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio campaignRepository, userReconciliationService, organizationLearnerRepository, + prescriptionOrganizationLearnerRepository, registrationOrganizationLearnerRepository, }); // then - expect(organizationLearnerRepository.reconcileUserToOrganizationLearner).to.have.been.calledOnceWithExactly( - { - userId: reconciliationInfo.id, - organizationLearnerId: currentOrganizationLearner.id, - }, - ); + expect( + prescriptionOrganizationLearnerRepository.reconcileUserToOrganizationLearner, + ).to.have.been.calledOnceWithExactly({ + userId: reconciliationInfo.id, + organizationLearnerId: currentOrganizationLearner.id, + }); }); }); }, @@ -525,7 +544,7 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio organizationLearner, ); userReconciliationService.assertStudentHasAnAlreadyReconciledAccount.resolves(); - organizationLearnerRepository.reconcileUserToOrganizationLearner + prescriptionOrganizationLearnerRepository.reconcileUserToOrganizationLearner .withArgs({ userId: user.id, organizationLearnerId: organizationLearnerId, @@ -541,6 +560,7 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio campaignRepository, userReconciliationService, organizationLearnerRepository, + prescriptionOrganizationLearnerRepository, registrationOrganizationLearnerRepository, }); @@ -574,12 +594,13 @@ describe('Unit | UseCase | reconcile-sco-organization-learner-manually', functio campaignRepository, userReconciliationService, organizationLearnerRepository, + prescriptionOrganizationLearnerRepository, registrationOrganizationLearnerRepository, }); // then expect(result).to.be.undefined; - expect(organizationLearnerRepository.reconcileUserToOrganizationLearner).to.not.have.been.called; + expect(prescriptionOrganizationLearnerRepository.reconcileUserToOrganizationLearner).to.not.have.been.called; }); }); });