diff --git a/api/src/profile/scripts/sixth-grade-attestation-reward.js b/api/src/profile/scripts/sixth-grade-attestation-reward.js new file mode 100644 index 00000000000..34d2ec3a6a6 --- /dev/null +++ b/api/src/profile/scripts/sixth-grade-attestation-reward.js @@ -0,0 +1,52 @@ +import { CampaignParticipationStatuses } from '../../prescription/shared/domain/constants.js'; +import { usecases } from '../../quest/domain/usecases/index.js'; +import { Script } from '../../shared/application/scripts/script.js'; +import { ScriptRunner } from '../../shared/application/scripts/script-runner.js'; +import { DomainTransaction } from '../../shared/domain/DomainTransaction.js'; + +export const PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS = [107068, 107074, 107078]; + +const firstDateLimitDefault = new Date('2024-12-01T00:00:00Z'); +const secondDateLimitDefault = new Date('2024-12-03T23:59:59Z'); + +export const fetchUserIds = async () => { + const knexConnection = DomainTransaction.getConnection(); + const users = await knexConnection('campaign-participations') + .select('campaign-participations.userId') + .distinct() + .join('campaigns', 'campaign-participations.campaignId', 'campaigns.id') + .whereIn('campaigns.targetProfileId', PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS) + .andWhere('campaign-participations.createdAt', '>', firstDateLimitDefault) + .andWhere('campaign-participations.createdAt', '<', secondDateLimitDefault) + .andWhere('campaign-participations.status', '<>', CampaignParticipationStatuses.STARTED); + return users.map(({ userId }) => userId); +}; + +export class SixthGradeAttestationRewardScript extends Script { + constructor() { + super({ + description: + 'This script awards attestations to sixth-grade students who have already completed a campaign linked to a target profile linked to them', + permanent: true, + options: { + firstDateLimitDefault, + secondDateLimitDefault, + }, + }); + } + + async handle({ options, logger }) { + const users = await fetchUserIds(options); + + logger.info(users.length); + + for (const userId of users) { + await usecases.rewardUser({ + userId, + }); + logger.info(`Traitement de l'utilisateur ${userId}`); + } + } +} + +await ScriptRunner.execute(import.meta.url, SixthGradeAttestationRewardScript); diff --git a/api/tests/profile/integration/scripts/sixth-grade-attestation-reward_test.js b/api/tests/profile/integration/scripts/sixth-grade-attestation-reward_test.js new file mode 100644 index 00000000000..6bbfb300751 --- /dev/null +++ b/api/tests/profile/integration/scripts/sixth-grade-attestation-reward_test.js @@ -0,0 +1,142 @@ +import { CampaignParticipationStatuses } from '../../../../src/prescription/shared/domain/constants.js'; +import { + fetchUserIds, + PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS, +} from '../../../../src/profile/scripts/sixth-grade-attestation-reward.js'; +import { databaseBuilder, expect } from '../../../test-helper.js'; + +describe('Integration | Profile | Scripts | sixth-grade-attestation-reward', function () { + describe('#fetchUsers', function () { + it('should not return the user if the participation date is not included between the start date and the end date ', async function () { + const { id: targetProfileId } = databaseBuilder.factory.buildTargetProfile({ + id: PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS[0], + }); + const campaign = databaseBuilder.factory.buildCampaign({ targetProfileId }); + const { userId } = databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign.id, + status: CampaignParticipationStatuses.SHARED, + createdAt: '2024-12-02T15:07:57.376Z', + }); + databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign.id, + status: CampaignParticipationStatuses.SHARED, + createdAt: '2024-12-07T15:07:57.376Z', + }); + databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign.id, + status: CampaignParticipationStatuses.SHARED, + createdAt: '2024-11-22T15:07:57.376Z', + }); + + await databaseBuilder.commit(); + const userIds = await fetchUserIds(); + expect(userIds).to.have.lengthOf(1); + expect(userIds).to.contains(userId); + }); + + it('should not return the user if the participation status is different from started', async function () { + const { id: targetProfileId } = databaseBuilder.factory.buildTargetProfile({ + id: PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS[0], + }); + const campaign = databaseBuilder.factory.buildCampaign({ targetProfileId }); + const { userId } = databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign.id, + status: CampaignParticipationStatuses.STARTED, + createdAt: '2024-12-02T15:07:57.376Z', + }); + databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign.id, + status: CampaignParticipationStatuses.SHARED, + createdAt: '2024-12-02T15:07:57.376Z', + }); + databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign.id, + status: CampaignParticipationStatuses.TO_SHARE, + createdAt: '2024-12-02T15:07:57.376Z', + }); + + await databaseBuilder.commit(); + const userIds = await fetchUserIds(); + expect(userIds).to.have.lengthOf(2); + expect(userIds).to.not.contains(userId); + }); + + it('should not return the user if the campaign target profile is not included in targeted target profiles', async function () { + const { id: targetProfileId1 } = databaseBuilder.factory.buildTargetProfile({ + id: PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS[0], + }); + const { id: targetProfileId2 } = databaseBuilder.factory.buildTargetProfile({ + id: PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS[1], + }); + const { id: targetProfileId3 } = databaseBuilder.factory.buildTargetProfile({ + id: PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS[2], + }); + const { id: targetProfileId4 } = databaseBuilder.factory.buildTargetProfile(); + const campaign1 = databaseBuilder.factory.buildCampaign({ targetProfileId: targetProfileId1 }); + const campaign2 = databaseBuilder.factory.buildCampaign({ targetProfileId: targetProfileId2 }); + const campaign3 = databaseBuilder.factory.buildCampaign({ targetProfileId: targetProfileId3 }); + const campaign4 = databaseBuilder.factory.buildCampaign({ targetProfileId: targetProfileId4 }); + const otherParameters = { status: CampaignParticipationStatuses.SHARED, createdAt: '2024-12-02T15:07:57.376Z' }; + databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign1.id, + ...otherParameters, + }); + databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign2.id, + ...otherParameters, + }); + databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign3.id, + ...otherParameters, + }); + const { userId: otherTargetProfileCampaignParticipationUserId } = + databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign4.id, + ...otherParameters, + }); + + await databaseBuilder.commit(); + const userIds = await fetchUserIds(); + expect(userIds).to.have.lengthOf(3); + expect(userIds).to.not.contains(otherTargetProfileCampaignParticipationUserId); + }); + + it('should return expected users', async function () { + const { id: targetProfileId1 } = databaseBuilder.factory.buildTargetProfile({ + id: PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS[0], + }); + const { id: targetProfileId2 } = databaseBuilder.factory.buildTargetProfile({ + id: PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS[1], + }); + const { id: targetProfileId3 } = databaseBuilder.factory.buildTargetProfile({ + id: PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS[2], + }); + const campaign1 = databaseBuilder.factory.buildCampaign({ targetProfileId: targetProfileId1 }); + const campaign2 = databaseBuilder.factory.buildCampaign({ targetProfileId: targetProfileId2 }); + const campaign3 = databaseBuilder.factory.buildCampaign({ targetProfileId: targetProfileId3 }); + databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign1.id, + status: CampaignParticipationStatuses.SHARED, + createdAt: '2024-12-01T00:00:01.000Z', + }); + databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign2.id, + status: CampaignParticipationStatuses.TO_SHARE, + createdAt: '2024-12-02T15:00:00.000Z', + }); + databaseBuilder.factory.buildCampaignParticipation({ + campaignId: campaign3.id, + status: CampaignParticipationStatuses.TO_SHARE, + createdAt: '2024-12-03T23:59:58.000Z', + }); + + await databaseBuilder.commit(); + const userIds = await fetchUserIds(); + expect(userIds).to.have.lengthOf(3); + }); + }); + + describe('#handle', function () { + it('should reward expected users', async function () {}); + }); +});