Merge pull request #4613 from MaximilianKrambach/assignmentFix
fix assignment calculations
This commit is contained in:
commit
259a408287
@ -139,11 +139,11 @@
|
|||||||
>{{ pollService.getLabel(vote.value) | translate }}:</span
|
>{{ pollService.getLabel(vote.value) | translate }}:</span
|
||||||
>
|
>
|
||||||
{{ pollService.getSpecialLabel(vote.weight) }}
|
{{ pollService.getSpecialLabel(vote.weight) }}
|
||||||
<span *ngIf="!pollService.isAbstractOption(poll, option)"
|
<span *ngIf="!pollService.isAbstractOption(poll, option, vote.value)"
|
||||||
>({{ pollService.getPercent(poll, option, vote.value) }}%)</span
|
>({{ pollService.getPercent(poll, option, vote.value) }}%)</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!pollService.isAbstractOption(poll, option)" class="poll-progress-bar">
|
<div *ngIf="!pollService.isAbstractOption(poll, option, vote.value)" class="poll-progress-bar">
|
||||||
<mat-progress-bar
|
<mat-progress-bar
|
||||||
mode="determinate"
|
mode="determinate"
|
||||||
[value]="pollService.getPercent(poll, option, vote.value)"
|
[value]="pollService.getPercent(poll, option, vote.value)"
|
||||||
@ -184,6 +184,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{{ pollService.getSpecialLabel(poll[key]) | translate }}
|
{{ pollService.getSpecialLabel(poll[key]) | translate }}
|
||||||
|
<span *ngIf="!pollService.isAbstractValue(poll, key)">
|
||||||
|
({{ pollService.getValuePercent(poll,key) }} %)
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
import { Component, OnInit, Input } from '@angular/core';
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder } from '@angular/forms';
|
import { FormGroup, FormBuilder } from '@angular/forms';
|
||||||
import { MatDialog, MatSnackBar } from '@angular/material';
|
import { MatDialog, MatSnackBar } from '@angular/material';
|
||||||
|
import { Title } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { AssignmentPoll } from 'app/shared/models/assignments/assignment-poll';
|
||||||
import { AssignmentPollDialogComponent } from '../assignment-poll-dialog/assignment-poll-dialog.component';
|
import { AssignmentPollDialogComponent } from '../assignment-poll-dialog/assignment-poll-dialog.component';
|
||||||
import { AssignmentPollService } from '../../services/assignment-poll.service';
|
import { AssignmentPollService, AssignmentPercentBase } from '../../services/assignment-poll.service';
|
||||||
import { AssignmentRepositoryService } from 'app/core/repositories/assignments/assignment-repository.service';
|
import { AssignmentRepositoryService } from 'app/core/repositories/assignments/assignment-repository.service';
|
||||||
import { BaseViewComponent } from 'app/site/base/base-view';
|
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||||
|
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||||
import { MajorityMethod, CalculablePollKey } from 'app/core/ui-services/poll.service';
|
import { MajorityMethod, CalculablePollKey } from 'app/core/ui-services/poll.service';
|
||||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||||
import { AssignmentPoll } from 'app/shared/models/assignments/assignment-poll';
|
|
||||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||||
import { Title } from '@angular/platform-browser';
|
|
||||||
import { ViewAssignment } from '../../models/view-assignment';
|
import { ViewAssignment } from '../../models/view-assignment';
|
||||||
import { ViewAssignmentPoll } from '../../models/view-assignment-poll';
|
import { ViewAssignmentPoll } from '../../models/view-assignment-poll';
|
||||||
import { ViewAssignmentPollOption } from '../../models/view-assignment-poll-option';
|
import { ViewAssignmentPollOption } from '../../models/view-assignment-poll-option';
|
||||||
@ -131,7 +132,8 @@ export class AssignmentPollComponent extends BaseViewComponent implements OnInit
|
|||||||
public translate: TranslateService,
|
public translate: TranslateService,
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private promptService: PromptService,
|
private promptService: PromptService,
|
||||||
private formBuilder: FormBuilder
|
private formBuilder: FormBuilder,
|
||||||
|
private config: ConfigService
|
||||||
) {
|
) {
|
||||||
super(titleService, translate, matSnackBar);
|
super(titleService, translate, matSnackBar);
|
||||||
}
|
}
|
||||||
@ -146,6 +148,13 @@ export class AssignmentPollComponent extends BaseViewComponent implements OnInit
|
|||||||
this.descriptionForm = this.formBuilder.group({
|
this.descriptionForm = this.formBuilder.group({
|
||||||
description: this.poll ? this.poll.description : ''
|
description: this.poll ? this.poll.description : ''
|
||||||
});
|
});
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.config.get<AssignmentPercentBase>('assignments_poll_100_percent_base').subscribe(() => {
|
||||||
|
if (this.poll) {
|
||||||
|
this.poll.pollBase = this.pollService.getBaseAmount(this.poll);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,6 +5,11 @@ import { Identifiable } from 'app/shared/models/base/identifiable';
|
|||||||
import { PollVoteValue } from 'app/core/ui-services/poll.service';
|
import { PollVoteValue } from 'app/core/ui-services/poll.service';
|
||||||
import { AssignmentPollOption } from 'app/shared/models/assignments/assignment-poll-option';
|
import { AssignmentPollOption } from 'app/shared/models/assignments/assignment-poll-option';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the order the option's votes are sorted in (server might send raw data in any order)
|
||||||
|
*/
|
||||||
|
const votesOrder: PollVoteValue[] = ['Votes', 'Yes', 'No', 'Abstain'];
|
||||||
|
|
||||||
export class ViewAssignmentPollOption implements Identifiable, Updateable {
|
export class ViewAssignmentPollOption implements Identifiable, Updateable {
|
||||||
private _assignmentPollOption: AssignmentPollOption;
|
private _assignmentPollOption: AssignmentPollOption;
|
||||||
private _user: ViewUser; // This is the "candidate". We'll stay consistent wich user here...
|
private _user: ViewUser; // This is the "candidate". We'll stay consistent wich user here...
|
||||||
@ -39,7 +44,7 @@ export class ViewAssignmentPollOption implements Identifiable, Updateable {
|
|||||||
weight: number;
|
weight: number;
|
||||||
value: PollVoteValue;
|
value: PollVoteValue;
|
||||||
}[] {
|
}[] {
|
||||||
return this.option.votes;
|
return this.option.votes.sort((a, b) => votesOrder.indexOf(a.value) - votesOrder.indexOf(b.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public get poll_id(): number {
|
public get poll_id(): number {
|
||||||
|
@ -13,7 +13,7 @@ import { ViewAssignmentPoll } from '../models/view-assignment-poll';
|
|||||||
|
|
||||||
type AssignmentPollValues = 'auto' | 'votes' | 'yesnoabstain' | 'yesno';
|
type AssignmentPollValues = 'auto' | 'votes' | 'yesnoabstain' | 'yesno';
|
||||||
export type AssignmentPollMethod = 'yn' | 'yna' | 'votes';
|
export type AssignmentPollMethod = 'yn' | 'yna' | 'votes';
|
||||||
type AssignmentPercentBase = 'YES_NO_ABSTAIN' | 'YES_NO' | 'VALID' | 'CAST' | 'DISABLED';
|
export type AssignmentPercentBase = 'YES_NO_ABSTAIN' | 'YES_NO' | 'VALID' | 'CAST' | 'DISABLED';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service class for assignment polls.
|
* Service class for assignment polls.
|
||||||
@ -77,7 +77,7 @@ export class AssignmentPollService extends PollService {
|
|||||||
case 'YES_NO_ABSTAIN':
|
case 'YES_NO_ABSTAIN':
|
||||||
if (poll.pollmethod === 'votes') {
|
if (poll.pollmethod === 'votes') {
|
||||||
const yes = poll.options.map(option => {
|
const yes = poll.options.map(option => {
|
||||||
const yesValue = option.votes.find(v => v.value === 'Yes');
|
const yesValue = option.votes.find(v => v.value === 'Votes');
|
||||||
return yesValue ? yesValue.weight : -99;
|
return yesValue ? yesValue.weight : -99;
|
||||||
});
|
});
|
||||||
if (Math.min(...yes) < 0) {
|
if (Math.min(...yes) < 0) {
|
||||||
@ -106,8 +106,17 @@ export class AssignmentPollService extends PollService {
|
|||||||
* @returns a percentage number with two digits, null if the value cannot be calculated
|
* @returns a percentage number with two digits, null if the value cannot be calculated
|
||||||
*/
|
*/
|
||||||
public getPercent(poll: ViewAssignmentPoll, option: ViewAssignmentPollOption, value: PollVoteValue): number | null {
|
public getPercent(poll: ViewAssignmentPoll, option: ViewAssignmentPollOption, value: PollVoteValue): number | null {
|
||||||
const base = poll.pollmethod === 'votes' ? poll.pollBase : this.getOptionBaseAmount(poll, option);
|
let base = 0;
|
||||||
if (!base) {
|
if (this.percentBase === 'DISABLED') {
|
||||||
|
return null;
|
||||||
|
} else if (this.percentBase === 'VALID') {
|
||||||
|
base = poll.votesvalid;
|
||||||
|
} else if (this.percentBase === 'CAST') {
|
||||||
|
base = poll.votescast;
|
||||||
|
} else {
|
||||||
|
base = poll.pollmethod === 'votes' ? poll.pollBase : this.getOptionBaseAmount(poll, option);
|
||||||
|
}
|
||||||
|
if (!base || base < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const vote = option.votes.find(v => v.value === value);
|
const vote = option.votes.find(v => v.value === value);
|
||||||
@ -141,11 +150,15 @@ export class AssignmentPollService extends PollService {
|
|||||||
*
|
*
|
||||||
* @param poll
|
* @param poll
|
||||||
* @param option
|
* @param option
|
||||||
|
* @param key (optional) the key to calculate
|
||||||
* @returns true if the poll has no percentages, the poll option is a special value,
|
* @returns true if the poll has no percentages, the poll option is a special value,
|
||||||
* or if the calculations are disabled in the config
|
* or if the calculations are disabled in the config
|
||||||
*/
|
*/
|
||||||
public isAbstractOption(poll: ViewAssignmentPoll, option: ViewAssignmentPollOption): boolean {
|
public isAbstractOption(poll: ViewAssignmentPoll, option: ViewAssignmentPollOption, key?: PollVoteValue): boolean {
|
||||||
if (!option.votes || !option.votes.length) {
|
if (this.percentBase === 'DISABLED' || !option.votes || !option.votes.length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (key === 'Abstain' && this.percentBase === 'YES_NO') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (poll.pollmethod === 'votes') {
|
if (poll.pollmethod === 'votes') {
|
||||||
@ -166,7 +179,7 @@ export class AssignmentPollService extends PollService {
|
|||||||
* Use {@link isAbstractOption} for these
|
* Use {@link isAbstractOption} for these
|
||||||
*/
|
*/
|
||||||
public isAbstractValue(poll: ViewAssignmentPoll, value: CalculablePollKey): boolean {
|
public isAbstractValue(poll: ViewAssignmentPoll, value: CalculablePollKey): boolean {
|
||||||
if (!poll.pollBase || !this.pollValues.includes(value)) {
|
if (this.percentBase === 'DISABLED' || !poll.pollBase || !this.pollValues.includes(value)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.percentBase === 'CAST' && poll[value] >= 0) {
|
if (this.percentBase === 'CAST' && poll[value] >= 0) {
|
||||||
@ -183,17 +196,21 @@ export class AssignmentPollService extends PollService {
|
|||||||
* @returns an positive integer to be used as percentage base, or null
|
* @returns an positive integer to be used as percentage base, or null
|
||||||
*/
|
*/
|
||||||
private getOptionBaseAmount(poll: ViewAssignmentPoll, option: ViewAssignmentPollOption): number | null {
|
private getOptionBaseAmount(poll: ViewAssignmentPoll, option: ViewAssignmentPollOption): number | null {
|
||||||
if (poll.pollmethod === 'votes') {
|
if (this.percentBase === 'DISABLED' || poll.pollmethod === 'votes') {
|
||||||
return null;
|
return null;
|
||||||
|
} else if (this.percentBase === 'CAST') {
|
||||||
|
return poll.votescast > 0 ? poll.votescast : null;
|
||||||
|
} else if (this.percentBase === 'VALID') {
|
||||||
|
return poll.votesvalid > 0 ? poll.votesvalid : null;
|
||||||
}
|
}
|
||||||
const yes = option.votes.find(v => v.value === 'Yes');
|
const yes = option.votes.find(v => v.value === 'Yes');
|
||||||
const no = option.votes.find(v => v.value === 'No');
|
const no = option.votes.find(v => v.value === 'No');
|
||||||
if (poll.pollmethod === 'yn') {
|
if (this.percentBase === 'YES_NO') {
|
||||||
if (!yes || yes.weight === undefined || !no || no.weight === undefined) {
|
if (!yes || yes.weight === undefined || !no || no.weight === undefined) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return yes.weight >= 0 && no.weight >= 0 ? yes.weight + no.weight : null;
|
return yes.weight >= 0 && no.weight >= 0 ? yes.weight + no.weight : null;
|
||||||
} else {
|
} else if (this.percentBase === 'YES_NO_ABSTAIN') {
|
||||||
const abstain = option.votes.find(v => v.value === 'Abstain');
|
const abstain = option.votes.find(v => v.value === 'Abstain');
|
||||||
if (!abstain || abstain.weight === undefined) {
|
if (!abstain || abstain.weight === undefined) {
|
||||||
return null;
|
return null;
|
||||||
|
Loading…
Reference in New Issue
Block a user