From 23577be953bbdbf009830443e2104addbcd7dfd1 Mon Sep 17 00:00:00 2001 From: GabrielInTheWorld Date: Thu, 6 Jan 2022 15:35:22 +0100 Subject: [PATCH] Fixes: Percentbases of candidates in assignments --- ...ignment-poll-detail-content.component.html | 4 +-- .../shared/pipes/poll-percent-base.pipe.ts | 12 ++++++-- .../services/assignment-poll.service.ts | 25 ++++++----------- .../services/assignment-pdf.service.ts | 7 ++++- .../motions/services/motion-pdf.service.ts | 5 +++- .../app/site/polls/services/poll.service.ts | 28 +++++++++++++++++-- server/requirements/development.txt | 2 +- 7 files changed, 56 insertions(+), 27 deletions(-) diff --git a/client/src/app/shared/components/assignment-poll-detail-content/assignment-poll-detail-content.component.html b/client/src/app/shared/components/assignment-poll-detail-content/assignment-poll-detail-content.component.html index 4d0040bad..9ccb2962d 100644 --- a/client/src/app/shared/components/assignment-poll-detail-content/assignment-poll-detail-content.component.html +++ b/client/src/app/shared/components/assignment-poll-detail-content/assignment-poll-detail-content.component.html @@ -41,7 +41,7 @@
- {{ getVoteAmount(vote, row) | pollPercentBase: poll:'assignment' }} + {{ getVoteAmount(vote, row) | pollPercentBase: poll:row:'assignment' }} {{ getVoteAmount(vote, row) | parsePollNumber }} @@ -59,7 +59,7 @@
- {{ poll.entitled_users_at_stop.length | pollPercentBase: poll:'assignment' }} + {{ poll.entitled_users_at_stop.length | pollPercentBase: poll:row:'assignment' }} {{ poll.entitled_users_at_stop.length }} diff --git a/client/src/app/shared/pipes/poll-percent-base.pipe.ts b/client/src/app/shared/pipes/poll-percent-base.pipe.ts index 72866be5f..51525d694 100644 --- a/client/src/app/shared/pipes/poll-percent-base.pipe.ts +++ b/client/src/app/shared/pipes/poll-percent-base.pipe.ts @@ -3,6 +3,7 @@ import { Pipe, PipeTransform } from '@angular/core'; import { AssignmentPollService } from 'app/site/assignments/modules/assignment-poll/services/assignment-poll.service'; import { MotionPollService } from 'app/site/motions/services/motion-poll.service'; import { PollData } from 'app/site/polls/services/poll.service'; +import { PollDataOption, PollTableData } from '../../site/polls/services/poll.service'; /** * Uses a number and a ViewPoll-object. @@ -26,7 +27,12 @@ export class PollPercentBasePipe implements PipeTransform { private motionPollService: MotionPollService ) {} - public transform(value: number, poll: PollData, type: 'motion' | 'assignment'): string | null { + public transform( + value: number, + poll: PollData, + row: PollDataOption | PollTableData, + type: 'motion' | 'assignment' + ): string | null { // logic handles over the pollService to avoid circular dependencies let voteValueInPercent: string; @@ -36,9 +42,9 @@ export class PollPercentBasePipe implements PipeTransform { * we cannot expect the projector to work with real types for now, we need to provice the type */ if (type === 'assignment') { - voteValueInPercent = this.assignmentPollService.getVoteValueInPercent(value, poll); + voteValueInPercent = this.assignmentPollService.getVoteValueInPercent(value, { poll, row }); } else { - voteValueInPercent = this.motionPollService.getVoteValueInPercent(value, poll); + voteValueInPercent = this.motionPollService.getVoteValueInPercent(value, { poll, row }); } if (voteValueInPercent) { diff --git a/client/src/app/site/assignments/modules/assignment-poll/services/assignment-poll.service.ts b/client/src/app/site/assignments/modules/assignment-poll/services/assignment-poll.service.ts index 47053bbc4..bc5f83665 100644 --- a/client/src/app/site/assignments/modules/assignment-poll/services/assignment-poll.service.ts +++ b/client/src/app/site/assignments/modules/assignment-poll/services/assignment-poll.service.ts @@ -196,33 +196,26 @@ export class AssignmentPollService extends PollService { })); } - private sumOptionsYN(poll: PollData): number { - return poll.options.reduce((o, n) => { - o += n.yes > 0 ? n.yes : 0; - o += n.no > 0 ? n.no : 0; - return o; - }, 0); + private sumOptionsYN(option: PollDataOption): number { + return (option?.yes ?? 0) + (option?.no ?? 0); } - private sumOptionsYNA(poll: PollData): number { - return poll.options.reduce((o, n) => { - o += n.abstain > 0 ? n.abstain : 0; - return o; - }, this.sumOptionsYN(poll)); + private sumOptionsYNA(option: PollDataOption): number { + return this.sumOptionsYN(option) + (option?.abstain ?? 0); } - public getPercentBase(poll: PollData): number { + public getPercentBase(poll: PollData, row: PollDataOption): number { const base: AssignmentPollPercentBase = poll.onehundred_percent_base as AssignmentPollPercentBase; let totalByBase: number; switch (base) { case AssignmentPollPercentBase.YN: - totalByBase = this.sumOptionsYN(poll); + totalByBase = this.sumOptionsYN(row); break; case AssignmentPollPercentBase.YNA: - totalByBase = this.sumOptionsYNA(poll); + totalByBase = this.sumOptionsYNA(row); break; case AssignmentPollPercentBase.Y: - totalByBase = this.sumOptionsYNA(poll); + totalByBase = this.sumOptionsYNA(row); break; case AssignmentPollPercentBase.Valid: totalByBase = poll.votesvalid; @@ -246,7 +239,7 @@ export class AssignmentPollService extends PollService { const voteValue = option[field]; const votingKey = this.translate.instant(this.pollKeyVerbose.transform(field)); const resultValue = this.parsePollNumber.transform(voteValue); - const resultInPercent = this.getVoteValueInPercent(voteValue, poll); + const resultInPercent = this.getVoteValueInPercent(voteValue, { poll, row: option }); let resultLabel = `${votingKey}: ${resultValue}`; // 0 is a valid number in this case diff --git a/client/src/app/site/assignments/services/assignment-pdf.service.ts b/client/src/app/site/assignments/services/assignment-pdf.service.ts index 491040f55..19a15ef33 100644 --- a/client/src/app/site/assignments/services/assignment-pdf.service.ts +++ b/client/src/app/site/assignments/services/assignment-pdf.service.ts @@ -241,7 +241,12 @@ export class AssignmentPdfService { .map((singleResult: VotingResult) => { const votingKey = this.translate.instant(this.pollKeyVerbose.transform(singleResult.vote)); const resultValue = this.parsePollNumber.transform(singleResult.amount); - const resultInPercent = this.pollPercentBase.transform(singleResult.amount, poll, 'assignment'); + const resultInPercent = this.pollPercentBase.transform( + singleResult.amount, + poll, + votingResult, + 'assignment' + ); return `${votingKey}${!!votingKey ? ': ' : ''}${resultValue} ${ singleResult.showPercent && resultInPercent ? resultInPercent : '' }`; diff --git a/client/src/app/site/motions/services/motion-pdf.service.ts b/client/src/app/site/motions/services/motion-pdf.service.ts index bd59f2655..f27ecd774 100644 --- a/client/src/app/site/motions/services/motion-pdf.service.ts +++ b/client/src/app/site/motions/services/motion-pdf.service.ts @@ -385,7 +385,10 @@ export class MotionPdfService { const resultValue = this.parsePollNumber.transform(value.amount); column1.push(`${votingOption}:`); if (value.showPercent) { - const resultInPercent = this.motionPollService.getVoteValueInPercent(value.amount, poll); + const resultInPercent = this.motionPollService.getVoteValueInPercent(value.amount, { + poll, + row: votingResult + }); // hard check for "null" since 0 is a valid number in this case if (resultInPercent !== null) { column2.push(`(${resultInPercent})`); diff --git a/client/src/app/site/polls/services/poll.service.ts b/client/src/app/site/polls/services/poll.service.ts index 3619b1022..b3bc89e0a 100644 --- a/client/src/app/site/polls/services/poll.service.ts +++ b/client/src/app/site/polls/services/poll.service.ts @@ -161,6 +161,13 @@ export interface VotingResult { const PollChartBarThickness = 20; +function isPollTableData(value: any): value is PollTableData { + if (!value) { + return false; + } + return !!value.votingOption && !!value.value; +} + /** * Shared service class for polls. Used by child classes {@link MotionPollService} * and {@link AssignmentPollService} @@ -215,10 +222,14 @@ export abstract class PollService { /** * return the total number of votes depending on the selected percent base */ - public abstract getPercentBase(poll: PollData): number; + public abstract getPercentBase(poll: PollData, row: PollDataOption): number; - public getVoteValueInPercent(value: number, poll: PollData): string | null { - const totalByBase = this.getPercentBase(poll); + public getVoteValueInPercent( + value: number, + { poll, row }: { poll: PollData; row: PollDataOption | PollTableData } + ): string | null { + const option = isPollTableData(row) ? this.transformToOptionData(row) : row; + const totalByBase = this.getPercentBase(poll, option); if (totalByBase && totalByBase > 0) { const percentNumber = (value / totalByBase) * 100; if (percentNumber >= 0) { @@ -342,6 +353,17 @@ export abstract class PollService { return isAssignment ? this.getPollDataFieldsByMethod(poll) : this.getPollDataFieldsByPercentBase(poll); } + protected transformToOptionData(data: PollTableData): PollDataOption { + const yes = data.value.find(vote => vote.vote === `yes`); + const no = data.value.find(vote => vote.vote === `no`); + const abstain = data.value.find(vote => vote.vote === `abstain`); + return { + yes: yes?.amount, + no: no?.amount, + abstain: abstain?.amount + }; + } + private getPollDataFieldsByMethod(poll: PollData | ViewBasePoll): CalculablePollKey[] { switch (poll.pollmethod) { case AssignmentPollMethod.YNA: { diff --git a/server/requirements/development.txt b/server/requirements/development.txt index 13348e7b9..9979d9c8c 100644 --- a/server/requirements/development.txt +++ b/server/requirements/development.txt @@ -2,7 +2,7 @@ black coverage flake8 isort<5.0.0 -mypy +mypy<0.920 pytest<5.4.2 pytest-django<3.9.0 pytest-asyncio<0.11.0