Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 25 additions & 11 deletions farm_onboarding/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,31 @@ enterprise types), how you keep books today (QBO / QBD / Excel / paper /
nothing), done — with a state machine, progress bar, save-as-you-go, and
back/next/skip/restart actions.

This MVP uses a regular form view with state-conditional groups so
sessions persist across browser closes. The original plan called for an
OWL client action with full-screen modal; that polish is deferred to v1
in favor of shipping the data model and flow first.
The wizard surfaces itself two ways:

- **Navbar bell.** A leaf icon with a red badge dot appears in the
systray when the current farm user has an unfinished session. Click it
to jump straight into the wizard. The bell is hidden for users outside
``farm_base.group_farm_user`` and disappears once the session is
marked done.
- **Farm → Setup Wizard menu item.** Same destination, accessible at any
time for a re-run.

The form itself is a regular Odoo form view with state-conditional
groups so sessions persist across browser closes. A richer custom-
chrome design pass lives in a follow-on PR (Step 2 of the UX refinement
plan).

Adds 12 pre-loaded ``farm.enterprise.type`` records (eggs, vegetables,
fruit, herbs, orchard, cattle, dairy, poultry, hogs, sheep/goats, value-
added, workshops) with emoji icons — these drive product catalog and
report pre-configuration in downstream modules.

The "Setup Wizard" menu item routes each user to their own open session
(creates one if none exists), so multiple farm-users on the same company
each get an independent walkthrough.
Each user gets their own session per company, so multiple farm-users on
the same company each get an independent walkthrough. The umbrella
``farm_pack`` module's ``post_init_hook`` seeds a session for every
existing internal farm user on install; new users created later pick one
up lazily on first wizard open.

.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Expand All @@ -59,14 +71,16 @@ each get an independent walkthrough.
Usage
=====

1. **Farm → Setup Wizard** — opens (or resumes) your active session.
1. **Look for the leaf icon + red dot in the navbar.** That's the
onboarding bell — click it to jump into the wizard. (Or use **Farm →
Setup Wizard** for the same destination.)
2. Click **Next** to step through: Welcome → Your Farm → What You Grow →
Books Today → All Set.
3. Each screen saves on Next/Back so closing the browser doesn't lose
progress. Skip jumps straight to Done.
4. Once done, the Farm menu's other items (Eggs, CSA, Markets, Delivery,
QuickBooks) are where the actual work happens — the wizard pre-tells
the pack what to surface for your operation.
4. Once done, the bell disappears and the Farm menu's other items (Eggs,
CSA, Markets, Delivery, QuickBooks) are where the actual work happens
— the wizard pre-tells the pack what to surface for your operation.

Bug Tracker
===========
Expand Down
8 changes: 7 additions & 1 deletion farm_onboarding/__manifest__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Farm Onboarding",
"summary": "60-second first-run wizard for new farm-pack installs",
"version": "19.0.1.0.0",
"version": "19.0.1.1.0",
"license": "AGPL-3",
"author": "Ledo Enterprises, Odoo Community Association (OCA)",
"website": "https://github.com/ledoent/farm-pack",
Expand All @@ -16,6 +16,12 @@
"views/farm_enterprise_type_views.xml",
"views/farm_onboarding_menu.xml",
],
"assets": {
"web.assets_backend": [
"farm_onboarding/static/src/js/onboarding_systray.esm.js",
"farm_onboarding/static/src/xml/onboarding_systray.xml",
],
},
"demo": [],
"installable": True,
"application": False,
Expand Down
16 changes: 16 additions & 0 deletions farm_onboarding/models/farm_onboarding_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,22 @@ def get_or_create_for_current_user(self):
)
return session

@api.model
def count_pending_for_current_user(self):
"""Pending-session count for the systray bell.

Kept separate from `get_or_create_for_current_user` so the
bell's mount path is read-only — the systray must not create
session rows on every page load.
"""
return self.search_count(
[
("company_id", "=", self.env.company.id),
("user_id", "=", self.env.user.id),
("state", "!=", "done"),
]
)

def action_open_for_current_user(self):
session = self.get_or_create_for_current_user()
return {
Expand Down
26 changes: 19 additions & 7 deletions farm_onboarding/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,28 @@ enterprise types), how you keep books today (QBO / QBD / Excel / paper /
nothing), done — with a state machine, progress bar, save-as-you-go, and
back/next/skip/restart actions.

This MVP uses a regular form view with state-conditional groups so
sessions persist across browser closes. The original plan called for an
OWL client action with full-screen modal; that polish is deferred to
v1 in favor of shipping the data model and flow first.
The wizard surfaces itself two ways:

- **Navbar bell.** A leaf icon with a red badge dot appears in the
systray when the current farm user has an unfinished session. Click
it to jump straight into the wizard. The bell is hidden for users
outside `farm_base.group_farm_user` and disappears once the session
is marked done.
- **Farm → Setup Wizard menu item.** Same destination, accessible at
any time for a re-run.

The form itself is a regular Odoo form view with state-conditional
groups so sessions persist across browser closes. A richer custom-
chrome design pass lives in a follow-on PR (Step 2 of the UX
refinement plan).

Adds 12 pre-loaded `farm.enterprise.type` records (eggs, vegetables,
fruit, herbs, orchard, cattle, dairy, poultry, hogs, sheep/goats, value-
added, workshops) with emoji icons — these drive product catalog and
report pre-configuration in downstream modules.

The "Setup Wizard" menu item routes each user to their own open session
(creates one if none exists), so multiple farm-users on the same company
each get an independent walkthrough.
Each user gets their own session per company, so multiple farm-users on
the same company each get an independent walkthrough. The umbrella
`farm_pack` module's `post_init_hook` seeds a session for every existing
internal farm user on install; new users created later pick one up
lazily on first wizard open.
11 changes: 7 additions & 4 deletions farm_onboarding/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
1. **Farm → Setup Wizard** — opens (or resumes) your active session.
1. **Look for the leaf icon + red dot in the navbar.** That's the
onboarding bell — click it to jump into the wizard. (Or use
**Farm → Setup Wizard** for the same destination.)
2. Click **Next** to step through: Welcome → Your Farm → What You Grow
→ Books Today → All Set.
3. Each screen saves on Next/Back so closing the browser doesn't lose
progress. Skip jumps straight to Done.
4. Once done, the Farm menu's other items (Eggs, CSA, Markets, Delivery,
QuickBooks) are where the actual work happens — the wizard pre-tells
the pack what to surface for your operation.
4. Once done, the bell disappears and the Farm menu's other items
(Eggs, CSA, Markets, Delivery, QuickBooks) are where the actual work
happens — the wizard pre-tells the pack what to surface for your
operation.
10 changes: 10 additions & 0 deletions farm_onboarding/readme/newsfragments/+systray_bell.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Adds a navbar systray bell (leaf icon + red badge dot) that surfaces
the setup wizard whenever the current farm user has an unfinished
onboarding session. The bell is hidden for users outside the
`farm_base.group_farm_user` group and disappears once the session
is marked done.

New `farm.onboarding.session.count_pending_for_current_user` RPC
endpoint drives the bell's visibility — read-only, scoped to the
current `(user, company)`, kept separate from
`get_or_create_for_current_user` so page loads cannot create rows.
36 changes: 25 additions & 11 deletions farm_onboarding/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -380,17 +380,29 @@ <h1>Farm Onboarding</h1>
enterprise types), how you keep books today (QBO / QBD / Excel / paper /
nothing), done — with a state machine, progress bar, save-as-you-go, and
back/next/skip/restart actions.</p>
<p>This MVP uses a regular form view with state-conditional groups so
sessions persist across browser closes. The original plan called for an
OWL client action with full-screen modal; that polish is deferred to v1
in favor of shipping the data model and flow first.</p>
<p>The wizard surfaces itself two ways:</p>
<ul class="simple">
<li><strong>Navbar bell.</strong> A leaf icon with a red badge dot appears in the
systray when the current farm user has an unfinished session. Click it
to jump straight into the wizard. The bell is hidden for users outside
<tt class="docutils literal">farm_base.group_farm_user</tt> and disappears once the session is
marked done.</li>
<li><strong>Farm → Setup Wizard menu item.</strong> Same destination, accessible at any
time for a re-run.</li>
</ul>
<p>The form itself is a regular Odoo form view with state-conditional
groups so sessions persist across browser closes. A richer custom-
chrome design pass lives in a follow-on PR (Step 2 of the UX refinement
plan).</p>
<p>Adds 12 pre-loaded <tt class="docutils literal">farm.enterprise.type</tt> records (eggs, vegetables,
fruit, herbs, orchard, cattle, dairy, poultry, hogs, sheep/goats, value-
added, workshops) with emoji icons — these drive product catalog and
report pre-configuration in downstream modules.</p>
<p>The “Setup Wizard” menu item routes each user to their own open session
(creates one if none exists), so multiple farm-users on the same company
each get an independent walkthrough.</p>
<p>Each user gets their own session per company, so multiple farm-users on
the same company each get an independent walkthrough. The umbrella
<tt class="docutils literal">farm_pack</tt> module’s <tt class="docutils literal">post_init_hook</tt> seeds a session for every
existing internal farm user on install; new users created later pick one
up lazily on first wizard open.</p>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">This is an alpha version, the data model and design can change at any time without warning.
Expand All @@ -413,14 +425,16 @@ <h1>Farm Onboarding</h1>
<div class="section" id="usage">
<h2><a class="toc-backref" href="#toc-entry-1">Usage</a></h2>
<ol class="arabic simple">
<li><strong>Farm → Setup Wizard</strong> — opens (or resumes) your active session.</li>
<li><strong>Look for the leaf icon + red dot in the navbar.</strong> That’s the
onboarding bell — click it to jump into the wizard. (Or use <strong>Farm →
Setup Wizard</strong> for the same destination.)</li>
<li>Click <strong>Next</strong> to step through: Welcome → Your Farm → What You Grow →
Books Today → All Set.</li>
<li>Each screen saves on Next/Back so closing the browser doesn’t lose
progress. Skip jumps straight to Done.</li>
<li>Once done, the Farm menu’s other items (Eggs, CSA, Markets, Delivery,
QuickBooks) are where the actual work happens — the wizard pre-tells
the pack what to surface for your operation.</li>
<li>Once done, the bell disappears and the Farm menu’s other items (Eggs,
CSA, Markets, Delivery, QuickBooks) are where the actual work happens
— the wizard pre-tells the pack what to surface for your operation.</li>
</ol>
</div>
<div class="section" id="bug-tracker">
Expand Down
65 changes: 65 additions & 0 deletions farm_onboarding/static/src/js/onboarding_systray.esm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/** @odoo-module **/

import {Component, onWillStart, useState} from "@odoo/owl";
import {registry} from "@web/core/registry";
import {useService} from "@web/core/utils/hooks";

/**
* Systray bell that surfaces unfinished farm-onboarding sessions.
*
* Hidden when the current user has no pending session (count == 0),
* so non-farm users see nothing. When pending, a pulsing dot draws
* the eye; click opens the wizard via the existing
* `action_open_for_current_user` server action.
*
* Deliberately lightweight — one `search_count` RPC on mount, no
* polling. The bell hides immediately on click (optimistic); if the
* user backs out of the wizard without finishing, the next page
* reload will surface it again.
*/
export class FarmOnboardingSystray extends Component {
static template = "farm_onboarding.SystrayBell";
static props = {};

setup() {
this.orm = useService("orm");
this.action = useService("action");
this.state = useState({pending: 0, loaded: false});

onWillStart(async () => {
// The systray is registered globally; users without
// farm_base.group_farm_user will hit AccessError on the
// search_count. Swallow it so we don't spam the console —
// a user who can't access the wizard shouldn't see the bell.
try {
this.state.pending = await this.orm.call(
"farm.onboarding.session",
"count_pending_for_current_user",
[]
);
} catch {
this.state.pending = 0;
} finally {
this.state.loaded = true;
}
});
}

async openWizard() {
const action = await this.orm.call(
"farm.onboarding.session",
"action_open_for_current_user",
[]
);
await this.action.doAction(action);
this.state.pending = 0;
}
}

registry
.category("systray")
.add(
"farm_onboarding.SystrayBell",
{Component: FarmOnboardingSystray},
{sequence: 100}
);
28 changes: 28 additions & 0 deletions farm_onboarding/static/src/xml/onboarding_systray.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="farm_onboarding.SystrayBell">
<div
t-if="state.loaded and state.pending > 0"
class="o-farm-onboarding-bell d-flex align-items-center"
role="button"
tabindex="0"
title="Finish setting up your farm"
t-on-click="openWizard"
t-on-keyup="(ev) => ev.key === 'Enter' &amp;&amp; openWizard()"
>
<button
class="btn btn-link p-0 d-flex align-items-center position-relative"
type="button"
>
<i class="fa fa-leaf" aria-hidden="true" />
<span
class="position-absolute top-0 start-100 translate-middle p-1 bg-danger rounded-circle"
aria-label="Onboarding pending"
/>
<span class="d-none d-md-inline ms-2">Finish setup</span>
</button>
</div>
</t>

</templates>
18 changes: 18 additions & 0 deletions farm_onboarding/tests/test_farm_onboarding_session.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from odoo import fields
from odoo.tests.common import TransactionCase


Expand Down Expand Up @@ -84,3 +85,20 @@ def test_enterprise_selection_persists(self):
veggies = self.env.ref("farm_onboarding.enterprise_vegetables")
sess = self.Session.create({"enterprise_ids": [(6, 0, [eggs.id, veggies.id])]})
self.assertEqual(len(sess.enterprise_ids), 2)

def test_count_pending_for_current_user(self):
# Drives the systray bell — must return 0 when nothing pending,
# > 0 when an active session exists. Don't count `done` sessions.
# Start from a clean slate: archive any sessions that exist for
# the test user from prior tests in this case.
self.Session.search([("user_id", "=", self.env.user.id)]).write(
{"state": "done", "finished_at": fields.Datetime.now()}
)
self.assertEqual(self.Session.count_pending_for_current_user(), 0)

self.Session.get_or_create_for_current_user()
self.assertEqual(self.Session.count_pending_for_current_user(), 1)

# Skipping completes the session — bell should go away.
self.Session.get_or_create_for_current_user().action_skip()
self.assertEqual(self.Session.count_pending_for_current_user(), 0)
6 changes: 6 additions & 0 deletions farm_pack/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ also install the leaf modules individually (``farm_egg_production``,
Composition rationale and the four-jobs plan: see
`plans/2-farm-pack-composition.md <https://github.com/ledoent/farm-pack/blob/main/plans/2-farm-pack-composition.md>`__.

On install, a ``post_init_hook`` seeds one ``farm.onboarding.session``
per (internal farm user, company) pair so the navbar bell from
``farm_onboarding`` shows up immediately for every existing farm user.
Portal users and tooling accounts are excluded. The hook is idempotent —
re-running it (e.g., after an upgrade) does not duplicate sessions.

.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
Expand Down
1 change: 1 addition & 0 deletions farm_pack/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import hooks
5 changes: 4 additions & 1 deletion farm_pack/__manifest__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Farm Pack",
"summary": "Umbrella: website + ordering + delivery + accounting for small farms",
"version": "19.0.1.0.0",
"version": "19.0.1.1.0",
"license": "AGPL-3",
"author": "Ledo Enterprises, Odoo Community Association (OCA)",
"website": "https://github.com/ledoent/farm-pack",
Expand Down Expand Up @@ -38,4 +38,7 @@
"application": True,
"development_status": "Alpha",
"maintainers": ["dkendall"],
# Seeds an onboarding session per (user, company) for existing installs
# so the systray bell + first-run wizard show up immediately.
"post_init_hook": "post_init_hook",
}
Loading
Loading