Source code for g2p_programs.models.managers.cycle_manager

# Part of Newlogic G2P. See LICENSE file for full copyright and licensing details.
import logging
from datetime import timedelta

from odoo import _, api, fields, models
from odoo.exceptions import ValidationError

from .. import constants

_logger = logging.getLogger(__name__)


class CycleManager(models.Model):
    _name = "g2p.cycle.manager"
    _description = "Cycle Manager"
    _inherit = "g2p.manager.mixin"

    program_id = fields.Many2one("g2p.program", "Program")

    @api.model
    def _selection_manager_ref_id(self):
        selection = super()._selection_manager_ref_id()
        new_manager = ("g2p.cycle.manager.default", "Default")
        if new_manager not in selection:
            selection.append(new_manager)
        return selection


[docs]class BaseCycleManager(models.AbstractModel): _name = "g2p.base.cycle.manager" _description = "Base Cycle Manager" name = fields.Char("Manager Name", required=True) program_id = fields.Many2one("g2p.program", string="Program", required=True) auto_approve_entitlements = fields.Boolean( string="Auto-approve Entitlements", default=False )
[docs] def check_eligibility(self, cycle, beneficiaries=None): """ Validate the eligibility of each beneficiary for the cycle """ raise NotImplementedError()
[docs] def prepare_entitlements(self, cycle): """ Prepare the entitlements for the cycle """ raise NotImplementedError()
[docs] def validate_entitlements(self, cycle, cycle_memberships): """ Validate the entitlements for the cycle """ raise NotImplementedError()
[docs] def new_cycle(self, name, new_start_date, sequence): """ Create a new cycle for the program """ raise NotImplementedError()
[docs] def mark_distributed(self, cycle): """ Mark the cycle as distributed """ raise NotImplementedError()
[docs] def mark_ended(self, cycle): """ Mark the cycle as ended """ raise NotImplementedError()
[docs] def mark_cancelled(self, cycle): """ Mark the cycle as cancelled """ raise NotImplementedError()
[docs] def add_beneficiaries(self, cycle, beneficiaries, state="draft"): """ Add beneficiaries to the cycle """ raise NotImplementedError()
[docs] def on_start_date_change(self, cycle): """ Hook for when the start date change """
[docs] def on_state_change(self, cycle): """ Hook for when the state change Args: cycle: Returns: """
[docs]class DefaultCycleManager(models.Model): _name = "g2p.cycle.manager.default" _inherit = ["g2p.base.cycle.manager", "g2p.manager.source.mixin"] _description = "Default Cycle Manager" cycle_duration = fields.Integer("Cycle Duration", default=30, required=True) approver_group_id = fields.Many2one( comodel_name="res.groups", string="Approver Group", copy=True, )
[docs] def check_eligibility(self, cycle, beneficiaries=None): """ :param cycle: The cycle that is being verified :type cycle: :class:`g2p_programs.models.cycle.G2PCycle` :param beneficiaries: the beneficiaries that need to be verified. By Default the one with the state ``draft`` or ``enrolled`` are verified. :type beneficiaries: list or None :return: The list of eligible beneficiaries :rtype: list Validate the eligibility of each beneficiary for the cycle using the configured manager(s) :class:`g2p_programs.models.managers.eligibility_manager.BaseEligibilityManager`. If there is multiple managers for eligibility, each of them are run using the filtered list of eligible beneficiaries from the previous one. The ``state`` of beneficiaries is updated to either ``enrolled`` if they match the enrollment criteria or ``not_eligible`` in case they do not match them. """ for rec in self: rec._ensure_can_edit_cycle(cycle) # Get all the enrolled beneficiaries if beneficiaries is None: beneficiaries = cycle.get_beneficiaries(["draft", "enrolled"]) eligibility_managers = rec.program_id.get_managers( constants.MANAGER_ELIGIBILITY ) filtered_beneficiaries = beneficiaries for manager in eligibility_managers: filtered_beneficiaries = manager.verify_cycle_eligibility( cycle, filtered_beneficiaries ) filtered_beneficiaries.write({"state": "enrolled"}) beneficiaries_ids = beneficiaries.ids filtered_beneficiaries_ids = filtered_beneficiaries.ids _logger.info("Beneficiaries: %s", beneficiaries_ids) _logger.info("Filtered beneficiaries: %s", filtered_beneficiaries_ids) ids_to_remove = list( set(beneficiaries_ids) - set(filtered_beneficiaries_ids) ) # Mark the beneficiaries as not eligible memberships_to_remove = self.env["g2p.cycle.membership"].browse( ids_to_remove ) memberships_to_remove.write({"state": "not_eligible"}) # Disable the entitlements of the beneficiaries entitlements = self.env["g2p.entitlement"].search( [ ("cycle_id", "=", cycle.id), ("partner_id", "in", memberships_to_remove.mapped("partner_id.id")), ] ) entitlements.write({"state": "cancelled"}) return filtered_beneficiaries
[docs] def prepare_entitlements(self, cycle): for rec in self: rec._ensure_can_edit_cycle(cycle) # Get all the enrolled beneficiaries beneficiaries = cycle.get_beneficiaries(["enrolled"]) rec.program_id.get_manager( constants.MANAGER_ENTITLEMENT ).prepare_entitlements(cycle, beneficiaries)
[docs] def mark_distributed(self, cycle): cycle.update({"state": constants.STATE_DISTRIBUTED})
[docs] def mark_ended(self, cycle): cycle.update({"state": constants.STATE_ENDED})
[docs] def mark_cancelled(self, cycle): cycle.update({"state": constants.STATE_CANCELLED})
[docs] def validate_entitlements(self, cycle, cycle_memberships): # TODO: call the program's entitlement manager and validate the entitlements # TODO: Use a Job attached to the cycle # TODO: Implement validation workflow for rec in self: rec.program_id.get_manager( constants.MANAGER_ENTITLEMENT ).validate_entitlements(cycle_memberships)
[docs] def new_cycle(self, name, new_start_date, sequence): _logger.info("Creating new cycle for program %s", self.program_id.name) _logger.info("New start date: %s", new_start_date) for rec in self: cycle = self.env["g2p.cycle"].create( { "program_id": rec.program_id.id, "name": name, "state": "draft", "sequence": sequence, "start_date": new_start_date, "end_date": new_start_date + timedelta(days=rec.cycle_duration), } ) _logger.info("New cycle created: %s", cycle.name) return cycle
[docs] def copy_beneficiaries_from_program(self, cycle, state="enrolled"): self._ensure_can_edit_cycle(cycle) for rec in self: beneficiary_ids = rec.program_id.get_beneficiaries(["enrolled"]).mapped( "partner_id.id" ) rec.add_beneficiaries(cycle, beneficiary_ids, state)
[docs] def add_beneficiaries(self, cycle, beneficiaries, state="draft"): """ Add beneficiaries to the cycle """ self._ensure_can_edit_cycle(cycle) _logger.info("Adding beneficiaries to the cycle %s", cycle.name) _logger.info("Beneficiaries: %s", beneficiaries) existing_ids = cycle.cycle_membership_ids.mapped("partner_id.id") new_beneficiaries = [] for r in beneficiaries: if r not in existing_ids: new_beneficiaries.append( [ 0, 0, { "partner_id": r, "enrollment_date": fields.Date.today(), "state": state, }, ] ) if new_beneficiaries: cycle.update({"cycle_membership_ids": new_beneficiaries}) return True else: return False
def _ensure_can_edit_cycle(self, cycle): if cycle.state not in [cycle.STATE_DRAFT]: raise ValidationError(_("The Cycle is not in Draft Mode"))
[docs] def on_state_change(self, cycle): if cycle.state == cycle.STATE_APPROVED: if not self.approver_group_id: raise ValidationError(_("The cycle approver group is not specified!")) else: if self.env.user.id not in self.approver_group_id.users.ids: raise ValidationError( _("You are not allowed to approve this cycle!") )