Ejemplo n.º 1
0
    def set_locked_version(self, tallySheetVersion: TallySheetVersion):
        if tallySheetVersion is None:
            if not has_role_based_access(self, ACCESS_TYPE_UNLOCK):
                raise ForbiddenException(
                    message="User not authorized to unlock the tally sheet.",
                    code=MESSAGE_CODE_TALLY_SHEET_NOT_AUTHORIZED_TO_UNLOCK)

            self.submission.set_locked_version(submissionVersion=None)
        else:
            if self.template.is_submit_allowed():
                if self.submittedVersionId is None:
                    raise ForbiddenException(
                        message=
                        "Data entry tally sheet cannot be locked before submitting",
                        code=MESSAGE_CODE_TALLY_SHEET_CANNOT_LOCK_BEFORE_SUBMIT
                    )
                elif self.submittedStamp.createdBy == get_user_name():
                    raise ForbiddenException(
                        message=
                        "Data entry tally sheet submitted user is not allowed to lock/unlock.",
                        code=
                        MESSAGE_CODE_TALLY_SHEET_SAME_USER_CANNOT_SAVE_AND_SUBMIT
                    )

            if not has_role_based_access(self, ACCESS_TYPE_LOCK):
                raise ForbiddenException(
                    message="User is not authorized to lock the tally sheet.",
                    code=MESSAGE_CODE_TALLY_SHEET_NOT_AUTHORIZED_TO_LOCK)

            self.submission.set_locked_version(
                submissionVersion=tallySheetVersion.submissionVersion)

        self.update_status_report()
Ejemplo n.º 2
0
    def set_notified_version(self):
        if self.lockedVersionId is None:
            raise ForbiddenException(
                message="Tally sheet cannot be notified before it's verified.",
                code=MESSAGE_CODE_TALLY_SHEET_CANNOT_BE_NOTIFIED_BEFORE_LOCK)
        elif self.notified is True:
            raise ForbiddenException(
                message="Tally sheet is already notified.",
                code=MESSAGE_CODE_TALLY_SHEET_ALREADY_NOTIFIED)
        else:
            self.submission.set_notified_version(
                submissionVersion=self.lockedVersion)

        self.update_status_report()
Ejemplo n.º 3
0
    def __init__(self, invoiceId, stationaryItemId):
        if Invoice.has_confirmed(invoiceId):
            raise ForbiddenException("Stationary items cannot be added to confirmed invoices (%d)" % invoiceId)
        elif StationaryItem.is_locked(stationaryItemId):
            raise ForbiddenException("Stationary item is not available (%d)" % stationaryItemId)
        else:
            received_proof = Proof.create(
                proofType=ProofTypeEnum.InvoiceStationaryItemReceive
            )

            super(InvoiceStationaryItemModel, self).__init__(
                invoiceId=invoiceId,
                stationaryItemId=stationaryItemId,
                receivedProofId=received_proof.proofId
            )
Ejemplo n.º 4
0
    def set_released_version(self):
        if self.notified is False:
            raise ForbiddenException(
                message="Tally sheet cannot be released before notifying",
                code=
                MESSAGE_CODE_TALLY_SHEET_CANNOT_BE_RELEASED_BEFORE_NOTIFYING)
        elif self.released is True:
            raise ForbiddenException(
                message="Tally sheet is already released.",
                code=MESSAGE_CODE_TALLY_SHEET_ALREADY_RELEASED)
        else:
            self.submission.set_released_version(
                submissionVersion=self.notifiedVersion)

        self.update_status_report()
Ejemplo n.º 5
0
    def get_template_column_to_query_filter_map(self, only_group_by_columns=False):
        extended_election = self.tallySheet.election.get_extended_election()

        template_column_to_query_filter_map = super(
            ExtendedTallySheet_PCE_42, self).get_template_column_to_query_filter_map(
            only_group_by_columns=only_group_by_columns)
        template_column_to_query_column_map = self.get_template_column_to_query_column_map()

        party_ids_to_be_filtered = []
        pe_r2_tally_sheets = db.session.query(TallySheet.Model).filter(
            TallySheet.Model.tallySheetId == TallySheetTallySheetModel.childTallySheetId,
            TallySheet.Model.latestVersionId != None,
            TallySheetTallySheetModel.parentTallySheetId == self.tallySheet.tallySheetId,
            TallySheet.Model.templateId == Template.Model.templateId,
            Template.Model.templateName == TALLY_SHEET_CODES.PCE_42,
            WorkflowInstance.Model.workflowInstanceId == TallySheet.Model.workflowInstanceId,
            WorkflowInstance.Model.status.in_(
                extended_election.tally_sheet_verified_statuses_list()
            ),
        ).all()

        if len(pe_r2_tally_sheets) == 0:
            raise ForbiddenException(
                message="Candidates cannot be allocated until the seat calculation (PCE-R2) is completed and verified.",
                code=MESSAGE_CODE_PE_21_CANNOT_BE_PROCESSED_WITHOUT_PE_R2
            )

        pe_r2_tally_sheet_ids = [tallySheet.tallySheetId for tallySheet in pe_r2_tally_sheets]

        for pe_r2_tally_sheet in pe_r2_tally_sheets:
            pe_r2_extended_tally_sheet_version = pe_r2_tally_sheet.get_extended_tally_sheet_version(
                tallySheetVersionId=pe_r2_tally_sheet.latestVersionId)
            party_wise_seat_calculation_df = pe_r2_extended_tally_sheet_version.get_party_wise_seat_calculations()
            for party_wise_seat_calculation_df_index in party_wise_seat_calculation_df.index:
                seats_allocated = party_wise_seat_calculation_df.at[
                    party_wise_seat_calculation_df_index, 'seatsAllocated']

                if seats_allocated > 0:
                    party_id = party_wise_seat_calculation_df.at[party_wise_seat_calculation_df_index, 'partyId']
                    party_ids_to_be_filtered.append(int(party_id))

        pe_ce_ro_pr_3_tally_sheets = db.session.query(
            TallySheet.Model.tallySheetId
        ).filter(
            TallySheet.Model.tallySheetId == TallySheetTallySheetModel.childTallySheetId,
            TallySheetTallySheetModel.parentTallySheetId == self.tallySheet.tallySheetId,
            TallySheet.Model.templateId == Template.Model.templateId,
            Template.Model.templateName == TALLY_SHEET_CODES.PE_CE_RO_PR_3,
            MetaData.Model.metaId == TallySheet.Model.metaId,
            MetaData.Model.metaDataKey == "partyId",
            MetaData.Model.metaDataValue.in_(party_ids_to_be_filtered)
        ).all()
        pe_ce_ro_pr_3_tally_sheet_ids = [tallySheet.tallySheetId for tallySheet in pe_ce_ro_pr_3_tally_sheets]

        template_column_to_query_filter_map["partyId"] += [
            template_column_to_query_column_map["partyId"].in_(party_ids_to_be_filtered),
            TallySheet.Model.tallySheetId.in_(pe_ce_ro_pr_3_tally_sheet_ids + pe_r2_tally_sheet_ids)
        ]

        return template_column_to_query_filter_map
def submit(tallySheetId, body):
    request_body = RequestBody(body)
    tallySheetVersionId = request_body.get("submittedVersionId")

    tally_sheet: TallySheetModel = TallySheet.get_by_id(tallySheetId=tallySheetId)

    if tally_sheet is None:
        raise NotFoundException(
            message="Tally sheet not found (tallySheetId=%d)" % tallySheetId,
            code=MESSAGE_CODE_TALLY_SHEET_NOT_FOUND
        )

    if tally_sheet.tallySheetCode not in [TallySheetCodeEnum.PRE_41, TallySheetCodeEnum.CE_201,
                                          TallySheetCodeEnum.CE_201_PV, TallySheetCodeEnum.PRE_34_CO]:
        raise ForbiddenException(
            message="Submit operation is not supported for this tally sheet type.",
            code=MESSAGE_CODE_TALLY_SHEET_SUBMIT_IS_NOT_SUPPORTED
        )

    tally_sheet_version = TallySheetVersion.get_by_id(tallySheetVersionId=tallySheetVersionId,
                                                      tallySheetId=tallySheetId)

    if tally_sheet_version is None:
        raise NotFoundException(
            message="Tally sheet version not found (tallySheetVersionId=%d)" % tallySheetVersionId,
            code=MESSAGE_CODE_TALLY_SHEET_VERSION_NOT_FOUND
        )

    tally_sheet.set_submitted_version(tally_sheet_version)

    if tally_sheet.tallySheetCode in [TallySheetCodeEnum.CE_201, TallySheetCodeEnum.CE_201_PV]:
        election = tally_sheet.submission.election
        electionId = election.parentElectionId
        countingCentreId = tally_sheet.areaId
        results = StatusCE201.get_status_records(electionId, countingCentreId)

        for item in results:
            item.status = "Submitted"

    if tally_sheet.tallySheetCode in [TallySheetCodeEnum.PRE_41]:
        election = tally_sheet.submission.election
        electionId = election.parentElectionId
        countingCentreId = tally_sheet.areaId
        results = StatusPRE41.get_status_records(electionId, countingCentreId)

        for item in results:
            item.status = "Submitted"

    if tally_sheet.tallySheetCode in [TallySheetCodeEnum.PRE_34_CO]:
        election = tally_sheet.submission.election
        electionId = election.parentElectionId
        countingCentreId = tally_sheet.areaId
        results = StatusPRE34.get_status_records(electionId, countingCentreId)

        for item in results:
            item.status = "Submitted"

    db.session.commit()

    return TallySheetSchema().dump(tally_sheet).data, 201
Ejemplo n.º 7
0
        def populate_seats_per_party(self, number_of_members_to_be_elected=0):
            df = self.get_party_wise_valid_vote_count_result()

            total_valid_vote_count = df['numValue'].sum()

            if total_valid_vote_count == 0:
                raise ForbiddenException(
                    message=
                    "Bonus Seat Allocation 1 (PCE_PC_BS_1) cannot be decided until the Provincial Vote Results (PCE-PC-V) is completed and verified.",
                    code=
                    MESSAGE_CODE_PCE_PC_BS_1_CANNOT_BE_PROCESSED_WITHOUT_PCE_PC_V
                )

            valid_vote_count_required_per_seat = total_valid_vote_count / number_of_members_to_be_elected
            valid_vote_count_required_per_seat_ceil = math.ceil(
                valid_vote_count_required_per_seat)

            df = df.sort_values(by=['numValue'], ascending=True)
            max_num_value_index = 0
            max_num_value = 0

            for index in df.index:
                num_value = df.at[index, 'numValue']
                if num_value > max_num_value:
                    max_num_value = num_value
                    max_num_value_index = index
                df.at[index, 'seatsAllocated'] = 0

            df.at[max_num_value_index, 'seatsAllocated'] = 2

            df["voteCountCeilPerSeat"] = pd.Series(np.full(
                len(df.index), valid_vote_count_required_per_seat_ceil),
                                                   index=df.index)

            return df
Ejemplo n.º 8
0
def upload_file(proofId, fileSource, fileType):
    proof = get_by_id(proofId=proofId)

    if proof is None:
        raise NotFoundException(
            message="Proof not found associated with the given proofId (proofId=%d)" % proofId,
            code=MESSAGE_CODE_PROOF_NOT_FOUND
        )
    elif proof.finished is True:
        raise ForbiddenException(
            message="No more evidence is accepted for this proof (proofId=%d)" % proofId,
            code=MESSAGE_CODE_PROOF_NOT_MORE_EVIDENCE_ACCEPTED
        )
    else:
        file = File.createFromFileSource(
            fileSource=fileSource,
            fileType=fileType
        )

        FolderFile.create(
            folderId=proof.scannedFilesFolderId,
            fileId=file.fileId
        )

        return proof
Ejemplo n.º 9
0
    def close(self):
        if self.size() is 0:
            raise ForbiddenException(
                message="A proof required at least one evidence. Please upload at least one evidence (proofId=%d)" % self.proofId,
                code=MESSAGE_CODE_PROOF_CANNOT_BE_CONFIRMED_WITHOUT_EVIDENCE
            )

        self.finished = True

        db.session.flush()
Ejemplo n.º 10
0
def delete(invoiceId, stationaryItemId):
    if Invoice.has_confirmed(invoiceId):
        raise ForbiddenException("Stationary items cannot be deleted from confirmed invoices (%d)" % invoiceId)
    else:
        result = Model.query.filter(
            Model.invoiceId == invoiceId,
            Model.stationaryItemId == stationaryItemId
        ).delete()

        db.session.flush()

        return result
Ejemplo n.º 11
0
    def set_submitted_version(self, tallySheetVersion: TallySheetVersion):
        if self.locked:
            raise ForbiddenException(
                message="Tally sheet is already locked.",
                code=MESSAGE_CODE_TALLY_SHEET_CANNOT_SUBMIT_AFTER_LOCK)

        if tallySheetVersion is None:
            self.submission.set_submitted_version(submissionVersion=None)
        else:
            self.submission.set_submitted_version(
                submissionVersion=tallySheetVersion.submissionVersion)

        self.update_status_report()
        def populate_seats_per_party(self, number_of_members_to_be_elected=0):
            df = self.get_party_wise_valid_vote_count_result()

            total_valid_vote_count = df['numValue'].sum()

            if total_valid_vote_count == 0:
                raise ForbiddenException(
                    message=
                    "National list seat calculation cannot be done on zero votes.",
                    code=
                    MESSAGE_CODE_PE_AI_NL_1_CANNOT_BE_PROCESSED_WITHOUT_PE_AI_ED
                )

            valid_vote_count_required_per_seat = total_valid_vote_count / number_of_members_to_be_elected
            valid_vote_count_required_per_seat_ceil = math.ceil(
                valid_vote_count_required_per_seat)

            for index in df.index:
                num_value = df.at[index, 'numValue']
                number_of_seats_qualified = math.floor(
                    num_value / valid_vote_count_required_per_seat_ceil)
                df.at[index,
                      'seatsAllocatedFromRound1'] = number_of_seats_qualified
                number_of_members_to_be_elected -= number_of_seats_qualified
                df.at[
                    index,
                    'validVotesRemainFromRound1'] = num_value % valid_vote_count_required_per_seat_ceil

            df = df.sort_values(by=['validVotesRemainFromRound1'],
                                ascending=False)
            for index in df.index:
                if number_of_members_to_be_elected > 0:
                    number_of_seats_qualified = 1
                    df.at[
                        index,
                        'seatsAllocatedFromRound2'] = number_of_seats_qualified
                    number_of_members_to_be_elected -= number_of_seats_qualified
                else:
                    df.at[index, 'seatsAllocatedFromRound2'] = 0

            df['seatsAllocated'] = df.seatsAllocatedFromRound1 + df.seatsAllocatedFromRound2

            df['draftSeatsAllocatedFromRound2'] = df.seatsAllocatedFromRound2

            df = df.sort_values(by=['numValue'], ascending=False)

            df["voteCountCeilPerSeat"] = pd.Series(np.full(
                len(df.index), valid_vote_count_required_per_seat_ceil),
                                                   index=df.index)

            return df
Ejemplo n.º 13
0
        def populate_seats_per_party(self, number_of_members_to_be_elected=0):
            df = self.get_party_wise_valid_vote_count_result()

            total_valid_vote_count = df['numValue'].sum()

            if total_valid_vote_count == 0:
                raise ForbiddenException(
                    message=
                    "Bonus Seat Allocation 1 (PCE_PC_BS_1) cannot be decided until the Provincial Vote Results (PCE-PC-V) is completed and verified.",
                    code=
                    MESSAGE_CODE_PCE_PC_BS_1_CANNOT_BE_PROCESSED_WITHOUT_PCE_PC_V
                )

            valid_vote_count_required_per_seat = total_valid_vote_count / number_of_members_to_be_elected
            valid_vote_count_required_per_seat_ceil = math.ceil(
                valid_vote_count_required_per_seat)

            for index in df.index:
                num_value = df.at[index, 'numValue']
                number_of_seats_qualified = math.floor(
                    num_value / valid_vote_count_required_per_seat_ceil)
                df.at[index,
                      'seatsAllocatedFromRound1'] = number_of_seats_qualified
                number_of_members_to_be_elected -= number_of_seats_qualified
                df.at[
                    index,
                    'validVotesRemainFromRound1'] = num_value % valid_vote_count_required_per_seat_ceil

            df = df.sort_values(by=['validVotesRemainFromRound1'],
                                ascending=False)
            for index in df.index:
                if number_of_members_to_be_elected > 0:
                    number_of_seats_qualified = 1
                    df.at[
                        index,
                        'seatsAllocatedFromRound2'] = number_of_seats_qualified
                    number_of_members_to_be_elected -= number_of_seats_qualified
                else:
                    df.at[index, 'seatsAllocatedFromRound2'] = 0

            df['seatsAllocated'] = df.seatsAllocatedFromRound1 + df.seatsAllocatedFromRound2

            df['draftSeatsAllocatedFromRound2'] = df.seatsAllocatedFromRound2

            df = df.sort_values(by=['numValue'], ascending=False)

            df["voteCountCeilPerSeat"] = pd.Series(np.full(
                len(df.index), valid_vote_count_required_per_seat_ceil),
                                                   index=df.index)

            return df
Ejemplo n.º 14
0
def validate_tally_sheet_version_request_content_special_characters(
        content_array):
    invalid_strings = ["'", "\"", "<", ">", "=", ",", ";"]
    for array_item in content_array:
        if "strValue" in array_item and array_item["strValue"] is not None:
            text_value = str(array_item["strValue"])
            for char in invalid_strings:
                if char in text_value or len(text_value) > 500:
                    raise ForbiddenException(
                        message=
                        "Invalid input detected. Use of disallowed characters/invalid input length detected. "
                        + char + " included in " + text_value,
                        code=MESSAGE_CODE_INVALID_INPUT)
    return True
def create(invoiceId, stationaryItemId):
    if Invoice.has_confirmed(invoiceId):
        raise ForbiddenException("Stationary items cannot be added to confirmed invoices (%d)" % invoiceId)
    elif StationaryItem.is_locked(stationaryItemId):
        raise ForbiddenException("Stationary item is not available (%d)" % stationaryItemId)
    else:
        received_proof = Proof.create(
            proofType=ProofTypeEnum.InvoiceStationaryItemReceive
        )

        print("######################### received_proof ###", received_proof)
        print("######################### received_proof.proofId ###", received_proof.proofId)

        result = Model(
            invoiceId=invoiceId,
            stationaryItemId=stationaryItemId,
            receivedProofId=received_proof.proofId
        )

        db.session.add(result)
        db.session.commit()

        return result
Ejemplo n.º 16
0
def delete(invoiceId):
    instance = get_by_id(invoiceId)

    if instance is None:
        raise NotFoundException(
            "Invoice not found associated with the given invoiceId (invoiceId=%d)"
            % invoiceId)
    elif instance.confirmed:
        raise ForbiddenException(
            "Confirmed invoices cannot be deleted (invoiceId=%d)" % invoiceId)
    else:
        instance.delete = True

        db.session.flush()

        return 1
Ejemplo n.º 17
0
def upload_file(proofId, fileSource, fileType):
    proof = get_by_id(proofId=proofId)

    if proof is None:
        raise NotFoundException(
            "Proof not found associated with the given proofId (proofId=%d)" %
            proofId)
    elif proof.finished is True:
        raise ForbiddenException(
            "No more evidence is accepted for this proof (proofId=%d)" %
            proofId)
    else:
        file = File.create(fileSource=fileSource, fileType=fileType)

        FolderFile.create(folderId=proof.scannedFilesFolderId,
                          fileId=file.fileId)

        return proof
Ejemplo n.º 18
0
def update(proofId, finished=None):
    instance = get_by_id(proofId)

    if instance is None:
        raise NotFoundException(
            "Proof not found associated with the given proofId (proofId=%d)" %
            proofId)
    else:
        if finished is not None:
            if len(instance.scannedFiles) is 0:
                raise ForbiddenException(
                    "A proof required at least one evidence. Please upload an evidence (proofId=%d)"
                    % proofId)

            instance.finished = finished

        db.session.commit()

        return instance
def request_edit(tallySheetId):
    tally_sheet = TallySheet.get_by_id(tallySheetId=tallySheetId)

    if tally_sheet is None:
        raise NotFoundException(
            message="Tally sheet not found (tallySheetId=%d)" % tallySheetId,
            code=MESSAGE_CODE_TALLY_SHEET_NOT_FOUND
        )

    if tally_sheet.tallySheetCode not in [TallySheetCodeEnum.PRE_41, TallySheetCodeEnum.CE_201,
                                          TallySheetCodeEnum.CE_201_PV, TallySheetCodeEnum.PRE_34_CO]:
        raise ForbiddenException(
            message="Submit operation is not supported for this tally sheet type.",
            code=MESSAGE_CODE_TALLY_SHEET_SUBMIT_IS_NOT_SUPPORTED
        )

    tally_sheet.set_submitted_version(None)

    db.session.commit()

    return TallySheetSchema().dump(tally_sheet).data, 201
Ejemplo n.º 20
0
def update(proofId, finished=None):
    instance = get_by_id(proofId)

    if instance is None:
        raise NotFoundException(
            "Proof not found associated with the given proofId (proofId=%d)" % proofId,
            code=MESSAGE_CODE_PROOF_NOT_FOUND
        )
    else:
        if finished is not None:
            if len(instance.scannedFiles) is 0:
                raise ForbiddenException(
                    message="A proof required at least one evidence. Please upload an evidence (proofId=%d)" % proofId,
                    code=MESSAGE_CODE_PROOF_CANNOT_BE_CONFIRMED_WITHOUT_EVIDENCE
                )

            instance.finished = finished

        db.session.flush()

        return instance
        def get_post_save_request_content(self):
            tally_sheet_id = self.tallySheetVersion.tallySheetId

            template_rows = db.session.query(
                TemplateRowModel.templateRowId,
                TemplateRowModel.templateRowType).filter(
                    TemplateModel.templateId == TallySheet.Model.templateId,
                    TemplateRowModel.templateId == TemplateModel.templateId,
                    TemplateRowModel.templateRowType.in_([
                        TEMPLATE_ROW_TYPE_ELECTED_CANDIDATE,
                        TEMPLATE_ROW_TYPE_DRAFT_ELECTED_CANDIDATE
                    ]),
                    TallySheet.Model.tallySheetId == tally_sheet_id).group_by(
                        TemplateRowModel.templateRowId).all()

            content = []

            seats_allocated_per_party_df = self.df.loc[(
                self.df['templateRowType'] == TEMPLATE_ROW_TYPE_SEATS_ALLOCATED
            ) & (self.df['numValue'] > 0)]

            if len(seats_allocated_per_party_df) == 0:
                raise ForbiddenException(
                    message=
                    "Bonus Seat Allocation 2 (PCE_PC_BS_2) cannot be determined until the Bonus Seat Allocation 1 (PCE_PC_BS_1) is decided and verified.",
                    code=
                    MESSAGE_CODE_PCE_PC_BS_2_CANNOT_BE_PROCESSED_WITHOUT_PCE_PC_BS_1
                )

            # The derived rows are calculated only if the PCE-R2 is available and verified.
            if len(seats_allocated_per_party_df) > 0:
                for index_1 in seats_allocated_per_party_df.index:
                    party_id = int(seats_allocated_per_party_df.at[index_1,
                                                                   "partyId"])
                    number_of_seats_allocated = seats_allocated_per_party_df.at[
                        index_1, "numValue"]

                    if number_of_seats_allocated is not None and not math.isnan(
                            number_of_seats_allocated):

                        candidates = db.session.query(
                            Candidate.Model.candidateId).filter(
                                Candidate.Model.candidateId ==
                                ElectionCandidateModel.candidateId,
                                ElectionCandidateModel.partyId ==
                                party_id).group_by(
                                    Candidate.Model.candidateId).order_by(
                                        Candidate.Model.candidateId).all()

                        for candidate in candidates:
                            if number_of_seats_allocated > 0:
                                for template_row in template_rows:
                                    candidate_id = candidate.candidateId
                                    content.append({
                                        "templateRowId":
                                        template_row.templateRowId,
                                        "templateRowType":
                                        template_row.templateRowType,
                                        "partyId":
                                        int(party_id),
                                        "candidateId":
                                        int(candidate_id),

                                        # TODO remove once the complete validation has been fixed.
                                        "numValue":
                                        0
                                    })

                                number_of_seats_allocated -= 1

            return content
Ejemplo n.º 22
0
    def __init__(self, reportId):
        report = Report_PRE_41.get_by_id(reportId=reportId)
        if report is None:
            raise NotFoundException("Report not found. (reportId=%d)" % reportId)

        if len(report.area.tallySheets_PRE_41) is 0:
            raise ForbiddenException(
                "There's no PRE-41 tally sheet for the counting centre (officeId)" % report.area.areaId)
        elif len(report.area.tallySheets_PRE_41) > 1:
            raise ForbiddenException(
                "There's more than one PRE-41 tally sheet for the counting centre (officeId)" % report.area.areaId)

        tallySheet = report.area.tallySheets_PRE_41[0]
        latestVersion = tallySheet.latestVersion

        if latestVersion is None:
            raise NotFoundException("No tallysheet data filled yet. (tallySheetId=%d)" % tallySheet.tallySheetId)

        tallySheetContent = latestVersion.content

        content = {
            "title": "PRESIDENTIAL ELECTION ACT NO. 15 OF 1981",
            "electoralDistrict": Area.get_associated_areas(report.area, AreaTypeEnum.ElectoralDistrict)[0].areaName,
            "pollingDivision": Area.get_associated_areas(report.area, AreaTypeEnum.PollingDivision)[0].areaName,
            "pollingDistrictNos": ", ".join([
                pollingDistrict.areaName for pollingDistrict in
                Area.get_associated_areas(report.area, AreaTypeEnum.PollingDistrict)
            ]),
            "countingHallNo": report.area.areaName,
            "data": [
            ],
            "total": 0,
            "rejectedVotes": 0,
            "grandTotal": 0
        }

        for row_index in range(len(tallySheetContent)):
            row = tallySheetContent[row_index]
            if row.count is not None:
                content["data"].append([
                    row_index + 1,
                    row.candidateName,
                    row.partySymbol,
                    row.countInWords,
                    row.count,
                    ""
                ])
                content["total"] = content["total"] + row.count
            else:
                content["data"].append([
                    row_index + 1,
                    row.candidateName,
                    row.partySymbol,
                    "",
                    "",
                    ""
                ])

        content["rejectedVotes"] = 0  # TODO
        content["grandTotal"] = content["total"] + content["rejectedVotes"]

        html = render_template(
            'pre-41.html',
            content=content
        )

        super(ReportVersion_PRE_41_Model, self).__init__(reportId=reportId, html=html)
        def populate_seats_per_party(self,
                                     minimum_vote_count_percentage_required,
                                     number_of_members_to_be_elected=0):
            df = self.get_party_wise_valid_vote_count_result()

            total_valid_vote_count = df['numValue'].sum()

            if total_valid_vote_count == 0:
                raise ForbiddenException(
                    message="Seat calculation cannot be done on zero votes.",
                    code=
                    MESSAGE_CODE_SEAT_CALCULATION_CANNOT_BE_DONE_ON_ZERO_VOTES)

            _minimum_valid_vote_count_required_per_party_to_be_qualified = total_valid_vote_count * minimum_vote_count_percentage_required

            total_valid_vote_count_of_qualified_parties = 0

            for index in df.index:
                if df.at[
                        index,
                        'numValue'] >= _minimum_valid_vote_count_required_per_party_to_be_qualified:
                    df.at[index, 'qualifiedForSeatsAllocation'] = True
                    total_valid_vote_count_of_qualified_parties += df.at[
                        index, 'numValue']
                else:
                    df.at[index, 'qualifiedForSeatsAllocation'] = False

            max_valid_vote_count_per_party = df['numValue'].max()

            for index in df.index:
                if df.at[index, 'numValue'] == max_valid_vote_count_per_party:
                    df.at[index, 'bonusSeatsAllocated'] = 1
                    number_of_members_to_be_elected -= 1
                else:
                    df.at[index, 'bonusSeatsAllocated'] = 0

            valid_vote_count_required_per_seat = total_valid_vote_count_of_qualified_parties / number_of_members_to_be_elected
            valid_vote_count_required_per_seat_ceil = math.ceil(
                valid_vote_count_required_per_seat)

            for index in df.index:
                num_value = df.at[index, 'numValue']
                if df.at[index, 'qualifiedForSeatsAllocation']:
                    number_of_seats_qualified = math.floor(
                        num_value / valid_vote_count_required_per_seat_ceil)
                    df.at[
                        index,
                        'seatsAllocatedFromRound1'] = number_of_seats_qualified
                    number_of_members_to_be_elected -= number_of_seats_qualified
                    df.at[
                        index,
                        'validVotesRemainFromRound1'] = num_value % valid_vote_count_required_per_seat_ceil
                else:
                    df.at[index, 'seatsAllocatedFromRound1'] = 0
                    df.at[index, 'validVotesRemainFromRound1'] = 0

            df = df.sort_values(by=['validVotesRemainFromRound1'],
                                ascending=False)
            for index in df.index:
                if df.at[
                        index,
                        'qualifiedForSeatsAllocation'] and number_of_members_to_be_elected > 0:
                    number_of_seats_qualified = 1
                    df.at[
                        index,
                        'seatsAllocatedFromRound2'] = number_of_seats_qualified
                    number_of_members_to_be_elected -= number_of_seats_qualified
                else:
                    df.at[index, 'seatsAllocatedFromRound2'] = 0

            df['seatsAllocated'] = df.seatsAllocatedFromRound1 + df.seatsAllocatedFromRound2 + df.bonusSeatsAllocated

            df['draftSeatsAllocatedFromRound2'] = df.seatsAllocatedFromRound2
            df['draftBonusSeatsAllocated'] = df.bonusSeatsAllocated

            df = df.sort_values(by=['numValue'], ascending=False)

            df["voteCountCeilPerSeat"] = pd.Series(np.full(
                len(df.index), valid_vote_count_required_per_seat_ceil),
                                                   index=df.index)
            df["minimumVoteCountRequiredForSeatAllocation"] = pd.Series(
                np.full(
                    len(df.index),
                    _minimum_valid_vote_count_required_per_party_to_be_qualified
                ),
                index=df.index)

            return df