From 4e416ed67acbf4404fbd4ad3df97c744241c1a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Habinshuti?= Date: Sun, 4 Oct 2020 20:08:51 +0300 Subject: [PATCH 1/4] Fix error in vetted distribution --- server/src/core/distribution/run-distribution.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/server/src/core/distribution/run-distribution.ts b/server/src/core/distribution/run-distribution.ts index 8f9afaa6..6d818620 100644 --- a/server/src/core/distribution/run-distribution.ts +++ b/server/src/core/distribution/run-distribution.ts @@ -62,7 +62,7 @@ export async function runDonationDistribution(db: Db, args: DonationDistribution donors = await computeDonorsBalances(db, Array.from(new Set(donorIds))); } - const plan = createDistributionPlan(beneficiaries, donors); + const plan = createDistributionPlan(beneficiaries, donors, onlyVettedBeneficiaries); const result = await executeDistributionPlan(users, plan.transfers); return result; } @@ -77,7 +77,6 @@ export async function runDonationDistribution(db: Db, args: DonationDistribution */ export async function findEligibleBeneficiaries(db: Db, periodLimit: number, periodLength: number, filter: any | BeneficiaryFilter = {}): Promise { const periodMilliseconds = periodLength * 24 * 3600 * 1000; - const projectDonors: number = !filter.isVetted ? 1 : 0; const result = db.collection(USERS_COLL).aggregate([ { $match: { ...filter, beneficiaryStatus: 'verified', roles: 'beneficiary' }, @@ -126,7 +125,7 @@ export async function findEligibleBeneficiaries(db: Db, periodLimit: number, per $match: { totalReceived: { $lt: periodLimit } } }, { - $project: { _id: 1, donors: projectDonors, totalReceived: 1, remaining: { $subtract: [periodLimit, '$totalReceived']} } + $project: { _id: 1, donors: 1, totalReceived: 1, remaining: { $subtract: [periodLimit, '$totalReceived']} } } ]); @@ -206,7 +205,7 @@ export async function computeDonorsBalances(db: Db, donors?: string[]): Promise< return result.toArray(); } -export function createDistributionPlan(beneficiaries: EligibleBeneficiary[], donors: DonorBalance[]): CreateDistributionPlanResult { +export function createDistributionPlan(beneficiaries: EligibleBeneficiary[], donors: DonorBalance[], onlyVettedBeneficiaries: boolean = false): CreateDistributionPlanResult { const transfers: DistributionPlanTransfer[] = []; const beneficiariesSummaries = beneficiaries.reduce((acc, b) => ({ @@ -220,7 +219,7 @@ export function createDistributionPlan(beneficiaries: EligibleBeneficiary[], don }), {} as DistributionPlanDonorsSummaries); beneficiaries.forEach((beneficiary) => { - const beneficiaryDonors = beneficiary.donors ? beneficiary.donors : donors; + const beneficiaryDonors = onlyVettedBeneficiaries ? donors : beneficiary.donors; beneficiaryDonors.forEach((donor: string | DonorBalance) => { const beneficiarySummary = beneficiariesSummaries[beneficiary._id]; const donorSummary = typeof donor === "object" ? donorsSummaries[donor._id] : donorsSummaries[donor]; From 0dbeafc9a6461ad32760dfbf0006e16f8ce4e11b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Habinshuti?= Date: Sun, 4 Oct 2020 20:08:59 +0300 Subject: [PATCH 2/4] Add test case for vetted distribution --- .../tests/distribution-service.test.ts | 19 +++++++++++++++++++ .../src/core/distribution/tests/fixtures.ts | 5 ++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/server/src/core/distribution/tests/distribution-service.test.ts b/server/src/core/distribution/tests/distribution-service.test.ts index 6751cdea..3a03609f 100644 --- a/server/src/core/distribution/tests/distribution-service.test.ts +++ b/server/src/core/distribution/tests/distribution-service.test.ts @@ -102,6 +102,25 @@ describe('DonationDistributionService tests', () => { await lock.ensureUnlocked(); }); + describe('Vetted distribution', () => { + test('should distribute only to vetted beneficiaries, from any donor', async () => { + const distributionService = createDistributionService(); + const res = await distributionService.distributeDonations(true); + + const savedData: DonationDistributionResults = await dbUtils.getCollection(COLL).findOne({ _id: res._id }); + const { distributions } = savedData; + // beneficiary3 should receive 630 + expect(distributions.filter(d => d.beneficiary === 'beneficiary3').reduce((a, b) => a + b.amount, 0)).toEqual(630); + // beneficiary4 should receive 2000 + expect(distributions.filter(d => d.beneficiary === 'beneficiary4').reduce((a, b) => a + b.amount, 0)).toEqual(2000); + // beneficiary5 should receive 2000 + expect(distributions.filter(d => d.beneficiary === 'beneficiary5').reduce((a, b) => a + b.amount, 0)).toEqual(2000); + + // confirm the total is 4630 to ensure no other beneficiary was included in the distribution + expect(distributions.reduce((a, b) => a + b.amount, 0)).toEqual(4630); + }); + }); + test('should not run if distribution lock is locked', async () => { const lock = systemLockService.distribution(); const lock2 = systemLockService.distribution(); diff --git a/server/src/core/distribution/tests/fixtures.ts b/server/src/core/distribution/tests/fixtures.ts index 8fb5568d..6017c380 100644 --- a/server/src/core/distribution/tests/fixtures.ts +++ b/server/src/core/distribution/tests/fixtures.ts @@ -40,6 +40,7 @@ export const users = [ }, { _id: 'beneficiary3', + isVetted: true, beneficiaryStatus: 'verified', roles: ['beneficiary'], donors: ['donor1', 'donor2'] @@ -47,6 +48,7 @@ export const users = [ // this beneficiary has no associated transactions { _id: 'beneficiary4', + isVetted: true, beneficiaryStatus: 'verified', roles: ['beneficiary'], donors: ['donor3'] @@ -54,9 +56,10 @@ export const users = [ // this beneficiary has neither donors nor transactions { _id: 'beneficiary5', + isVetted: true, beneficiaryStatus: 'verified', roles: ['beneficiary'], - donors: [] + donors: [] } ]; From 602d299912ffe87a6fba8b56d542168cfd74e633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Habinshuti?= Date: Sun, 4 Oct 2020 20:21:45 +0300 Subject: [PATCH 3/4] Indicate when distribution results were for vetted beneficiaries --- server/src/core/distribution/distribution-service.ts | 1 + server/src/core/distribution/tests/distribution-service.test.ts | 2 ++ server/src/core/distribution/types.ts | 1 + 3 files changed, 4 insertions(+) diff --git a/server/src/core/distribution/distribution-service.ts b/server/src/core/distribution/distribution-service.ts index 1d8760c1..44d3c688 100644 --- a/server/src/core/distribution/distribution-service.ts +++ b/server/src/core/distribution/distribution-service.ts @@ -27,6 +27,7 @@ export class DonationDistributions implements DonationDistributionService { const results: DonationDistributionResults = { _id: generateId(), + onlyVettedBeneficiaries, startedAt, finishedAt, distributions diff --git a/server/src/core/distribution/tests/distribution-service.test.ts b/server/src/core/distribution/tests/distribution-service.test.ts index 3a03609f..026a2025 100644 --- a/server/src/core/distribution/tests/distribution-service.test.ts +++ b/server/src/core/distribution/tests/distribution-service.test.ts @@ -118,6 +118,8 @@ describe('DonationDistributionService tests', () => { // confirm the total is 4630 to ensure no other beneficiary was included in the distribution expect(distributions.reduce((a, b) => a + b.amount, 0)).toEqual(4630); + + expect(savedData.onlyVettedBeneficiaries).toBe(true); }); }); diff --git a/server/src/core/distribution/types.ts b/server/src/core/distribution/types.ts index 572f602d..c8724779 100644 --- a/server/src/core/distribution/types.ts +++ b/server/src/core/distribution/types.ts @@ -32,6 +32,7 @@ export interface DonationDistributionEvent { export interface DonationDistributionResults { _id: string; + onlyVettedBeneficiaries?: boolean; startedAt: Date; finishedAt: Date; distributions: DonationDistributionEvent[]; From d82fecca6b17de4c90b42d1abd2577eb92c3e492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Habinshuti?= Date: Sun, 4 Oct 2020 20:27:03 +0300 Subject: [PATCH 4/4] Test that onlyVettedBeneficiaries is false for unvetted distribution --- server/src/core/distribution/tests/distribution-service.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/src/core/distribution/tests/distribution-service.test.ts b/server/src/core/distribution/tests/distribution-service.test.ts index 026a2025..ef48a34c 100644 --- a/server/src/core/distribution/tests/distribution-service.test.ts +++ b/server/src/core/distribution/tests/distribution-service.test.ts @@ -97,6 +97,8 @@ describe('DonationDistributionService tests', () => { } ]); + expect(savedData.onlyVettedBeneficiaries).not.toBe(true); + expect(lock.lock).toHaveBeenCalledTimes(1); expect(lock.unlock).toHaveBeenCalledTimes(1); await lock.ensureUnlocked();