Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .weblate.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@
"filemask": "construction/i18n/*.po",
"new_base": "construction/i18n/construction.pot"
},
{
"name": "construction_progress_management",
"filemask": "construction_progress_management/i18n/*.po",
"new_base": "construction_progress_management/i18n/construction_progress_management.pot"
},
{
"name": "corporate_gifts",
"filemask": "corporate_gifts/i18n/*.po",
Expand Down
74 changes: 53 additions & 21 deletions construction/data/knowledge_article.xml
Original file line number Diff line number Diff line change
Expand Up @@ -268,39 +268,71 @@
<a href="https://www.odoo.com/documentation/latest/applications/services/timesheets.html" class="btn btn-outline-primary btn-sm">🎓 Timesheets</a>
</p>
<h2><br /></h2>
<h2>Invoice at the right time 📈</h2>
<h2>📈 Invoice the right amount at the right time</h2>
<p>
As the first invoicing step, create a down payment from the sales order. This will generate the first invoice in the
<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
your cash flow.
The <strong><font class="text-o-color-1">Invoicing App</font></strong> ensures timely billing, automate recurring invoices, and integrate with project milestones.
</p>
<p>
<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>
</p>
<p>
Before generating an intermediary invoice in the
<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:
<strong>How to use it:</strong>
</p>
<ul>
<li>
Time spent on the project.
</li>
<li>
Materials purchased.
</li>
<li>
Materials sold.
</li>
<li><strong>Invoice from Quotation</strong>: Convert approved quotes into invoices.</li>
<li><strong>Billing</strong>: Invoice based on work completion or project milestones.</li>
<li><strong>Payment Tracking</strong>: Monitor outstanding client payments.</li>
</ul>
<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">
<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="Banner Success" aria-label="Banner Success">✅</i>
<div class="o_editor_banner_content o-contenteditable-true w-100 px-3" contenteditable="true">
<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>
</div>
</div>
<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">
<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="Banner Info" aria-label="Banner Info">💡</i>
<div class="w-100 px-3 o_editor_banner_content o-contenteditable-true" contenteditable="true">
<p>Before generating an intermediary invoice, capture a project update from its dashboard.</p>
</div>
</div>
<p>
All these components will give you an accurate overview on the project profitability.
<a href="https://www.odoo.com/documentation/latest/applications/finance/accounting/customer_invoices.html" class="btn btn-outline-primary btn-sm">🎓 Invoicing</a>
</p>
<h3><span class="h3-fs">Manual delivery progress management </span>🏁</h3>
<p>
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.
Typically, work items products are priced in a scale-able fashion and billed based on delivered quantity.
Those are defined as service products with invoicing based on manual delivery.
</p>
<ul>
<li>From the project, expose all related aspects you want to have at fingertips with the slider icon (🎚️).</li>
<li>Open the Progress view. It captures all sale order lines associated to this project.</li>
<li>For each line, adjust the increment fields to capture delivered work since last invoice.</li>
<li>
Once at the periodic billing moment, select those lines and trigger the delivery update.
This will update sale order to capture those increments and create a draft invoice.
</li>
</ul>
<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">
<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="Banner Info" aria-label="Banner Info">💡</i>
<div class="w-100 px-3 o_editor_banner_content o-contenteditable-true" contenteditable="true">
<p>Pro tip: Set progress increment directly on a section to go faster!</p>
</div>
</div>
<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">
<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="Banner Success" aria-label="Banner Success">✅</i>
<div class="o_editor_banner_content o-contenteditable-true w-100 px-3" contenteditable="true">
<p>This manual progress view is as well available from the sale order, in the Progress tab!</p>
</div>
</div>
<h3><span class="h3-fs">Time sheet based progress management </span>⏲️</h3>
<p>
<a href="https://www.odoo.com/documentation/latest/applications/finance/accounting/customer_invoices.html" class="btn btn-outline-primary btn-sm">🎓 Invoicing</a>
Some other work items will be invoiced given the amount of time spent.
The time sheet do not only help you to keep track of your costs, they as well are the lever to charge your customers.
Those are defined as service products with invoicing based on time sheets.
</p>
<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">
<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="Banner Success" aria-label="Banner Success">✅</i>
<div class="o_editor_banner_content o-contenteditable-true w-100 px-3" contenteditable="true">
<p>As soon as time sheets associated to sale order lines are approved, the recorded time is used as delivery metric!</p>
</div>
</div>
<h2><br /></h2>
<h2><span class="h2-fs">Make your customers happy </span>🆘</h2>
<p>
Expand Down
5 changes: 5 additions & 0 deletions construction/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@ <h2><strong>Tailored Setup for Construction Businesses</strong></h2>
focusing on accurate quoting, efficient planning, seamless execution, and excellent customer service.
The setup integrates all necessary modules (Project, Inventory, Sales, Purchase, ...) to streamline your operations,
with the possibility to expand into advanced functionalities using additional applications.

<h3>Customizations</h3>
<ul>
<li><strong>Progress management</strong> – Easily handle sale orders and project progress in a dedicated view</li>
</ul>
</p>
1 change: 1 addition & 0 deletions construction_progress_management/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

26 changes: 26 additions & 0 deletions construction_progress_management/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
'name': 'Construction Progress Management',
'version': '1.0',
'category': 'Hidden/Tools',
'depends': [
'base_industry_data',
'construction',
'web_studio',
],
'data': [
'data/ir_model_fields.xml',
'data/ir_actions_act_window.xml',
'data/ir_embedded_actions.xml',
'data/ir_actions_server.xml',
'data/base_automation.xml',
'data/ir_ui_view.xml',
'data/project_project.xml',
],
'demo': [
'demo/project_project.xml',
],
'license': 'OPL-1',
'author': 'Odoo S.A.',
"cloc_exclude": [
],
}
23 changes: 23 additions & 0 deletions construction_progress_management/data/base_automation.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version='1.0' encoding='UTF-8'?>
<odoo>
<record id="automation_update_progress_increment_on_change" model="base.automation">
<field name="name">Construction - Update Sale Order Line Progress Increment</field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="action_server_ids" eval="[(6, 0, [ref('construction_progress_management.action_sol_update_progress_increment_on_change')])]"/>
<field name="trigger">on_change</field>
<field name="on_change_field_ids" eval="[(6, 0, [ref('construction_progress_management.field_sale_order_line_quantity_increment')])]"/>
</record>
<record id="automation_update_quantity_increment_on_change" model="base.automation">
<field name="name">Construction - Update Sale Order Line Progress Increment</field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="action_server_ids" eval="[(6, 0, [ref('construction_progress_management.action_sol_update_quantity_increment_on_change')])]"/>
<field name="trigger">on_create_or_write</field>
<field name="on_change_field_ids" eval="[(6, 0, [ref('construction_progress_management.field_sale_order_line_progress_increment')])]"/>
</record>
<record id="automation_initialize_sales_order_line_sequence_on_sales_order_create" model="base.automation">
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="action_server_ids" eval="[(6, 0, [ref('action_initialize_sales_order_line_sequence_on_sales_order_create')])]"/>
<field name="trigger">on_create</field>
<field name="name">Construction - Initialize Sales Order Line Sequence on Sales Order create</field>
</record>
</odoo>
10 changes: 10 additions & 0 deletions construction_progress_management/data/ir_actions_act_window.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version='1.0' encoding='UTF-8'?>
<odoo>
<record id="action_progress_view" model="ir.actions.act_window">
<field name="name">Progress</field>
<field name="res_model">sale.order.line</field>
<field name="view_mode">list</field>
<field name="domain">[('order_id.project_id','=', active_id)]</field>
<field name="context">{'default_project_id': active_id}</field>
</record>
</odoo>
61 changes: 61 additions & 0 deletions construction_progress_management/data/ir_actions_server.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?xml version='1.0' encoding='UTF-8'?>
<odoo>
<record id="action_sol_update_progress_increment_on_change" model="ir.actions.server">
<field name="code"><![CDATA[
record['x_progress_increment'] = record.x_quantity_increment / record.product_uom_qty if record.product_uom_qty > 0 else False
]]></field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="state">code</field>
<field name="name">Construction - Update Progress Increment on Quantity Increment change</field>
</record>
<record id="action_sol_update_quantity_increment_on_change" model="ir.actions.server">
<field name="code"><![CDATA[
record['x_quantity_increment'] = record.x_progress_increment * record.product_uom_qty
]]></field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="state">code</field>
<field name="name">Construction - Update Quantity Increment on Progress Increment change</field>
</record>
<record id="action_sol_update_section_progress" model="ir.actions.server">
<field name="code"><![CDATA[
lines = record.order_id.order_line.sorted(key=lambda sol: sol.sequence)
i = [sol.sequence for sol in lines].index(record.sequence) + 1
while (i < len(lines) and
((record.display_type == 'line_section' and lines[i].display_type != 'line_section')
or (record.display_type == 'line_subsection' and (lines[i].display_type not in ['line_subsection', 'line_section'])))):
if lines[i].is_service and lines[i].x_service_policy == 'delivered_manual':
if record.x_progress_increment * lines[i].product_uom_qty + lines[i].qty_delivered > lines[i].product_uom_qty:
increment = lines[i].product_uom_qty - lines[i].qty_delivered
else:
increment = lines[i].product_uom_qty * record.x_progress_increment
percentage = increment / lines[i].product_uom_qty
lines[i]['x_quantity_increment'], lines[i]['x_progress_increment'] = increment, percentage
i += 1
record['x_progress_increment'] = 0
]]></field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="state">code</field>
<field name="name">Construction - Update Quantity Increment on section button click</field>
</record>
<record id="action_sol_update_qty_delivered" model="ir.actions.server">
<field name="code"><![CDATA[
for sol in records:
sol['qty_delivered'], sol['x_quantity_increment'], sol['x_progress_increment'] = sol.qty_delivered + sol.x_quantity_increment, 0, 0
action = {'type': 'ir.actions.client', 'tag': 'display_notification', 'params': {'message': "Delivered quantities updated.", 'type': 'success', 'next': {'type': 'ir.actions.client', 'tag': 'soft_reload'}}}
]]></field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="state">code</field>
<field name="name">Construction - Update Quantity Delivered</field>
</record>
<record id="action_initialize_sales_order_line_sequence_on_sales_order_create" model="ir.actions.server">
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="update_path">sequence</field>
<field name="state">object_write</field>
<field name="crud_model_id" ref="sale.model_sale_order"/>
<field name="evaluation_type">equation</field>
<field name="name">Construction - Initialize Sales Order Line Sequence on Sales Order create</field>
<field name="update_field_id" ref="sale.field_sale_order_line__sequence"/>
<field name="usage">base_automation</field>
<field name="value"><![CDATA[list(record.order_id.order_line._ids).index(record.id)]]></field>
</record>
</odoo>
17 changes: 17 additions & 0 deletions construction_progress_management/data/ir_embedded_actions.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="construction_embedded_action_sales_order_lines" model="ir.embedded.actions">
<field name="parent_res_model">project.project</field>
<field name="name">Progress</field>
<field name="sequence">55</field>
<field name="parent_action_id" ref="project.act_project_project_2_project_task_all"/>
<field name="action_id" eval="ref('construction_progress_management.action_progress_view')"/>
</record>
<record id="construction_embedded_action_sales_order_lines_dashboard" model="ir.embedded.actions">
<field name="parent_res_model">project.project</field>
<field name="name">Progress</field>
<field name="sequence">55</field>
<field name="parent_action_id" ref="project.project_update_all_action"/>
<field name="action_id" eval="ref('construction_progress_management.action_progress_view')"/>
</record>
</odoo>
43 changes: 43 additions & 0 deletions construction_progress_management/data/ir_model_fields.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version='1.0' encoding='UTF-8'?>
<odoo>
<record id="field_sale_order_line_delivered_progress" model="ir.model.fields">
<field name="ttype">float</field>
<field name="field_description">Delivered Progress</field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="name">x_delivered_progress</field>
<field name="depends">qty_delivered,product_uom_qty</field>
<field name="compute"><![CDATA[
for sol in self: sol['x_delivered_progress'] = False if not sol.product_uom_qty else 100 * (sol.qty_delivered / sol.product_uom_qty)
]]></field>
</record>
<record id="field_sale_order_line_quantity_increment" model="ir.model.fields">
<field name="ttype">float</field>
<field name="field_description">Quantity Increment</field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="name">x_quantity_increment</field>
</record>
<record id="field_sale_order_line_progress_increment" model="ir.model.fields">
<field name="ttype">float</field>
<field name="field_description">Progress Increment</field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="name">x_progress_increment</field>
</record>
<record id="field_sale_order_line_current_progress" model="ir.model.fields">
<field name="ttype">float</field>
<field name="field_description">Current Progress</field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="name">x_current_progress</field>
<field name="depends">x_delivered_progress,x_progress_increment</field>
<field name="compute"><![CDATA[
for sol in self: sol['x_current_progress'] = sol.x_delivered_progress + 100 * sol.x_progress_increment
]]></field>
</record>
<record id="field_sale_order_line_service_policy" model="ir.model.fields">
<field name="name">x_service_policy</field>
<field name="field_description">Product Service Policy</field>
<field name="ttype">selection</field>
<field name="related">product_id.service_policy</field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="store" eval="False"/>
</record>
</odoo>
Loading