Skip to content

Commit 8f02e80

Browse files
dhrs-odoovava-odoo
authored andcommitted
[ADD] handyman: add module for Handyman Services
This industry package includes all the essential features to manage your handyman business, from customer relationship management to field service operations and invoicing. Basics - Use the CRM App to track your leads and prospects. - Create great quotations and manage your products in the Sales App. - Follow your interventions using the Field Service App. - Track your inventory and your purchases in the related Apps. - Invoice in seconds and keep track of your payment in the Invoicing App. Customisations - Add a link from vendor bills to task - Add a button to create an vendor bills from a field service task, and link the vendor bills with the task. - Add a smart button on tasks to see related vendor bills. - Add a computed field on tasks providing the total amount of vendor bills registered for this task and a progress field computing the consumption between the Materials budget and the invoices. Task-4314101 closes #295 Signed-off-by: Vallaeys Valentin (vava) <[email protected]>
1 parent f71a1fb commit 8f02e80

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2092
-0
lines changed

.tx/config

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,15 @@ resource_name = hair_salon
226226
replace_edited_strings = false
227227
keep_translations = false
228228

229+
[o:odoo:p:odoo-18:r:handyman]
230+
file_filter = handyman/i18n/<lang>.po
231+
source_file = handyman/i18n/handyman.pot
232+
type = PO
233+
minimum_perc = 0
234+
resource_name = handyman
235+
replace_edited_strings = false
236+
keep_translations = false
237+
229238
[o:odoo:p:odoo-18:r:hardware_shop]
230239
file_filter = hardware_shop/i18n/<lang>.po
231240
source_file = hardware_shop/i18n/hardware_shop.pot

handyman/__manifest__.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
'name': 'Handyman Services',
3+
'version': '1.0',
4+
'category': 'Services',
5+
'description': "",
6+
'depends': [
7+
'account_accountant',
8+
'appointment_account_payment',
9+
'hr',
10+
'industry_fsm_sale_report',
11+
'industry_fsm_stock',
12+
'knowledge',
13+
'project_purchase',
14+
'project_timesheet_forecast_sale',
15+
'sale_crm',
16+
'sale_purchase_stock',
17+
'spreadsheet_sale_management',
18+
'web_studio',
19+
],
20+
'data': [
21+
'data/res_config_setting.xml',
22+
'data/ir_attachment_pre.xml',
23+
'data/ir_model_fields.xml',
24+
'data/ir_actions_server.xml',
25+
'data/ir_actions_act_window.xml',
26+
'data/ir_ui_view.xml',
27+
'data/knowledge_cover.xml',
28+
'data/knowledge_article.xml',
29+
'data/knowledge_article_favorite.xml',
30+
'data/mail_message.xml',
31+
'data/planning_role.xml',
32+
'data/project_task_type.xml',
33+
'data/project_project.xml',
34+
'data/product_product.xml',
35+
'data/sale_order_spreadsheet.xml',
36+
'data/sale_order_template.xml',
37+
'data/sale_order_template_line.xml',
38+
'data/knowledge_tour.xml',
39+
],
40+
'demo': [
41+
'demo/res_partner.xml',
42+
'demo/crm_lead.xml',
43+
'demo/mail_activity.xml',
44+
'demo/hr_employee.xml',
45+
'demo/planning_recurrency.xml',
46+
'demo/sale_order.xml',
47+
'demo/sale_order_line.xml',
48+
'demo/sale_order_confirm.xml',
49+
'demo/planning_slot_template.xml',
50+
'demo/planning_slot.xml',
51+
'demo/product_supplierinfo.xml',
52+
'demo/account_analytic_line.xml',
53+
'demo/purchase_order.xml',
54+
'demo/purchase_order_line.xml',
55+
'demo/purchase_order_confirm.xml',
56+
],
57+
'license': 'OPL-1',
58+
'assets': {
59+
'web.assets_backend': [
60+
'handyman/static/src/js/my_tour.js',
61+
],
62+
},
63+
'author': 'Odoo S.A.',
64+
"cloc_exclude": [
65+
"data/knowledge_article.xml",
66+
"static/src/js/my_tour.js",
67+
],
68+
'images': ['images/main.png'],
69+
}
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+
<odoo>
3+
<record id="action_vendor_bill_button" model="ir.actions.act_window">
4+
<field name="name">Vendor Bills</field>
5+
<field name="res_model">account.move</field>
6+
<field name="context">{'search_default_x_task': active_id, 'default_x_task': active_id}</field>
7+
<field name="domain">[('x_task_id', '=', active_id)]</field>
8+
</record>
9+
</odoo>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo>
3+
<record id="action_create_bill_from_task" model="ir.actions.server">
4+
<field name="name">Create Bill from Task</field>
5+
<field name="model_id" ref = "project.model_project_task"/>
6+
<field name="state">code</field>
7+
<field name="code"><![CDATA[
8+
invoice = env['account.move'].create({'move_type': 'in_invoice', 'x_task_id': record.id})
9+
action = env['ir.actions.act_window']._for_xml_id('account.action_move_in_invoice_type')
10+
action['views'] = [(env.ref('account.view_move_form').id, 'form')]
11+
action['res_id'] = invoice.id
12+
]]></field>
13+
</record>
14+
</odoo>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo noupdate="1">
3+
<record id="ir_attachment_583" model="ir.attachment">
4+
<field name="name">Handyman Cover</field>
5+
<field name="datas" type="base64" file="handyman/static/src/binary/ir_attachment/ir_attachment_583.jpg"/>
6+
</record>
7+
</odoo>

handyman/data/ir_model_fields.xml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo>
3+
<record id="field_various_material_budget" model="ir.model.fields">
4+
<field name="name">x_various_materials_budget</field>
5+
<field name="ttype">monetary</field>
6+
<field name="copied" eval="True"/>
7+
<field name="field_description">Various Materials Budget</field>
8+
<field name="model_id" ref="sale.model_sale_order"/>
9+
<field name="currency_field">currency_id</field>
10+
</record>
11+
<record id="new_material_budget_related_field" model="ir.model.fields">
12+
<field name="name">x_related_material_budget_field</field>
13+
<field name="ttype">monetary</field>
14+
<field name="related">sale_order_id.x_various_materials_budget</field>
15+
<field name="field_description">Materials Budget</field>
16+
<field name="model_id" ref="project.model_project_task"/>
17+
<field name="readonly" eval="True"/>
18+
<field name="store" eval="False"/>
19+
<field name="currency_field">currency_id</field>
20+
</record>
21+
<record id="x_task_field" model="ir.model.fields">
22+
<field name="name">x_task_id</field>
23+
<field name="ttype">many2one</field>
24+
<field name="copied" eval="True"/>
25+
<field name="field_description">Task</field>
26+
<field name="model_id" ref="account.model_account_move"/>
27+
<field name="relation">project.task</field>
28+
</record>
29+
<record id="x_x_task_account_move_count_field" model="ir.model.fields">
30+
<field name="name">x_x_task_account_move_count</field>
31+
<field name="compute"><![CDATA[
32+
for record in self:
33+
record['x_x_task_account_move_count'] = self.env['account.move'].search_count([('x_task_id', '=', record.id)])]]></field>
34+
<field name="ttype">integer</field>
35+
<field name="field_description">Task count</field>
36+
<field name="model_id" ref="project.model_project_task"/>
37+
<field name="selectable" eval="False"/>
38+
<field name="store" eval="False"/>
39+
<field name="readonly" eval="True"/>
40+
</record>
41+
<record id="x_vendor_bills_field" model="ir.model.fields">
42+
<field name="name">x_vendor_bills</field>
43+
<field name="compute"><![CDATA[
44+
bills = self.env['account.move']._read_group(domain=[('x_task_id', 'in', self.ids)], groupby=['x_task_id'], aggregates=['amount_untaxed:sum'])
45+
mapped_data = {task.id: total for task, total in bills}
46+
for task in self:
47+
task['x_vendor_bills'] = mapped_data.get(task.id, 0)]]></field>
48+
<field name="ttype">monetary</field>
49+
<field name="field_description">Vendor Bills</field>
50+
<field name="model_id" ref="project.model_project_task"/>
51+
<field name="readonly" eval="True"/>
52+
<field name="selectable" eval="False"/>
53+
<field name="store" eval="False"/>
54+
<field name="currency_field">currency_id</field>
55+
</record>
56+
<record id="x_percent_bills_1_field" model="ir.model.fields">
57+
<field name="name">x_percent_bills_1</field>
58+
<field name="compute"><![CDATA[
59+
for task in self:
60+
task['x_percent_bills_1'] = task.x_vendor_bills / task.x_related_material_budget_field if task.x_related_material_budget_field else 0]]></field>
61+
<field name="ttype">float</field>
62+
<field name="depends">name</field>
63+
<field name="field_description">Percent bills</field>
64+
<field name="model_id" ref="project.model_project_task"/>
65+
<field name="readonly" eval="True"/>
66+
<field name="selectable" eval="False"/>
67+
<field name="store" eval="False"/>
68+
</record>
69+
</odoo>

handyman/data/ir_ui_view.xml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo>
3+
<record id="sale_order_form_custom" model="ir.ui.view">
4+
<field name="name">sale.order.form customization</field>
5+
<field name="inherit_id" ref="sale.view_order_form"/>
6+
<field name="mode">extension</field>
7+
<field name="model">sale.order</field>
8+
<field name="active" eval="True"/>
9+
<field name="priority">160</field>
10+
<field name="type">form</field>
11+
<field name="arch" type="xml">
12+
<xpath expr="//field[@name='sale_order_template_id']" position="after">
13+
<field name="x_various_materials_budget"/>
14+
</xpath>
15+
</field>
16+
</record>
17+
<record id="project_task_form_custom" model="ir.ui.view">
18+
<field name="name">project.task.form customization</field>
19+
<field name="inherit_id" ref="project.view_task_form2"/>
20+
<field name="mode">extension</field>
21+
<field name="model">project.task</field>
22+
<field name="active" eval="True"/>
23+
<field name="priority">9990</field>
24+
<field name="type">form</field>
25+
<field name="arch" type="xml">
26+
<xpath expr="//field[@name='personal_stage_type_id']" position="after">
27+
<button name="%(action_create_bill_from_task)d" string="Add Vendor Bill" type="action"/>
28+
</xpath>
29+
<xpath expr="//button[@name='action_fsm_worksheet']" position="after">
30+
<button name="%(action_vendor_bill_button)d" class="oe_stat_button" icon="fa-file-text-o" type="action">
31+
<field name="x_x_task_account_move_count" widget="statinfo" string="Vendor Bills"/>
32+
</button>
33+
</xpath>
34+
<xpath expr="//field[@name='tag_ids']" position="after">
35+
<field name="x_related_material_budget_field" string="Materials Budget"/>
36+
<label for="x_vendor_bills"/>
37+
<div class="d-flex" name="bills">
38+
<field class="oe_inline" name="x_vendor_bills"/>
39+
<span class="ml4">(</span>
40+
<field class="oe_inline" name="x_percent_bills_1" widget="percentage"/>
41+
<span>)</span>
42+
</div>
43+
</xpath>
44+
</field>
45+
</record>
46+
<record id="account_move_form_custom" model="ir.ui.view">
47+
<field name="name">account.move.form customization</field>
48+
<field name="inherit_id" ref="account.view_move_form"/>
49+
<field name="mode">extension</field>
50+
<field name="model">account.move</field>
51+
<field name="active" eval="True"/>
52+
<field name="priority">160</field>
53+
<field name="type">form</field>
54+
<field name="arch" type="xml">
55+
<xpath expr="//field[@name='ref']" position="after">
56+
<field name="x_task_id" options="{'no_create':true}"/>
57+
</xpath>
58+
</field>
59+
</record>
60+
<record id="project_task_list_fsm_my_task_customization" model="ir.ui.view">
61+
<field name="name">project.task.list.fsm.my.task customization</field>
62+
<field name="model">project.task</field>
63+
<field name="inherit_id" ref="industry_fsm.project_task_view_list_fsm_my_task"/>
64+
<field name="active" eval="True"/>
65+
<field name="mode">extension</field>
66+
<field name="priority">99</field>
67+
<field name="type">list</field>
68+
<field name="arch" type="xml">
69+
<xpath expr="//field[@name='tag_ids']" position="replace"/>
70+
<xpath expr="//field[@name='activity_ids']" position="replace"/>
71+
<xpath expr="//field[@name='worksheet_template_id']" position="replace"/>
72+
<xpath expr="//field[@name='progress'][2]" position="after">
73+
<field name="x_percent_bills_1" optional="show" widget="percentage"/>
74+
<field name="rating_avg" optional="show" widget="percentpie"/>
75+
</xpath>
76+
</field>
77+
</record>
78+
</odoo>

0 commit comments

Comments
 (0)