diff --git a/results-tabulation-api/ext/ExtendedElection/__init__.py b/results-tabulation-api/ext/ExtendedElection/__init__.py index 302e171b..033979a9 100644 --- a/results-tabulation-api/ext/ExtendedElection/__init__.py +++ b/results-tabulation-api/ext/ExtendedElection/__init__.py @@ -60,12 +60,122 @@ def get_area_map_for_tally_sheet(self, tally_sheet): return self.get_area_map(area=area) - def get_area_map(self): + def get_area_map(self, area=None, group_by=None, filter_by=None): + from orm.enums import AreaTypeEnum + area_map_subquery = self.get_area_map_query().subquery() - return db.session.query(area_map_subquery).filter( - area_map_subquery.c.electionId.in_(self.election.get_this_and_below_election_ids()) - ) + if area is None: + return db.session.query(area_map_subquery).filter( + area_map_subquery.c.electionId.in_(self.election.get_this_and_below_election_ids()) + ) + + column_name_list = [ + "pollingStationId", "pollingStationName", + "pollingDistrictId", "pollingDistrictName", + "countingCentreId", "countingCentreName", + "pollingDivisionId", "pollingDivisionName", + "electoralDistrictId", "electoralDistrictName", + "countryId", "countryName" + ] + column_name_to_column_map = { + "pollingStationId": area_map_subquery.c.pollingStationId, + "pollingStationName": area_map_subquery.c.pollingStationName, + "pollingDistrictId": area_map_subquery.c.pollingDistrictId, + "pollingDistrictName": area_map_subquery.c.pollingDistrictName, + "countingCentreId": area_map_subquery.c.countingCentreId, + "countingCentreName": area_map_subquery.c.countingCentreName, + "pollingDivisionId": area_map_subquery.c.pollingDivisionId, + "pollingDivisionName": area_map_subquery.c.pollingDivisionName, + "electoralDistrictId": area_map_subquery.c.electoralDistrictId, + "electoralDistrictName": area_map_subquery.c.electoralDistrictName, + "countryId": area_map_subquery.c.countryId, + "countryName": area_map_subquery.c.countryName + } + query_args = [] + query_filter = [] + query_group_by = [] + area_and_vote_type_wise_group_by_map = { + AreaTypeEnum.CountingCentre: [ + "countingCentreId", + "countingCentreName", + "pollingDivisionId", + "pollingDivisionName", + "electoralDistrictId", + "electoralDistrictName", + "countryId", + "countryName" + ], + AreaTypeEnum.PollingStation: [ + "pollingDistrictId", + "pollingDistrictName", + "pollingStationId", + "pollingStationName", + "countingCentreId", + "countingCentreName", + "pollingDivisionId", + "pollingDivisionName", + "electoralDistrictId", + "electoralDistrictName", + "countryId", + "countryName" + ], + AreaTypeEnum.PollingDivision: [ + "pollingDivisionId", + "pollingDivisionName", + "electoralDistrictId", + "electoralDistrictName", + "countryId", + "countryName" + ], + AreaTypeEnum.ElectoralDistrict: [ + "electoralDistrictId", + "electoralDistrictName", + "countryId", + "countryName" + ], + AreaTypeEnum.Country: [ + "countryId", + "countryName" + ] + } + + area_and_vote_type_wise_filter_map = { + AreaTypeEnum.PollingStation: [area_map_subquery.c.pollingStationId == area.areaId], + AreaTypeEnum.PollingDistrict: [area_map_subquery.c.pollingDistrictId == area.areaId], + AreaTypeEnum.CountingCentre: [area_map_subquery.c.countingCentreId == area.areaId], + AreaTypeEnum.PollingDivision: [area_map_subquery.c.pollingDivisionId == area.areaId], + AreaTypeEnum.ElectoralDistrict: [area_map_subquery.c.electoralDistrictId == area.areaId], + AreaTypeEnum.Country: [area_map_subquery.c.countryId == area.areaId] + } + + if group_by is None: + if area.areaType in area_and_vote_type_wise_group_by_map: + group_by = area_and_vote_type_wise_group_by_map[area.areaType] + else: + group_by = [] + + for column_name in column_name_list: + column = column_name_to_column_map[column_name] + if column_name in group_by: + query_group_by.append(column) + + # Append the column to query. + query_args.append(column) + else: + query_args.append(bindparam(column_name, None)) + + if filter_by is None: + if area.areaType in area_and_vote_type_wise_filter_map: + filter_by = area_and_vote_type_wise_filter_map[area.areaType] + else: + filter_by = [] + + query_filter = filter_by + + area_map = db.session.query(*query_args).filter(*query_filter).group_by(*query_group_by).all() + + return area_map def get_area_map_query(self): diff --git a/results-tabulation-api/orm/entities/Submission/TallySheet/__init__.py b/results-tabulation-api/orm/entities/Submission/TallySheet/__init__.py index 6508b145..82faf346 100644 --- a/results-tabulation-api/orm/entities/Submission/TallySheet/__init__.py +++ b/results-tabulation-api/orm/entities/Submission/TallySheet/__init__.py @@ -68,47 +68,6 @@ class TallySheetModel(db.Model): secondaryjoin="TallySheetModel.tallySheetId==TallySheetTallySheetModel.parentTallySheetId" ) - def get_tally_sheet_workflow_instance_actions(self): - tally_sheet_workflow_instance_actions = db.session.query( - WorkflowActionModel.workflowActionId, - WorkflowActionModel.actionName, - WorkflowActionModel.actionType, - WorkflowActionModel.fromStatus, - WorkflowActionModel.toStatus, - WorkflowInstance.Model.status - ).filter( - WorkflowInstance.Model.workflowInstanceId == self.workflowInstanceId, - WorkflowActionModel.workflowId == WorkflowInstance.Model.workflowId - ).order_by( - WorkflowActionModel.workflowActionId - ).all() - - processed_tally_sheet_workflow_instance_actions = [] - for tally_sheet_workflow_instance_action in tally_sheet_workflow_instance_actions: - processed_tally_sheet_workflow_instance_actions.append({ - "workflowActionId": tally_sheet_workflow_instance_action.workflowActionId, - "actionName": tally_sheet_workflow_instance_action.actionName, - "actionType": tally_sheet_workflow_instance_action.actionType, - "fromStatus": tally_sheet_workflow_instance_action.fromStatus, - "toStatus": tally_sheet_workflow_instance_action.toStatus, - "allowed": tally_sheet_workflow_instance_action.fromStatus == tally_sheet_workflow_instance_action.status, - "authorized": has_role_based_access(tally_sheet=self, - access_type=tally_sheet_workflow_instance_action.actionType) - }) - - return processed_tally_sheet_workflow_instance_actions - - @hybrid_property - def workflowInstanceActions(self): - return self.get_tally_sheet_workflow_instance_actions() - - @hybrid_property - def areaMapList(self): - extended_election = self.submission.election.get_extended_election() - area_map = extended_election.get_area_map_for_tally_sheet(tally_sheet=self) - - return area_map - def add_parent(self, parentTallySheet): parentTallySheet.add_child(self) @@ -140,8 +99,6 @@ def set_latest_version(self, tallySheetVersion: TallySheetVersion): else: self.submission.set_latest_version(submissionVersion=tallySheetVersion.submissionVersion) - self.update_status_report() - @hybrid_property def latestVersion(self): return TallySheetVersion.Model.query.filter( @@ -425,6 +382,21 @@ def _get_electoral_district_name(polling_division): return electoral_district_name +def refactor_tally_sheet_response(tally_sheet): + workflow_instance = tally_sheet.workflowInstance + workflow_actions = tally_sheet.workflowInstance.workflow.actions + for workflow_action in workflow_actions: + setattr(workflow_action, "allowed", workflow_action.fromStatus == workflow_instance.status) + setattr(workflow_action, "authorized", has_role_based_access(tally_sheet=tally_sheet, + access_type=workflow_action.actionType)) + setattr(tally_sheet.workflowInstance, "actions", workflow_actions) + + setattr(tally_sheet, "areaId", tally_sheet.submission.areaId) + setattr(tally_sheet, "area", tally_sheet.submission.area) + + return tally_sheet + + def get_by_id(tallySheetId, tallySheetCode=None): # Filter by authorized areas user_access_area_ids: Set[int] = get_user_access_area_ids() @@ -450,7 +422,7 @@ def get_by_id(tallySheetId, tallySheetCode=None): code=MESSAGE_CODE_TALLY_SHEET_NOT_AUTHORIZED_TO_VIEW ) - return tally_sheet + return refactor_tally_sheet_response(tally_sheet) def get_all(electionId=None, areaId=None, tallySheetCode=None, voteType=None): @@ -484,6 +456,7 @@ def get_all(electionId=None, areaId=None, tallySheetCode=None, voteType=None): authorized_tally_sheet_list = [] for tally_sheet in tally_sheet_list: if has_role_based_access(tally_sheet=tally_sheet, access_type=WORKFLOW_ACTION_TYPE_VIEW): + refactor_tally_sheet_response(tally_sheet) authorized_tally_sheet_list.append(tally_sheet) return authorized_tally_sheet_list diff --git a/results-tabulation-api/orm/entities/Workflow/WorkflowInstance/__init__.py b/results-tabulation-api/orm/entities/Workflow/WorkflowInstance/__init__.py index 277a5629..d281be82 100644 --- a/results-tabulation-api/orm/entities/Workflow/WorkflowInstance/__init__.py +++ b/results-tabulation-api/orm/entities/Workflow/WorkflowInstance/__init__.py @@ -18,6 +18,7 @@ class WorkflowInstanceModel(db.Model): latestLogId = db.Column(db.Integer, db.ForeignKey("workflowInstanceLog.workflowInstanceLogId"), nullable=True) proofId = db.Column(db.Integer, db.ForeignKey("proof.proofId"), nullable=True) + workflow = relationship("WorkflowModel", foreign_keys=[workflowId], lazy='subquery') latestLog = relationship(WorkflowInstanceLog.Model, foreign_keys=[latestLogId]) proof = relationship(Proof.Model, foreign_keys=[proofId]) diff --git a/results-tabulation-api/orm/entities/Workflow/__init__.py b/results-tabulation-api/orm/entities/Workflow/__init__.py index 26be0d61..9058ec8e 100644 --- a/results-tabulation-api/orm/entities/Workflow/__init__.py +++ b/results-tabulation-api/orm/entities/Workflow/__init__.py @@ -1,5 +1,6 @@ from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy import case +from sqlalchemy.orm import relationship from app import db @@ -12,6 +13,8 @@ class WorkflowModel(db.Model): firstStatus = db.Column(db.String(100), nullable=False) lastStatus = db.Column(db.String(100), nullable=False) + actions = relationship("WorkflowActionModel", lazy='subquery') + @classmethod def create(cls, workflowName, statuses, actions, firstStatus, lastStatus): workflow: WorkflowModel = cls(workflowName=workflowName, firstStatus=firstStatus, lastStatus=lastStatus) diff --git a/results-tabulation-api/schemas/__init__.py b/results-tabulation-api/schemas/__init__.py index 521e5aad..a18165c5 100644 --- a/results-tabulation-api/schemas/__init__.py +++ b/results-tabulation-api/schemas/__init__.py @@ -393,12 +393,12 @@ class Meta: "templateId", "template", "electionId", - # "areaId", - # "area", + "areaId", + "area", # "areaMapList", "latestVersion", "metaDataList", - # "workflowInstance", + "workflowInstance", "latestVersionId" ) @@ -407,7 +407,7 @@ class Meta: # to use for deserialization sqla_session = db.session - template = ma.Nested("TemplateSchema", only=["templateId", "templateName", "isDerived"]) + template = ma.Nested("TemplateSchema", only=["templateId", "templateName", "isDerived", "rows"]) area = ma.Nested(AreaSchema, only=["areaId", "areaName"]) versions = ma.Nested(SubmissionVersionSchema, only="submissionVersionId", many=True) latestVersion = ma.Nested(TallySheetVersionSchema) @@ -417,7 +417,7 @@ class Meta: submissionProof = ma.Nested(Proof_Schema) metaDataList = ma.Nested(MetaDataSchema, many=True) areaMapList = ma.Nested('AreaMapSchema', many=True, partial=True) - workflowInstance = ma.Nested(WorkflowInstanceSchema, only=["workflowId", "statuses", "status"]) + workflowInstance = ma.Nested(WorkflowInstanceSchema, only=["workflowId", "actions", "status"]) class TallySheetSchema(ma.ModelSchema): @@ -428,14 +428,12 @@ class Meta: "templateId", "template", "electionId", - # "areaId", - # "area", + "areaId", + "area", # "areaMapList", "metaDataList", "workflowInstance", - "workflowInstanceActions", - "latestVersionId", - "submission" + "latestVersionId" ) model = TallySheet.Model @@ -454,7 +452,7 @@ class Meta: submissionProof = ma.Nested(Proof_Schema) metaDataList = ma.Nested(MetaDataSchema, many=True) areaMapList = ma.Nested('AreaMapSchema', many=True, partial=True) - workflowInstance = ma.Nested(WorkflowInstanceSchema, only=["workflowId", "status"]) + workflowInstance = ma.Nested(WorkflowInstanceSchema, only=["workflowId", "actions", "status"]) workflowInstanceActions = ma.Nested(StatusActionSchema, many=True) diff --git a/results-tabulation-ui/src/components/election/extended-election/ParliamentElection2020/tally-sheet-edit/tally-sheet-edit-pe-27.js b/results-tabulation-ui/src/components/election/extended-election/ParliamentElection2020/tally-sheet-edit/tally-sheet-edit-pe-27.js index 810825f5..935f5c7f 100644 --- a/results-tabulation-ui/src/components/election/extended-election/ParliamentElection2020/tally-sheet-edit/tally-sheet-edit-pe-27.js +++ b/results-tabulation-ui/src/components/election/extended-election/ParliamentElection2020/tally-sheet-edit/tally-sheet-edit-pe-27.js @@ -244,7 +244,7 @@ export default function TallySheetEdit_PE_27({history, queryString, election, ta Party Name Party Symbol Count in words - Count in figures + Count in figures @@ -270,7 +270,7 @@ export default function TallySheetEdit_PE_27({history, queryString, election, ta }} /> - + Total valid vote count - + Total rejected vote count - Total vote count - + { @@ -126,21 +126,6 @@ export default function TallySheetEdit_PE_4({history, queryString, election, tal return total; } - function calculateTotalFirstPreferenceCount() { - return calculateTotalValidFirstPreferenceCount(); - } - - - const handleTotalFirstPreferenceCountChange = () => event => { - const {value} = event.target; - setFirstPreferenceCountRow((firstPreferenceCountRow) => { - return { - ...firstPreferenceCountRow, - numValue: processNumericValue(value) - } - }); - }; - function getTallySheetEditForm() { if (saved) { return @@ -154,10 +139,10 @@ export default function TallySheetEdit_PE_4({history, queryString, election, tal {candidateWiseFirstPreferenceCountRows.map((candidateWiseFirstPreferenceCountRow) => { - const {candidateId, candidateName, strValue, numValue} = candidateWiseFirstPreferenceCountRow; + const {candidateId, candidateName, candidateNumber, strValue, numValue} = candidateWiseFirstPreferenceCountRow; return {candidateName} - + {candidateNumber} {strValue} {numValue} @@ -165,16 +150,11 @@ export default function TallySheetEdit_PE_4({history, queryString, election, tal - - Total vote count - {calculateTotalFirstPreferenceCount()} - {getActionsBar()} -
@@ -185,17 +165,17 @@ export default function TallySheetEdit_PE_4({history, queryString, election, tal Candidate Name Candidate Number Count in words - Count in figures + Count in figures
{candidateWiseFirstPreferenceCountRows.map((candidateWiseFirstPreferenceCountRow, candidateWiseFirstPreferenceCountRowIndex) => { - const {candidateId, candidateName, strValue, numValue} = candidateWiseFirstPreferenceCountRow; + const {candidateId, candidateName, candidateNumber, strValue, numValue} = candidateWiseFirstPreferenceCountRow; return {candidateName} - + {candidateNumber} - - Total vote count - - - - {getActionsBar()} - diff --git a/results-tabulation-ui/src/services/tally-sheet.provider.js b/results-tabulation-ui/src/services/tally-sheet.provider.js index 093e2d5c..282da8e3 100644 --- a/results-tabulation-ui/src/services/tally-sheet.provider.js +++ b/results-tabulation-ui/src/services/tally-sheet.provider.js @@ -29,8 +29,6 @@ export function TallySheetProvider(props) { async function refactorTallySheetObject(tallySheet) { tallySheet.tallySheetCode = tallySheet.tallySheetCode.replace(/_/g, "-"); tallySheet.election = await electionContext.getElectionById(tallySheet.electionId); - tallySheet.workflowInstance.actions = tallySheet.workflowInstanceActions; - tallySheet.area = tallySheet.submission.area; tallySheet.areaMapList = await electionContext.getElectionAreaMap(tallySheet.electionId); // TODO fetch actions and area maps @@ -88,9 +86,10 @@ export function TallySheetProvider(props) { url: ENDPOINT_PATH_TALLY_SHEETS_BY_ID(tallySheetId), method: 'get', params: {} - }).then((tallySheet) => { + }).then(async (tallySheet) => { + await refactorTallySheetObject(tallySheet); _updateTallySheetState(tallySheet); - return refactorTallySheetObject(tallySheet); + return tallySheet; }) }