Skip to content

Commit 8269a04

Browse files
committed
[ADD] construction_progress_management: add new construction submodule
This commit improves the Construction industry by creating a new submodule adding several new features related to Progress Management: - A progress view for projects to centralize the Sales Order Lines from all Sales Orders linked to a project, and manage their delivery progress using Increments which can be used to update the delivery progress. - A 'Progress' button in the project top bar to access that view. task-5172327
1 parent e836db5 commit 8269a04

File tree

13 files changed

+383
-21
lines changed

13 files changed

+383
-21
lines changed

.weblate.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@
141141
"filemask": "construction/i18n/*.po",
142142
"new_base": "construction/i18n/construction.pot"
143143
},
144+
{
145+
"name": "construction_progress_management",
146+
"filemask": "construction_progress_management/i18n/*.po",
147+
"new_base": "construction_progress_management/i18n/construction_progress_management.pot"
148+
},
144149
{
145150
"name": "corporate_gifts",
146151
"filemask": "corporate_gifts/i18n/*.po",

construction/data/knowledge_article.xml

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -268,39 +268,71 @@
268268
<a href="https://www.odoo.com/documentation/latest/applications/services/timesheets.html" class="btn btn-outline-primary btn-sm">🎓 Timesheets</a>
269269
</p>
270270
<h2><br /></h2>
271-
<h2>Invoice at the right time 📈</h2>
271+
<h2>📈 Invoice the right amount at the right time</h2>
272272
<p>
273-
As the first invoicing step, create a down payment from the sales order. This will generate the first invoice in the
274-
<strong><font class="text-o-color-1">Invoicing</font></strong> app. Then, schedule one or several "Invoicing Schedule" activities on the sales order with the aim to never forget to send an intermediary invoice in order to sustain
275-
your cash flow.
273+
The <strong><font class="text-o-color-1">Invoicing App</font></strong> ensures timely billing, automate recurring invoices, and integrate with project milestones.
276274
</p>
277275
<p>
278-
<a href="https://www.odoo.com/documentation/latest/applications/productivity/discuss/overview/plan_activities.html?highlight=activities" class="btn btn-outline-primary btn-sm">🎓 Activities</a>
279-
</p>
280-
<p>
281-
Before generating an intermediary invoice in the
282-
<strong><font class="text-o-color-1">Invoicing</font></strong> app, freeze the project status in the <strong><font class="text-o-color-1">Project</font></strong> app to get an overview on the progress in terms of:
276+
<strong>How to use it:</strong>
283277
</p>
284278
<ul>
285-
<li>
286-
Time spent on the project.
287-
</li>
288-
<li>
289-
Materials purchased.
290-
</li>
291-
<li>
292-
Materials sold.
293-
</li>
279+
<li><strong>Invoice from Quotation</strong>: Convert approved quotes into invoices.</li>
280+
<li><strong>Billing</strong>: Invoice based on work completion or project milestones.</li>
281+
<li><strong>Payment Tracking</strong>: Monitor outstanding client payments.</li>
294282
</ul>
283+
<div class="o_editor_banner user-select-none o-contenteditable-false lh-1 d-flex align-items-center alert alert-success pb-0 pt-3" data-oe-role="status" role="status">
284+
<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="Banner Success" aria-label="Banner Success">✅</i>
285+
<div class="o_editor_banner_content o-contenteditable-true w-100 px-3" contenteditable="true">
286+
<p>Schedule one or several "Invoicing Schedule" activities on the sales order with the aim to never forget to send an intermediary invoice in order to sustain your cash flow.</p>
287+
</div>
288+
</div>
289+
<div class="o_editor_banner user-select-none lh-1 d-flex align-items-center alert alert-info pb-0 pt-3 o-contenteditable-false" data-oe-role="status" role="status">
290+
<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="Banner Info" aria-label="Banner Info">💡</i>
291+
<div class="w-100 px-3 o_editor_banner_content o-contenteditable-true" contenteditable="true">
292+
<p>Before generating an intermediary invoice, capture a project update from its dashboard.</p>
293+
</div>
294+
</div>
295295
<p>
296-
All these components will give you an accurate overview on the project profitability.
296+
<a href="https://www.odoo.com/documentation/latest/applications/finance/accounting/customer_invoices.html" class="btn btn-outline-primary btn-sm">🎓 Invoicing</a>
297297
</p>
298+
<h3><span class="h3-fs">Manual delivery progress management </span>🏁</h3>
298299
<p>
299-
Thanks to the invoicing policy set on delivered quantities, the generated invoice is always the reflect of the reality on the field and it is fair for the customer.
300+
Typically, work items products are priced in a scale-able fashion and billed based on delivered quantity.
301+
Those are defined as service products with invoicing based on manual delivery.
300302
</p>
303+
<ul>
304+
<li>From the project, expose all related aspects you want to have at fingertips with the slider icon (🎚️).</li>
305+
<li>Open the Progress view. It captures all sale order lines associated to this project.</li>
306+
<li>For each line, adjust the increment fields to capture delivered work since last invoice.</li>
307+
<li>
308+
Once at the periodic billing moment, select those lines and trigger the delivery update.
309+
This will update sale order to capture those increments and create a draft invoice.
310+
</li>
311+
</ul>
312+
<div class="o_editor_banner user-select-none lh-1 d-flex align-items-center alert alert-info pb-0 pt-3 o-contenteditable-false" data-oe-role="status" role="status">
313+
<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="Banner Info" aria-label="Banner Info">💡</i>
314+
<div class="w-100 px-3 o_editor_banner_content o-contenteditable-true" contenteditable="true">
315+
<p>Pro tip: Set progress increment directly on a section to go faster!</p>
316+
</div>
317+
</div>
318+
<div class="o_editor_banner user-select-none o-contenteditable-false lh-1 d-flex align-items-center alert alert-success pb-0 pt-3" data-oe-role="status" role="status">
319+
<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="Banner Success" aria-label="Banner Success">✅</i>
320+
<div class="o_editor_banner_content o-contenteditable-true w-100 px-3" contenteditable="true">
321+
<p>This manual progress view is as well available from the sale order, in the Progress tab!</p>
322+
</div>
323+
</div>
324+
<h3><span class="h3-fs">Time sheet based progress management </span>⏲️</h3>
301325
<p>
302-
<a href="https://www.odoo.com/documentation/latest/applications/finance/accounting/customer_invoices.html" class="btn btn-outline-primary btn-sm">🎓 Invoicing</a>
326+
Some other work items will be invoiced given the amount of time spent.
327+
The time sheet do not only help you to keep track of your costs, they as well are the lever to charge your customers.
328+
Those are defined as service products with invoicing based on time sheets.
303329
</p>
330+
<div class="o_editor_banner user-select-none o-contenteditable-false lh-1 d-flex align-items-center alert alert-success pb-0 pt-3" data-oe-role="status" role="status">
331+
<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="Banner Success" aria-label="Banner Success">✅</i>
332+
<div class="o_editor_banner_content o-contenteditable-true w-100 px-3" contenteditable="true">
333+
<p>As soon as time sheets associated to sale order lines are approved, the recorded time is used as delivery metric!</p>
334+
</div>
335+
</div>
304336
<h2><br /></h2>
305337
<h2><span class="h2-fs">Make your customers happy </span>🆘</h2>
306338
<p>

construction/static/description/index.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,9 @@ <h2><strong>Tailored Setup for Construction Businesses</strong></h2>
44
focusing on accurate quoting, efficient planning, seamless execution, and excellent customer service.
55
The setup integrates all necessary modules (Project, Inventory, Sales, Purchase, ...) to streamline your operations,
66
with the possibility to expand into advanced functionalities using additional applications.
7+
8+
<h3>Customizations</h3>
9+
<ul>
10+
<li><strong>Progress management</strong> – Easily handle sale orders and project progress in a dedicated view</li>
11+
</ul>
712
</p>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
'name': 'Construction Progress Management',
3+
'version': '1.0',
4+
'category': 'Hidden/Tools',
5+
'depends': [
6+
'base_industry_data',
7+
'construction',
8+
'web_studio',
9+
],
10+
'data': [
11+
'data/ir_model_fields.xml',
12+
'data/ir_actions_act_window.xml',
13+
'data/ir_embedded_actions.xml',
14+
'data/ir_actions_server.xml',
15+
'data/base_automation.xml',
16+
'data/ir_ui_view.xml',
17+
'data/project_project.xml',
18+
],
19+
'demo': [
20+
'demo/project_project.xml',
21+
],
22+
'license': 'OPL-1',
23+
'author': 'Odoo S.A.',
24+
"cloc_exclude": [
25+
],
26+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo>
3+
<record id="automation_update_progress_increment_on_change" model="base.automation">
4+
<field name="name">Construction - Update Sale Order Line Progress Increment</field>
5+
<field name="model_id" ref="sale.model_sale_order_line"/>
6+
<field name="action_server_ids" eval="[(6, 0, [ref('construction_progress_management.action_sol_update_progress_increment_on_change')])]"/>
7+
<field name="trigger">on_change</field>
8+
<field name="on_change_field_ids" eval="[(6, 0, [ref('construction_progress_management.field_sale_order_line_quantity_increment')])]"/>
9+
</record>
10+
<record id="automation_update_quantity_increment_on_change" model="base.automation">
11+
<field name="name">Construction - Update Sale Order Line Progress Increment</field>
12+
<field name="model_id" ref="sale.model_sale_order_line"/>
13+
<field name="action_server_ids" eval="[(6, 0, [ref('construction_progress_management.action_sol_update_quantity_increment_on_change')])]"/>
14+
<field name="trigger">on_create_or_write</field>
15+
<field name="on_change_field_ids" eval="[(6, 0, [ref('construction_progress_management.field_sale_order_line_progress_increment')])]"/>
16+
</record>
17+
<record id="automation_initialize_sales_order_line_sequence_on_sales_order_create" model="base.automation">
18+
<field name="model_id" ref="sale.model_sale_order_line"/>
19+
<field name="action_server_ids" eval="[(6, 0, [ref('action_initialize_sales_order_line_sequence_on_sales_order_create')])]"/>
20+
<field name="trigger">on_create</field>
21+
<field name="name">Construction - Initialize Sales Order Line Sequence on Sales Order create</field>
22+
</record>
23+
</odoo>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo>
3+
<record id="action_progress_view" model="ir.actions.act_window">
4+
<field name="name">Progress</field>
5+
<field name="res_model">sale.order.line</field>
6+
<field name="view_mode">list</field>
7+
<field name="domain">[('order_id.project_id','=', active_id)]</field>
8+
<field name="context">{'default_project_id': active_id}</field>
9+
</record>
10+
</odoo>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo>
3+
<record id="action_sol_update_progress_increment_on_change" model="ir.actions.server">
4+
<field name="code"><![CDATA[
5+
record['x_progress_increment'] = record.x_quantity_increment / record.product_uom_qty if record.product_uom_qty > 0 else False
6+
]]></field>
7+
<field name="model_id" ref="sale.model_sale_order_line"/>
8+
<field name="state">code</field>
9+
<field name="name">Construction - Update Progress Increment on Quantity Increment change</field>
10+
</record>
11+
<record id="action_sol_update_quantity_increment_on_change" model="ir.actions.server">
12+
<field name="code"><![CDATA[
13+
record['x_quantity_increment'] = record.x_progress_increment * record.product_uom_qty
14+
]]></field>
15+
<field name="model_id" ref="sale.model_sale_order_line"/>
16+
<field name="state">code</field>
17+
<field name="name">Construction - Update Quantity Increment on Progress Increment change</field>
18+
</record>
19+
<record id="action_sol_update_section_progress" model="ir.actions.server">
20+
<field name="code"><![CDATA[
21+
lines = record.order_id.order_line.sorted(key=lambda sol: sol.sequence)
22+
i = [sol.sequence for sol in lines].index(record.sequence) + 1
23+
while (i < len(lines) and
24+
((record.display_type == 'line_section' and lines[i].display_type != 'line_section')
25+
or (record.display_type == 'line_subsection' and (lines[i].display_type not in ['line_subsection', 'line_section'])))):
26+
if lines[i].is_service and lines[i].x_service_policy == 'delivered_manual':
27+
new_inc = lines[i].product_uom_qty * (record.x_progress_increment if record.x_progress_increment + lines[i].x_current_progress < 100 else 100 - lines[i].x_current_progress)
28+
lines[i]['x_quantity_increment'], lines[i]['x_progress_increment'] = new_inc, new_inc / lines[i].product_uom_qty if lines[i].product_uom_qty > 0 else False
29+
i += 1
30+
record['x_progress_increment'] = 0
31+
]]></field>
32+
<field name="model_id" ref="sale.model_sale_order_line"/>
33+
<field name="state">code</field>
34+
<field name="name">Construction - Update Quantity Increment on section button click</field>
35+
</record>
36+
<record id="action_sol_update_qty_delivered" model="ir.actions.server">
37+
<field name="code"><![CDATA[
38+
for sol in records:
39+
sol['qty_delivered'], sol['x_quantity_increment'], sol['x_progress_increment'] = sol.qty_delivered + sol.x_quantity_increment, 0, 0
40+
action = {'type': 'ir.actions.client', 'tag': 'display_notification', 'params': {'message': "Delivered quantities updated.", 'type': 'success', 'next': {'type': 'ir.actions.client', 'tag': 'soft_reload'}}}
41+
]]></field>
42+
<field name="model_id" ref="sale.model_sale_order_line"/>
43+
<field name="state">code</field>
44+
<field name="name">Construction - Update Quantity Delivered</field>
45+
</record>
46+
<record id="action_initialize_sales_order_line_sequence_on_sales_order_create" model="ir.actions.server">
47+
<field name="model_id" ref="sale.model_sale_order_line"/>
48+
<field name="update_path">sequence</field>
49+
<field name="state">object_write</field>
50+
<field name="crud_model_id" ref="sale.model_sale_order"/>
51+
<field name="evaluation_type">equation</field>
52+
<field name="name">Construction - Initialize Sales Order Line Sequence on Sales Order create</field>
53+
<field name="update_field_id" ref="sale.field_sale_order_line__sequence"/>
54+
<field name="usage">base_automation</field>
55+
<field name="value"><![CDATA[list(record.order_id.order_line._ids).index(record.id)]]></field>
56+
</record>
57+
</odoo>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo noupdate="1">
3+
<record id="construction_embedded_action_sales_order_lines" model="ir.embedded.actions">
4+
<field name="parent_res_model">project.project</field>
5+
<field name="name">Progress</field>
6+
<field name="sequence">55</field>
7+
<field name="parent_action_id" ref="project.act_project_project_2_project_task_all"/>
8+
<field name="action_id" eval="ref('construction_progress_management.action_progress_view')"/>
9+
</record>
10+
<record id="construction_embedded_action_sales_order_lines_dashboard" model="ir.embedded.actions">
11+
<field name="parent_res_model">project.project</field>
12+
<field name="name">Progress</field>
13+
<field name="sequence">55</field>
14+
<field name="parent_action_id" ref="project.project_update_all_action"/>
15+
<field name="action_id" eval="ref('construction_progress_management.action_progress_view')"/>
16+
</record>
17+
</odoo>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo>
3+
<record id="field_sale_order_line_delivered_progress" model="ir.model.fields">
4+
<field name="ttype">float</field>
5+
<field name="field_description">Delivered Progress</field>
6+
<field name="model_id" ref="sale.model_sale_order_line"/>
7+
<field name="name">x_delivered_progress</field>
8+
<field name="depends">qty_delivered,product_uom_qty</field>
9+
<field name="compute"><![CDATA[
10+
for sol in self: sol['x_delivered_progress'] = False if not sol.product_uom_qty else 100 * (sol.qty_delivered / sol.product_uom_qty)
11+
]]></field>
12+
</record>
13+
<record id="field_sale_order_line_quantity_increment" model="ir.model.fields">
14+
<field name="ttype">float</field>
15+
<field name="field_description">Quantity Increment</field>
16+
<field name="model_id" ref="sale.model_sale_order_line"/>
17+
<field name="name">x_quantity_increment</field>
18+
</record>
19+
<record id="field_sale_order_line_progress_increment" model="ir.model.fields">
20+
<field name="ttype">float</field>
21+
<field name="field_description">Progress Increment</field>
22+
<field name="model_id" ref="sale.model_sale_order_line"/>
23+
<field name="name">x_progress_increment</field>
24+
</record>
25+
<record id="field_sale_order_line_current_progress" model="ir.model.fields">
26+
<field name="ttype">float</field>
27+
<field name="field_description">Current Progress</field>
28+
<field name="model_id" ref="sale.model_sale_order_line"/>
29+
<field name="name">x_current_progress</field>
30+
<field name="depends">x_delivered_progress,x_progress_increment</field>
31+
<field name="compute"><![CDATA[
32+
for sol in self: sol['x_current_progress'] = sol.x_delivered_progress + 100 * sol.x_progress_increment
33+
]]></field>
34+
</record>
35+
<record id="field_sale_order_line_service_policy" model="ir.model.fields">
36+
<field name="name">x_service_policy</field>
37+
<field name="field_description">Product Service Policy</field>
38+
<field name="ttype">selection</field>
39+
<field name="related">product_id.service_policy</field>
40+
<field name="model_id" ref="sale.model_sale_order_line"/>
41+
<field name="store" eval="False"/>
42+
</record>
43+
</odoo>

0 commit comments

Comments
 (0)