Skip to content

Commit

Permalink
[WIP] membership changes
Browse files Browse the repository at this point in the history
  • Loading branch information
gbrito committed Feb 18, 2025
1 parent 5c09bc6 commit 937a838
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 39 deletions.
17 changes: 17 additions & 0 deletions membership_group/data/ir_cron_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">

<record id="ir_cron_revoke_memberships" model="ir.cron">
<field name="name">Membership: Revoke expired memberships</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="nextcall"
eval="(DateTime.now().replace(hour=05, minute=0, second=0) + timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')" />
<field name="numbercall">-1</field>
<field name="model_id" ref="model_membership_group_member" />
<field name="state">code</field>
<field name="code">model._cron_revoke_membership()</field>
<field name="active" eval="True" />
</record>

</odoo>
23 changes: 22 additions & 1 deletion membership_group/menuitems.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,30 @@

<menuitem
id="membership_group_membership_menu"
name="Membership Group Members"
name="Current Members"
action="action_membership_group_member"
parent="membership_group.membership_group_reporting_menu"
/>

<menuitem
id="membership_group_future_membership_menu"
name="Future Members"
action="action_membership_group_future_member"
parent="membership_group.membership_group_reporting_menu"
/>

<menuitem
id="membership_group_past_membership_menu"
name="Past Members"
action="action_membership_group_past_member"
parent="membership_group.membership_group_reporting_menu"
/>

<menuitem
id="membership_group_voting_membership_menu"
name="Voting Members"
action="action_membership_group_voting_member"
parent="membership_group.membership_group_reporting_menu"
/>

</odoo>
22 changes: 17 additions & 5 deletions membership_group/models/membership_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,37 @@ class MembershipGroup(models.Model):
)
partner_ids_count = fields.Integer("# of Members", compute="_compute_partner_ids")

termination_cycle = fields.Boolean(
help="""
Members from a group with a termination cycle will be
removed from the group on the termination date",
""",
)
next_termination_date = fields.Date(
help="Next termination date for members of this group",
)

@api.depends("name", "parent_id.complete_name")
def _compute_complete_name(self):
for group in self:
if group.parent_id:
group.complete_name = "%s / %s" % (
group.parent_id.complete_name,
group.name,
)
group.complete_name = f"{group.parent_id.complete_name} / {group.name}"
else:
group.complete_name = group.name

@api.depends(
"membership_group_member_ids", "membership_group_member_ids.partner_id"
"membership_group_member_ids",
"membership_group_member_ids.partner_id",
)
def _compute_partner_ids(self):
for group in self:
group.partner_ids = group.membership_group_member_ids.mapped("partner_id")
group.partner_ids_count = len(group.partner_ids)

def _has_termination_cycle(self):
self.ensure_one()
return bool(self.termination_cycle and self.next_termination_date)

def action_open_partner_view(self):
action_name = "membership.action_membership_members"
action_vals = self.env["ir.actions.act_window"]._for_xml_id(action_name)
Expand Down
50 changes: 48 additions & 2 deletions membership_group/models/membership_group_member.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from odoo import fields, models
from odoo import api, fields, models


class MembershipGroupMember(models.Model):
_name = "membership.group.member"
_description = "Membership Group Member"

active = fields.Boolean(default=True)
partner_id = fields.Many2one("res.partner", required=True, ondelete="cascade")
group_id = fields.Many2one("membership.group", required=True, ondelete="cascade")
wants_to_collaborate = fields.Boolean()
can_vote = fields.Boolean()
type = fields.Selection(
[
("follower", "Follower"),
Expand All @@ -18,11 +20,55 @@ class MembershipGroupMember(models.Model):
("committee", "Committee"),
],
)
date_from = fields.Date(
default=fields.Date.context_today,
help="Start date of the membership",
)
date_to = fields.Date(
compute="_compute_date_to",
store=True,
readonly=False,
precompute=True,
help="Planned end date of the membership",
)
date_end = fields.Date(
help="End date of the membership",
)
can_revoke_membership = fields.Boolean(compute="_compute_can_revoke_membership")

_sql_constraints = [
(
"partner_group_uniq",
"unique(partner_id, group_id)",
"unique(active, partner_id, group_id)",
"Member already exists for this group!",
)
]

@api.depends("group_id")
def _compute_date_to(self):
for record in self:
if (
not record.date_to
and record.group_id
and record.group_id._has_termination_cycle()
):
record.date_to = record.group_id.next_termination_date

@api.depends("date_to")
def _compute_can_revoke_membership(self):
for record in self:
record.can_revoke_membership = record._can_revoke_membership()

def _can_revoke_membership(self):
self.ensure_one()
return self.date_to < fields.Date.today() if self.date_to else True

def action_revoke_membership(self):
if active_records := self.filtered(lambda x: x.active):
active_records.active = False
active_records.date_end = fields.Date.today()
return True

@api.model
def _cron_revoke_membership(self):
self.search([("date_to", "<=", fields.date.today())]).action_revoke_membership()
2 changes: 1 addition & 1 deletion membership_group/security/ir.model.access.csv
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ access_membership_group_portal,access_membership_group_portal,model_membership_g
access_membership_group,access_membership_group,model_membership_group,base.group_user,1,1,1,1
access_membership_group_member_public,access_membership_group_member_public,model_membership_group_member,base.group_public,1,0,0,0
access_membership_group_member_portal,access_membership_group_member_portal,model_membership_group_member,base.group_portal,1,0,0,0
access_membership_group_member,access_membership_group_member,model_membership_group_member,base.group_user,1,1,1,1
access_membership_group_member,access_membership_group_member,model_membership_group_member,base.group_user,1,1,1,0
36 changes: 36 additions & 0 deletions membership_group/tests/test_membership_group.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import freezegun
from odoo.tests import common


Expand Down Expand Up @@ -84,3 +85,38 @@ def test_04_action_open_membership_group_view(self):
],
)
self.assertEqual(res["res_id"], self.group_1.id)

def test_05_membership_group_with_revoke_date(self):
group_1_with_termination = self.env["membership.group"].create(
{
"name": "Test Group 1 with termination",
"termination_cycle": True,
"next_termination_date": "2025-06-01",
}
)
member_group_termination = self.env["membership.group.member"].create(
{
"partner_id": self.partner_1.id,
"group_id": group_1_with_termination.id,
}
)

self.assertEqual(
member_group_termination.date_to,
group_1_with_termination.next_termination_date,
)
self.assertTrue(member_group_termination.active)

with freezegun.freeze_time("2025-05-01"):
self.env["membership.group.member"]._cron_revoke_membership()

self.assertTrue(member_group_termination.active)

with freezegun.freeze_time("2025-06-01"):
self.env["membership.group.member"]._cron_revoke_membership()

self.assertFalse(member_group_termination.active)
self.assertEqual(
str(member_group_termination.date_end),
"2025-06-01",
)
65 changes: 54 additions & 11 deletions membership_group/views/membership_group_member_view.xml
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<odoo>

<record id="membership_group_member_view_tree" model="ir.ui.view">
<field name="model">membership.group.member</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="active" invisible="1" />
<field name="partner_id" />
<field name="group_id" />
<field name="type" />
<field name="wants_to_collaborate" />
<field name="date_from" optional="show" />
<field name="date_to" optional="show" />
<field name="date_end" optional="hide" />
<field name="type" optional="hide" />
<field name="wants_to_collaborate" optional="hide" />
<field name="can_vote" widget="boolean_toggle"
readonly="context.get('membership_remove_options', False)" optional="hide" />
<button type="object" name="action_revoke_membership" string="Revoke"
icon="fa-trash" attrs="{'invisible': [('active','=', False)]}" />
</tree>
</field>
</record>
Expand All @@ -17,32 +25,67 @@
<field name="model">membership.group.member</field>
<field name="arch" type="xml">
<pivot string="Membership Group Members" disable_linking="True">
<field name="partner_id" type="row"/>
<field name="group_id" type="row"/>
<field name="type" type="col"/>
<field name="partner_id" type="row" />
<field name="group_id" type="row" />
<field name="type" type="col" />
</pivot>
</field>
</record>

<record id="membership_group_member_view_search" model="ir.ui.view">
<record id="membership_group_member_view_search" model="ir.ui.view">
<field name="model">membership.group.member</field>
<field name="arch" type="xml">
<search>
<field name="partner_id" />
<field name="group_id" />
<field name="type" />
<filter name="show_voters" string="Can Vote" domain="[('can_vote', '=', True)]" />
<filter name="show_collaborators" string="Want to Collaborate"
domain="[('wants_to_collaborate', '=', True)]" />
<separator />
<group expand="0" name="claims" string="Group By">
<filter string="Partner" name="partner_id" domain="[]" help="Partner" context="{'group_by':'partner_id'}" />
<filter string="Group" name="group_id" domain="[]" help="Group" context="{'group_by':'group_id'}" />
<filter string="Type" name="type" domain="[]" help="Group" context="{'group_by':'type'}" />
<filter string="Partner" name="groupby_partner_id" domain="[]" help="Partner"
context="{'group_by':'partner_id'}" />
<filter string="Group" name="groupby_group_id" domain="[]" help="Group"
context="{'group_by':'group_id'}" />
<filter string="Type" name="groupby_type" domain="[]" help="Group"
context="{'group_by':'type'}" />
</group>
</search>
</field>
</record>

<record id="action_membership_group_member" model="ir.actions.act_window">
<field name="name">Membership Group Members</field>
<field name="name">Current Members</field>
<field name="res_model">membership.group.member</field>
<field name="view_mode">tree,pivot</field>
</record>

<record id="action_membership_group_future_member" model="ir.actions.act_window">
<field name="name">Future Members</field>
<field name="res_model">membership.group.member</field>
<field name="view_mode">tree,pivot</field>
<field name="context">{'active_test': False, 'create': False, 'edit': False}</field>
<field name="domain">[('active', '=', False), ('date_from', '&gt;',
context_today().strftime('%Y-%m-%d'))]</field>
</record>

<record id="action_membership_group_past_member" model="ir.actions.act_window">
<field name="name">Past Members</field>
<field name="res_model">membership.group.member</field>
<field name="view_mode">tree,pivot</field>
<field name="context">{'active_test': False, 'create': False, 'edit': False,
'membership_remove_options': True}</field>
<field name="domain">[('active', '=', False), ('date_end', '!=', False)]</field>
</record>

<record id="action_membership_group_voting_member" model="ir.actions.act_window">
<field name="name">Voting Members</field>
<field name="res_model">membership.group.member</field>
<field name="view_mode">tree,pivot</field>
<field name="context">{'create': False, 'edit': False, 'membership_remove_options': True,
'search_default_groupby_group_id': 1}</field>
<field name="domain">[('can_vote', '=', True)]</field>
</record>

</odoo>
21 changes: 10 additions & 11 deletions membership_group/views/membership_group_view.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<odoo>

<record id="membership_group_view_tree" model="ir.ui.view">
Expand Down Expand Up @@ -48,20 +48,19 @@
</group>
</group>
<group name="form_body" />

<notebook>
<page string="Membership" name="membership">
<field name="membership_group_member_ids">
<tree editable="top">
<field
name="partner_id"
domain="[('membership_state', 'in', ['invoiced', 'paid', 'free'])]"
/>
</tree>
</field>
<field name="membership_group_member_ids"/>
</page>
<page string="Subgroups">
<field name="child_ids"/>
<field name="child_ids" />
</page>
<page string="Configuration">
<group>
<field name="termination_cycle" widget="boolean_toggle" />
<field name="next_termination_date"
attrs="{'required': [('termination_cycle','=', True)], 'invisible': [('termination_cycle', '=', False)]}" />
</group>
</page>
</notebook>
</sheet>
Expand Down
10 changes: 2 additions & 8 deletions membership_group/views/res_partner_view.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<odoo>

<record id="view_partner_form" model="ir.ui.view">
Expand All @@ -22,13 +22,7 @@
</xpath>
<xpath expr="//field[@name='member_lines']" position="after">
<group>
<field name="membership_group_member_ids" string="Groups" colspan="4">
<tree editable="bottom">
<field name="group_id"/>
<field name="type" />
<field name="wants_to_collaborate" />
</tree>
</field>
<field name="membership_group_member_ids" string="Groups" colspan="2" />
</group>
</xpath>
</field>
Expand Down

0 comments on commit 937a838

Please sign in to comment.