Skip to content

Commit 7f91f1e

Browse files
committed
Merge PR #1691 into 19.0
Signed-off-by AaronHForgeFlow
2 parents d1e6600 + a691ea3 commit 7f91f1e

19 files changed

Lines changed: 991 additions & 0 deletions
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
.. image:: https://odoo-community.org/readme-banner-image
2+
:target: https://odoo-community.org/get-involved?utm_source=readme
3+
:alt: Odoo Community Association
4+
5+
===============================
6+
Project Task Customer Reference
7+
===============================
8+
9+
..
10+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
11+
!! This file is generated by oca-gen-addon-readme !!
12+
!! changes will be overwritten. !!
13+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14+
!! source digest: sha256:43e36c2954bc2c1ff0ae498553e1549a833d04330fbeb5ec2cbe8678065bbef0
15+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
16+
17+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
18+
:target: https://odoo-community.org/page/development-status
19+
:alt: Beta
20+
.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png
21+
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
22+
:alt: License: LGPL-3
23+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproject-lightgray.png?logo=github
24+
:target: https://github.com/OCA/project/tree/19.0/project_task_customer_ref
25+
:alt: OCA/project
26+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
27+
:target: https://translation.odoo-community.org/projects/project-19-0/project-19-0-project_task_customer_ref
28+
:alt: Translate me on Weblate
29+
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
30+
:target: https://runboat.odoo-community.org/builds?repo=OCA/project&target_branch=19.0
31+
:alt: Try me on Runboat
32+
33+
|badge1| |badge2| |badge3| |badge4| |badge5|
34+
35+
Adds an **Order Customer Reference** field (``customer_reference``) to
36+
``project.task`` so that customer PO/requisition numbers are visible on
37+
tasks, capturable via website webforms, and kept in sync with the linked
38+
sale order.
39+
40+
Features:
41+
42+
- **Task field**: ``customer_reference`` (Char, not copied on
43+
duplication) is added to the task form view and list view (hidden by
44+
default, toggleable via the optional-columns menu).
45+
- **Auto-populated from sale order**: when a task is created
46+
automatically from a confirmed sale order (service lines with
47+
``service_tracking``), the task inherits the SO's ``client_order_ref``
48+
as its ``customer_reference``.
49+
- **Propagation back to sale order**: when ``customer_reference`` is set
50+
or updated on a task, it is written to ``client_order_ref`` on the
51+
linked sale order — but only if that field is currently empty,
52+
preventing unintended overwrites.
53+
- **Website webform support**: the field is whitelisted for the website
54+
form builder so it appears in the field picker when configuring a
55+
webform that creates ``project.task`` records.
56+
57+
**Table of contents**
58+
59+
.. contents::
60+
:local:
61+
62+
Configuration
63+
=============
64+
65+
After installing the module, open the Website form builder and add a
66+
text input mapped to **Order Customer Reference**
67+
(``customer_reference``) to allow customers to supply their PO number
68+
when submitting a request.
69+
70+
Bug Tracker
71+
===========
72+
73+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/project/issues>`_.
74+
In case of trouble, please check there if your issue has already been reported.
75+
If you spotted it first, help us to smash it by providing a detailed and welcomed
76+
`feedback <https://github.com/OCA/project/issues/new?body=module:%20project_task_customer_ref%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
77+
78+
Do not contact contributors directly about support or help with technical issues.
79+
80+
Credits
81+
=======
82+
83+
Authors
84+
-------
85+
86+
* ForgeFlow
87+
88+
Contributors
89+
------------
90+
91+
- Jasmin Solanki <jasmin.solanki@forgeflow.com>
92+
93+
Maintainers
94+
-----------
95+
96+
This module is maintained by the OCA.
97+
98+
.. image:: https://odoo-community.org/logo.png
99+
:alt: Odoo Community Association
100+
:target: https://odoo-community.org
101+
102+
OCA, or the Odoo Community Association, is a nonprofit organization whose
103+
mission is to support the collaborative development of Odoo features and
104+
promote its widespread use.
105+
106+
This module is part of the `OCA/project <https://github.com/OCA/project/tree/19.0/project_task_customer_ref>`_ project on GitHub.
107+
108+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License LGPLv3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html).
3+
from . import models
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License LGPLv3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html).
3+
{
4+
"name": "Project Task Customer Reference",
5+
"summary": (
6+
"Adds Order Customer Reference to tasks, syncs it to the linked "
7+
"sale order, and exposes it on website webforms."
8+
),
9+
"version": "19.0.1.0.0",
10+
"author": "ForgeFlow, Odoo Community Association (OCA)",
11+
"website": "https://github.com/OCA/project",
12+
"category": "Project",
13+
"license": "LGPL-3",
14+
"depends": ["sale_project", "website_project"],
15+
"data": [
16+
"data/website_form.xml",
17+
"views/project_task_views.xml",
18+
],
19+
"installable": True,
20+
"application": False,
21+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<!-- Copyright 2026 ForgeFlow
3+
Part of ForgeFlow. See LICENSE file for full copyright and licensing details. -->
4+
<odoo noupdate="1">
5+
<function model="ir.model.fields" name="formbuilder_whitelist">
6+
<value>project.task</value>
7+
<value eval="['customer_reference']" />
8+
</function>
9+
</odoo>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Translation of Odoo Server.
2+
# This file contains the translation of the following modules:
3+
# * project_task_customer_ref
4+
#
5+
# Translators:
6+
# ForgeFlow S.L., 2026
7+
#
8+
msgid ""
9+
msgstr ""
10+
"Project-Id-Version: Odoo Server 19.0\n"
11+
"Report-Msgid-Bugs-To: \n"
12+
"POT-Creation-Date: 2026-03-16 00:00+0000\n"
13+
"PO-Revision-Date: 2026-03-16 00:00+0000\n"
14+
"Last-Translator: ForgeFlow S.L.\n"
15+
"Language-Team: Danish\n"
16+
"Language: da\n"
17+
"MIME-Version: 1.0\n"
18+
"Content-Type: text/plain; charset=UTF-8\n"
19+
"Content-Transfer-Encoding: 8bit\n"
20+
21+
#. module: project_task_customer_ref
22+
#: model:ir.module.module,shortdesc:project_task_customer_ref.module_project_task_customer_ref
23+
msgid "Project Task Customer Reference"
24+
msgstr "Projektsopgave kundereferencer"
25+
26+
#. module: project_task_customer_ref
27+
#: model:ir.model.fields,field_description:project_task_customer_ref.field_project_task__customer_reference
28+
msgid "Order Customer Reference"
29+
msgstr "Kundens ordreference"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Translation of Odoo Server.
2+
# This file contains the translation of the following modules:
3+
# * project_task_customer_ref
4+
#
5+
# Translators:
6+
# ForgeFlow S.L., 2026
7+
#
8+
msgid ""
9+
msgstr ""
10+
"Project-Id-Version: Odoo Server 19.0\n"
11+
"Report-Msgid-Bugs-To: \n"
12+
"POT-Creation-Date: 2026-03-16 00:00+0000\n"
13+
"PO-Revision-Date: 2026-03-16 00:00+0000\n"
14+
"Last-Translator: ForgeFlow S.L.\n"
15+
"Language-Team: Swedish\n"
16+
"Language: sv\n"
17+
"MIME-Version: 1.0\n"
18+
"Content-Type: text/plain; charset=UTF-8\n"
19+
"Content-Transfer-Encoding: 8bit\n"
20+
21+
#. module: project_task_customer_ref
22+
#: model:ir.module.module,shortdesc:project_task_customer_ref.module_project_task_customer_ref
23+
msgid "Project Task Customer Reference"
24+
msgstr "Projektuppgift kundreferens"
25+
26+
#. module: project_task_customer_ref
27+
#: model:ir.model.fields,field_description:project_task_customer_ref.field_project_task__customer_reference
28+
msgid "Order Customer Reference"
29+
msgstr "Kundens orderreferens"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License LGPLv3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html).
3+
from . import project_task
4+
from . import sale_order
5+
from . import sale_order_line
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License LGPLv3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html).
3+
from odoo import api, fields, models
4+
5+
6+
class ProjectTask(models.Model):
7+
_inherit = "project.task"
8+
9+
customer_reference = fields.Char(string="Order Customer Reference", copy=False)
10+
11+
def _get_linked_sale_order(self):
12+
"""Return the sale order linked to this task (via line or project)."""
13+
self.ensure_one()
14+
return self.sale_order_id or self.project_id.sale_order_id
15+
16+
@api.model_create_multi
17+
def create(self, vals_list):
18+
tasks = super().create(vals_list)
19+
if not self.env.context.get("_syncing_customer_reference"):
20+
for task, vals in zip(tasks, vals_list, strict=False):
21+
ref = vals.get("customer_reference")
22+
if ref:
23+
so = task._get_linked_sale_order()
24+
if so and so.client_order_ref != ref:
25+
so.with_context(
26+
_syncing_customer_reference=True
27+
).client_order_ref = ref
28+
return tasks
29+
30+
def write(self, vals):
31+
res = super().write(vals)
32+
ref = vals.get("customer_reference")
33+
if ref and not self.env.context.get("_syncing_customer_reference"):
34+
for task in self:
35+
so = task._get_linked_sale_order()
36+
if so and so.client_order_ref != ref:
37+
so.with_context(
38+
_syncing_customer_reference=True
39+
).client_order_ref = ref
40+
return res
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License LGPLv3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html).
3+
from odoo import api, models
4+
5+
6+
class SaleOrder(models.Model):
7+
_inherit = "sale.order"
8+
9+
@api.model_create_multi
10+
def create(self, vals_list):
11+
# create_for_task_id is injected into the context when a sale order is
12+
# created directly from a task (e.g. via the "Create Sale Order" action
13+
# on project.task). It allows us to pre-fill client_order_ref from the
14+
# task's customer_reference before the SO record is saved.
15+
task = self.env["project.task"].browse(
16+
self.env.context.get("create_for_task_id")
17+
)
18+
if task and task.customer_reference:
19+
for vals in vals_list:
20+
if not vals.get("client_order_ref"):
21+
vals["client_order_ref"] = task.customer_reference
22+
return super().create(vals_list)
23+
24+
def write(self, vals):
25+
res = super().write(vals)
26+
ref = vals.get("client_order_ref")
27+
if ref and not self.env.context.get("_syncing_customer_reference"):
28+
tasks = self.env["project.task"].search([("sale_order_id", "in", self.ids)])
29+
tasks_to_update = tasks.filtered(lambda t: t.customer_reference != ref)
30+
if tasks_to_update:
31+
tasks_to_update.with_context(_syncing_customer_reference=True).write(
32+
{"customer_reference": ref}
33+
)
34+
return res
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2026 ForgeFlow S.L.
2+
# License LGPLv3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html).
3+
from odoo import models
4+
5+
6+
class SaleOrderLine(models.Model):
7+
_inherit = "sale.order.line"
8+
9+
def _timesheet_create_task_prepare_values(self, project):
10+
res = super()._timesheet_create_task_prepare_values(project)
11+
if self.order_id.client_order_ref:
12+
res["customer_reference"] = self.order_id.client_order_ref
13+
return res

0 commit comments

Comments
 (0)