Skip to content

[16.0][ADD] volunteer: add generator kanban view#582

Open
aydrpm wants to merge 4 commits into16.0from
16.0-volunteer-generator-kanban
Open

[16.0][ADD] volunteer: add generator kanban view#582
aydrpm wants to merge 4 commits into16.0from
16.0-volunteer-generator-kanban

Conversation

@aydrpm
Copy link

@aydrpm aydrpm commented Mar 10, 2026

Description

This PR adds generator kanban view with filters and demo data.

UI:

  • Add generator kanban view with search filters and searchpanel
  • Invert remaining-slots color badge on shift kanban view (full is now green and empty red)
  • Fix display of Regular badge on volunteer kanban view

Demo data:

  • Allow generator creation in canceled state during install_mode
  • Add new demo data for generator
  • Rename and adjust existing demo data

Odoo task (if applicable)

Checklist before approval

  • Tests are present (or not needed).
  • Credits/copyright have been changed correctly.
  • Change log snippet is present.
  • (If a new module) Moving this to OCA has been considered.

@aydrpm aydrpm requested a review from remytms March 10, 2026 13:16
@github-grap-bot
Copy link
Contributor

Hi @remytms,
some modules you are maintaining are being modified, check this out!

@aydrpm aydrpm force-pushed the 16.0-volunteer-generator-kanban branch from db3d312 to 03b680a Compare March 10, 2026 13:22
aydrpm added 3 commits March 10, 2026 14:28
- Add kanban view for generators
- Add filters and searchpanel for generators
- Add custom styles for generators display
- Fix regular fields display volunteer kanban view
- Remove unused t-set from shift kanban view
Full shift is considered successful (green), empty shifts require attention (red)
Allow generator creation in canceled state during install_mode
@aydrpm aydrpm force-pushed the 16.0-volunteer-generator-kanban branch from 03b680a to 8f376dc Compare March 10, 2026 13:29
Copy link
Collaborator

@remytms remytms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the great work. A small change to test.

Comment on lines +201 to +205
<field
name="volunteer_subscription_ids"
filter_domain="[('volunteer_subscription_ids.volunteer_id', 'ilike', self)]"
string="Volunteer"
/>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to filter on ongoing subscription by this quick search. Like this (to be tested):

Suggested change
<field
name="volunteer_subscription_ids"
filter_domain="[('volunteer_subscription_ids.volunteer_id', 'ilike', self)]"
string="Volunteer"
/>
<field
name="volunteer_subscription_ids"
filter_domain="[('volunteer_subscription_ids.volunteer_id', 'ilike', self), ('volunteer_subscription_ids.temporal_state', '=', 'ongoing')]"
string="Volunteer (Ongoing)"
/>

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this nice improvement suggestion!

Unfortunately the suggested code doesn't work as expected. When a generator has more than one subscription with one matching the searched volunteer but with an undesired temporal_state, and at least another subscription with the desired temporal_state but a different volunteer, the generator is incorrectly displayed in the results.

See this example of a false positive:
False positive example

Looking at the SQL logs, it appears that Odoo generates two independent subqueries as shown in this simplified SQL extract :

SELECT generator.id FROM generator
WHERE generator.id IN (
    SELECT generator_id FROM subscription
    WHERE volunteer_id IN (
        SELECT id FROM volunteer
        JOIN partner ON volunteer.partner_id = partner.id
        WHERE partner.name ILIKE '%jean%'
    )
)
AND generator.id IN (
    SELECT generator_id FROM subscription
    WHERE temporal_state = 'ongoing'
)

A solution could be to use an unstored field with search parameters which allow to build a suitable domain.

Also, since the global filter will be removed, it may be relevant to add another search field to display upcoming subscriptions and have a more global view of the volunteer's subscriptions. Maybe a combined "(Ongoing and upcoming)" search field is even better.

Here is a possible implementation:

ongoing_volunteer_name = fields.Char(  
    store=False,  
    search="_search_ongoing_volunteer_name",  
    help="Dummy field to search generators by volunteer name with ongoing subscription.",  
)  
ongoing_and_upcoming_volunteer_name = fields.Char(  
    store=False,  
    search="_search_ongoing_and_upcoming_volunteer_name",  
    help="Dummy field to search generators by volunteer name "  
    "with ongoing or upcoming subscription state.",  
)

def _search_volunteer_name_by_states(self, operator, value, states):  
    all_volunteer_subscriptions = self.env[  
        "volunteer.shift.recurrent.subscription"  
    ].search([("volunteer_id.name", "ilike", value)])  
    matching_subscriptions = all_volunteer_subscriptions.filtered(  
        lambda sub: sub.active and sub._get_current_temporal_state() in states  
    )  
    return [("id", "in", matching_subscriptions.mapped("generator_id").ids)]  
  
def _search_ongoing_volunteer_name(self, operator, value):  
    return self._search_volunteer_name_by_states(operator, value, ["ongoing"])  
  
def _search_ongoing_and_upcoming_volunteer_name(self, operator, value):  
    return self._search_volunteer_name_by_states(  
        operator, value, ["ongoing", "upcoming"]  
    )
<search string="Shift Generators">
    <field
        name="ongoing_volunteer_name"
        string="Volunteer (Ongoing)" />
    <field
        name="ongoing_and_upcoming_volunteer_name"
        string="Volunteer (Ongoing and upcoming)"
    />

Additionally, temporal_state depends on the current date and was planned to be kept up to date via a cron job (next PR). However, it feels more reliable to call _get_current_temporal_state() explicitly, but if the cron fails, the search results would be accurate while the badge on the subscription could be outdated and confusing for the user.

Since the getter is already called explicitly throughout the codebase, the cron job feels unnecessary, so temporal_state could be unstored which would ensure the badge is always up to date on display.

Does this approach work for you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants