diff --git a/LICENSE b/LICENSE index 7e5dad22c284347a94943bae488585d0f873592e..33aa54e42256094f481eb4f0de5dfb73e4b50bb5 100644 --- a/LICENSE +++ b/LICENSE @@ -201,30 +201,3 @@ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY C If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. -Also add information on how to contact you by electronic and paper mail. - -If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. - -You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <https://www.gnu.org/licenses/>. \ No newline at end of file diff --git a/README.rst b/README.rst index 4b6fe88cae463238d29c542a7579e48d3fcf07f0..f1e1522c5155409b61187a476decd957e49cde08 100644 --- a/README.rst +++ b/README.rst @@ -3,9 +3,9 @@ :alt: License: AGPL-3 -================= +================================ Le Filament Link Sale to Project -================= +================================ This module provides a new functionality to transform your sale order in projects and tasks (and to update those in case sale order is updated) @@ -15,7 +15,7 @@ This module depends upon *sale_service* and *lefilament_projets* modules. Configuration -===== +============= 1. In *Sales > Products* when creating a product of Service type, in *Invoicing > Invoicing policy* you can now use an extra *track service* named 'Create a project and link tasks'. @@ -69,8 +69,8 @@ Contributors Maintainer ------------ -.. image:: https://le-filament.com/images/logo-lefilament.png +.. image:: https://le-filament.com/img/logo-lefilament.png :alt: Le Filament :target: https://le-filament.com -This module is maintained by Le Filament \ No newline at end of file +This module is maintained by Le Filament diff --git a/__init__.py b/__init__.py index eb6cc70758afc3954ae75ff55a99aa10415dffa2..55f67ffe1480146c675bbe892c1aa4f3c01dc86f 100644 --- a/__init__.py +++ b/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -import models -import wizard \ No newline at end of file +from . import models +from . import wizard diff --git a/__manifest__.py b/__manifest__.py index e3c373ba961a79929768cd06e6393542d23cee17..55d8491878866520649857046ffc8629ae14f5bd 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -1,31 +1,36 @@ +# -*- coding: utf-8 -*- +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { - 'name': 'Le Filament - Link Sales Order to Project', - 'version': '10.0.1.0', - 'license': 'AGPL-3', - 'description': """ - MODULE LINK SALE ORDER / PROJECT LE FILAMENT + 'name': 'Le Filament - Link Sales Order to Project', + 'version': '10.0.1.0.0', + 'license': 'AGPL-3', + 'description': """ + MODULE LINK SALE ORDER / PROJECT LE FILAMENT - This module depends upon *sale_service* and *lefilament_projets* modules. + This module depends upon *sale_service* and *lefilament_projets* modules. - - This module provides a new functionality to transform your sale order in projects and tasks (and to update those in case sale order is updated) - - Product template has been enhanced, invoicing policy section in order to set how each product should behave when transformed from sale order to project/task. - """, - 'author': 'LE FILAMENT', - 'category': 'LE FILAMENT', - 'depends': ['sale_timesheet', 'lefilament_projets'], - 'contributors': [ + - This module provides a new functionality to transform your sale order in + projects and tasks (and to update those in case sale order is updated) + - Product template has been enhanced, invoicing policy section in order to + set how each product should behave when transformed from sale order to + project/task. + """, + 'author': 'LE FILAMENT', + 'category': 'LE FILAMENT', + 'depends': ['sale_timesheet', 'lefilament_projets'], + 'contributors': [ 'Juliana Poudou <juliana@le-filament.com>', ], - 'website': 'http://www.le-filament.com', - 'data': [ - 'views/product_views.xml', - 'views/sale_config_settings_views.xml', - 'wizard/sale_views_wizard.xml', - 'views/sale_views.xml', - 'views/res_config_views.xml', - 'views/project_views.xml', - 'views/project_task_views.xml', - ], - 'qweb': [ + 'website': 'http://www.le-filament.com', + 'data': [ + 'views/product_views.xml', + 'views/sale_config_settings_views.xml', + 'wizard/sale_views_wizard.xml', + 'views/sale_views.xml', + 'views/res_config_views.xml', + 'views/project_views.xml', + 'views/project_task_views.xml', + ], + 'qweb': [ ], } diff --git a/models/__init__.py b/models/__init__.py index 6c5713ee1fca38f6180bea4ac8f1547f1eca38cd..b98ff0d95189d8b2b71a54ac21d375da3cf7b35c 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -import product -import sale_config_settings -import res_config -import project_task_type -import project -import project_task -import sale_order \ No newline at end of file +from . import product +from . import sale_config_settings +from . import res_config +from . import project_task_type +from . import project +from . import project_task +from . import sale_order \ No newline at end of file diff --git a/models/product.py b/models/product.py index 31cfb4be7ff04d355a1761a81c2c4b4456eef0fa..8e39c66c6f60f36a1157654238cea886ef4b6036 100644 --- a/models/product.py +++ b/models/product.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- -# © 2017 Le Filament (<http://www.le-filament.com>) +# © 2017 Le Filament (<https://le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import api, fields, models +from odoo import fields, models + class LeFilamentProductTemplate(models.Model): _inherit = 'product.template' @@ -11,4 +12,4 @@ class LeFilamentProductTemplate(models.Model): project_task_type_id = fields.Many2one( 'project.task.type', 'Project task stage') track_service = fields.Selection(selection_add=[ - ('project', 'Create a project and link tasks')]) \ No newline at end of file + ('project', 'Create a project and link tasks')]) diff --git a/models/project.py b/models/project.py index c76d8fe731a088a2c21c50b8ed92c406e371e1a9..d376bfec6410a097c6e73a4d0d5ce8db3365baf6 100644 --- a/models/project.py +++ b/models/project.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- -# © 2017 Le Filament (<http://www.le-filament.com>) + +# © 2017 Le Filament (<https://le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import models, fields diff --git a/models/project_task.py b/models/project_task.py index 565ae6c116a95b27823f43ad4e379bc798a69ae6..9965638914d37ace88192385083f88d35c5759bc 100644 --- a/models/project_task.py +++ b/models/project_task.py @@ -1,13 +1,20 @@ # -*- coding: utf-8 -*- -# © 2017 Le Filament (<http://www.le-filament.com>) + +# © 2017 Le Filament (<https://le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import models, fields -from odoo.tools import float_is_zero, float_compare, DEFAULT_SERVER_DATETIME_FORMAT -import odoo.addons.decimal_precision as dp + class LeFilamentProjectTask(models.Model): _inherit = 'project.task' - price_subtotal = fields.Monetary(string='Subtotal initial', readonly=True, store='True') - currency_id = fields.Many2one(related='sale_line_id.currency_id', store=True, string='Currency', readonly=True) \ No newline at end of file + price_subtotal = fields.Monetary( + string='Subtotal initial', readonly=True, store='True' + ) + currency_id = fields.Many2one( + related='sale_line_id.currency_id', + store=True, + string='Currency', + readonly=True + ) diff --git a/models/project_task_type.py b/models/project_task_type.py index d1f8e8fd7ac5e2a66cf08a06bfbb53c53a830ee3..207d91a03d043605dadea945aa72a14fc0216171 100644 --- a/models/project_task_type.py +++ b/models/project_task_type.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- -# © 2017 Le Filament (<http://www.le-filament.com>) + +# © 2017 Le Filament (<https://le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import models, fields diff --git a/models/res_config.py b/models/res_config.py index ee44d99af32f56504512e0e958c2e8063b59b423..7b1bc4de0965400c50127f57f091a173869a4809 100644 --- a/models/res_config.py +++ b/models/res_config.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- -# © 2017 Le Filament (<http://www.le-filament.com>) +# © 2017 Le Filament (<https://le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import api, fields, models + class ProjectLFConfiguration(models.TransientModel): _name = 'project.config.settings' _inherit = 'project.config.settings' @@ -16,7 +17,9 @@ class ProjectLFConfiguration(models.TransientModel): def set_default_generate_project_alias(self): Values = self.env['ir.values'].sudo() or self.env['ir.values'] for config in self: - Values.set_default('project.config.settings', 'generate_project_alias', config.generate_project_alias) + Values.set_default('project.config.settings', + 'generate_project_alias', + config.generate_project_alias) @api.multi def set_default_lf_tarif_jour(self): @@ -26,4 +29,7 @@ class ProjectLFConfiguration(models.TransientModel): @api.multi def set_default_alias_prefix(self): return self.env['ir.values'].sudo().set_default( - 'project.config.settings', 'lf_alias_prefix', self.lf_alias_prefix) \ No newline at end of file + 'project.config.settings', + 'lf_alias_prefix', + self.lf_alias_prefix + ) diff --git a/models/sale_config_settings.py b/models/sale_config_settings.py index b1c4d1798ecb27f597738f66295712889eba227f..f41b27f9231c20a8ee357346d3f1a41637003811 100644 --- a/models/sale_config_settings.py +++ b/models/sale_config_settings.py @@ -1,14 +1,10 @@ # -*- coding: utf-8 -*- -# © 2017 Le Filament (<http://www.le-filament.com>) +# © 2017 Le Filament (<https://le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -import logging - from odoo import api, fields, models -_logger = logging.getLogger(__name__) - class LeFilamentSaleConfiguration(models.TransientModel): _inherit = 'sale.config.settings' @@ -19,4 +15,7 @@ class LeFilamentSaleConfiguration(models.TransientModel): @api.multi def set_project_task_type(self): return self.env['ir.values'].sudo().set_default( - 'sale.config.settings', 'project_task_type_id', self.project_task_type_id.id) \ No newline at end of file + 'sale.config.settings', + 'project_task_type_id', + self.project_task_type_id.id + ) diff --git a/models/sale_order.py b/models/sale_order.py index 764fa676c21406b51d126e62620e1db83a4955e5..a0fbc69e5ebc143d7e14b00565e80532922e71e3 100644 --- a/models/sale_order.py +++ b/models/sale_order.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- -# © 2017 Le Filament (<http://www.le-filament.com>) + +# © 2017 Le Filament (<https://le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import api, fields, models, _ from datetime import datetime +from odoo import api, models from dateutil.relativedelta import relativedelta -from odoo.exceptions import ValidationError class SaleOrder(models.Model): @@ -14,28 +14,39 @@ class SaleOrder(models.Model): @api.multi def lefilament_update_tasks(self): for order in self: - stage_id_new = self.env['ir.values'].get_default('sale.config.settings', 'project_task_type_id') + stage_id_new = self.env['ir.values'].get_default( + 'sale.config.settings', 'project_task_type_id') stage_new = self.env['project.task.type'].browse(stage_id_new) - lf_tarif_jour = self.env['ir.values'].get_default('project.config.settings', 'lf_tarif_jour') - lf_heures_jour = self.env['ir.values'].get_default('project.config.settings', 'lf_heures_jour') + lf_tarif_jour = self.env['ir.values'].get_default( + 'project.config.settings', 'lf_tarif_jour') + lf_heures_jour = self.env['ir.values'].get_default( + 'project.config.settings', 'lf_heures_jour') sale_project_id = order.project_project_id - sale_task_ids = order.tasks_ids project_id = sale_project_id.id project_total_budget = 0 for line in order.order_line: - task_id_refer = self.env['project.task'].search([('sale_line_id', '=', line.id)]) + task_id_refer = self.env['project.task'].search( + [('sale_line_id', '=', line.id)]) if task_id_refer: if not line.product_id.project_id: - project_total_budget = project_total_budget + line.price_subtotal - planned_hours = (line.price_subtotal / lf_tarif_jour) * lf_heures_jour + project_total_budget = (project_total_budget + + line.price_subtotal) + planned_hours = ((line.price_subtotal / lf_tarif_jour) + * lf_heures_jour) task_id_refer.planned_hours = planned_hours else: if line.price_subtotal != task_id_refer.price_subtotal: project = line.product_id.project_id project_id_maint = project.id - project_update = self.env['project.project'].browse(project_id_maint) - project_update.lf_total_budget = ( project_update.lf_total_budget - task_id_refer.price_subtotal ) + line.price_subtotal - planned_hours = (line.price_subtotal / lf_tarif_jour) * lf_heures_jour + project_update = self.env[ + 'project.project'].browse(project_id_maint) + project_update.lf_total_budget = ( + (project_update.lf_total_budget + - task_id_refer.price_subtotal) + + line.price_subtotal) + planned_hours = ( + (line.price_subtotal / lf_tarif_jour) + * lf_heures_jour) task_id_refer.planned_hours = planned_hours task_id_refer.price_subtotal = line.price_subtotal else: @@ -43,32 +54,42 @@ class SaleOrder(models.Model): if line.product_id.project_id: project = line.product_id.project_id project_id = project.id - date_plan = datetime.strptime(order.confirmation_date,'%Y-%m-%d %H:%M:%S') - date_deadline = (date_plan.date() + relativedelta(years=int(line.product_uom_qty))).strftime('%Y-%m-%d') + date_plan = datetime.strptime( + order.confirmation_date, '%Y-%m-%d %H:%M:%S') + date_deadline = ( + date_plan.date() + + relativedelta( + years=int(line.product_uom_qty))).strftime( + '%Y-%m-%d') stage = line.product_id.project_task_type_id - if order.partner_id.is_company == True: - name_task = order.partner_id.name + " - " + stage.name + if order.partner_id.is_company is True: + name_task = (order.partner_id.name + " - " + + stage.name) else: - name_task = order.partner_id.parent_id.name + " - " + stage.name + name_task = (order.partner_id.parent_id.name + + " - " + stage.name) else: stage = stage_new project_id = sale_project_id.id date_deadline = False name_task = line.name.split('\n', 1)[0] - project_total_budget = project_total_budget + line.price_subtotal - planned_hours = (line.price_subtotal / lf_tarif_jour) * lf_heures_jour + project_total_budget = (project_total_budget + + line.price_subtotal) + planned_hours = ((line.price_subtotal / lf_tarif_jour) + * lf_heures_jour) description_line = "<p>" for line_name in line.name: if line_name == '\n': description_line = description_line + "</p><p>" else: description_line = description_line + line_name - task = self.env['project.task'].create({ + self.env['project.task'].create({ 'name': name_task, 'date_deadline': date_deadline, 'planned_hours': planned_hours, 'remaining_hours': planned_hours, - 'partner_id': order.partner_id.id or self.partner_dest_id.id, + 'partner_id': (order.partner_id.id + or self.partner_dest_id.id), 'user_id': self.env.uid, # 'procurement_id': line.procurement_ids.id, 'description': description_line + '</p><br/>', @@ -80,9 +101,11 @@ class SaleOrder(models.Model): project_date = self.env['project.project'].browse(project_id) project_date.lf_tarif_jour = lf_tarif_jour project_date.lf_total_budget = project_total_budget - order.tasks_ids = self.env['project.task'].search([('sale_line_id', 'in', order.order_line.ids)]) + order.tasks_ids = self.env['project.task'].search( + [('sale_line_id', 'in', order.order_line.ids)]) order.tasks_count = len(order.tasks_ids) + class LeFilamentSaleOrderLine(models.Model): _inherit = "sale.order.line" @@ -90,8 +113,18 @@ class LeFilamentSaleOrderLine(models.Model): def _compute_analytic(self, domain=None): if not domain and self.ids: # To filter on analyic lines linked to an expense - expense_type_id = self.env.ref('account.data_account_type_expenses', raise_if_not_found=False) + expense_type_id = self.env.ref( + 'account.data_account_type_expenses', + raise_if_not_found=False + ) expense_type_id = expense_type_id and expense_type_id.id - prod_list = self.env['product.template'].search([('track_service','in', ['task','timesheet'])]) - domain = [('product_id', 'in', prod_list.ids), ('so_line', 'in', self.ids), '|', ('amount', '<=', 0.0), ('project_id', '!=', False)] - return super(LeFilamentSaleOrderLine, self)._compute_analytic(domain=domain) \ No newline at end of file + prod_list = self.env['product.template'].search( + [('track_service', 'in', ['task', 'timesheet'])] + ) + domain = [ + ('product_id', 'in', prod_list.ids), + ('so_line', 'in', self.ids), + '|', ('amount', '<=', 0.0), ('project_id', '!=', False) + ] + return super(LeFilamentSaleOrderLine, self)._compute_analytic( + domain=domain) diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv deleted file mode 100644 index 77ff07c253745bc6ebb4f172d819f8695b936afe..0000000000000000000000000000000000000000 --- a/security/ir.model.access.csv +++ /dev/null @@ -1,2 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_project_config_settings_group_user,project.config.settings,model_project_config_settings,base.group_user,1,1,1,1 \ No newline at end of file diff --git a/views/product_views.xml b/views/product_views.xml index 4443b8ed1226f752d20804d3d825853b46a5416f..0e936eb110b08372ec1f75838eb95677affaeb59 100644 --- a/views/product_views.xml +++ b/views/product_views.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2017 Le Filament (<https://le-filament.com>) + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> <odoo> <record id="lefilament_view_product_timesheet_form" model="ir.ui.view"> <field name="name">lefilament.product.template.timesheet.form</field> @@ -13,4 +15,4 @@ </field> </field> </record> -</odoo> \ No newline at end of file +</odoo> diff --git a/views/project_task_views.xml b/views/project_task_views.xml index 73c5518387167fbf296dce201e25e9f0bd51dc7f..f9e1023868202053aeec7f6202f16b872d018404 100644 --- a/views/project_task_views.xml +++ b/views/project_task_views.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2017 Le Filament (<https://le-filament.com>) + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> <odoo> <record id="lefilament_view_sale_service_inherit_form2" model="ir.ui.view"> <field name="name">lefilament.sale.service.form.view.inherit</field> diff --git a/views/project_views.xml b/views/project_views.xml index 771eb9f6f28f7c0923745e307675623dd01d8bfb..c28863c704ec0a639189ea683293dd0f35e3973c 100644 --- a/views/project_views.xml +++ b/views/project_views.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2017 Le Filament (<https://le-filament.com>) + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> <odoo> - <record id="lefilament_task_type_edit" model="ir.ui.view"> <field name="name">lefilament.task.type.form</field> <field name="model">project.task.type</field> @@ -37,5 +38,4 @@ </xpath> </field> </record> - </odoo> diff --git a/views/res_config_views.xml b/views/res_config_views.xml index d808fb50a49d36b7f064e44a0c66c94228485e7b..6c33c6f545ab2a808b2cb866a90843f5cd163a96 100644 --- a/views/res_config_views.xml +++ b/views/res_config_views.xml @@ -1,14 +1,16 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2017 Le Filament (<https://le-filament.com>) + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> <odoo> - <record id="view_lefilament_project_config_settings" model="ir.ui.view"> + <record id="view_lefilament_project_config_settings" model="ir.ui.view"> <field name="name">project.lefilament.settings</field> <field name="model">project.config.settings</field> <field name="inherit_id" ref="project.view_config_settings"/> <field name="arch" type="xml"> <xpath expr="//field[@name='module_rating_project']" position="after"> <field name="lf_tarif_jour" class="oe_inline oe_text_right" /> - <field name="lf_alias_prefix" class="oe_inline" /> + <field name="lf_alias_prefix" class="oe_inline" /> </xpath> </field> </record> -</odoo> \ No newline at end of file +</odoo> diff --git a/views/sale_config_settings_views.xml b/views/sale_config_settings_views.xml index f12e47ab6714ac024196ef1a82c6720d671656f8..94987bd6a464c4b821feb1d4e65857c92cdf6861 100644 --- a/views/sale_config_settings_views.xml +++ b/views/sale_config_settings_views.xml @@ -1,16 +1,17 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2017 Le Filament (<https://le-filament.com>) + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> <odoo> - <record id="lefilament_view_sales_config" model="ir.ui.view"> - <field name="name">lefilament.sale.settings</field> - <field name="model">sale.config.settings</field> - <field name="inherit_id" ref="sale.view_sales_config"/> - <field name="arch" type="xml"> - <div id="main" position="inside"> - <group string="Task"> - <field name="project_task_type_id" class="oe_inline"/> - </group> - </div> - </field> - </record> - + <record id="lefilament_view_sales_config" model="ir.ui.view"> + <field name="name">lefilament.sale.settings</field> + <field name="model">sale.config.settings</field> + <field name="inherit_id" ref="sale.view_sales_config"/> + <field name="arch" type="xml"> + <div id="main" position="inside"> + <group string="Task"> + <field name="project_task_type_id" class="oe_inline"/> + </group> + </div> + </field> + </record> </odoo> diff --git a/views/sale_views.xml b/views/sale_views.xml index 1857e77842d090a11c30428f3ec3658e16684f0c..5babd05b9a3d4204c25e66c7c305d7cc1d8e52d4 100644 --- a/views/sale_views.xml +++ b/views/sale_views.xml @@ -1,9 +1,10 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2017 Le Filament (<https://le-filament.com>) + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> <odoo> - <data> - - <record id="lefilament_view_order_form" model="ir.ui.view"> + <data> + <record id="lefilament_view_order_form" model="ir.ui.view"> <field name="name">lefilament.sale.order.form</field> <field name="model">sale.order</field> <field name="inherit_id" ref="sale.view_order_form"/> @@ -14,6 +15,5 @@ </header> </field> </record> - - </data> -</odoo> \ No newline at end of file + </data> +</odoo> diff --git a/wizard/__init__.py b/wizard/__init__.py index 5a7174336b765bcf453d3b2503e362b53f67c763..a38a69208d728f9e0290d265edb023c74068422a 100644 --- a/wizard/__init__.py +++ b/wizard/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -import sale_views_wizard \ No newline at end of file +from . import sale_views_wizard diff --git a/wizard/sale_views_wizard.py b/wizard/sale_views_wizard.py index 3a132e75caabc1268e408023d4f0debd12977d24..1e4ea7bf4d9c1799c4ce544372403ebe06983adb 100644 --- a/wizard/sale_views_wizard.py +++ b/wizard/sale_views_wizard.py @@ -1,40 +1,46 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- -# © 2017 Le Filament (<http://www.le-filament.com>) +# © 2017 Le Filament (<https://le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import models, fields, api from datetime import datetime +from odoo import models, fields, api from dateutil.relativedelta import relativedelta - -class LeFilamentSaleWizard(models.TransientModel): - _name = 'lefilament.sale.views.wizard' + + +class LeFilamentSaleWizard(models.TransientModel): + _name = 'lefilament.sale.views.wizard' _description = 'Sale Project Assignment' @api.model def _default_sale_id(self): - return self.env['sale.order'].browse(self.env.context.get('active_id')) + return self.env['sale.order'].browse(self.env.context.get('active_id')) @api.model def _default_project_project_id(self): - return self._default_sale_id().project_project_id + return self._default_sale_id().project_project_id @api.model def _default_related_project_id(self): - return self._default_sale_id().related_project_id + return self._default_sale_id().related_project_id @api.model def _default_project_name(self): - if self._default_sale_id().partner_id.is_company == True: + if self._default_sale_id().partner_id.is_company is True: return self._default_sale_id().partner_id.name - else: - return self._default_sale_id().partner_id.parent_id.name - sale_id = fields.Many2one('sale.order', string='Sale', default=_default_sale_id) - project_id = fields.Many2one('project.project', string='Existing project', default=_default_project_project_id) + return self._default_sale_id().partner_id.parent_id.name + + sale_id = fields.Many2one('sale.order', string='Sale', + default=_default_sale_id) + project_id = fields.Many2one('project.project', string='Existing project', + default=_default_project_project_id) project_name = fields.Char('New project', default=_default_project_name) - related_project_id = fields.Many2one('account.analytic.account', string='Analytical account related', default=_default_related_project_id) - related_project_name = fields.Char('New Analytical Account', default=_default_project_name) + related_project_id = fields.Many2one('account.analytic.account', + string='Analytical account related', + default=_default_related_project_id) + related_project_name = fields.Char('New Analytical Account', + default=_default_project_name) @api.onchange('project_id') def onchange_project_id(self): @@ -42,36 +48,49 @@ class LeFilamentSaleWizard(models.TransientModel): @api.multi def close_dialog(self): - sale_id = self.env['sale.order'].browse(self.env.context.get('active_id')) + sale_id = self.env['sale.order'].browse( + self.env.context.get('active_id')) if self.project_id: sale_id.project_id = self.project_id.analytic_account_id sale_id.project_project_id = self.project_id project_id_new = self.project_id.id else: sale_id._create_analytic_account(prefix=None) - project_id_new = sale_id.project_id.project_create({'name': self.project_name, 'use_tasks': True}) - stage_id_new = self.env['ir.values'].get_default('sale.config.settings', 'project_task_type_id') + project_id_new = sale_id.project_id.project_create( + {'name': self.project_name, 'use_tasks': True}) + stage_id_new = self.env['ir.values'].get_default( + 'sale.config.settings', 'project_task_type_id') stage_new = self.env['project.task.type'].browse(stage_id_new) - lf_tarif_jour = self.env['ir.values'].get_default('project.config.settings', 'lf_tarif_jour') - lf_heures_jour = self.env['ir.values'].get_default('project.config.settings', 'lf_heures_jour') - lf_alias_prefix = self.env['ir.values'].get_default('project.config.settings', 'lf_alias_prefix') - ir_values = self.env['ir.values'].get_default('project.config.settings', 'generate_project_alias') + lf_tarif_jour = self.env['ir.values'].get_default( + 'project.config.settings', 'lf_tarif_jour') + lf_heures_jour = self.env['ir.values'].get_default( + 'project.config.settings', 'lf_heures_jour') + lf_alias_prefix = self.env['ir.values'].get_default( + 'project.config.settings', 'lf_alias_prefix') + ir_values = self.env['ir.values'].get_default( + 'project.config.settings', 'generate_project_alias') for line in sale_id.order_line: if line.product_id.track_service == 'project': if line.product_id.project_id: project = line.product_id.project_id project_id = project.id - date_plan = datetime.strptime(sale_id.confirmation_date,'%Y-%m-%d %H:%M:%S') - date_deadline = (date_plan.date() + relativedelta(years=int(line.product_uom_qty))).strftime('%Y-%m-%d') + date_plan = datetime.strptime(sale_id.confirmation_date, + '%Y-%m-%d %H:%M:%S') + date_deadline = (date_plan.date() + + relativedelta(years=int( + line.product_uom_qty))).strftime( + '%Y-%m-%d') stage = line.product_id.project_task_type_id - if sale_id.partner_id.is_company == True: + if sale_id.partner_id.is_company is True: if stage.name: - name_task = sale_id.partner_id.name + " - " + stage.name + name_task = (sale_id.partner_id.name + + " - " + stage.name) else: name_task = sale_id.partner_id.name else: if stage.name: - name_task = sale_id.partner_id.parent_id.name + " - " + stage.name + name_task = (sale_id.partner_id.parent_id.name + + " - " + stage.name) else: name_task = sale_id.partner_id.parent_id.name else: @@ -80,26 +99,28 @@ class LeFilamentSaleWizard(models.TransientModel): date_deadline = False name_task = line.name.split('\n', 1)[0] project_date = self.env['project.project'].browse(project_id) - project_date.lf_total_budget = project_date.lf_total_budget + line.price_subtotal + project_date.lf_total_budget = (project_date.lf_total_budget + + line.price_subtotal) project_date.lf_tarif_jour = lf_tarif_jour - if not line.product_id.project_id: + if not line.product_id.project_id: if ir_values and lf_alias_prefix: lf_alias_name = lf_alias_prefix + project_date.name project_date.alias_name = lf_alias_name - planned_hours = (line.price_subtotal / lf_tarif_jour) * lf_heures_jour + planned_hours = ((line.price_subtotal / lf_tarif_jour) + * lf_heures_jour) description_line = "<p>" - i = 1 for line_name in line.name: if line_name == '\n': description_line = description_line + "</p><p>" else: description_line = description_line + line_name - task = self.env['project.task'].create({ + self.env['project.task'].create({ 'name': name_task, 'date_deadline': date_deadline, 'planned_hours': planned_hours, 'remaining_hours': planned_hours, - 'partner_id': sale_id.partner_id.id or self.partner_dest_id.id, + 'partner_id': (sale_id.partner_id.id + or self.partner_dest_id.id), 'user_id': self.env.uid, # 'procurement_id': line.procurement_ids.id, 'description': description_line + '</p><br/>', @@ -110,6 +131,7 @@ class LeFilamentSaleWizard(models.TransientModel): 'price_subtotal': line.price_subtotal, 'currency_id': line.currency_id.id }) - sale_id.tasks_ids = self.env['project.task'].search([('sale_line_id', 'in', sale_id.order_line.ids)]) + sale_id.tasks_ids = self.env['project.task'].search( + [('sale_line_id', 'in', sale_id.order_line.ids)]) sale_id.tasks_count = len(sale_id.tasks_ids) - return {'type': 'ir.actions.act_window_close'} \ No newline at end of file + return {'type': 'ir.actions.act_window_close'} diff --git a/wizard/sale_views_wizard.xml b/wizard/sale_views_wizard.xml index 329e5168f326fb5d23d3f0e8be6dd134c999f6b5..8f12996b673261955b945d76ec78d88a2499f5b9 100644 --- a/wizard/sale_views_wizard.xml +++ b/wizard/sale_views_wizard.xml @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> - +<!-- Copyright 2017 Le Filament (<https://le-filament.com>) + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> <odoo> - <data> - - <record id="lefilament_project_view_form_create" model="ir.ui.view"> + <data> + <record id="lefilament_project_view_form_create" model="ir.ui.view"> <field name="name">lefilament.project.view.form.create</field> <field name="model">lefilament.sale.views.wizard</field> <field name="arch" type="xml"> @@ -24,19 +24,17 @@ <button string="Create" name="close_dialog" type="object" class="btn-primary"/> <button string="Discard" class="btn-default" special="cancel"/> </footer> - </sheet> </form> </field> </record> - <record id="lefilament_open_create_project" model="ir.actions.act_window"> + <record id="lefilament_open_create_project" model="ir.actions.act_window"> <field name="name">Create project</field> <field name="res_model">lefilament.sale.views.wizard</field> <field name="view_type">form</field> <field name="view_mode">form</field> <field name="target">new</field> </record> - - </data> -</odoo> \ No newline at end of file + </data> +</odoo>