Skip to content

Commit

Permalink
[FEATURE][BACK] Exposer les meta données pour la reconciliation des i…
Browse files Browse the repository at this point in the history
…mports à format (PIX-13234)

 #9414
  • Loading branch information
pix-service-auto-merge committed Jul 8, 2024
2 parents 50e07dc + 14d15ba commit f448c8d
Show file tree
Hide file tree
Showing 40 changed files with 611 additions and 216 deletions.
128 changes: 66 additions & 62 deletions api/db/seeds/data/common/tooling/campaign-tooling.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,74 +305,78 @@ async function createProfilesCollectionCampaign({
multipleSendings,
assessmentMethod,
});
const userAndLearnerIds = await _createOrRetrieveUsersAndLearners(
databaseBuilder,
realOrganizationId,
configCampaign.participantCount,
);
const profileDistribution = [
...Array(configCampaign.profileDistribution.blank || 0).fill('BLANK'),
...Array(configCampaign.profileDistribution.beginner || 0).fill('BEGINNER'),
...Array(configCampaign.profileDistribution.intermediate || 0).fill('INTERMEDIATE'),
...Array(configCampaign.profileDistribution.advanced || 0).fill('ADVANCED'),
...Array(configCampaign.profileDistribution.perfect || 0).fill('PERFECT'),
];
if (profileDistribution.length < configCampaign.participantCount)
profileDistribution.push(...Array(configCampaign.participantCount - profileDistribution.length).fill('BEGINNER'));

for (const { userId, organizationLearnerId } of userAndLearnerIds) {
const answersAndKnowledgeElementsForProfile = await _getProfile(profileDistribution.shift());

const campaignParticipationId = databaseBuilder.factory.buildCampaignParticipation({
campaignId: realCampaignId,
userId,
organizationLearnerId,
sharedAt,
masteryRate: null,
pixScore: _.floor(_.sumBy(answersAndKnowledgeElementsForProfile, ({ keData }) => keData.earnedPix)),
status: CampaignParticipationStatuses.SHARED,
isImproved: false,
}).id;
const assessmentId = databaseBuilder.factory.buildAssessment({
userId,
type: Assessment.types.CAMPAIGN,
state: Assessment.states.COMPLETED,
isImproving: false,
lastQuestionDate: new Date(),
lastQuestionState: Assessment.statesOfLastQuestion.ASKED,
competenceId: null,
campaignParticipationId,
}).id;
const keDataForSnapshot = [];
for (const { answerData, keData } of answersAndKnowledgeElementsForProfile) {
const answerId = databaseBuilder.factory.buildAnswer({
assessmentId,
answerData,
if (configCampaign) {
const userAndLearnerIds = await _createOrRetrieveUsersAndLearners(
databaseBuilder,
realOrganizationId,
configCampaign.participantCount,
);
const profileDistribution = [
...Array(configCampaign.profileDistribution.blank || 0).fill('BLANK'),
...Array(configCampaign.profileDistribution.beginner || 0).fill('BEGINNER'),
...Array(configCampaign.profileDistribution.intermediate || 0).fill('INTERMEDIATE'),
...Array(configCampaign.profileDistribution.advanced || 0).fill('ADVANCED'),
...Array(configCampaign.profileDistribution.perfect || 0).fill('PERFECT'),
];
if (profileDistribution.length < configCampaign.participantCount)
profileDistribution.push(...Array(configCampaign.participantCount - profileDistribution.length).fill('BEGINNER'));

for (const { userId, organizationLearnerId } of userAndLearnerIds) {
const answersAndKnowledgeElementsForProfile = await _getProfile(profileDistribution.shift());

const campaignParticipationId = databaseBuilder.factory.buildCampaignParticipation({
campaignId: realCampaignId,
userId,
organizationLearnerId,
sharedAt,
masteryRate: null,
pixScore: _.floor(_.sumBy(answersAndKnowledgeElementsForProfile, ({ keData }) => keData.earnedPix)),
status: CampaignParticipationStatuses.SHARED,
isImproved: false,
}).id;
keDataForSnapshot.push(
databaseBuilder.factory.buildKnowledgeElement({
const assessmentId = databaseBuilder.factory.buildAssessment({
userId,
type: Assessment.types.CAMPAIGN,
state: Assessment.states.COMPLETED,
isImproving: false,
lastQuestionDate: new Date(),
lastQuestionState: Assessment.statesOfLastQuestion.ASKED,
competenceId: null,
campaignParticipationId,
}).id;
const keDataForSnapshot = [];
for (const { answerData, keData } of answersAndKnowledgeElementsForProfile) {
const answerId = databaseBuilder.factory.buildAnswer({
assessmentId,
answerId,
userId,
...keData,
createdAt: dayjs().subtract(1, 'day'),
}),
);
}
databaseBuilder.factory.buildKnowledgeElementSnapshot({
userId,
snappedAt: sharedAt,
snapshot: JSON.stringify(keDataForSnapshot),
});
answerData,
}).id;
keDataForSnapshot.push(
databaseBuilder.factory.buildKnowledgeElement({
assessmentId,
answerId,
userId,
...keData,
createdAt: dayjs().subtract(1, 'day'),
}),
);
}
databaseBuilder.factory.buildKnowledgeElementSnapshot({
userId,
snappedAt: sharedAt,
snapshot: JSON.stringify(keDataForSnapshot),
});

await databaseBuilder.commit();
const placementProfile = await getPlacementProfile({ userId, limitDate: sharedAt });
await databaseBuilder.commit();
const placementProfile = await getPlacementProfile({ userId, limitDate: sharedAt });

await databaseBuilder
.knex('campaign-participations')
.where('id', campaignParticipationId)
.update('isCertifiable', placementProfile.isCertifiable());
await databaseBuilder
.knex('campaign-participations')
.where('id', campaignParticipationId)
.update('isCertifiable', placementProfile.isCertifiable());
}
}

await databaseBuilder.commit();
return { campaignId: realCampaignId };
}
Expand Down
39 changes: 27 additions & 12 deletions api/db/seeds/data/team-prescription/build-campaigns.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import dayjs from 'dayjs';
import { CampaignParticipationStatuses } from '../../../../src/prescription/shared/domain/constants.js';
import { Assessment } from '../../../../src/shared/domain/models/Assessment.js';
import {
PRO_MANAGING_ORGANIZATION_ID,
PRO_ORGANIZATION_ID,
SCO_MANAGING_ORGANIZATION_ID,
SUP_MANAGING_ORGANIZATION_ID,
Expand Down Expand Up @@ -117,7 +118,32 @@ async function _createSupCampaigns(databaseBuilder) {
});
}

async function _createProGenericCampaigns(databaseBuilder) {
await createProfilesCollectionCampaign({
databaseBuilder,
organizationId: PRO_MANAGING_ORGANIZATION_ID,
ownerId: USER_ID_ADMIN_ORGANIZATION,
name: 'Campagne de collecte de profil PRO',
multipleSendings: true,
code: 'PROGENCOL',
type: 'PROFILES_COLLECTION',
title: null,
});
}

async function _createProCampaigns(databaseBuilder) {
await createProfilesCollectionCampaign({
databaseBuilder,
organizationId: PRO_ORGANIZATION_ID,
ownerId: USER_ID_ADMIN_ORGANIZATION,
name: 'Campagne de collecte de profil PRO',
multipleSendings: true,
code: 'PROCOLMUL',
type: 'PROFILES_COLLECTION',
title: null,
configCampaign: { participantCount: 3, profileDistribution: { beginner: 1, perfect: 1, blank: 1 } },
});

await createAssessmentCampaign({
databaseBuilder,
targetProfileId: TARGET_PROFILE_NO_BADGES_NO_STAGES_ID,
Expand Down Expand Up @@ -233,22 +259,11 @@ async function _createProCampaigns(databaseBuilder) {
competenceId: null,
campaignParticipationId: thirdCampaignParticipationId,
});

await createProfilesCollectionCampaign({
databaseBuilder,
organizationId: PRO_ORGANIZATION_ID,
ownerId: USER_ID_ADMIN_ORGANIZATION,
name: 'Campagne de collecte de profil PRO',
multipleSendings: true,
code: 'PROCOLMUL',
type: 'PROFILES_COLLECTION',
title: null,
configCampaign: { participantCount: 3, profileDistribution: { beginner: 1, perfect: 1, blank: 1 } },
});
}

export async function buildCampaigns(databaseBuilder) {
await _createProCampaigns(databaseBuilder);
await _createSupCampaigns(databaseBuilder);
await _createProGenericCampaigns(databaseBuilder);
return _createScoCampaigns(databaseBuilder);
}
2 changes: 0 additions & 2 deletions api/lib/domain/usecases/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ import * as userRepository from '../../../src/identity-access-management/infrast
import { userToCreateRepository } from '../../../src/identity-access-management/infrastructure/repositories/user-to-create.repository.js';
import { organizationForAdminRepository } from '../../../src/organizational-entities/infrastructure/repositories/organization-for-admin.repository.js';
import * as campaignManagementRepository from '../../../src/prescription/campaign/infrastructure/repositories/campaign-management-repository.js';
import * as campaignToJoinRepository from '../../../src/prescription/campaign/infrastructure/repositories/campaign-to-join-repository.js';
import * as divisionRepository from '../../../src/prescription/campaign/infrastructure/repositories/division-repository.js';
import * as campaignAssessmentParticipationRepository from '../../../src/prescription/campaign-participation/infrastructure/repositories/campaign-assessment-participation-repository.js';
import * as campaignAssessmentParticipationResultRepository from '../../../src/prescription/campaign-participation/infrastructure/repositories/campaign-assessment-participation-result-repository.js';
Expand Down Expand Up @@ -223,7 +222,6 @@ const dependencies = {
campaignParticipationResultRepository,
campaignProfileRepository,
campaignRepository,
campaignToJoinRepository,
centerRepository,
certifiableProfileForLearningContentRepository,
certificateRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const authenticateAnonymousUser = async function ({
userToCreateRepository,
tokenService,
}) {
const campaign = await campaignToJoinRepository.getByCode(campaignCode);
const campaign = await campaignToJoinRepository.getByCode({ code: campaignCode });
if (!campaign.isSimplifiedAccess) {
throw new UserCantBeCreatedError();
}
Expand Down
4 changes: 2 additions & 2 deletions api/src/identity-access-management/domain/usecases/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as campaignParticipationRepository from '../../../../lib/infrastructure
import * as campaignRepository from '../../../../lib/infrastructure/repositories/campaign-repository.js';
import * as organizationLearnerRepository from '../../../../lib/infrastructure/repositories/organization-learner-repository.js';
import * as userRecommendedTrainingRepository from '../../../devcomp/infrastructure/repositories/user-recommended-training-repository.js';
import * as campaignToJoinRepository from '../../../prescription/campaign/infrastructure/repositories/campaign-to-join-repository.js';
import { repositories as campaignRepositories } from '../../../prescription/campaign/infrastructure/repositories/index.js';
import { config } from '../../../shared/config.js';
import { cryptoService } from '../../../shared/domain/services/crypto-service.js';
import { tokenService } from '../../../shared/domain/services/token-service.js';
Expand Down Expand Up @@ -42,8 +42,8 @@ const repositories = {
authenticationMethodRepository,
campaignParticipationRepository,
campaignRepository,
campaignToJoinRepository,
emailValidationDemandRepository,
campaignToJoinRepository: campaignRepositories.campaignToJoinRepository,
oidcProviderRepository,
organizationLearnerRepository,
resetPasswordDemandRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class OrganizationFeaturesDTO {
this.features = features;
}

get hasLeanersImportFeature() {
get hasLearnersImportFeature() {
return this.features.some((feature) => feature.name === ORGANIZATION_FEATURE.LEARNER_IMPORT.key);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ class CampaignToStartParticipation {
idPixLabel,
archivedAt,
type,
isRestricted,
isManagingStudents,
hasLearnersImportFeature,
multipleSendings,
assessmentMethod,
skillCount,
Expand All @@ -17,12 +18,12 @@ class CampaignToStartParticipation {
this.type = type;
this.idPixLabel = idPixLabel;
this.archivedAt = archivedAt;
this.isRestricted = isRestricted;
this.multipleSendings = multipleSendings;
this.assessmentMethod = assessmentMethod;
this.skillCount = skillCount;
this.organizationId = organizationId;
this.deletedAt = deletedAt;
this.isRestricted = isManagingStudents || hasLearnersImportFeature;
}

get isAssessment() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import { importNamedExportsFromDirectory } from '../../../../shared/infrastructu
import * as campaignAnalysisRepository from '../../infrastructure/repositories/campaign-analysis-repository.js';
import * as campaignAssessmentParticipationRepository from '../../infrastructure/repositories/campaign-assessment-participation-repository.js';
import * as campaignAssessmentParticipationResultRepository from '../../infrastructure/repositories/campaign-assessment-participation-result-repository.js';
import * as campaignParticipantRepository from '../../infrastructure/repositories/campaign-participant-repository.js';
import * as campaignParticipationRepository from '../../infrastructure/repositories/campaign-participation-repository.js';
import * as campaignProfileRepository from '../../infrastructure/repositories/campaign-profile-repository.js';
import { repositories as campaignRepositories } from '../../infrastructure/repositories/index.js';
import * as participationsForCampaignManagementRepository from '../../infrastructure/repositories/participations-for-campaign-management-repository.js';
import * as participationsForUserManagementRepository from '../../infrastructure/repositories/participations-for-user-management-repository.js';

Expand All @@ -28,7 +28,7 @@ const dependencies = {
campaignAnalysisRepository,
campaignAssessmentParticipationRepository,
campaignAssessmentParticipationResultRepository,
campaignParticipantRepository,
campaignParticipantRepository: campaignRepositories.campaignParticipantRepository,
campaignProfileRepository,
campaignRepository,
competenceEvaluationRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const startCampaignParticipation = async function ({
isReset: campaignParticipation.isReset,
});

const campaignParticipationId = await campaignParticipantRepository.save(campaignParticipant, domainTransaction);
const campaignParticipationId = await campaignParticipantRepository.save({ campaignParticipant, domainTransaction });

const createdCampaignParticipation = await campaignParticipationRepository.get(
campaignParticipationId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { CampaignParticipant } from '../../domain/models/CampaignParticipant.js'
import { CampaignToStartParticipation } from '../../domain/models/CampaignToStartParticipation.js';
import { PreviousCampaignParticipation } from '../../domain/models/PreviousCampaignParticipation.js';

async function save(campaignParticipant, domainTransaction) {
async function save({ campaignParticipant, domainTransaction }) {
const newlyCreatedOrganizationLearnerId = await _createNewOrganizationLearner(
campaignParticipant.organizationLearner,
domainTransaction.knexTransaction,
Expand All @@ -35,10 +35,14 @@ async function save(campaignParticipant, domainTransaction) {
return campaignParticipationId;
}

async function get({ userId, campaignId, domainTransaction }) {
async function get({ userId, campaignId, domainTransaction, organizationFeatureAPI }) {
const userIdentity = await _getUserIdentityForTrainee(userId, domainTransaction);

const campaignToStartParticipation = await _getCampaignToStart(campaignId, domainTransaction);
const campaignToStartParticipation = await _getCampaignToStart({
campaignId,
domainTransaction,
organizationFeatureAPI,
});

const organizationLearner = await _getOrganizationLearner(campaignId, userId, domainTransaction);

Expand Down Expand Up @@ -148,7 +152,7 @@ async function _getUserIdentityForTrainee(userId, domainTransaction) {
return new UserIdentity(userIdentity);
}

async function _getCampaignToStart(campaignId, domainTransaction) {
async function _getCampaignToStart({ campaignId, domainTransaction, organizationFeatureAPI }) {
const campaignAttributes = await domainTransaction
.knexTransaction('campaigns')
.join('organizations', 'organizations.id', 'organizationId')
Expand All @@ -158,7 +162,7 @@ async function _getCampaignToStart(campaignId, domainTransaction) {
'idPixLabel',
'campaigns.archivedAt',
'campaigns.deletedAt',
'isManagingStudents AS isRestricted',
'isManagingStudents',
'multipleSendings',
'assessmentMethod',
'organizationId',
Expand All @@ -171,7 +175,15 @@ async function _getCampaignToStart(campaignId, domainTransaction) {
}
const skillIds = await campaignRepository.findSkillIds({ campaignId, domainTransaction });

return new CampaignToStartParticipation({ ...campaignAttributes, skillCount: skillIds.length });
const { hasLearnersImportFeature } = await organizationFeatureAPI.getAllFeaturesFromOrganization(
campaignAttributes.organizationId,
);

return new CampaignToStartParticipation({
...campaignAttributes,
hasLearnersImportFeature,
skillCount: skillIds.length,
});
}

async function _getOrganizationLearner(campaignId, userId, domainTransaction) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as organizationFeatureAPI from '../../../../organizational-entities/application/api/organization-features-api.js';
import { injectDependencies } from '../../../../shared/infrastructure/utils/dependency-injection.js';
import * as campaignParticipantRepository from './campaign-participant-repository.js';

const repositoriesWithoutInjectedDependencies = {
campaignParticipantRepository,
};

const dependencies = {
organizationFeatureAPI,
};

const repositories = injectDependencies(repositoriesWithoutInjectedDependencies, dependencies);

export { repositories };
Loading

0 comments on commit f448c8d

Please sign in to comment.