mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
Merge branch '11.0' of https://github.com/hibou-io/hibou-odoo-suite into 11.0
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "external/hibou-oca/account-analytic"]
|
||||
path = external/hibou-oca/account-analytic
|
||||
url = https://github.com/hibou-io/oca-account-analytic.git
|
||||
@@ -22,6 +22,11 @@ Main Features
|
||||
* New buttons to easily fill or pre-populate amount remaining or amount due.
|
||||
* Tests to ensure that all the stock payment mechanisms work, and that we make the right reconciliations.
|
||||
|
||||
.. image:: https://user-images.githubusercontent.com/15882954/39149575-62a0a1d6-46f4-11e8-8e59-b315cf8f9277.png
|
||||
:alt: 'Register Payment Detail'
|
||||
:width: 988
|
||||
:align: left
|
||||
|
||||
=============
|
||||
Known Issues
|
||||
=============
|
||||
@@ -35,3 +40,4 @@ License
|
||||
Please see `LICENSE <https://github.com/hibou-io/hibou-odoo-suite/blob/11.0/LICENSE>`_.
|
||||
|
||||
Copyright Hibou Corp. 2018
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
'version': '11.0.1.0.0',
|
||||
'category': 'Stock',
|
||||
'sequence': 95,
|
||||
'summary': 'Fedex Partner Shipping Accounts',
|
||||
'summary': 'DHL Partner Shipping Accounts',
|
||||
'description': """
|
||||
""",
|
||||
'website': 'https://hibou.io/',
|
||||
|
||||
1
external/hibou-oca/account-analytic
vendored
Submodule
1
external/hibou-oca/account-analytic
vendored
Submodule
Submodule external/hibou-oca/account-analytic added at 7e06779e23
2
hr_department_project/__init__.py
Normal file
2
hr_department_project/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import models
|
||||
24
hr_department_project/__manifest__.py
Normal file
24
hr_department_project/__manifest__.py
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
'name': 'HR Department Project',
|
||||
'version': '11.0.1.0.0',
|
||||
'author': 'Hibou Corp. <hello@hibou.io>',
|
||||
'category': 'Human Resources',
|
||||
'summary': 'Provide default project per Department',
|
||||
'description': """
|
||||
HR Department Project
|
||||
=====================
|
||||
|
||||
Define a 'default project' for every department. This is a bridge module to allow other modules to use this behavior.
|
||||
""",
|
||||
'website': 'https://hibou.io/',
|
||||
'depends': [
|
||||
'project',
|
||||
'hr',
|
||||
],
|
||||
'data': [
|
||||
'views/hr_views.xml',
|
||||
'views/project_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
3
hr_department_project/models/__init__.py
Normal file
3
hr_department_project/models/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import project
|
||||
from . import hr
|
||||
22
hr_department_project/models/hr.py
Normal file
22
hr_department_project/models/hr.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
|
||||
class Department(models.Model):
|
||||
_inherit = 'hr.department'
|
||||
|
||||
project_ids = fields.One2many('project.project', 'department_id', string='Projects')
|
||||
project_count = fields.Integer(compute='_compute_project_count', string='Project Count')
|
||||
|
||||
def _compute_project_count(self):
|
||||
for department in self:
|
||||
department.project_count = len(department.with_context(active_test=False).project_ids)
|
||||
|
||||
def project_tree_view(self):
|
||||
self.ensure_one()
|
||||
action = self.env.ref('project.open_view_project_all').read()[0]
|
||||
action['domain'] = [('department_id', '=', self.id)]
|
||||
action['context'] = {
|
||||
'default_department_id': self.id,
|
||||
'default_user_id': self.manager_id.id if self.manager_id else 0,
|
||||
}
|
||||
return action
|
||||
7
hr_department_project/models/project.py
Normal file
7
hr_department_project/models/project.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
|
||||
class Project(models.Model):
|
||||
_inherit = 'project.project'
|
||||
|
||||
department_id = fields.Many2one('hr.department', string='Department')
|
||||
15
hr_department_project/views/hr_views.xml
Normal file
15
hr_department_project/views/hr_views.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="view_department_form_inherited">
|
||||
<field name="name">hr.department.form.inherited</field>
|
||||
<field name="model">hr.department</field>
|
||||
<field name="inherit_id" ref="hr.view_department_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//button[@name='toggle_active']" position="before">
|
||||
<button class="oe_stat_button" name="project_tree_view" type="object" icon="fa-puzzle-piece">
|
||||
<field string="Projects" name="project_count" widget="statinfo"/>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
24
hr_department_project/views/project_views.xml
Normal file
24
hr_department_project/views/project_views.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="edit_project_inherited">
|
||||
<field name="name">project.project.form.inherited</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='user_id']" position="before">
|
||||
<field name="department_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_project_project_filter_inherited">
|
||||
<field name="name">project.project.select.inherited</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.view_project_project_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group/filter[@name='Manager']" position="before">
|
||||
<filter string="Department" name="group_department" context="{'group_by': 'department_id'}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
1
maintenance_equipment_charge/__init__.py
Normal file
1
maintenance_equipment_charge/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
23
maintenance_equipment_charge/__manifest__.py
Normal file
23
maintenance_equipment_charge/__manifest__.py
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
'name': 'Equipment Charges',
|
||||
'version': '11.0.1.0.0',
|
||||
'author': 'Hibou Corp. <hello@hibou.io>',
|
||||
'category': 'Human Resources',
|
||||
'summary': 'Record related equipment charges.',
|
||||
'description': """
|
||||
Equipment Charges
|
||||
=================
|
||||
|
||||
Record related equipment charges, for example fuel charges.
|
||||
""",
|
||||
'website': 'https://www.odoo.com/page/manufacturing',
|
||||
'depends': [
|
||||
'hr_maintenance',
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'views/maintenance_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
1
maintenance_equipment_charge/models/__init__.py
Normal file
1
maintenance_equipment_charge/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import maintenance
|
||||
46
maintenance_equipment_charge/models/maintenance.py
Normal file
46
maintenance_equipment_charge/models/maintenance.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class EquipmentChargeType(models.Model):
|
||||
_name = 'maintenance.equipment.charge.type'
|
||||
|
||||
name = fields.Char(string='Charge Type')
|
||||
uom_id = fields.Many2one('product.uom', string='Charge UOM')
|
||||
|
||||
|
||||
class Equipment(models.Model):
|
||||
_inherit = 'maintenance.equipment'
|
||||
|
||||
charge_ids = fields.One2many('maintenance.equipment.charge', 'equipment_id', 'Charges', copy=False)
|
||||
charge_count = fields.Integer(string='Charges', compute='_compute_charge_count')
|
||||
|
||||
@api.multi
|
||||
def _compute_charge_count(self):
|
||||
for equipment in self:
|
||||
self.charge_count = len(equipment.charge_ids)
|
||||
|
||||
def action_open_charges(self):
|
||||
self.ensure_one()
|
||||
action = self.env.ref('maintenance_equipment_charge.maintenance_charge_action_reports').read()[0]
|
||||
action['domain'] = [('equipment_id', '=', self.id)]
|
||||
action['context'] = {
|
||||
'default_equipment_id': self.id,
|
||||
'default_employee_id': self.employee_id.id,
|
||||
'default_department_id': self.department_id.id,
|
||||
}
|
||||
return action
|
||||
|
||||
|
||||
class EquipmentCharge(models.Model):
|
||||
_name = 'maintenance.equipment.charge'
|
||||
_order = 'date DESC'
|
||||
|
||||
name = fields.Char(string='Description')
|
||||
date = fields.Date(string='Date', default=fields.Date.today, index=True)
|
||||
equipment_id = fields.Many2one('maintenance.equipment', copy=False)
|
||||
type_id = fields.Many2one('maintenance.equipment.charge.type', string='Type')
|
||||
employee_id = fields.Many2one('hr.employee', string='Employee')
|
||||
department_id = fields.Many2one('hr.department', string='Department')
|
||||
qty = fields.Float(string='Quantity', default=1.0)
|
||||
uom_id = fields.Many2one('product.uom', related='type_id.uom_id')
|
||||
amount = fields.Float(string='Amount')
|
||||
@@ -0,0 +1,5 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"manage_maintenance_equipment_charge","manage maintenance.equipment.charge","model_maintenance_equipment_charge","stock.group_stock_manager",1,1,1,1
|
||||
"access_maintenance_equipment_charge","access maintenance.equipment.charge","model_maintenance_equipment_charge","base.group_user",1,0,1,0
|
||||
"manage_maintenance_equipment_charge_type","manage maintenance.equipment.charge.type","model_maintenance_equipment_charge_type","stock.group_stock_manager",1,1,1,1
|
||||
"access_maintenance_equipment_charge_type","access maintenance.equipment.charge.type","model_maintenance_equipment_charge_type","base.group_user",1,0,1,0
|
||||
|
1
maintenance_equipment_charge/tests/__init__.py
Normal file
1
maintenance_equipment_charge/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import test_maintenance_usage
|
||||
21
maintenance_equipment_charge/tests/test_maintenance_usage.py
Normal file
21
maintenance_equipment_charge/tests/test_maintenance_usage.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
class TestMaintenanceCharge(common.TransactionCase):
|
||||
"""Tests for charges
|
||||
"""
|
||||
|
||||
def test_create(self):
|
||||
test_charge = 21.0
|
||||
equipment = self.env['maintenance.equipment'].create({
|
||||
'name': 'Monitor',
|
||||
})
|
||||
|
||||
self.assertFalse(equipment.charge_ids)
|
||||
self.env['maintenance.equipment.charge'].create({
|
||||
'equipment_id': equipment.id,
|
||||
'name': 'test',
|
||||
'amount': test_charge,
|
||||
})
|
||||
self.assertTrue(equipment.charge_ids)
|
||||
self.assertAlmostEqual(equipment.charge_ids[0].amount, test_charge)
|
||||
184
maintenance_equipment_charge/views/maintenance_views.xml
Normal file
184
maintenance_equipment_charge/views/maintenance_views.xml
Normal file
@@ -0,0 +1,184 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record model="maintenance.equipment.charge.type" id="equipment_charge_other">
|
||||
<field name="name">Other</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_equipment_view_form_inherited">
|
||||
<field name="name">equipment.form.inherited</field>
|
||||
<field name="model">maintenance.equipment</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="action_open_charges"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-dollar"
|
||||
help="show the usage charges for equipment" >
|
||||
<field string="Charges" name="charge_count" widget="statinfo"/>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- maintenance.equipment.charge : views -->
|
||||
<record id="hr_equipment_charge_view_search" model="ir.ui.view">
|
||||
<field name="name">equipment.charge.search</field>
|
||||
<field name="model">maintenance.equipment.charge</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Equipment Charge Search">
|
||||
<field name="equipment_id"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="type_id"/>
|
||||
<separator/>
|
||||
<group expand='0' string='Group by...'>
|
||||
<filter string='Charge Type' domain="[]" context="{'group_by': 'type_id'}"/>
|
||||
<filter string='Equipment' domain="[]" context="{'group_by': 'equipment_id'}"/>
|
||||
<filter string='Employee' domain="[]" context="{'group_by': 'employee_id'}"/>
|
||||
<filter string='Department' domain="[]" context="{'group_by': 'department_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_equipment_charge_view_form" model="ir.ui.view">
|
||||
<field name="name">equipment.charge.form</field>
|
||||
<field name="model">maintenance.equipment.charge</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Equipment Charge Form">
|
||||
<header/>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="date"/>
|
||||
<field name="equipment_id"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
</group>
|
||||
<group name="charge_info" string="Charge">
|
||||
<field name="type_id" widget="selection"/>
|
||||
<label for="qty"/>
|
||||
<div class="o_row" name="qty">
|
||||
<field name="qty" nolabel="1"/>
|
||||
<field name="uom_id" nolabel="1" readonly="1"/>
|
||||
</div>
|
||||
<field name="amount"/>
|
||||
<field name="name"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_equipment_charge_view_tree" model="ir.ui.view">
|
||||
<field name="name">equipment.charge.tree</field>
|
||||
<field name="model">maintenance.equipment.charge</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Equipment Charge">
|
||||
<field name="date"/>
|
||||
<field name="type_id"/>
|
||||
<field name="equipment_id"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="qty"/>
|
||||
<field name="amount"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_equipment_charge_view_graph" model="ir.ui.view">
|
||||
<field name="name">equipment.charge.graph</field>
|
||||
<field name="model">maintenance.equipment.charge</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Equipment Charge">
|
||||
<field name="type_id"/>
|
||||
<field name="equipment_id"/>
|
||||
<field name="amount"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_equipment_charge_view_pivot" model="ir.ui.view">
|
||||
<field name="name">equipment.charge.pivot</field>
|
||||
<field name="model">maintenance.equipment.charge</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Equipment Charge">
|
||||
<field name="type_id"/>
|
||||
<field name="equipment_id"/>
|
||||
<field name="amount"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_equipment_charge_view_calendar" model="ir.ui.view">
|
||||
<field name="name">equipment.charge.calendar</field>
|
||||
<field name="model">maintenance.equipment.charge</field>
|
||||
<field name="arch" type="xml">
|
||||
<calendar date_start="date" color="equipment_id">
|
||||
<field name="equipment_id"/>
|
||||
<field name="amount"/>
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- maintenance.equipment.charge : actions -->
|
||||
<record id="maintenance_charge_action_reports" model="ir.actions.act_window">
|
||||
<field name="name">Equipment Charges</field>
|
||||
<field name="res_model">maintenance.equipment.charge</field>
|
||||
<field name="view_mode">tree,form,graph,pivot,calendar</field>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
No charges.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="maintenance_equipment_charge_reporting"
|
||||
action="maintenance_charge_action_reports"
|
||||
parent="maintenance.maintenance_reporting"/>
|
||||
|
||||
<!-- maintenance.equipment.charge.type : views -->
|
||||
<record id="hr_equipment_charge_type_view_form" model="ir.ui.view">
|
||||
<field name="name">equipment.charge.type.form</field>
|
||||
<field name="model">maintenance.equipment.charge.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Equipment Charge Type Form">
|
||||
<header/>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="uom_id"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_equipment_charge_type_view_tree" model="ir.ui.view">
|
||||
<field name="name">equipment.charge.type.tree</field>
|
||||
<field name="model">maintenance.equipment.charge.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Equipment Charge Type">
|
||||
<field name="name"/>
|
||||
<field name="uom_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- maintenance.equipment.charge.type : actions -->
|
||||
<record id="maintenance_charge_type_action" model="ir.actions.act_window">
|
||||
<field name="name">Equipment Charge Types</field>
|
||||
<field name="res_model">maintenance.equipment.charge.type</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="maintenance_equipment_charge_type"
|
||||
action="maintenance_charge_type_action"
|
||||
parent="maintenance.menu_maintenance_configuration"/>
|
||||
</odoo>
|
||||
1
maintenance_notebook/__init__.py
Normal file
1
maintenance_notebook/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
22
maintenance_notebook/__manifest__.py
Normal file
22
maintenance_notebook/__manifest__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
'name': 'Maintenance Notebook',
|
||||
'version': '11.0.1.0.0',
|
||||
'author': 'Hibou Corp. <hello@hibou.io>',
|
||||
'category': 'Human Resources',
|
||||
'summary': 'Record time on maintenance requests.',
|
||||
'description': """
|
||||
Maintenance Notebook
|
||||
====================
|
||||
|
||||
Adds a 'notebook' XML element to the Maintenance form to add pages in other modules.
|
||||
""",
|
||||
'website': 'https://hibou.io/',
|
||||
'depends': [
|
||||
'maintenance',
|
||||
],
|
||||
'data': [
|
||||
'views/maintenance_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
13
maintenance_notebook/views/maintenance_views.xml
Normal file
13
maintenance_notebook/views/maintenance_views.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="hr_equipment_request_view_form_notebook">
|
||||
<field name="name">equipment.request.form.notebook</field>
|
||||
<field name="model">maintenance.request</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_request_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='description']" position="after">
|
||||
<notebook/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
1
maintenance_repair/__init__.py
Normal file
1
maintenance_repair/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
25
maintenance_repair/__manifest__.py
Normal file
25
maintenance_repair/__manifest__.py
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
'name': 'Equipment Repair',
|
||||
'version': '11.0.1.0.0',
|
||||
'author': 'Hibou Corp. <hello@hibou.io>',
|
||||
'category': 'Human Resources',
|
||||
'summary': 'Consume products on Maintenance Requests',
|
||||
'description': """
|
||||
Equipment Repair
|
||||
================
|
||||
|
||||
Keep track of parts required to repair equipment.
|
||||
""",
|
||||
'website': 'https://hibou.io/',
|
||||
'depends': [
|
||||
'stock',
|
||||
'maintenance_notebook',
|
||||
'hr_department_project',
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'views/maintenance_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
1
maintenance_repair/models/__init__.py
Normal file
1
maintenance_repair/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import maintenance
|
||||
142
maintenance_repair/models/maintenance.py
Normal file
142
maintenance_repair/models/maintenance.py
Normal file
@@ -0,0 +1,142 @@
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.addons import decimal_precision as dp
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
maintenance_request_id = fields.Many2one('maintenance.request')
|
||||
|
||||
|
||||
class MaintenanceTeam(models.Model):
|
||||
_inherit = 'maintenance.team'
|
||||
|
||||
repair_location_id = fields.Many2one('stock.location', string='Default Repair Parts Source')
|
||||
repair_location_dest_id = fields.Many2one('stock.location', string='Default Repair Parts Destination')
|
||||
|
||||
|
||||
class MaintenanceRequest(models.Model):
|
||||
_inherit = 'maintenance.request'
|
||||
|
||||
maintenance_type = fields.Selection(selection_add=[('negligence', 'Negligence')])
|
||||
repair_line_ids = fields.One2many('maintenance.request.repair.line', 'request_id', 'Parts', copy=True)
|
||||
repair_status = fields.Selection([
|
||||
('repaired', 'Repaired'),
|
||||
('to repair', 'To Repair'),
|
||||
('no', 'Nothing to Repair')
|
||||
], string='Repair Status', compute='_get_repaired', store=True, readonly=True)
|
||||
repair_location_id = fields.Many2one('stock.location', string='Source Location')
|
||||
repair_location_dest_id = fields.Many2one('stock.location', string='Destination Location')
|
||||
total_lst_price = fields.Float(string='Total Price', compute='_compute_repair_totals', stored=True)
|
||||
total_standard_price = fields.Float(string='Total Est. Cost', compute='_compute_repair_totals', stored=True)
|
||||
total_cost = fields.Float(string='Total Cost', compute='_compute_repair_totals', stored=True)
|
||||
|
||||
@api.depends('repair_line_ids.lst_price', 'repair_line_ids.standard_price', 'repair_line_ids.cost')
|
||||
def _compute_repair_totals(self):
|
||||
for repair in self:
|
||||
repair.total_lst_price = sum(l.lst_price for l in repair.repair_line_ids)
|
||||
repair.total_standard_price = sum(l.standard_price for l in repair.repair_line_ids)
|
||||
repair.total_cost = sum(l.cost for l in repair.repair_line_ids)
|
||||
|
||||
@api.depends('repair_line_ids.state')
|
||||
def _get_repaired(self):
|
||||
for request in self:
|
||||
if not request.repair_line_ids:
|
||||
request.repair_status = 'no'
|
||||
elif request.repair_line_ids.filtered(lambda l: l.state != 'done'):
|
||||
request.repair_status = 'to repair'
|
||||
else:
|
||||
request.repair_status = 'repaired'
|
||||
|
||||
@api.onchange('maintenance_team_id')
|
||||
def _onchange_maintenance_team(self):
|
||||
for request in self:
|
||||
if request.maintenance_team_id:
|
||||
request.repair_location_id = request.maintenance_team_id.repair_location_id
|
||||
request.repair_location_dest_id = request.maintenance_team_id.repair_location_dest_id
|
||||
|
||||
|
||||
def action_complete_repair(self):
|
||||
for request in self.filtered(lambda r: r.repair_status == 'to repair'):
|
||||
request.repair_line_ids.action_complete()
|
||||
return True
|
||||
|
||||
|
||||
class MaintenanceRequestRepairLine(models.Model):
|
||||
_name = 'maintenance.request.repair.line'
|
||||
|
||||
request_id = fields.Many2one('maintenance.request', copy=False)
|
||||
product_id = fields.Many2one('product.product', 'Product', required=True,
|
||||
states={'done': [('readonly', True)]})
|
||||
product_uom_qty = fields.Float('Quantity', default=1.0,
|
||||
digits=dp.get_precision('Product Unit of Measure'), required=True,
|
||||
states={'done': [('readonly', True)]})
|
||||
product_uom_id = fields.Many2one('product.uom', 'Product Unit of Measure', required=True,
|
||||
states={'done': [('readonly', True)]})
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('done', 'Done'),
|
||||
], string='State', copy=False, default='draft')
|
||||
move_id = fields.Many2one('stock.move', string='Stock Move')
|
||||
lst_price = fields.Float(string='Sale Price', states={'done': [('readonly', True)]})
|
||||
standard_price = fields.Float(string='Est. Cost', states={'done': [('readonly', True)]})
|
||||
cost = fields.Float(string='Cost', compute='_compute_actual_cost', stored=True)
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
if self.filtered(lambda l: l.state == 'done'):
|
||||
raise UserError(_('Only draft lines can be deleted.'))
|
||||
return super(MaintenanceRequestRepairLine, self).unlink()
|
||||
|
||||
@api.onchange('product_id', 'product_uom_qty')
|
||||
def onchange_product_id(self):
|
||||
if self.product_id:
|
||||
self.product_uom_id = self.product_id.uom_id
|
||||
self.lst_price = self.product_id.lst_price * self.product_uom_qty
|
||||
self.standard_price = self.product_id.standard_price * self.product_uom_qty
|
||||
|
||||
@api.depends('product_id', 'move_id')
|
||||
def _compute_actual_cost(self):
|
||||
for line in self:
|
||||
if line.move_id:
|
||||
line.cost = sum(abs(m.amount) for m in line.move_id.account_move_ids)
|
||||
else:
|
||||
line.cost = 0.0
|
||||
|
||||
@api.multi
|
||||
def action_complete(self):
|
||||
# Create stock movements. - Inspired by mrp_repair
|
||||
MoveObj = self.env['stock.move']
|
||||
for line in self.filtered(lambda l: not l.state == 'done'):
|
||||
request = line.request_id
|
||||
|
||||
# Optional hooks to `maintenance_timesheet` and `stock_analytic`
|
||||
analytic_account_id = False
|
||||
if getattr(request, 'project_id', False):
|
||||
analytic_account_id = request.project_id.analytic_account_id.id
|
||||
|
||||
move = MoveObj.create({
|
||||
'name': request.name,
|
||||
'product_id': line.product_id.id,
|
||||
'product_uom_qty': line.product_uom_qty,
|
||||
'product_uom': line.product_uom_id.id,
|
||||
'location_id': request.repair_location_id.id,
|
||||
'location_dest_id': request.repair_location_dest_id.id,
|
||||
'maintenance_request_id': request.id,
|
||||
'origin': request.name,
|
||||
'analytic_account_id': analytic_account_id,
|
||||
})
|
||||
move = move.sudo()
|
||||
move._action_confirm()
|
||||
move._action_assign()
|
||||
if move.state != 'assigned':
|
||||
raise ValidationError(_('Unable to reserve inventory.'))
|
||||
|
||||
move.quantity_done = line.product_uom_qty
|
||||
move._action_done()
|
||||
if move.state != 'done':
|
||||
raise ValidationError(_('Unable to move inventory.'))
|
||||
|
||||
line.write({'move_id': move.id, 'state': 'done'})
|
||||
return True
|
||||
2
maintenance_repair/security/ir.model.access.csv
Normal file
2
maintenance_repair/security/ir.model.access.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_maintenance_request_repair_line","access maintenance.request.repair.line","model_maintenance_request_repair_line","base.group_user",1,1,1,1
|
||||
|
1
maintenance_repair/tests/__init__.py
Normal file
1
maintenance_repair/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import test_maintenance_repair
|
||||
37
maintenance_repair/tests/test_maintenance_repair.py
Normal file
37
maintenance_repair/tests/test_maintenance_repair.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
class TestMaintenanceRepair(common.TransactionCase):
|
||||
"""Tests for repairs
|
||||
"""
|
||||
|
||||
def test_create(self):
|
||||
equipment = self.env['maintenance.equipment'].create({
|
||||
'name': 'Monitor',
|
||||
})
|
||||
|
||||
loc_from = self.env.ref('stock.stock_location_stock')
|
||||
loc_to = self.env.ref('stock.location_inventory')
|
||||
request = self.env['maintenance.request'].create({
|
||||
'name': 'Repair Monitor',
|
||||
'equipment_id': equipment.id,
|
||||
'repair_location_id': loc_from.id,
|
||||
'repair_location_dest_id': loc_to.id,
|
||||
})
|
||||
self.assertEqual(request.repair_status, 'no')
|
||||
|
||||
product_to_repair = self.env.ref('product.product_product_24_product_template')
|
||||
line = self.env['maintenance.request.repair.line'].create({
|
||||
'request_id': request.id,
|
||||
'product_id': product_to_repair.id,
|
||||
'product_uom_id': product_to_repair.uom_id.id,
|
||||
})
|
||||
|
||||
self.assertEqual(request.repair_status, 'to repair')
|
||||
line.action_complete()
|
||||
self.assertEqual(request.repair_status, 'repaired')
|
||||
self.assertEqual(line.state, 'done')
|
||||
self.assertTrue(line.move_id, 'Expect a stock move to be done.')
|
||||
|
||||
|
||||
|
||||
81
maintenance_repair/views/maintenance_views.xml
Normal file
81
maintenance_repair/views/maintenance_views.xml
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="maintenance_team_view_form_inherited">
|
||||
<field name="name">maintenance.team.form.inherited</field>
|
||||
<field name="model">maintenance.team</field>
|
||||
<field name="inherit_id" ref="maintenance.maintenance_team_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='member_ids']" position="after">
|
||||
<field name="repair_location_id"/>
|
||||
<field name="repair_location_dest_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_equipment_request_view_form_inherited">
|
||||
<field name="name">equipment.request.form.inherited</field>
|
||||
<field name="model">maintenance.request</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_request_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//button[@name='archive_equipment_request']" position="before">
|
||||
<field name="repair_status" invisible="1"/>
|
||||
<button type="object" name="action_complete_repair" string="Complete Repair" class="oe_highlight"
|
||||
attrs="{'invisible': [('repair_status', '!=', 'to repair')]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_equipment_request_view_form_notebook_inherited">
|
||||
<field name="name">equipment.request.form.notebook.inherited</field>
|
||||
<field name="model">maintenance.request</field>
|
||||
<field name="inherit_id" ref="maintenance_notebook.hr_equipment_request_view_form_notebook"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Parts">
|
||||
<group>
|
||||
<group>
|
||||
<field name="repair_location_id"/>
|
||||
<field name="repair_status" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="repair_location_dest_id"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<field name="repair_line_ids">
|
||||
<tree editable="bottom" string="Part Operations" colors="blue:state=='draft'">
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="product_id" domain="[('type', 'in', ['product', 'consu'])]"/>
|
||||
<field name="product_uom_id"/>
|
||||
<field name="product_uom_qty"/>
|
||||
<field name="lst_price"/>
|
||||
<field name="standard_price" groups="account.group_account_user"/>
|
||||
<field name="cost" groups="account.group_account_user"/>
|
||||
<button type="object" name="action_complete" string="Complete" class="oe_highlight"
|
||||
attrs="{'invisible': [('state', '=', 'done')]}"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
<group>
|
||||
<group class="oe_subtotal_footer oe_right" name="repair_totals">
|
||||
<field name="total_lst_price" />
|
||||
<field name="total_standard_price" groups="account.group_account_user"/>
|
||||
<field name="total_cost" groups="account.group_account_user"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_equipment_request_view_search_inherited">
|
||||
<field name="name">equipment.request.search.inherited</field>
|
||||
<field name="model">maintenance.request</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_request_view_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//filter[@name='top_priority']" position="after">
|
||||
<filter string="To Repair" name="to_repair" domain="[('repair_status', '=', 'to repair')]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
1
maintenance_timesheet/__init__.py
Normal file
1
maintenance_timesheet/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
24
maintenance_timesheet/__manifest__.py
Normal file
24
maintenance_timesheet/__manifest__.py
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
'name': 'Equipment Timesheets',
|
||||
'version': '11.0.1.0.0',
|
||||
'author': 'Hibou Corp. <hello@hibou.io>',
|
||||
'category': 'Human Resources',
|
||||
'summary': 'Record time on maintenance requests.',
|
||||
'description': """
|
||||
Equipment Timesheets
|
||||
====================
|
||||
|
||||
Adds Timesheets to Maintenance Requests to record time and labor costs.
|
||||
""",
|
||||
'website': 'https://hibou.io/',
|
||||
'depends': [
|
||||
'maintenance_notebook',
|
||||
'hr_department_project',
|
||||
'hr_timesheet',
|
||||
],
|
||||
'data': [
|
||||
'views/maintenance_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
1
maintenance_timesheet/models/__init__.py
Normal file
1
maintenance_timesheet/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import maintenance
|
||||
55
maintenance_timesheet/models/maintenance.py
Normal file
55
maintenance_timesheet/models/maintenance.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AnalyticLine(models.Model):
|
||||
_inherit = 'account.analytic.line'
|
||||
|
||||
maintenance_request_id = fields.Many2one('maintenance.request')
|
||||
|
||||
|
||||
class MaintenanceEquipment(models.Model):
|
||||
_inherit = 'maintenance.equipment'
|
||||
|
||||
def action_open_maintenance_requests(self):
|
||||
self.ensure_one()
|
||||
action = self.env.ref('maintenance.hr_equipment_request_action_from_equipment').read()[0]
|
||||
action['domain'] = [('equipment_id', '=', self.id)]
|
||||
action['context'] = {
|
||||
'default_equipment_id': self.id,
|
||||
'default_employee_id': self.employee_id.id,
|
||||
'default_department_id': self.department_id.id,
|
||||
}
|
||||
return action
|
||||
|
||||
|
||||
class MaintenanceRequest(models.Model):
|
||||
_inherit = 'maintenance.request'
|
||||
|
||||
project_id = fields.Many2one('project.project', string='Billing Project')
|
||||
timesheet_ids = fields.One2many('account.analytic.line', 'maintenance_request_id', 'Timesheets')
|
||||
effective_hours = fields.Float(compute='_hours_get', store=True, string='Hours Spent',
|
||||
help="Computed using the sum of the maintenance work done.")
|
||||
remaining_hours = fields.Float(compute='_hours_get', store=True, string='Remaining Hours',
|
||||
help="Total remaining time.")
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
if not values.get('project_id') and values.get('department_id'):
|
||||
department = self.env['hr.department'].browse(values.get('department_id'))
|
||||
if department and department.project_ids:
|
||||
values.update({'project_id': department.project_ids.ids[0]})
|
||||
return super(MaintenanceRequest, self).create(values)
|
||||
|
||||
@api.depends('duration', 'timesheet_ids.unit_amount')
|
||||
def _hours_get(self):
|
||||
for request in self:
|
||||
effective_hours = sum(request.sudo().timesheet_ids.mapped('unit_amount'))
|
||||
request.effective_hours = effective_hours
|
||||
request.remaining_hours = (request.duration or 0.0) - effective_hours
|
||||
|
||||
@api.onchange('department_id')
|
||||
def _onchange_department_id_project(self):
|
||||
for request in self:
|
||||
if request.department_id and request.department_id.project_ids:
|
||||
request.project_id = request.department_id.project_ids[0]
|
||||
|
||||
67
maintenance_timesheet/views/maintenance_views.xml
Normal file
67
maintenance_timesheet/views/maintenance_views.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="hr_equipment_view_form_inherited">
|
||||
<field name="name">equipment.form.inherited</field>
|
||||
<field name="model">maintenance.equipment</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='button_box']/button[1]" position="replace">
|
||||
<button name="action_open_maintenance_requests" type="object" class="oe_stat_button" icon="fa-ticket">
|
||||
<field string="Maintenance" name="maintenance_count" widget="statinfo"/>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="maintenance_request_view_form_inherit_hr_inherited">
|
||||
<field name="name">maintenance.request.view.form.inherit.hr.inherited</field>
|
||||
<field name="model">maintenance.request</field>
|
||||
<field name="inherit_id" ref="hr_maintenance.maintenance_request_view_form_inherit_hr"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='employee_id']" position="after">
|
||||
<field name="department_id"/>
|
||||
<field name="project_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_equipment_request_view_form_notebook_inherited">
|
||||
<field name="name">equipment.request.form.notebook.inherited</field>
|
||||
<field name="model">maintenance.request</field>
|
||||
<field name="inherit_id" ref="maintenance_notebook.hr_equipment_request_view_form_notebook"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Timesheets" attrs="{'invisible': [('project_id', '=', False)]}">
|
||||
<field name="timesheet_ids" context="{'default_project_id': project_id}">
|
||||
<tree editable="bottom" string="Timesheet Activities" default_order="date">
|
||||
<field name="date"/>
|
||||
<field name="user_id" invisible="1"/>
|
||||
<field name="employee_id" required="1"/>
|
||||
<field name="name"/>
|
||||
<field name="unit_amount" string="Duration" widget="float_time"/>
|
||||
<field name="project_id" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
<group>
|
||||
<group class="oe_subtotal_footer oe_right" name="project_hours">
|
||||
<field name="effective_hours" widget="float_time" readonly="1"/>
|
||||
<field name="remaining_hours" widget="float_time" class="oe_subtotal_footer_separator"
|
||||
readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_equipment_request_view_tree_inherited">
|
||||
<field name="name">equipment.request.tree.inherited</field>
|
||||
<field name="model">maintenance.request</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_request_view_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='stage_id']" position="after">
|
||||
<field name="effective_hours"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
1
maintenance_usage/__init__.py
Normal file
1
maintenance_usage/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
26
maintenance_usage/__manifest__.py
Normal file
26
maintenance_usage/__manifest__.py
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
'name': 'Equipment Usage',
|
||||
'version': '11.0.1.0.0',
|
||||
'author': 'Hibou Corp. <hello@hibou.io>',
|
||||
'category': 'Human Resources',
|
||||
'summary': 'Keep track of usage on different types of equipment.',
|
||||
'description': """
|
||||
Equipment Usage
|
||||
===============
|
||||
|
||||
Keep track of usage on different types of equipment. Adds fields for usage on equipments
|
||||
and descriptive UOM on categories.
|
||||
|
||||
Create preventative maintenance requests based on usage.
|
||||
""",
|
||||
'website': 'https://hibou.io/',
|
||||
'depends': [
|
||||
'hr_maintenance',
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'views/maintenance_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
1
maintenance_usage/models/__init__.py
Normal file
1
maintenance_usage/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import maintenance
|
||||
113
maintenance_usage/models/maintenance.py
Normal file
113
maintenance_usage/models/maintenance.py
Normal file
@@ -0,0 +1,113 @@
|
||||
from math import floor
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class MaintenanceEquipmentCategory(models.Model):
|
||||
_inherit = 'maintenance.equipment.category'
|
||||
|
||||
usage_uom_id = fields.Many2one('product.uom', string='Usage UOM')
|
||||
|
||||
|
||||
class MaintenanceEquipment(models.Model):
|
||||
_inherit = 'maintenance.equipment'
|
||||
|
||||
employee_id = fields.Many2one(track_visibility=False)
|
||||
department_id = fields.Many2one(track_visibility=False)
|
||||
usage_qty = fields.Float(string='Usage', default=0.0)
|
||||
usage_uom_id = fields.Many2one('product.uom', related='category_id.usage_uom_id')
|
||||
usage_log_ids = fields.One2many('maintenance.usage.log', 'equipment_id', string='Usage')
|
||||
usage_count = fields.Integer(string='Usage Count', compute='_compute_usage_count')
|
||||
maintenance_usage = fields.Float(string='Preventative Usage')
|
||||
|
||||
def _compute_usage_count(self):
|
||||
for equipment in self:
|
||||
equipment.usage_count = len(equipment.usage_log_ids)
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
record = super(MaintenanceEquipment, self).create(values)
|
||||
# create first usage record
|
||||
record._log_usage()
|
||||
return record
|
||||
|
||||
@api.multi
|
||||
def write(self, values):
|
||||
usage_qty = values.get('usage_qty')
|
||||
employee_id = values.get('employee_id')
|
||||
department_id = values.get('department_id')
|
||||
if any((usage_qty, employee_id, department_id)):
|
||||
for equipment in self:
|
||||
log_values = {}
|
||||
|
||||
if (equipment.usage_qty is not None
|
||||
and usage_qty is not None
|
||||
and abs(usage_qty - equipment.usage_qty) > 0.0001):
|
||||
log_values['qty'] = usage_qty
|
||||
if employee_id != equipment.employee_id.id:
|
||||
log_values['employee_id'] = employee_id
|
||||
if department_id != equipment.department_id.id:
|
||||
log_values['department_id'] = department_id
|
||||
|
||||
if log_values:
|
||||
equipment._log_usage(values=log_values)
|
||||
|
||||
# Check to have the original fields before write.
|
||||
self._check_maintenance_usage(usage_qty)
|
||||
|
||||
result = super(MaintenanceEquipment, self).write(values)
|
||||
return result
|
||||
|
||||
def _log_usage(self, values={}):
|
||||
values['equipment_id'] = self.id
|
||||
values['date'] = fields.Datetime.now()
|
||||
self.env['maintenance.usage.log'].create(values)
|
||||
|
||||
@api.multi
|
||||
def _check_maintenance_usage(self, usage_qty):
|
||||
for e in self.filtered(lambda e: e.maintenance_usage):
|
||||
try:
|
||||
if floor(e.usage_qty / e.maintenance_usage) != floor(usage_qty / e.maintenance_usage):
|
||||
next_requests = self.env['maintenance.request'].search([('stage_id.done', '=', False),
|
||||
('equipment_id', '=', e.id),
|
||||
('maintenance_type', '=', 'preventive'),
|
||||
])
|
||||
if not next_requests:
|
||||
e._create_new_request(fields.Date.today())
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
def action_open_usage_log(self):
|
||||
for equipment in self:
|
||||
action = self.env.ref('maintenance_usage.maintenance_usage_log_action_reports').read()[0]
|
||||
action['domain'] = [('equipment_id', '=', equipment.id)]
|
||||
action['context'] = {
|
||||
'default_equipment_id': equipment.id,
|
||||
'default_employee_id': equipment.employee_id.id,
|
||||
'default_department_id': equipment.department_id.id,
|
||||
'default_qty': equipment.usage_qty,
|
||||
}
|
||||
return action
|
||||
|
||||
|
||||
class MaintenanceUsageLog(models.Model):
|
||||
_name = 'maintenance.usage.log'
|
||||
_order = 'date DESC'
|
||||
_log_access = False
|
||||
|
||||
date = fields.Datetime(string='Date', default=fields.Datetime.now)
|
||||
equipment_id = fields.Many2one('maintenance.equipment', string='Equipment', required=True)
|
||||
employee_id = fields.Many2one('hr.employee', string='Employee')
|
||||
department_id = fields.Many2one('hr.department', string='Department')
|
||||
qty = fields.Float(string='Quantity')
|
||||
uom_id = fields.Many2one(string='Unit of Measure', related='equipment_id.category_id.usage_uom_id')
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
equipment = self.env['maintenance.equipment'].browse(values.get('equipment_id'))
|
||||
if not values.get('employee_id'):
|
||||
values['employee_id'] = equipment.employee_id.id
|
||||
if not values.get('department_id'):
|
||||
values['department_id'] = equipment.department_id.id
|
||||
if not values.get('qty'):
|
||||
values['qty'] = equipment.usage_qty
|
||||
return super(MaintenanceUsageLog, self).create(values)
|
||||
3
maintenance_usage/security/ir.model.access.csv
Normal file
3
maintenance_usage/security/ir.model.access.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"manage_maintenance_usage_log","manage maintenance.usage.log","model_maintenance_usage_log","stock.group_stock_manager",1,1,1,1
|
||||
"access_maintenance_usage_log","access maintenance.usage.log","model_maintenance_usage_log","base.group_user",1,0,1,0
|
||||
|
1
maintenance_usage/tests/__init__.py
Normal file
1
maintenance_usage/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import test_maintenance_usage
|
||||
43
maintenance_usage/tests/test_maintenance_usage.py
Normal file
43
maintenance_usage/tests/test_maintenance_usage.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
class TestMaintenanceUsage(common.TransactionCase):
|
||||
"""Tests for usage on creation and update
|
||||
"""
|
||||
|
||||
def test_create(self):
|
||||
test_usage = 21.0
|
||||
equipment = self.env['maintenance.equipment'].create({
|
||||
'name': 'Monitor',
|
||||
'usage_qty': test_usage,
|
||||
})
|
||||
|
||||
self.assertTrue(equipment.usage_log_ids)
|
||||
self.assertEqual(equipment.usage_log_ids[0].qty, test_usage)
|
||||
|
||||
def test_update(self):
|
||||
test_usage = 21.0
|
||||
test_usage2 = 50.1
|
||||
equipment = self.env['maintenance.equipment'].create({
|
||||
'name': 'Monitor',
|
||||
'usage_qty': test_usage,
|
||||
})
|
||||
equipment.usage_qty = test_usage2
|
||||
updated_usage = equipment.usage_log_ids.filtered(lambda u: abs(u.qty - test_usage2) < 0.01)
|
||||
|
||||
self.assertTrue(updated_usage)
|
||||
self.assertAlmostEqual(updated_usage[0].qty, test_usage2)
|
||||
|
||||
def test_maintenance_usage(self):
|
||||
test_usage = 21.0
|
||||
test_usage2 = 50.1
|
||||
equipment = self.env['maintenance.equipment'].create({
|
||||
'name': 'Monitor',
|
||||
'usage_qty': test_usage,
|
||||
'maintenance_usage': 20.0,
|
||||
'maintenance_team_id': self.env['maintenance.team'].search([], limit=1).id
|
||||
})
|
||||
self.assertFalse(equipment.maintenance_ids)
|
||||
|
||||
equipment.usage_qty = test_usage2
|
||||
self.assertTrue(equipment.maintenance_ids)
|
||||
157
maintenance_usage/views/maintenance_views.xml
Normal file
157
maintenance_usage/views/maintenance_views.xml
Normal file
@@ -0,0 +1,157 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="hr_equipment_category_view_form_inherited">
|
||||
<field name="name">maintenance.equipment.category.inherited</field>
|
||||
<field name="model">maintenance.equipment.category</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_category_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='note']" position="before">
|
||||
<group>
|
||||
<field name="usage_uom_id"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_equipment_view_form_inherited">
|
||||
<field name="name">equipment.form.inherited</field>
|
||||
<field name="model">maintenance.equipment</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="action_open_usage_log"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-tachometer"
|
||||
help="show the usage logs for equipment" >
|
||||
<field string="Usage" name="usage_count" widget="statinfo"/>
|
||||
</button>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='note']" position="before">
|
||||
<group>
|
||||
<group name="usage_info" string="Usage">
|
||||
<label for="usage_qty"/>
|
||||
<div class="o_row" name="usage">
|
||||
<field name="usage_qty" nolabel="1"/>
|
||||
<field name="usage_uom_id" nolabel="1" readonly="1"/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
</xpath>
|
||||
<xpath expr="//group[@name='maintenance']" position="inside">
|
||||
<field name="maintenance_usage"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- maintenance.usage.log : views -->
|
||||
<record id="hr_equipment_usage_log_view_search" model="ir.ui.view">
|
||||
<field name="name">equipment.usage.log.search</field>
|
||||
<field name="model">maintenance.usage.log</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Equipment Usage Search">
|
||||
<field name="equipment_id"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<separator/>
|
||||
<group expand='0' string='Group by...'>
|
||||
<filter string='Equipment' domain="[]" context="{'group_by': 'equipment_id'}"/>
|
||||
<filter string='Employee' domain="[]" context="{'group_by': 'employee_id'}"/>
|
||||
<filter string='Department' domain="[]" context="{'group_by': 'department_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_equipment_usage_log_view_form" model="ir.ui.view">
|
||||
<field name="name">equipment.usage.log.form</field>
|
||||
<field name="model">maintenance.usage.log</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Equipment Usage Form">
|
||||
<header/>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="date"/>
|
||||
<field name="equipment_id"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
</group>
|
||||
<group name="usage_info" string="Usage">
|
||||
<label for="qty"/>
|
||||
<div class="o_row" name="usage">
|
||||
<field name="qty" nolabel="1"/>
|
||||
<field name="uom_id" nolabel="1" readonly="1"/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_equipment_usage_log_view_tree" model="ir.ui.view">
|
||||
<field name="name">equipment.usage.log.tree</field>
|
||||
<field name="model">maintenance.usage.log</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Equipment Usage">
|
||||
<field name="date"/>
|
||||
<field name="equipment_id"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="qty"/>
|
||||
<field name="uom_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_equipment_usage_log_view_graph" model="ir.ui.view">
|
||||
<field name="name">equipment.usage.log.graph</field>
|
||||
<field name="model">maintenance.usage.log</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Equipment Usage">
|
||||
<field name="equipment_id"/>
|
||||
<field name="qty"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_equipment_usage_log_view_pivot" model="ir.ui.view">
|
||||
<field name="name">equipment.usage.log.pivot</field>
|
||||
<field name="model">maintenance.usage.log</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Equipment Usage">
|
||||
<field name="equipment_id"/>
|
||||
<field name="qty"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_equipment_usage_log_view_calendar" model="ir.ui.view">
|
||||
<field name="name">equipment.usage.log.calendar</field>
|
||||
<field name="model">maintenance.usage.log</field>
|
||||
<field name="arch" type="xml">
|
||||
<calendar date_start="date" color="equipment_id">
|
||||
<field name="equipment_id"/>
|
||||
<field name="qty"/>
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- maintenance.usage.log : actions -->
|
||||
<record id="maintenance_usage_log_action_reports" model="ir.actions.act_window">
|
||||
<field name="name">Equipment Usage</field>
|
||||
<field name="res_model">maintenance.usage.log</field>
|
||||
<field name="view_mode">tree,form,graph,pivot,calendar</field>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
No usage.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="maintenance_usage_reporting"
|
||||
action="maintenance_usage_log_action_reports"
|
||||
parent="maintenance.maintenance_reporting"/>
|
||||
</odoo>
|
||||
1
stock_analytic
Symbolic link
1
stock_analytic
Symbolic link
@@ -0,0 +1 @@
|
||||
external/hibou-oca/account-analytic/stock_analytic
|
||||
Reference in New Issue
Block a user