From da508b47fb3d172a47e25475b17db3146a9a9849 Mon Sep 17 00:00:00 2001 From: ps-tubtim Date: Thu, 24 Oct 2019 10:22:26 +0700 Subject: [PATCH 001/210] [12.0][ADD] purchase_work_acceptance --- purchase_work_acceptance/README.rst | 144 +++++ purchase_work_acceptance/__init__.py | 4 + purchase_work_acceptance/__manifest__.py | 31 ++ .../data/work_acceptance_sequence.xml | 14 + purchase_work_acceptance/models/__init__.py | 7 + .../models/account_invoice.py | 74 +++ purchase_work_acceptance/models/purchase.py | 96 ++++ .../models/res_config_settings.py | 29 ++ .../models/stock_picking.py | 80 +++ .../models/work_acceptance.py | 224 ++++++++ purchase_work_acceptance/readme/CONFIGURE.rst | 30 ++ .../readme/CONTRIBUTORS.rst | 1 + .../readme/DESCRIPTION.rst | 3 + purchase_work_acceptance/readme/USAGE.rst | 26 + .../security/ir.model.access.csv | 3 + .../security/security.xml | 29 ++ .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 493 ++++++++++++++++++ purchase_work_acceptance/tests/__init__.py | 3 + .../tests/test_purchase_work_acceptance.py | 171 ++++++ .../views/account_invoice_views.xml | 22 + .../views/purchase_views.xml | 37 ++ .../views/res_config_settings_views.xml | 44 ++ .../views/stock_picking_views.xml | 22 + .../views/work_acceptance_views.xml | 137 +++++ purchase_work_acceptance/wizard/__init__.py | 3 + .../wizard/select_work_acceptance_wizard.py | 41 ++ .../select_work_acceptance_wizard_views.xml | 27 + 28 files changed, 1795 insertions(+) create mode 100644 purchase_work_acceptance/README.rst create mode 100644 purchase_work_acceptance/__init__.py create mode 100644 purchase_work_acceptance/__manifest__.py create mode 100644 purchase_work_acceptance/data/work_acceptance_sequence.xml create mode 100644 purchase_work_acceptance/models/__init__.py create mode 100644 purchase_work_acceptance/models/account_invoice.py create mode 100644 purchase_work_acceptance/models/purchase.py create mode 100644 purchase_work_acceptance/models/res_config_settings.py create mode 100644 purchase_work_acceptance/models/stock_picking.py create mode 100644 purchase_work_acceptance/models/work_acceptance.py create mode 100644 purchase_work_acceptance/readme/CONFIGURE.rst create mode 100644 purchase_work_acceptance/readme/CONTRIBUTORS.rst create mode 100644 purchase_work_acceptance/readme/DESCRIPTION.rst create mode 100644 purchase_work_acceptance/readme/USAGE.rst create mode 100644 purchase_work_acceptance/security/ir.model.access.csv create mode 100644 purchase_work_acceptance/security/security.xml create mode 100644 purchase_work_acceptance/static/description/icon.png create mode 100644 purchase_work_acceptance/static/description/index.html create mode 100644 purchase_work_acceptance/tests/__init__.py create mode 100644 purchase_work_acceptance/tests/test_purchase_work_acceptance.py create mode 100644 purchase_work_acceptance/views/account_invoice_views.xml create mode 100644 purchase_work_acceptance/views/purchase_views.xml create mode 100644 purchase_work_acceptance/views/res_config_settings_views.xml create mode 100644 purchase_work_acceptance/views/stock_picking_views.xml create mode 100644 purchase_work_acceptance/views/work_acceptance_views.xml create mode 100644 purchase_work_acceptance/wizard/__init__.py create mode 100644 purchase_work_acceptance/wizard/select_work_acceptance_wizard.py create mode 100644 purchase_work_acceptance/wizard/select_work_acceptance_wizard_views.xml diff --git a/purchase_work_acceptance/README.rst b/purchase_work_acceptance/README.rst new file mode 100644 index 00000000000..ad8bd431f7f --- /dev/null +++ b/purchase_work_acceptance/README.rst @@ -0,0 +1,144 @@ +======================== +Purchase Work Acceptance +======================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github + :target: https://github.com/OCA/purchase-workflow/tree/12.0/purchase_work_acceptance + :alt: OCA/purchase-workflow +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/purchase-workflow-12-0/purchase-workflow-12-0-purchase_work_acceptance + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/142/12.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module introduces the ability to define a quantity control point on Receipts and Vendor Bills by +Work Acceptance. Only the products and services that have been included in a Work Acceptance can be +received and/or invoiced. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +** Show Button Create WA on Purchase Order ** + +#. Go to *Purchase > Configuration > Settings* +#. Check 'Enable WA on Purchase Order' + +** Show WA Reference fields on Receipt ** + +#. Go to *Purchase > Configuration > Settings* +#. Check 'Enable WA on Goods Receipt' + +** Control Receipt by Work Acceptance** + +#. Go to *Purchase > Configuration > Settings* +#. Check 'Enforce WA on Goods Receipt' + +** Show WA Reference fields on Vendor Bill ** + +#. Go to *Purchase > Configuration > Settings* +#. Check 'Enable WA on Vendor Bill' + +** Control Vendor Bill by Work Acceptance** + +#. Go to *Purchase > Configuration > Settings* +#. Check 'Enforce WA on Vendor Bill' + +Note: + +* You can check 'Enable WA on Goods Receipt' and 'Enable WA on Vendor Bill' after checked 'Enable WA on Purchase Order' +* You can check 'Enforce WA on Goods Receipt' after checked 'Enable WA on Goods Receipt' +* You can check 'Enforce WA on Vendor Bill' after checked 'Enable WA on Vendor Bill' + +Usage +===== + +** Usual process of Purchasing with Work Acceptance ** + +#. Create a New Purchase Order +#. Confirm the Purchase Order +#. Create a new Work Acceptance +#. Accept the Work Acceptance +#. Receive the products following a specific Work Acceptance +#. Create the Vendor Bill following a specific Work Acceptance + +** Create a Work Acceptance ** + +#. Create Purchase Order normally +#. After 'Confirm Order' (Status = 'Purchase'), Click button 'Create WA' +#. Accept order + +** Control Receipt by Work Acceptance ** + +#. After 'Confirm Order' in Purchase Order, a smart button 'Receipt' will appear on the Purchase Order +#. Click 'Receipt' to go to the Transfer +#. Select the Work Acceptance relating to this picking in the field 'WA Reference'. + The quantity done filled automatically for the items that have been already accepted. + +** Control Vendor Bill by Work Acceptance ** + +#. After once the products and/or services have been accepted, Click 'Create Bill' +#. You will be prompted to select a Work Acceptance. Select it and Click 'Create Vendor Bill' + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Ecosoft + +Contributors +~~~~~~~~~~~~ + +* Pimolnat Suntian + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/purchase-workflow `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/purchase_work_acceptance/__init__.py b/purchase_work_acceptance/__init__.py new file mode 100644 index 00000000000..4d7a49b5e28 --- /dev/null +++ b/purchase_work_acceptance/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models +from . import wizard diff --git a/purchase_work_acceptance/__manifest__.py b/purchase_work_acceptance/__manifest__.py new file mode 100644 index 00000000000..1855029b2d0 --- /dev/null +++ b/purchase_work_acceptance/__manifest__.py @@ -0,0 +1,31 @@ +# Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Purchase Work Acceptance', + 'version': '12.0.1.0.0', + 'category': 'Purchase Management', + 'author': 'Ecosoft, ' + 'Odoo Community Association (OCA)', + 'license': 'AGPL-3', + 'website': 'https://github.com/OCA/purchase-workflow', + 'depends': [ + 'purchase_stock', + ], + 'data': [ + 'data/work_acceptance_sequence.xml', + 'security/ir.model.access.csv', + 'security/security.xml', + 'views/account_invoice_views.xml', + 'views/purchase_views.xml', + 'views/res_config_settings_views.xml', + 'views/stock_picking_views.xml', + 'views/work_acceptance_views.xml', + 'wizard/select_work_acceptance_wizard_views.xml', + ], + 'maintainer': [ + 'ps-tubtim', + ], + 'installable': True, + 'development_status': 'Alpha', +} diff --git a/purchase_work_acceptance/data/work_acceptance_sequence.xml b/purchase_work_acceptance/data/work_acceptance_sequence.xml new file mode 100644 index 00000000000..12cfb883d7b --- /dev/null +++ b/purchase_work_acceptance/data/work_acceptance_sequence.xml @@ -0,0 +1,14 @@ + + + + + + Work Acceptance + work.acceptance + WA + 5 + + + + + diff --git a/purchase_work_acceptance/models/__init__.py b/purchase_work_acceptance/models/__init__.py new file mode 100644 index 00000000000..ec77fa9ef3e --- /dev/null +++ b/purchase_work_acceptance/models/__init__.py @@ -0,0 +1,7 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import account_invoice +from . import purchase +from . import res_config_settings +from . import stock_picking +from . import work_acceptance diff --git a/purchase_work_acceptance/models/account_invoice.py b/purchase_work_acceptance/models/account_invoice.py new file mode 100644 index 00000000000..52ee9b2fef2 --- /dev/null +++ b/purchase_work_acceptance/models/account_invoice.py @@ -0,0 +1,74 @@ +# Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError + + +class AccountInvoice(models.Model): + _inherit = 'account.invoice' + + require_wa = fields.Boolean( + compute='_compute_require_wa', + ) + wa_id = fields.Many2one( + comodel_name='work.acceptance', + string='WA Reference', + copy=False, + domain=lambda self: [ + ('state', '=', 'accept'), + ('purchase_id', '=', self._context.get('active_id'))], + help='To control quantity and unit price of the vendor bill, to be ' + 'according to the quantity and unit price of the work acceptance.', + ) + + @api.multi + def _compute_require_wa(self): + self.require_wa = self.env.user.has_group( + 'purchase_work_acceptance.group_enforce_wa_on_invoice') + + def _prepare_invoice_line_from_po_line(self, line): + res = super()._prepare_invoice_line_from_po_line(line) + wa_line = self.wa_id.wa_line_ids.filtered( + lambda l: l.purchase_line_id == line) + if wa_line: + res['quantity'] = wa_line.product_qty + res['uom_id'] = wa_line.product_uom + return res + + @api.onchange('purchase_id') + def purchase_order_change(self): + res = super().purchase_order_change() + if self.wa_id: + self.reference = self.wa_id.invoice_ref + self.currency_id = self.wa_id.currency_id + return res + + @api.multi + def action_invoice_open(self): + for rec in self: + if rec.wa_id: + wa_line = {} + for line in rec.wa_id.wa_line_ids: + qty = line.product_uom._compute_quantity( + line.product_qty, line.product_id.uom_id) + if qty > 0.0: + if line.product_id.id in wa_line.keys(): + qty_old = wa_line[line.product_id.id] + wa_line[line.product_id.id] = qty_old + qty + else: + wa_line[line.product_id.id] = qty + invoice_line = {} + for line in rec.invoice_line_ids: + qty = line.uom_id._compute_quantity( + line.quantity, line.product_id.uom_id) + if qty > 0.0: + if line.product_id.id in invoice_line.keys(): + qty_old = invoice_line[line.product_id.id] + invoice_line[line.product_id.id] = qty_old + qty + else: + invoice_line[line.product_id.id] = qty + if wa_line != invoice_line: + raise ValidationError(_('You cannot validate a bill if ' + 'Quantity not equal accepted quantity')) + return super().action_invoice_open() diff --git a/purchase_work_acceptance/models/purchase.py b/purchase_work_acceptance/models/purchase.py new file mode 100644 index 00000000000..dd2d6b6ebfb --- /dev/null +++ b/purchase_work_acceptance/models/purchase.py @@ -0,0 +1,96 @@ +# Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models, _ + + +class PurchaseOrder(models.Model): + _inherit = 'purchase.order' + + wa_count = fields.Integer( + compute='_compute_wa_ids', + string='WA count', + default=0, + ) + wa_ids = fields.One2many( + comodel_name='work.acceptance', + compute='_compute_wa_ids', + string='Work Acceptances', + ) + wa_line_ids = fields.One2many( + comodel_name='work.acceptance.line', + inverse_name='purchase_line_id', + string="WA Lines", + readonly=True, + ) + + def _compute_wa_ids(self): + for order in self: + order.wa_ids = \ + order.mapped('order_line').mapped('wa_line_ids').mapped('wa_id') + order.wa_count = len(order.wa_ids) + + @api.multi + def action_view_wa(self): + self.ensure_one() + act = self.env.ref('purchase_work_acceptance.action_work_acceptance') + result = act.read()[0] + create_wa = self.env.context.get('create_wa', False) + result['context'] = { + 'default_purchase_id': self.id, + 'default_partner_id': self.partner_id.id, + 'default_company_id': self.company_id.id, + 'default_currency_id': self.currency_id.id, + 'default_date_due': self.date_planned, + 'default_wa_line_ids': [(0, 0, { + 'purchase_line_id': line.id, + 'name': line.name, + 'product_uom': line.product_uom.id, + 'product_id': line.product_id.id, + 'price_unit': line.price_unit, + 'product_qty': line._get_product_qty(), + }) for line in self.order_line if line._get_product_qty() != 0], + } + if len(self.wa_ids) > 1 and not create_wa: + result['domain'] = "[('id', 'in', " + str(self.wa_ids.ids) + ")]" + else: + res = self.env.ref( + 'purchase_work_acceptance.view_work_acceptance_form', False) + result['views'] = [(res and res.id or False, 'form')] + if not create_wa: + result['res_id'] = self.wa_ids.id or False + return result + + @api.multi + def action_view_invoice(self): + if self.env.context.get('create_bill', False) and self.env.user.has_group( + 'purchase_work_acceptance.group_enable_wa_on_invoice'): + wizard = self.env.ref( + 'purchase_work_acceptance.view_select_work_acceptance_wizard') + return { + 'name': _('Select Work Acceptance'), + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'select.work.acceptance.wizard', + 'views': [(wizard.id, 'form')], + 'view_id': wizard.id, + 'target': 'new', + } + return super(PurchaseOrder, self).action_view_invoice() + + +class PurchaseOrderLine(models.Model): + _inherit = 'purchase.order.line' + + wa_line_ids = fields.One2many( + comodel_name='work.acceptance.line', + inverse_name='purchase_line_id', + string="WA Lines", + readonly=True, + ) + + def _get_product_qty(self): + return self.product_qty - sum( + wa_line.product_qty for wa_line in self.wa_line_ids + if wa_line.wa_id.state != 'cancel') diff --git a/purchase_work_acceptance/models/res_config_settings.py b/purchase_work_acceptance/models/res_config_settings.py new file mode 100644 index 00000000000..e8814a1f213 --- /dev/null +++ b/purchase_work_acceptance/models/res_config_settings.py @@ -0,0 +1,29 @@ +# Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = 'res.config.settings' + + group_enable_wa_on_po = fields.Boolean( + string="Enable WA on Purchase Order", + implied_group='purchase_work_acceptance.group_enable_wa_on_po', + ) + group_enable_wa_on_in = fields.Boolean( + string="Enable WA on Goods Receipt", + implied_group='purchase_work_acceptance.group_enable_wa_on_in', + ) + group_enforce_wa_on_in = fields.Boolean( + string="Enforce WA on Goods Receipt", + implied_group='purchase_work_acceptance.group_enforce_wa_on_in', + ) + group_enable_wa_on_invoice = fields.Boolean( + string="Enable WA on Vendor Bill", + implied_group='purchase_work_acceptance.group_enable_wa_on_invoice', + ) + group_enforce_wa_on_invoice = fields.Boolean( + string="Enforce WA on Vendor Bill", + implied_group='purchase_work_acceptance.group_enforce_wa_on_invoice', + ) diff --git a/purchase_work_acceptance/models/stock_picking.py b/purchase_work_acceptance/models/stock_picking.py new file mode 100644 index 00000000000..f729f9c06f3 --- /dev/null +++ b/purchase_work_acceptance/models/stock_picking.py @@ -0,0 +1,80 @@ +# Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError + + +class Picking(models.Model): + _inherit = "stock.picking" + + require_wa = fields.Boolean( + compute='_compute_require_wa', + ) + wa_id = fields.Many2one( + comodel_name='work.acceptance', + string='WA Reference', + copy=False, + domain=lambda self: [ + ('state', '=', 'accept'), + ('purchase_id', '=', self._context.get('active_id'))], + ) + + @api.multi + def _compute_require_wa(self): + self.require_wa = self.env.user.has_group( + 'purchase_work_acceptance.group_enforce_wa_on_in') + + @api.multi + def button_validate(self): + if self.wa_id: + order = self.env['purchase.order'].browse(self._context.get('active_id')) + if any(picking.wa_id == self.wa_id and picking != self + for picking in order.picking_ids): + raise ValidationError(_( + '%s was used in some picking.') % self.wa_id.name) + wa_line = {} + for line in self.wa_id.wa_line_ids: + qty = line.product_uom._compute_quantity( + line.product_qty, line.product_id.uom_id) + if qty > 0.0 and line.product_id.type in ['product', 'consu']: + if line.product_id.id in wa_line.keys(): + qty_old = wa_line[line.product_id.id] + wa_line[line.product_id.id] = qty_old + qty + else: + wa_line[line.product_id.id] = qty + move_line = {} + for move in self.move_ids_without_package: + qty = move.product_uom._compute_quantity( + move.quantity_done, line.product_id.uom_id) + if qty > 0.0: + if move.product_id.id in move_line.keys(): + qty_old = move_line[move.product_id.id] + move_line[move.product_id.id] = qty_old + qty + else: + move_line[move.product_id.id] = qty + if wa_line != move_line: + raise ValidationError(_('You cannot validate a transfer if done' + ' quantity not equal accepted quantity')) + return super(Picking, self).button_validate() + + @api.onchange('wa_id') + def _onchange_wa_id(self): + if self.wa_id: + wa_line = {} + for line in self.wa_id.wa_line_ids: + qty = line.product_uom._compute_quantity( + line.product_qty, line.product_id.uom_id) + if line.product_id.id in wa_line.keys(): + qty_old = wa_line[line.product_id.id] + wa_line[line.product_id.id] = qty_old + qty + else: + wa_line[line.product_id.id] = qty + for move_line in self.move_line_ids_without_package: + if move_line.product_id.id in wa_line.keys(): + qty = wa_line[move_line.product_id.id] + if move_line.product_uom_qty < qty: + move_line.qty_done = move_line.product_uom_qty + wa_line[line.product_id.id] = qty - move_line.product_uom_qty + else: + move_line.qty_done = qty diff --git a/purchase_work_acceptance/models/work_acceptance.py b/purchase_work_acceptance/models/work_acceptance.py new file mode 100644 index 00000000000..433f3b9b34c --- /dev/null +++ b/purchase_work_acceptance/models/work_acceptance.py @@ -0,0 +1,224 @@ +# Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class WorkAcceptance(models.Model): + _name = 'work.acceptance' + _inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin'] + _description = 'Work Acceptance' + _order = 'id desc' + + name = fields.Char( + required=True, + index=True, + copy=False, + default='New' + ) + date_due = fields.Datetime( + string='Due Date', + required=True, + readonly=True, + states={'draft': [('readonly', False)]}, + ) + date_receive = fields.Datetime( + string='Received Date', + default=fields.Datetime.now, + required=True, + readonly=True, + states={'draft': [('readonly', False)]}, + ) + date_accept = fields.Datetime( + string='Accepted Date', + readonly=True, + ) + invoice_ref = fields.Char( + string='Invoice Reference', + copy=False, + ) + partner_id = fields.Many2one( + comodel_name='res.partner', + string='Vendor', + required=True, + change_default=True, + track_visibility='always', + readonly=True, + states={'draft': [('readonly', False)]}, + ) + responsible_id = fields.Many2one( + comodel_name='res.users', + string='Responsible Person', + default=lambda self: self.env.user, + required=True, + change_default=True, + track_visibility='always', + readonly=True, + states={'draft': [('readonly', False)]}, + ) + currency_id = fields.Many2one( + comodel_name='res.currency', + string='Currency', + default=lambda self: self.env.user.company_id.currency_id.id, + required=True, + readonly=True, + ) + state = fields.Selection( + [('draft', 'Draft'), + ('accept', 'Accepted'), + ('cancel', 'Cancelled')], + string='Status', + readonly=True, + index=True, + copy=False, + default='draft', + track_visibility='onchange' + ) + wa_line_ids = fields.One2many( + comodel_name='work.acceptance.line', + inverse_name='wa_id', + string='Work Acceptance Lines', + ) + notes = fields.Text( + string='Notes', + ) + product_id = fields.Many2one( + comodel_name='product.product', + related='wa_line_ids.product_id', + string='Product', + readonly=False, + ) + user_id = fields.Many2one( + comodel_name='res.users', + string='Work Acceptance Representative', + default=lambda self: self.env.user, + index=True, + track_visibility='onchange', + ) + company_id = fields.Many2one( + comodel_name='res.company', + string='Company', + default=lambda self: self.env.user.company_id.id, + required=True, + index=True, + readonly=True, + states={'draft': [('readonly', False)]}, + ) + purchase_id = fields.Many2one( + comodel_name='purchase.order', + string='Purchase Order', + readonly=True, + ) + + @api.model + def create(self, vals): + if vals.get('name', 'New') == 'New': + vals['name'] = self.env['ir.sequence'].next_by_code( + 'work.acceptance') or '/' + return super(WorkAcceptance, self).create(vals) + + @api.multi + def button_accept(self, force=False): + self._unlink_zero_quantity() + po_lines = self.purchase_id.order_line + for po_line in po_lines: + if po_line.product_id.type not in ['product', 'consu']: + po_line.qty_received = self.wa_line_ids.filtered( + lambda l: l.purchase_line_id == po_line).product_qty + self.write({'state': 'accept', 'date_accept': fields.Datetime.now()}) + + @api.multi + def button_draft(self): + self.write({'state': 'draft'}) + + @api.multi + def button_cancel(self): + self.write({'state': 'cancel'}) + + def _unlink_zero_quantity(self): + wa_line_zero_quantity = self.wa_line_ids.filtered( + lambda l: l.product_qty == 0.0) + wa_line_zero_quantity.unlink() + + +class WorkAcceptanceLine(models.Model): + _name = 'work.acceptance.line' + _description = 'Work Acceptance Line' + _order = 'id' + + name = fields.Text( + string='Description', + required=True + ) + product_qty = fields.Float( + string='Quantity', + required=True, + ) + product_id = fields.Many2one( + comodel_name='product.product', + string='Product', + required=True, + ) + product_uom = fields.Many2one( + comodel_name='uom.uom', + string='Product Unit of Measure', + required=True, + ) + price_unit = fields.Float( + string='Unit Price', + required=True, + ) + price_subtotal = fields.Monetary( + compute='_compute_amount', + string='Subtotal', + ) + wa_id = fields.Many2one( + comodel_name='work.acceptance', + string='WA Reference', + index=True, + required=True, + ondelete='cascade' + ) + partner_id = fields.Many2one( + comodel_name='res.partner', + related='wa_id.partner_id', + string='Partner', + readonly=True, + ) + responsible_id = fields.Many2one( + comodel_name='res.users', + related='wa_id.responsible_id', + string='Responsible Person', + readonly=True, + ) + currency_id = fields.Many2one( + related='wa_id.currency_id', + string='Currency', + readonly=True, + ) + date_due = fields.Datetime( + related='wa_id.date_due', + string='Due Date', + readonly=True, + ) + date_receive = fields.Datetime( + related='wa_id.date_receive', + string='Received Date', + readonly=True, + ) + date_accept = fields.Datetime( + related='wa_id.date_accept', + string='Accepted Date', + readonly=True, + ) + purchase_line_id = fields.Many2one( + comodel_name='purchase.order.line', + string='Purchase Order Line', + ondelete='set null', + index=True, + readonly=True, + ) + + def _compute_amount(self): + for line in self: + line.price_subtotal = line.product_qty * line.price_unit diff --git a/purchase_work_acceptance/readme/CONFIGURE.rst b/purchase_work_acceptance/readme/CONFIGURE.rst new file mode 100644 index 00000000000..7a071edf319 --- /dev/null +++ b/purchase_work_acceptance/readme/CONFIGURE.rst @@ -0,0 +1,30 @@ +** Show Button Create WA on Purchase Order ** + +#. Go to *Purchase > Configuration > Settings* +#. Check 'Enable WA on Purchase Order' + +** Show WA Reference fields on Receipt ** + +#. Go to *Purchase > Configuration > Settings* +#. Check 'Enable WA on Goods Receipt' + +** Control Receipt by Work Acceptance** + +#. Go to *Purchase > Configuration > Settings* +#. Check 'Enforce WA on Goods Receipt' + +** Show WA Reference fields on Vendor Bill ** + +#. Go to *Purchase > Configuration > Settings* +#. Check 'Enable WA on Vendor Bill' + +** Control Vendor Bill by Work Acceptance** + +#. Go to *Purchase > Configuration > Settings* +#. Check 'Enforce WA on Vendor Bill' + +Note: + +* You can check 'Enable WA on Goods Receipt' and 'Enable WA on Vendor Bill' after checked 'Enable WA on Purchase Order' +* You can check 'Enforce WA on Goods Receipt' after checked 'Enable WA on Goods Receipt' +* You can check 'Enforce WA on Vendor Bill' after checked 'Enable WA on Vendor Bill' diff --git a/purchase_work_acceptance/readme/CONTRIBUTORS.rst b/purchase_work_acceptance/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..0ef1f84c3fd --- /dev/null +++ b/purchase_work_acceptance/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Pimolnat Suntian diff --git a/purchase_work_acceptance/readme/DESCRIPTION.rst b/purchase_work_acceptance/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..b9a818b39d0 --- /dev/null +++ b/purchase_work_acceptance/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module introduces the ability to define a quantity control point on Receipts and Vendor Bills by +Work Acceptance. Only the products and services that have been included in a Work Acceptance can be +received and/or invoiced. diff --git a/purchase_work_acceptance/readme/USAGE.rst b/purchase_work_acceptance/readme/USAGE.rst new file mode 100644 index 00000000000..a9b4a125112 --- /dev/null +++ b/purchase_work_acceptance/readme/USAGE.rst @@ -0,0 +1,26 @@ +** Usual process of Purchasing with Work Acceptance ** + +#. Create a New Purchase Order +#. Confirm the Purchase Order +#. Create a new Work Acceptance +#. Accept the Work Acceptance +#. Receive the products following a specific Work Acceptance +#. Create the Vendor Bill following a specific Work Acceptance + +** Create a Work Acceptance ** + +#. Create Purchase Order normally +#. After 'Confirm Order' (Status = 'Purchase'), Click button 'Create WA' +#. Accept order + +** Control Receipt by Work Acceptance ** + +#. After 'Confirm Order' in Purchase Order, a smart button 'Receipt' will appear on the Purchase Order +#. Click 'Receipt' to go to the Transfer +#. Select the Work Acceptance relating to this picking in the field 'WA Reference'. + The quantity done filled automatically for the items that have been already accepted. + +** Control Vendor Bill by Work Acceptance ** + +#. After once the products and/or services have been accepted, Click 'Create Bill' +#. You will be prompted to select a Work Acceptance. Select it and Click 'Create Vendor Bill' diff --git a/purchase_work_acceptance/security/ir.model.access.csv b/purchase_work_acceptance/security/ir.model.access.csv new file mode 100644 index 00000000000..8a600c6e5a5 --- /dev/null +++ b/purchase_work_acceptance/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_work_acceptance,access_work_acceptance,model_work_acceptance,purchase.group_purchase_user,1,1,1,1 +access_work_acceptance_line,access_work_acceptance_line,model_work_acceptance_line,purchase.group_purchase_user,1,1,1,1 diff --git a/purchase_work_acceptance/security/security.xml b/purchase_work_acceptance/security/security.xml new file mode 100644 index 00000000000..2c0f7f4257b --- /dev/null +++ b/purchase_work_acceptance/security/security.xml @@ -0,0 +1,29 @@ + + + + + Enable WA on Purchase Order + + + + + Enable WA on Goods Receipt + + + + + Enforce WA on Goods Receipt + + + + + Enable WA on Vendor Bill + + + + + Enforce WA on Vendor Bill + + + + diff --git a/purchase_work_acceptance/static/description/icon.png b/purchase_work_acceptance/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 zcmW++2RxMjAAjx~&dlBk9S+%}OXg)AGE&Cb*&}d0jUxM@u(PQx^-s)697TX`ehR4?GS^qbkof1cslKgkU)h65qZ9Oc=ml_0temigYLJfnz{IDzUf>bGs4N!v3=Z3jMq&A#7%rM5eQ#dc?k~! zVpnB`o+K7|Al`Q_U;eD$B zfJtP*jH`siUq~{KE)`jP2|#TUEFGRryE2`i0**z#*^6~AI|YzIWy$Cu#CSLW3q=GA z6`?GZymC;dCPk~rBS%eCb`5OLr;RUZ;D`}um=H)BfVIq%7VhiMr)_#G0N#zrNH|__ zc+blN2UAB0=617@>_u;MPHN;P;N#YoE=)R#i$k_`UAA>WWCcEVMh~L_ zj--gtp&|K1#58Yz*AHCTMziU1Jzt_jG0I@qAOHsk$2}yTmVkBp_eHuY$A9)>P6o~I z%aQ?!(GqeQ-Y+b0I(m9pwgi(IIZZzsbMv+9w{PFtd_<_(LA~0H(xz{=FhLB@(1&qHA5EJw1>>=%q2f&^X>IQ{!GJ4e9U z&KlB)z(84HmNgm2hg2C0>WM{E(DdPr+EeU_N@57;PC2&DmGFW_9kP&%?X4}+xWi)( z;)z%wI5>D4a*5XwD)P--sPkoY(a~WBw;E~AW`Yue4kFa^LM3X`8x|}ZUeMnqr}>kH zG%WWW>3ml$Yez?i%)2pbKPI7?5o?hydokgQyZsNEr{a|mLdt;X2TX(#B1j35xPnPW z*bMSSOauW>o;*=kO8ojw91VX!qoOQb)zHJ!odWB}d+*K?#sY_jqPdg{Sm2HdYzdEx zOGVPhVRTGPtv0o}RfVP;Nd(|CB)I;*t&QO8h zFfekr30S!-LHmV_Su-W+rEwYXJ^;6&3|L$mMC8*bQptyOo9;>Qb9Q9`ySe3%V$A*9 zeKEe+b0{#KWGp$F+tga)0RtI)nhMa-K@JS}2krK~n8vJ=Ngm?R!9G<~RyuU0d?nz# z-5EK$o(!F?hmX*2Yt6+coY`6jGbb7tF#6nHA zuKk=GGJ;ZwON1iAfG$E#Y7MnZVmrY|j0eVI(DN_MNFJmyZ|;w4tf@=CCDZ#5N_0K= z$;R~bbk?}TpfDjfB&aiQ$VA}s?P}xPERJG{kxk5~R`iRS(SK5d+Xs9swCozZISbnS zk!)I0>t=A<-^z(cmSFz3=jZ23u13X><0b)P)^1T_))Kr`e!-pb#q&J*Q`p+B6la%C zuVl&0duN<;uOsB3%T9Fp8t{ED108<+W(nOZd?gDnfNBC3>M8WE61$So|P zVvqH0SNtDTcsUdzaMDpT=Ty0pDHHNL@Z0w$Y`XO z2M-_r1S+GaH%pz#Uy0*w$Vdl=X=rQXEzO}d6J^R6zjM1u&c9vYLvLp?W7w(?np9x1 zE_0JSAJCPB%i7p*Wvg)pn5T`8k3-uR?*NT|J`eS#_#54p>!p(mLDvmc-3o0mX*mp_ zN*AeS<>#^-{S%W<*mz^!X$w_2dHWpcJ6^j64qFBft-o}o_Vx80o0>}Du;>kLts;$8 zC`7q$QI(dKYG`Wa8#wl@V4jVWBRGQ@1dr-hstpQL)Tl+aqVpGpbSfN>5i&QMXfiZ> zaA?T1VGe?rpQ@;+pkrVdd{klI&jVS@I5_iz!=UMpTsa~mBga?1r}aRBm1WS;TT*s0f0lY=JBl66Upy)-k4J}lh=P^8(SXk~0xW=T9v*B|gzIhN z>qsO7dFd~mgxAy4V?&)=5ieYq?zi?ZEoj)&2o)RLy=@hbCRcfT5jigwtQGE{L*8<@Yd{zg;CsL5mvzfDY}P-wos_6PfprFVaeqNE%h zKZhLtcQld;ZD+>=nqN~>GvROfueSzJD&BE*}XfU|H&(FssBqY=hPCt`d zH?@s2>I(|;fcW&YM6#V#!kUIP8$Nkdh0A(bEVj``-AAyYgwY~jB zT|I7Bf@%;7aL7Wf4dZ%VqF$eiaC38OV6oy3Z#TER2G+fOCd9Iaoy6aLYbPTN{XRPz z;U!V|vBf%H!}52L2gH_+j;`bTcQRXB+y9onc^wLm5wi3-Be}U>k_u>2Eg$=k!(l@I zcCg+flakT2Nej3i0yn+g+}%NYb?ta;R?(g5SnwsQ49U8Wng8d|{B+lyRcEDvR3+`O{zfmrmvFrL6acVP%yG98X zo&+VBg@px@i)%o?dG(`T;n*$S5*rnyiR#=wW}}GsAcfyQpE|>a{=$Hjg=-*_K;UtD z#z-)AXwSRY?OPefw^iI+ z)AXz#PfEjlwTes|_{sB?4(O@fg0AJ^g8gP}ex9Ucf*@_^J(s_5jJV}c)s$`Myn|Kd z$6>}#q^n{4vN@+Os$m7KV+`}c%4)4pv@06af4-x5#wj!KKb%caK{A&Y#Rfs z-po?Dcb1({W=6FKIUirH&(yg=*6aLCekcKwyfK^JN5{wcA3nhO(o}SK#!CINhI`-I z1)6&n7O&ZmyFMuNwvEic#IiOAwNkR=u5it{B9n2sAJV5pNhar=j5`*N!Na;c7g!l$ z3aYBqUkqqTJ=Re-;)s!EOeij=7SQZ3Hq}ZRds%IM*PtM$wV z@;rlc*NRK7i3y5BETSKuumEN`Xu_8GP1Ri=OKQ$@I^ko8>H6)4rjiG5{VBM>B|%`&&s^)jS|-_95&yc=GqjNo{zFkw%%HHhS~e=s zD#sfS+-?*t|J!+ozP6KvtOl!R)@@-z24}`9{QaVLD^9VCSR2b`b!KC#o;Ki<+wXB6 zx3&O0LOWcg4&rv4QG0)4yb}7BFSEg~=IR5#ZRj8kg}dS7_V&^%#Do==#`u zpy6{ox?jWuR(;pg+f@mT>#HGWHAJRRDDDv~@(IDw&R>9643kK#HN`!1vBJHnC+RM&yIh8{gG2q zA%e*U3|N0XSRa~oX-3EAneep)@{h2vvd3Xvy$7og(sayr@95+e6~Xvi1tUqnIxoIH zVWo*OwYElb#uyW{Imam6f2rGbjR!Y3`#gPqkv57dB6K^wRGxc9B(t|aYDGS=m$&S!NmCtrMMaUg(c zc2qC=2Z`EEFMW-me5B)24AqF*bV5Dr-M5ig(l-WPS%CgaPzs6p_gnCIvTJ=Y<6!gT zVt@AfYCzjjsMEGi=rDQHo0yc;HqoRNnNFeWZgcm?f;cp(6CNylj36DoL(?TS7eU#+ z7&mfr#y))+CJOXQKUMZ7QIdS9@#-}7y2K1{8)cCt0~-X0O!O?Qx#E4Og+;A2SjalQ zs7r?qn0H044=sDN$SRG$arw~n=+T_DNdSrarmu)V6@|?1-ZB#hRn`uilTGPJ@fqEy zGt(f0B+^JDP&f=r{#Y_wi#AVDf-y!RIXU^0jXsFpf>=Ji*TeqSY!H~AMbJdCGLhC) zn7Rx+sXw6uYj;WRYrLd^5IZq@6JI1C^YkgnedZEYy<&4(z%Q$5yv#Boo{AH8n$a zhb4Y3PWdr269&?V%uI$xMcUrMzl=;w<_nm*qr=c3Rl@i5wWB;e-`t7D&c-mcQl7x! zZWB`UGcw=Y2=}~wzrfLx=uet<;m3~=8I~ZRuzvMQUQdr+yTV|ATf1Uuomr__nDf=X zZ3WYJtHp_ri(}SQAPjv+Y+0=fH4krOP@S&=zZ-t1jW1o@}z;xk8 z(Nz1co&El^HK^NrhVHa-_;&88vTU>_J33=%{if;BEY*J#1n59=07jrGQ#IP>@u#3A z;!q+E1Rj3ZJ+!4bq9F8PXJ@yMgZL;>&gYA0%_Kbi8?S=XGM~dnQZQ!yBSgcZhY96H zrWnU;k)qy`rX&&xlDyA%(a1Hhi5CWkmg(`Gb%m(HKi-7Z!LKGRP_B8@`7&hdDy5n= z`OIxqxiVfX@OX1p(mQu>0Ai*v_cTMiw4qRt3~NBvr9oBy0)r>w3p~V0SCm=An6@3n)>@z!|o-$HvDK z|3D2ZMJkLE5loMKl6R^ez@Zz%S$&mbeoqH5`Bb){Ei21q&VP)hWS2tjShfFtGE+$z zzCR$P#uktu+#!w)cX!lWN1XU%K-r=s{|j?)Akf@q#3b#{6cZCuJ~gCxuMXRmI$nGtnH+-h z+GEi!*X=AP<|fG`1>MBdTb?28JYc=fGvAi2I<$B(rs$;eoJCyR6_bc~p!XR@O-+sD z=eH`-ye})I5ic1eL~TDmtfJ|8`0VJ*Yr=hNCd)G1p2MMz4C3^Mj?7;!w|Ly%JqmuW zlIEW^Ft%z?*|fpXda>Jr^1noFZEwFgVV%|*XhH@acv8rdGxeEX{M$(vG{Zw+x(ei@ zmfXb22}8-?Fi`vo-YVrTH*C?a8%M=Hv9MqVH7H^J$KsD?>!SFZ;ZsvnHr_gn=7acz z#W?0eCdVhVMWN12VV^$>WlQ?f;P^{(&pYTops|btm6aj>_Uz+hqpGwB)vWp0Cf5y< zft8-je~nn?W11plq}N)4A{l8I7$!ks_x$PXW-2XaRFswX_BnF{R#6YIwMhAgd5F9X zGmwdadS6(a^fjHtXg8=l?Rc0Sm%hk6E9!5cLVloEy4eh(=FwgP`)~I^5~pBEWo+F6 zSf2ncyMurJN91#cJTy_u8Y}@%!bq1RkGC~-bV@SXRd4F{R-*V`bS+6;W5vZ(&+I<9$;-V|eNfLa5n-6% z2(}&uGRF;p92eS*sE*oR$@pexaqr*meB)VhmIg@h{uzkk$9~qh#cHhw#>O%)b@+(| z^IQgqzuj~Sk(J;swEM-3TrJAPCq9k^^^`q{IItKBRXYe}e0Tdr=Huf7da3$l4PdpwWDop%^}n;dD#K4s#DYA8SHZ z&1!riV4W4R7R#C))JH1~axJ)RYnM$$lIR%6fIVA@zV{XVyx}C+a-Dt8Y9M)^KU0+H zR4IUb2CJ{Hg>CuaXtD50jB(_Tcx=Z$^WYu2u5kubqmwp%drJ6 z?Fo40g!Qd<-l=TQxqHEOuPX0;^z7iX?Ke^a%XT<13TA^5`4Xcw6D@Ur&VT&CUe0d} z1GjOVF1^L@>O)l@?bD~$wzgf(nxX1OGD8fEV?TdJcZc2KoUe|oP1#=$$7ee|xbY)A zDZq+cuTpc(fFdj^=!;{k03C69lMQ(|>uhRfRu%+!k&YOi-3|1QKB z z?n?eq1XP>p-IM$Z^C;2L3itnbJZAip*Zo0aw2bs8@(s^~*8T9go!%dHcAz2lM;`yp zD=7&xjFV$S&5uDaiScyD?B-i1ze`+CoRtz`Wn+Zl&#s4&}MO{@N!ufrzjG$B79)Y2d3tBk&)TxUTw@QS0TEL_?njX|@vq?Uz(nBFK5Pq7*xj#u*R&i|?7+6# z+|r_n#SW&LXhtheZdah{ZVoqwyT{D>MC3nkFF#N)xLi{p7J1jXlmVeb;cP5?e(=f# zuT7fvjSbjS781v?7{)-X3*?>tq?)Yd)~|1{BDS(pqC zC}~H#WXlkUW*H5CDOo<)#x7%RY)A;ShGhI5s*#cRDA8YgqG(HeKDx+#(ZQ?386dv! zlXCO)w91~Vw4AmOcATuV653fa9R$fyK8ul%rG z-wfS zihugoZyr38Im?Zuh6@RcF~t1anQu7>#lPpb#}4cOA!EM11`%f*07RqOVkmX{p~KJ9 z^zP;K#|)$`^Rb{rnHGH{~>1(fawV0*Z#)}M`m8-?ZJV<+e}s9wE# z)l&az?w^5{)`S(%MRzxdNqrs1n*-=jS^_jqE*5XDrA0+VE`5^*p3CuM<&dZEeCjoz zR;uu_H9ZPZV|fQq`Cyw4nscrVwi!fE6ciMmX$!_hN7uF;jjKG)d2@aC4ropY)8etW=xJvni)8eHi`H$%#zn^WJ5NLc-rqk|u&&4Z6fD_m&JfSI1Bvb?b<*n&sfl0^t z=HnmRl`XrFvMKB%9}>PaA`m-fK6a0(8=qPkWS5bb4=v?XcWi&hRY?O5HdulRi4?fN zlsJ*N-0Qw+Yic@s0(2uy%F@ib;GjXt01Fmx5XbRo6+n|pP(&nodMoap^z{~q ziEeaUT@Mxe3vJSfI6?uLND(CNr=#^W<1b}jzW58bIfyWTDle$mmS(|x-0|2UlX+9k zQ^EX7Nw}?EzVoBfT(-LT|=9N@^hcn-_p&sqG z&*oVs2JSU+N4ZD`FhCAWaS;>|wH2G*Id|?pa#@>tyxX`+4HyIArWDvVrX)2WAOQff z0qyHu&-S@i^MS-+j--!pr4fPBj~_8({~e1bfcl0wI1kaoN>mJL6KUPQm5N7lB(ui1 zE-o%kq)&djzWJ}ob<-GfDlkB;F31j-VHKvQUGQ3sp`CwyGJk_i!y^sD0fqC@$9|jO zOqN!r!8-p==F@ZVP=U$qSpY(gQ0)59P1&t@y?5rvg<}E+GB}26NYPp4f2YFQrQtot5mn3wu_qprZ=>Ig-$ zbW26Ws~IgY>}^5w`vTB(G`PTZaDiGBo5o(tp)qli|NeV( z@H_=R8V39rt5J5YB2Ky?4eJJ#b`_iBe2ot~6%7mLt5t8Vwi^Jy7|jWXqa3amOIoRb zOr}WVFP--DsS`1WpN%~)t3R!arKF^Q$e12KEqU36AWwnCBICpH4XCsfnyrHr>$I$4 z!DpKX$OKLWarN7nv@!uIA+~RNO)l$$w}p(;b>mx8pwYvu;dD_unryX_NhT8*Tj>BTrTTL&!?O+%Rv;b?B??gSzdp?6Uug9{ zd@V08Z$BdI?fpoCS$)t4mg4rT8Q_I}h`0d-vYZ^|dOB*Q^S|xqTV*vIg?@fVFSmMpaw0qtTRbx} z({Pg?#{2`sc9)M5N$*N|4;^t$+QP?#mov zGVC@I*lBVrOU-%2y!7%)fAKjpEFsgQc4{amtiHb95KQEwvf<(3T<9-Zm$xIew#P22 zc2Ix|App^>v6(3L_MCU0d3W##AB0M~3D00EWoKZqsJYT(#@w$Y_H7G22M~ApVFTRHMI_3be)Lkn#0F*V8Pq zc}`Cjy$bE;FJ6H7p=0y#R>`}-m4(0F>%@P|?7fx{=R^uFdISRnZ2W_xQhD{YuR3t< z{6yxu=4~JkeA;|(J6_nv#>Nvs&FuLA&PW^he@t(UwFFE8)|a!R{`E`K`i^ZnyE4$k z;(749Ix|oi$c3QbEJ3b~D_kQsPz~fIUKym($a_7dJ?o+40*OLl^{=&oq$<#Q(yyrp z{J-FAniyAw9tPbe&IhQ|a`DqFTVQGQ&Gq3!C2==4x{6EJwiPZ8zub-iXoUtkJiG{} zPaR&}_fn8_z~(=;5lD-aPWD3z8PZS@AaUiomF!G8I}Mf>e~0g#BelA-5#`cj;O5>N Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/purchase_work_acceptance/static/description/index.html b/purchase_work_acceptance/static/description/index.html new file mode 100644 index 00000000000..9bf6c1f05e4 --- /dev/null +++ b/purchase_work_acceptance/static/description/index.html @@ -0,0 +1,493 @@ + + + + + + +Purchase Work Acceptance + + + +
+

Purchase Work Acceptance

+ + +

Alpha License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runbot

+

This module introduces the ability to define a quantity control point on Receipts and Vendor Bills by +Work Acceptance. Only the products and services that have been included in a Work Acceptance can be +received and/or invoiced.

+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

Table of contents

+ +
+

Configuration

+

** Show Button Create WA on Purchase Order **

+
    +
  1. Go to Purchase > Configuration > Settings
  2. +
  3. Check ‘Enable WA on Purchase Order’
  4. +
+

** Show WA Reference fields on Receipt **

+
    +
  1. Go to Purchase > Configuration > Settings
  2. +
  3. Check ‘Enable WA on Goods Receipt’
  4. +
+

** Control Receipt by Work Acceptance**

+
    +
  1. Go to Purchase > Configuration > Settings
  2. +
  3. Check ‘Enforce WA on Goods Receipt’
  4. +
+

** Show WA Reference fields on Vendor Bill **

+
    +
  1. Go to Purchase > Configuration > Settings
  2. +
  3. Check ‘Enable WA on Vendor Bill’
  4. +
+

** Control Vendor Bill by Work Acceptance**

+
    +
  1. Go to Purchase > Configuration > Settings
  2. +
  3. Check ‘Enforce WA on Vendor Bill’
  4. +
+

Note:

+
    +
  • You can check ‘Enable WA on Goods Receipt’ and ‘Enable WA on Vendor Bill’ after checked ‘Enable WA on Purchase Order’
  • +
  • You can check ‘Enforce WA on Goods Receipt’ after checked ‘Enable WA on Goods Receipt’
  • +
  • You can check ‘Enforce WA on Vendor Bill’ after checked ‘Enable WA on Vendor Bill’
  • +
+
+
+

Usage

+

** Usual process of Purchasing with Work Acceptance **

+
    +
  1. Create a New Purchase Order
  2. +
  3. Confirm the Purchase Order
  4. +
  5. Create a new Work Acceptance
  6. +
  7. Accept the Work Acceptance
  8. +
  9. Receive the products following a specific Work Acceptance
  10. +
  11. Create the Vendor Bill following a specific Work Acceptance
  12. +
+

** Create a Work Acceptance **

+
    +
  1. Create Purchase Order normally
  2. +
  3. After ‘Confirm Order’ (Status = ‘Purchase’), Click button ‘Create WA’
  4. +
  5. Accept order
  6. +
+

** Control Receipt by Work Acceptance **

+
    +
  1. After ‘Confirm Order’ in Purchase Order, a smart button ‘Receipt’ will appear on the Purchase Order
  2. +
  3. Click ‘Receipt’ to go to the Transfer
  4. +
  5. Select the Work Acceptance relating to this picking in the field ‘WA Reference’. +The quantity done filled automatically for the items that have been already accepted.
  6. +
+

** Control Vendor Bill by Work Acceptance **

+
    +
  1. After once the products and/or services have been accepted, Click ‘Create Bill’
  2. +
  3. You will be prompted to select a Work Acceptance. Select it and Click ‘Create Vendor Bill’
  4. +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Ecosoft
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/purchase-workflow project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/purchase_work_acceptance/tests/__init__.py b/purchase_work_acceptance/tests/__init__.py new file mode 100644 index 00000000000..de27bbbe5f6 --- /dev/null +++ b/purchase_work_acceptance/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_purchase_work_acceptance diff --git a/purchase_work_acceptance/tests/test_purchase_work_acceptance.py b/purchase_work_acceptance/tests/test_purchase_work_acceptance.py new file mode 100644 index 00000000000..992452658d5 --- /dev/null +++ b/purchase_work_acceptance/tests/test_purchase_work_acceptance.py @@ -0,0 +1,171 @@ +# Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase, Form + + +class TestPurchaseWorkAcceptance(TransactionCase): + def setUp(self): + super(TestPurchaseWorkAcceptance, self).setUp() + # Create Product + self.service_product = self.env.ref('product.product_product_1') + self.product_product = self.env.ref('product.product_product_6') + # Create Vendor + self.res_partner = self.env.ref('base.res_partner_3') + # Create Employee + self.employee = self.env.ref('base.user_demo') + # Create Date + self.date_now = fields.Datetime.now() + + def test_00_wa_button(self): + work_acceptance = self.env['work.acceptance'].create({ + 'partner_id': self.res_partner.id, + 'responsible_id': self.employee.id, + 'date_due': self.date_now, + 'date_receive': self.date_now, + 'company_id': self.env.ref('base.main_company').id, + 'wa_line_ids': [ + (0, 0, {'product_id': self.service_product.id, + 'name': self.service_product.name, + 'price_unit': self.service_product.standard_price, + 'product_qty': 3.0, + 'product_uom': self.service_product.uom_id.id, + })] + }) + work_acceptance.button_accept() + self.assertEqual(work_acceptance.state, 'accept') + work_acceptance.button_cancel() + self.assertEqual(work_acceptance.state, 'cancel') + work_acceptance.button_draft() + self.assertEqual(work_acceptance.state, 'draft') + + def test_01_action_view_wa(self): + # Create Purchase Order + purchase_order = self.env['purchase.order'].create({ + 'partner_id': self.res_partner.id, + 'order_line': [ + (0, 0, {'product_id': self.service_product.id, + 'product_uom': self.service_product.uom_id.id, + 'name': self.service_product.name, + 'price_unit': self.service_product.standard_price, + 'date_planned': self.date_now, + 'product_qty': 42.0})]}) + purchase_order.button_confirm() + self.assertEqual(purchase_order.state, 'purchase') + + res = purchase_order.with_context(create_wa=True).action_view_wa() + ctx = res.get('context') + work_acceptance = Form(self.env['work.acceptance'].with_context(ctx)) + self.assertEqual(work_acceptance.state, 'draft') + + def test_02_flow_product(self): + # Create Purchase Order + purchase_order = self.env['purchase.order'].create({ + 'partner_id': self.res_partner.id, + 'order_line': [ + (0, 0, {'product_id': self.product_product.id, + 'product_uom': self.product_product.uom_id.id, + 'name': self.product_product.name, + 'price_unit': self.product_product.standard_price, + 'date_planned': self.date_now, + 'product_qty': 42.0})] + }) + purchase_order.button_confirm() + self.assertEqual(purchase_order.state, 'purchase') + self.assertEqual(purchase_order.picking_count, 1) + # Create Work Acceptance + work_acceptance = self.env['work.acceptance'].create({ + 'purchase_id': purchase_order.id, + 'partner_id': self.res_partner.id, + 'responsible_id': self.employee.id, + 'date_due': self.date_now, + 'date_receive': self.date_now, + 'company_id': self.env.ref('base.main_company').id, + 'wa_line_ids': [ + (0, 0, {'purchase_line_id': purchase_order.order_line[0].id, + 'product_id': purchase_order.order_line[0].product_id.id, + 'name': purchase_order.order_line[0].name, + 'price_unit': purchase_order.order_line[0].price_unit, + 'product_uom': purchase_order.order_line[0].product_uom.id, + 'product_qty': 42.0})] + }) + work_acceptance.button_accept() + self.assertEqual(work_acceptance.state, 'accept') + self.assertEqual(purchase_order.wa_count, 1) + # Received Products + picking = purchase_order.picking_ids[0] + self.assertEqual(len(picking.move_ids_without_package), 1) + picking.wa_id = work_acceptance + picking._onchange_wa_id() + + with self.assertRaises(ValidationError): + picking.move_ids_without_package[0].quantity_done = 30.0 + picking.button_validate() + picking.move_ids_without_package[0].quantity_done = 42.0 + picking.button_validate() + # Create Vendor Bill + invoice = self.env['account.invoice'].create({ + 'partner_id': self.res_partner.id, + 'purchase_id': purchase_order.id, + 'account_id': self.res_partner.property_account_payable_id.id, + 'type': 'in_invoice', + }) + invoice.purchase_order_change() + invoice.wa_id = work_acceptance + with self.assertRaises(ValidationError): + invoice.invoice_line_ids[0].quantity = 6.0 + invoice.action_invoice_open() + invoice.invoice_line_ids[0].quantity = 42.0 + invoice.action_invoice_open() + + def test_03_flow_service(self): + # Create Purchase Order + purchase_order = self.env['purchase.order'].create({ + 'partner_id': self.res_partner.id, + 'order_line': [ + (0, 0, {'product_id': self.service_product.id, + 'product_uom': self.service_product.uom_id.id, + 'name': self.service_product.name, + 'price_unit': self.service_product.standard_price, + 'date_planned': self.date_now, + 'product_qty': 30.0})] + }) + purchase_order.button_confirm() + self.assertEqual(purchase_order.state, 'purchase') + # Create Work Acceptance + work_acceptance = self.env['work.acceptance'].create({ + 'purchase_id': purchase_order.id, + 'partner_id': self.res_partner.id, + 'responsible_id': self.employee.id, + 'date_due': self.date_now, + 'date_receive': self.date_now, + 'company_id': self.env.ref('base.main_company').id, + 'wa_line_ids': [ + (0, 0, {'purchase_line_id': purchase_order.order_line[0].id, + 'product_id': purchase_order.order_line[0].product_id.id, + 'name': purchase_order.order_line[0].name, + 'price_unit': purchase_order.order_line[0].price_unit, + 'product_uom': purchase_order.order_line[0].product_uom.id, + 'product_qty': 30.0})] + }) + work_acceptance.button_accept() + self.assertEqual(work_acceptance.state, 'accept') + self.assertEqual(purchase_order.wa_count, 1) + # Create Vendor Bill + purchase_order.with_context(create_bill=True).action_view_invoice() + wizard = self.env['select.work.acceptance.wizard'].create({ + 'wa_id': work_acceptance.id, + }) + wizard.button_create_vendor_bill() + invoice = self.env['account.invoice'].create({ + 'partner_id': self.res_partner.id, + 'purchase_id': purchase_order.id, + 'account_id': self.res_partner.property_account_payable_id.id, + 'type': 'in_invoice', + }) + invoice.wa_id = work_acceptance + invoice.purchase_order_change() + self.assertEqual(invoice.state, 'draft') + invoice.action_invoice_open() diff --git a/purchase_work_acceptance/views/account_invoice_views.xml b/purchase_work_acceptance/views/account_invoice_views.xml new file mode 100644 index 00000000000..2ae663e94a0 --- /dev/null +++ b/purchase_work_acceptance/views/account_invoice_views.xml @@ -0,0 +1,22 @@ + + + + + account.invoice.supplier.form + account.invoice + + + + + + + + + + diff --git a/purchase_work_acceptance/views/purchase_views.xml b/purchase_work_acceptance/views/purchase_views.xml new file mode 100644 index 00000000000..fafc580ee81 --- /dev/null +++ b/purchase_work_acceptance/views/purchase_views.xml @@ -0,0 +1,37 @@ + + + + + purchase.order.form.inherit + purchase.order + + + + + + + + + + {'column_invisible': [('parent.state', 'not in', ('purchase', 'done'))], 'readonly': ['|', ('product_type', 'in', ('consu', 'product')), ('wa_line_ids', '!=', ())]} + + + + + diff --git a/purchase_work_acceptance/views/res_config_settings_views.xml b/purchase_work_acceptance/views/res_config_settings_views.xml new file mode 100644 index 00000000000..d9e977eab09 --- /dev/null +++ b/purchase_work_acceptance/views/res_config_settings_views.xml @@ -0,0 +1,44 @@ + + + + + res.config.settings.view.form.inherit.purchase + res.config.settings + + + + +

Work Acceptance

+
+
+
+ +
+
+
+
+
+
+
+
+ +
diff --git a/purchase_work_acceptance/views/stock_picking_views.xml b/purchase_work_acceptance/views/stock_picking_views.xml new file mode 100644 index 00000000000..397e30844e3 --- /dev/null +++ b/purchase_work_acceptance/views/stock_picking_views.xml @@ -0,0 +1,22 @@ + + + + + stock.picking.form + stock.picking + + + + + + + + + + diff --git a/purchase_work_acceptance/views/work_acceptance_views.xml b/purchase_work_acceptance/views/work_acceptance_views.xml new file mode 100644 index 00000000000..816b9b2a9e8 --- /dev/null +++ b/purchase_work_acceptance/views/work_acceptance_views.xml @@ -0,0 +1,137 @@ + + + + + work.acceptance.form + work.acceptance + +
+
+
+ +
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ +
+
+ + + work.acceptance.tree + work.acceptance + + + + + + + + + + + + + + + + + work.acceptance.search + work.acceptance + + + + + + + + + + + + + + + + + + + + + + + + + Work Acceptance + work.acceptance + form + tree,form + + + +

+ Create a new work acceptance +

+
+
+ + + +
diff --git a/purchase_work_acceptance/wizard/__init__.py b/purchase_work_acceptance/wizard/__init__.py new file mode 100644 index 00000000000..cec65a008ec --- /dev/null +++ b/purchase_work_acceptance/wizard/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import select_work_acceptance_wizard diff --git a/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py b/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py new file mode 100644 index 00000000000..0b3e0be2fa2 --- /dev/null +++ b/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py @@ -0,0 +1,41 @@ +# Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError + + +class SelectWorkAcceptanceWizard(models.TransientModel): + _name = 'select.work.acceptance.wizard' + _description = 'Select Work Acceptance Wizard' + + require_wa = fields.Boolean( + default=lambda self: self._get_require_wa(), + ) + wa_id = fields.Many2one( + comodel_name='work.acceptance', + string='Work Acceptance', + domain=lambda self: [ + ('state', '=', 'accept'), + ('purchase_id', '=', self._context.get('active_id'))] + ) + + def _get_require_wa(self): + return self.env.user.has_group( + 'purchase_work_acceptance.group_enforce_wa_on_invoice') + + @api.multi + def button_create_vendor_bill(self): + order = self.env['purchase.order'].browse(self._context.get('active_id')) + if any(invoice.wa_id == self.wa_id for invoice in order.invoice_ids): + raise ValidationError(_('%s was used in some bill.') % self.wa_id.name) + action = self.env.ref('account.action_vendor_bill_template') + result = action.read()[0] + result['context'] = { + 'type': 'in_invoice', + 'default_wa_id': self.wa_id.id, + 'default_purchase_id': self._context.get('active_id'), + } + res = self.env.ref('account.invoice_supplier_form', False) + result['views'] = [(res and res.id or False, 'form')] + return result diff --git a/purchase_work_acceptance/wizard/select_work_acceptance_wizard_views.xml b/purchase_work_acceptance/wizard/select_work_acceptance_wizard_views.xml new file mode 100644 index 00000000000..dc8650810fa --- /dev/null +++ b/purchase_work_acceptance/wizard/select_work_acceptance_wizard_views.xml @@ -0,0 +1,27 @@ + + + + + select_work_acceptance_wizard + select.work.acceptance.wizard + form + +
+ + + + +
+
+
+
+
+ +
From 7b00d279297891f01fe7145f3f1032194cc175d2 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Tue, 3 Dec 2019 15:45:23 +0000 Subject: [PATCH 002/210] [UPD] Update purchase_work_acceptance.pot --- .../i18n/purchase_work_acceptance.pot | 596 ++++++++++++++++++ 1 file changed, 596 insertions(+) create mode 100644 purchase_work_acceptance/i18n/purchase_work_acceptance.pot diff --git a/purchase_work_acceptance/i18n/purchase_work_acceptance.pot b/purchase_work_acceptance/i18n/purchase_work_acceptance.pot new file mode 100644 index 00000000000..623d962e1ce --- /dev/null +++ b/purchase_work_acceptance/i18n/purchase_work_acceptance.pot @@ -0,0 +1,596 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_work_acceptance +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: purchase_work_acceptance +#: code:addons/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py:31 +#, python-format +msgid "%s was used in some bill." +msgstr "" + +#. module: purchase_work_acceptance +#: code:addons/purchase_work_acceptance/models/stock_picking.py:34 +#, python-format +msgid "%s was used in some picking." +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_form +msgid "Accept" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_search +msgid "Accepte Date" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_search +#: selection:work.acceptance,state:0 +msgid "Accepted" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_search +msgid "Accepted By" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__date_accept +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__date_accept +msgid "Accepted Date" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__access_warning +msgid "Access warning" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__activity_ids +msgid "Activities" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__activity_state +msgid "Activity State" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_select_work_acceptance_wizard +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_form +msgid "Cancel" +msgstr "" + +#. module: purchase_work_acceptance +#: selection:work.acceptance,state:0 +msgid "Cancelled" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__company_id +msgid "Company" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model,name:purchase_work_acceptance.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_select_work_acceptance_wizard +msgid "Create Vendor Bill" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.purchase_order_form_inherit +msgid "Create WA" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.actions.act_window,help:purchase_work_acceptance.action_work_acceptance +msgid "Create a new work acceptance" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_select_work_acceptance_wizard__create_uid +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__create_uid +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__create_uid +msgid "Created by" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_select_work_acceptance_wizard__create_date +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__create_date +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__create_date +msgid "Created on" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__currency_id +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__currency_id +msgid "Currency" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,help:purchase_work_acceptance.field_work_acceptance__access_url +msgid "Customer Portal URL" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_form +msgid "Define your terms and conditions ..." +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__name +msgid "Description" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_select_work_acceptance_wizard__display_name +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__display_name +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__display_name +msgid "Display Name" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_search +#: selection:work.acceptance,state:0 +msgid "Draft" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__date_due +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__date_due +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_search +msgid "Due Date" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_res_config_settings__group_enable_wa_on_in +#: model:res.groups,name:purchase_work_acceptance.group_enable_wa_on_in +msgid "Enable WA on Goods Receipt" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_res_config_settings__group_enable_wa_on_po +#: model:res.groups,name:purchase_work_acceptance.group_enable_wa_on_po +msgid "Enable WA on Purchase Order" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_res_config_settings__group_enable_wa_on_invoice +#: model:res.groups,name:purchase_work_acceptance.group_enable_wa_on_invoice +msgid "Enable WA on Vendor Bill" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_res_config_settings__group_enforce_wa_on_in +#: model:res.groups,name:purchase_work_acceptance.group_enforce_wa_on_in +msgid "Enforce WA on Goods Receipt" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_res_config_settings__group_enforce_wa_on_invoice +#: model:res.groups,name:purchase_work_acceptance.group_enforce_wa_on_invoice +msgid "Enforce WA on Vendor Bill" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_channel_ids +msgid "Followers (Channels)" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_search +msgid "Group By" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_select_work_acceptance_wizard__id +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__id +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__id +msgid "ID" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,help:purchase_work_acceptance.field_work_acceptance__message_unread +msgid "If checked new messages require your attention." +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,help:purchase_work_acceptance.field_work_acceptance__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,help:purchase_work_acceptance.field_work_acceptance__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model,name:purchase_work_acceptance.model_account_invoice +msgid "Invoice" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__invoice_ref +msgid "Invoice Reference" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_select_work_acceptance_wizard____last_update +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance____last_update +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line____last_update +msgid "Last Modified on" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_select_work_acceptance_wizard__write_uid +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__write_uid +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_select_work_acceptance_wizard__write_date +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__write_date +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__write_date +msgid "Last Updated on" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_ids +msgid "Messages" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_search +msgid "My Work Acceptance" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__name +msgid "Name" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__activity_summary +msgid "Next Activity Summary" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__activity_type_id +msgid "Next Activity Type" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__notes +msgid "Notes" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_has_error_counter +msgid "Number of error" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,help:purchase_work_acceptance.field_work_acceptance__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,help:purchase_work_acceptance.field_work_acceptance__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,help:purchase_work_acceptance.field_work_acceptance__message_unread_counter +msgid "Number of unread messages" +msgstr "" + +#. module: purchase_work_acceptance +#: selection:work.acceptance,activity_state:0 +msgid "Overdue" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__partner_id +msgid "Partner" +msgstr "" + +#. module: purchase_work_acceptance +#: selection:work.acceptance,activity_state:0 +msgid "Planned" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__access_url +msgid "Portal Access URL" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__product_id +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__product_id +msgid "Product" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__product_uom +msgid "Product Unit of Measure" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_form +msgid "Products" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model,name:purchase_work_acceptance.model_purchase_order +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__purchase_id +msgid "Purchase Order" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model,name:purchase_work_acceptance.model_purchase_order_line +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__purchase_line_id +msgid "Purchase Order Line" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__product_qty +msgid "Quantity" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_search +msgid "Receive Date" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__date_receive +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__date_receive +msgid "Received Date" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_search +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_tree +msgid "Reference" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_account_invoice__require_wa +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_select_work_acceptance_wizard__require_wa +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_stock_picking__require_wa +msgid "Require Wa" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__responsible_id +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__responsible_id +msgid "Responsible Person" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__activity_user_id +msgid "Responsible User" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__access_token +msgid "Security Token" +msgstr "" + +#. module: purchase_work_acceptance +#: code:addons/purchase_work_acceptance/models/purchase.py:71 +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_select_work_acceptance_wizard +#, python-format +msgid "Select Work Acceptance" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model,name:purchase_work_acceptance.model_select_work_acceptance_wizard +msgid "Select Work Acceptance Wizard" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_form +msgid "Set to draft" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__state +msgid "Status" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,help:purchase_work_acceptance.field_work_acceptance__activity_state +msgid "Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__price_subtotal +msgid "Subtotal" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,help:purchase_work_acceptance.field_account_invoice__wa_id +msgid "To control quantity and unit price of the vendor bill, to be according to the quantity and unit price of the work acceptance." +msgstr "" + +#. module: purchase_work_acceptance +#: selection:work.acceptance,activity_state:0 +msgid "Today" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_form +msgid "Total" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model,name:purchase_work_acceptance.model_stock_picking +msgid "Transfer" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__price_unit +msgid "Unit Price" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_unread +msgid "Unread Messages" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__message_unread_counter +msgid "Unread Messages Counter" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__partner_id +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_search +msgid "Vendor" +msgstr "" + +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.purchase_order_form_inherit +msgid "WA" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_purchase_order__wa_line_ids +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_purchase_order_line__wa_line_ids +msgid "WA Lines" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_account_invoice__wa_id +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_stock_picking__wa_id +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__wa_id +msgid "WA Reference" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_purchase_order__wa_count +msgid "WA count" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__website_message_ids +msgid "Website Messages" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,help:purchase_work_acceptance.field_work_acceptance__website_message_ids +msgid "Website communication history" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.actions.act_window,name:purchase_work_acceptance.action_work_acceptance +#: model:ir.model,name:purchase_work_acceptance.model_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_select_work_acceptance_wizard__wa_id +#: model:ir.ui.menu,name:purchase_work_acceptance.menu_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.res_config_settings_view_form_purchase +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_form +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_search +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_tree +msgid "Work Acceptance" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model,name:purchase_work_acceptance.model_work_acceptance_line +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_form +msgid "Work Acceptance Line" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__wa_line_ids +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_work_acceptance_form +msgid "Work Acceptance Lines" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance__user_id +msgid "Work Acceptance Representative" +msgstr "" + +#. module: purchase_work_acceptance +#: model:ir.model.fields,field_description:purchase_work_acceptance.field_purchase_order__wa_ids +msgid "Work Acceptances" +msgstr "" + +#. module: purchase_work_acceptance +#: code:addons/purchase_work_acceptance/models/account_invoice.py:72 +#, python-format +msgid "You cannot validate a bill if Quantity not equal accepted quantity" +msgstr "" + +#. module: purchase_work_acceptance +#: code:addons/purchase_work_acceptance/models/stock_picking.py:57 +#, python-format +msgid "You cannot validate a transfer if done quantity not equal accepted quantity" +msgstr "" + From b0ceaecb32af18ab612f983cae9308bea9a71d34 Mon Sep 17 00:00:00 2001 From: ps-tubtim Date: Mon, 9 Mar 2020 15:55:30 +0700 Subject: [PATCH 003/210] [IMP] purchase_work_acceptance: black, isort --- purchase_work_acceptance/__manifest__.py | 45 ++- .../models/account_invoice.py | 47 +-- purchase_work_acceptance/models/purchase.py | 110 +++---- .../models/res_config_settings.py | 12 +- .../models/stock_picking.py | 52 ++-- .../models/work_acceptance.py | 190 +++++-------- .../tests/test_purchase_work_acceptance.py | 268 +++++++++++------- .../wizard/select_work_acceptance_wizard.py | 40 +-- 8 files changed, 402 insertions(+), 362 deletions(-) diff --git a/purchase_work_acceptance/__manifest__.py b/purchase_work_acceptance/__manifest__.py index 1855029b2d0..bbb2e5ae961 100644 --- a/purchase_work_acceptance/__manifest__.py +++ b/purchase_work_acceptance/__manifest__.py @@ -2,30 +2,25 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': 'Purchase Work Acceptance', - 'version': '12.0.1.0.0', - 'category': 'Purchase Management', - 'author': 'Ecosoft, ' - 'Odoo Community Association (OCA)', - 'license': 'AGPL-3', - 'website': 'https://github.com/OCA/purchase-workflow', - 'depends': [ - 'purchase_stock', + "name": "Purchase Work Acceptance", + "version": "13.0.1.0.0", + "category": "Purchase Management", + "author": "Ecosoft, " "Odoo Community Association (OCA)", + "license": "AGPL-3", + "website": "https://github.com/OCA/purchase-workflow", + "depends": ["purchase_stock"], + "data": [ + "data/work_acceptance_sequence.xml", + "security/ir.model.access.csv", + "security/security.xml", + "views/account_invoice_views.xml", + "views/purchase_views.xml", + "views/res_config_settings_views.xml", + "views/stock_picking_views.xml", + "views/work_acceptance_views.xml", + "wizard/select_work_acceptance_wizard_views.xml", ], - 'data': [ - 'data/work_acceptance_sequence.xml', - 'security/ir.model.access.csv', - 'security/security.xml', - 'views/account_invoice_views.xml', - 'views/purchase_views.xml', - 'views/res_config_settings_views.xml', - 'views/stock_picking_views.xml', - 'views/work_acceptance_views.xml', - 'wizard/select_work_acceptance_wizard_views.xml', - ], - 'maintainer': [ - 'ps-tubtim', - ], - 'installable': True, - 'development_status': 'Alpha', + "maintainer": ["ps-tubtim"], + "installable": True, + "development_status": "Alpha", } diff --git a/purchase_work_acceptance/models/account_invoice.py b/purchase_work_acceptance/models/account_invoice.py index 52ee9b2fef2..7988398e1a5 100644 --- a/purchase_work_acceptance/models/account_invoice.py +++ b/purchase_work_acceptance/models/account_invoice.py @@ -1,42 +1,41 @@ # Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError class AccountInvoice(models.Model): - _inherit = 'account.invoice' + _inherit = "account.invoice" - require_wa = fields.Boolean( - compute='_compute_require_wa', - ) + require_wa = fields.Boolean(compute="_compute_require_wa") wa_id = fields.Many2one( - comodel_name='work.acceptance', - string='WA Reference', + comodel_name="work.acceptance", + string="WA Reference", copy=False, domain=lambda self: [ - ('state', '=', 'accept'), - ('purchase_id', '=', self._context.get('active_id'))], - help='To control quantity and unit price of the vendor bill, to be ' - 'according to the quantity and unit price of the work acceptance.', + ("state", "=", "accept"), + ("purchase_id", "=", self._context.get("active_id")), + ], + help="To control quantity and unit price of the vendor bill, to be " + "according to the quantity and unit price of the work acceptance.", ) @api.multi def _compute_require_wa(self): self.require_wa = self.env.user.has_group( - 'purchase_work_acceptance.group_enforce_wa_on_invoice') + "purchase_work_acceptance.group_enforce_wa_on_invoice" + ) def _prepare_invoice_line_from_po_line(self, line): res = super()._prepare_invoice_line_from_po_line(line) - wa_line = self.wa_id.wa_line_ids.filtered( - lambda l: l.purchase_line_id == line) + wa_line = self.wa_id.wa_line_ids.filtered(lambda l: l.purchase_line_id == line) if wa_line: - res['quantity'] = wa_line.product_qty - res['uom_id'] = wa_line.product_uom + res["quantity"] = wa_line.product_qty + res["uom_id"] = wa_line.product_uom return res - @api.onchange('purchase_id') + @api.onchange("purchase_id") def purchase_order_change(self): res = super().purchase_order_change() if self.wa_id: @@ -51,7 +50,8 @@ def action_invoice_open(self): wa_line = {} for line in rec.wa_id.wa_line_ids: qty = line.product_uom._compute_quantity( - line.product_qty, line.product_id.uom_id) + line.product_qty, line.product_id.uom_id + ) if qty > 0.0: if line.product_id.id in wa_line.keys(): qty_old = wa_line[line.product_id.id] @@ -61,7 +61,8 @@ def action_invoice_open(self): invoice_line = {} for line in rec.invoice_line_ids: qty = line.uom_id._compute_quantity( - line.quantity, line.product_id.uom_id) + line.quantity, line.product_id.uom_id + ) if qty > 0.0: if line.product_id.id in invoice_line.keys(): qty_old = invoice_line[line.product_id.id] @@ -69,6 +70,10 @@ def action_invoice_open(self): else: invoice_line[line.product_id.id] = qty if wa_line != invoice_line: - raise ValidationError(_('You cannot validate a bill if ' - 'Quantity not equal accepted quantity')) + raise ValidationError( + _( + "You cannot validate a bill if " + "Quantity not equal accepted quantity" + ) + ) return super().action_invoice_open() diff --git a/purchase_work_acceptance/models/purchase.py b/purchase_work_acceptance/models/purchase.py index dd2d6b6ebfb..22a69507957 100644 --- a/purchase_work_acceptance/models/purchase.py +++ b/purchase_work_acceptance/models/purchase.py @@ -1,96 +1,106 @@ # Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models class PurchaseOrder(models.Model): - _inherit = 'purchase.order' + _inherit = "purchase.order" - wa_count = fields.Integer( - compute='_compute_wa_ids', - string='WA count', - default=0, - ) + wa_count = fields.Integer(compute="_compute_wa_ids", string="WA count", default=0) wa_ids = fields.One2many( - comodel_name='work.acceptance', - compute='_compute_wa_ids', - string='Work Acceptances', + comodel_name="work.acceptance", + compute="_compute_wa_ids", + string="Work Acceptances", ) wa_line_ids = fields.One2many( - comodel_name='work.acceptance.line', - inverse_name='purchase_line_id', + comodel_name="work.acceptance.line", + inverse_name="purchase_line_id", string="WA Lines", readonly=True, ) def _compute_wa_ids(self): for order in self: - order.wa_ids = \ - order.mapped('order_line').mapped('wa_line_ids').mapped('wa_id') + order.wa_ids = ( + order.mapped("order_line").mapped("wa_line_ids").mapped("wa_id") + ) order.wa_count = len(order.wa_ids) @api.multi def action_view_wa(self): self.ensure_one() - act = self.env.ref('purchase_work_acceptance.action_work_acceptance') + act = self.env.ref("purchase_work_acceptance.action_work_acceptance") result = act.read()[0] - create_wa = self.env.context.get('create_wa', False) - result['context'] = { - 'default_purchase_id': self.id, - 'default_partner_id': self.partner_id.id, - 'default_company_id': self.company_id.id, - 'default_currency_id': self.currency_id.id, - 'default_date_due': self.date_planned, - 'default_wa_line_ids': [(0, 0, { - 'purchase_line_id': line.id, - 'name': line.name, - 'product_uom': line.product_uom.id, - 'product_id': line.product_id.id, - 'price_unit': line.price_unit, - 'product_qty': line._get_product_qty(), - }) for line in self.order_line if line._get_product_qty() != 0], + create_wa = self.env.context.get("create_wa", False) + result["context"] = { + "default_purchase_id": self.id, + "default_partner_id": self.partner_id.id, + "default_company_id": self.company_id.id, + "default_currency_id": self.currency_id.id, + "default_date_due": self.date_planned, + "default_wa_line_ids": [ + ( + 0, + 0, + { + "purchase_line_id": line.id, + "name": line.name, + "product_uom": line.product_uom.id, + "product_id": line.product_id.id, + "price_unit": line.price_unit, + "product_qty": line._get_product_qty(), + }, + ) + for line in self.order_line + if line._get_product_qty() != 0 + ], } if len(self.wa_ids) > 1 and not create_wa: - result['domain'] = "[('id', 'in', " + str(self.wa_ids.ids) + ")]" + result["domain"] = "[('id', 'in', " + str(self.wa_ids.ids) + ")]" else: res = self.env.ref( - 'purchase_work_acceptance.view_work_acceptance_form', False) - result['views'] = [(res and res.id or False, 'form')] + "purchase_work_acceptance.view_work_acceptance_form", False + ) + result["views"] = [(res and res.id or False, "form")] if not create_wa: - result['res_id'] = self.wa_ids.id or False + result["res_id"] = self.wa_ids.id or False return result @api.multi def action_view_invoice(self): - if self.env.context.get('create_bill', False) and self.env.user.has_group( - 'purchase_work_acceptance.group_enable_wa_on_invoice'): + if self.env.context.get("create_bill", False) and self.env.user.has_group( + "purchase_work_acceptance.group_enable_wa_on_invoice" + ): wizard = self.env.ref( - 'purchase_work_acceptance.view_select_work_acceptance_wizard') + "purchase_work_acceptance.view_select_work_acceptance_wizard" + ) return { - 'name': _('Select Work Acceptance'), - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'select.work.acceptance.wizard', - 'views': [(wizard.id, 'form')], - 'view_id': wizard.id, - 'target': 'new', + "name": _("Select Work Acceptance"), + "type": "ir.actions.act_window", + "view_type": "form", + "view_mode": "form", + "res_model": "select.work.acceptance.wizard", + "views": [(wizard.id, "form")], + "view_id": wizard.id, + "target": "new", } return super(PurchaseOrder, self).action_view_invoice() class PurchaseOrderLine(models.Model): - _inherit = 'purchase.order.line' + _inherit = "purchase.order.line" wa_line_ids = fields.One2many( - comodel_name='work.acceptance.line', - inverse_name='purchase_line_id', + comodel_name="work.acceptance.line", + inverse_name="purchase_line_id", string="WA Lines", readonly=True, ) def _get_product_qty(self): return self.product_qty - sum( - wa_line.product_qty for wa_line in self.wa_line_ids - if wa_line.wa_id.state != 'cancel') + wa_line.product_qty + for wa_line in self.wa_line_ids + if wa_line.wa_id.state != "cancel" + ) diff --git a/purchase_work_acceptance/models/res_config_settings.py b/purchase_work_acceptance/models/res_config_settings.py index e8814a1f213..3320f9e8f87 100644 --- a/purchase_work_acceptance/models/res_config_settings.py +++ b/purchase_work_acceptance/models/res_config_settings.py @@ -5,25 +5,25 @@ class ResConfigSettings(models.TransientModel): - _inherit = 'res.config.settings' + _inherit = "res.config.settings" group_enable_wa_on_po = fields.Boolean( string="Enable WA on Purchase Order", - implied_group='purchase_work_acceptance.group_enable_wa_on_po', + implied_group="purchase_work_acceptance.group_enable_wa_on_po", ) group_enable_wa_on_in = fields.Boolean( string="Enable WA on Goods Receipt", - implied_group='purchase_work_acceptance.group_enable_wa_on_in', + implied_group="purchase_work_acceptance.group_enable_wa_on_in", ) group_enforce_wa_on_in = fields.Boolean( string="Enforce WA on Goods Receipt", - implied_group='purchase_work_acceptance.group_enforce_wa_on_in', + implied_group="purchase_work_acceptance.group_enforce_wa_on_in", ) group_enable_wa_on_invoice = fields.Boolean( string="Enable WA on Vendor Bill", - implied_group='purchase_work_acceptance.group_enable_wa_on_invoice', + implied_group="purchase_work_acceptance.group_enable_wa_on_invoice", ) group_enforce_wa_on_invoice = fields.Boolean( string="Enforce WA on Vendor Bill", - implied_group='purchase_work_acceptance.group_enforce_wa_on_invoice', + implied_group="purchase_work_acceptance.group_enforce_wa_on_invoice", ) diff --git a/purchase_work_acceptance/models/stock_picking.py b/purchase_work_acceptance/models/stock_picking.py index f729f9c06f3..2b4b0d0d406 100644 --- a/purchase_work_acceptance/models/stock_picking.py +++ b/purchase_work_acceptance/models/stock_picking.py @@ -1,43 +1,47 @@ # Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError class Picking(models.Model): _inherit = "stock.picking" - require_wa = fields.Boolean( - compute='_compute_require_wa', - ) + require_wa = fields.Boolean(compute="_compute_require_wa") wa_id = fields.Many2one( - comodel_name='work.acceptance', - string='WA Reference', + comodel_name="work.acceptance", + string="WA Reference", copy=False, domain=lambda self: [ - ('state', '=', 'accept'), - ('purchase_id', '=', self._context.get('active_id'))], + ("state", "=", "accept"), + ("purchase_id", "=", self._context.get("active_id")), + ], ) @api.multi def _compute_require_wa(self): self.require_wa = self.env.user.has_group( - 'purchase_work_acceptance.group_enforce_wa_on_in') + "purchase_work_acceptance.group_enforce_wa_on_in" + ) @api.multi def button_validate(self): if self.wa_id: - order = self.env['purchase.order'].browse(self._context.get('active_id')) - if any(picking.wa_id == self.wa_id and picking != self - for picking in order.picking_ids): - raise ValidationError(_( - '%s was used in some picking.') % self.wa_id.name) + order = self.env["purchase.order"].browse(self._context.get("active_id")) + if any( + picking.wa_id == self.wa_id and picking != self + for picking in order.picking_ids + ): + raise ValidationError( + _("%s was used in some picking.") % self.wa_id.name + ) wa_line = {} for line in self.wa_id.wa_line_ids: qty = line.product_uom._compute_quantity( - line.product_qty, line.product_id.uom_id) - if qty > 0.0 and line.product_id.type in ['product', 'consu']: + line.product_qty, line.product_id.uom_id + ) + if qty > 0.0 and line.product_id.type in ["product", "consu"]: if line.product_id.id in wa_line.keys(): qty_old = wa_line[line.product_id.id] wa_line[line.product_id.id] = qty_old + qty @@ -46,7 +50,8 @@ def button_validate(self): move_line = {} for move in self.move_ids_without_package: qty = move.product_uom._compute_quantity( - move.quantity_done, line.product_id.uom_id) + move.quantity_done, line.product_id.uom_id + ) if qty > 0.0: if move.product_id.id in move_line.keys(): qty_old = move_line[move.product_id.id] @@ -54,17 +59,22 @@ def button_validate(self): else: move_line[move.product_id.id] = qty if wa_line != move_line: - raise ValidationError(_('You cannot validate a transfer if done' - ' quantity not equal accepted quantity')) + raise ValidationError( + _( + "You cannot validate a transfer if done" + " quantity not equal accepted quantity" + ) + ) return super(Picking, self).button_validate() - @api.onchange('wa_id') + @api.onchange("wa_id") def _onchange_wa_id(self): if self.wa_id: wa_line = {} for line in self.wa_id.wa_line_ids: qty = line.product_uom._compute_quantity( - line.product_qty, line.product_id.uom_id) + line.product_qty, line.product_id.uom_id + ) if line.product_id.id in wa_line.keys(): qty_old = wa_line[line.product_id.id] wa_line[line.product_id.id] = qty_old + qty diff --git a/purchase_work_acceptance/models/work_acceptance.py b/purchase_work_acceptance/models/work_acceptance.py index 433f3b9b34c..ca4a2375131 100644 --- a/purchase_work_acceptance/models/work_acceptance.py +++ b/purchase_work_acceptance/models/work_acceptance.py @@ -5,116 +5,100 @@ class WorkAcceptance(models.Model): - _name = 'work.acceptance' - _inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin'] - _description = 'Work Acceptance' - _order = 'id desc' + _name = "work.acceptance" + _inherit = ["mail.thread", "mail.activity.mixin", "portal.mixin"] + _description = "Work Acceptance" + _order = "id desc" - name = fields.Char( - required=True, - index=True, - copy=False, - default='New' - ) + name = fields.Char(required=True, index=True, copy=False, default="New") date_due = fields.Datetime( - string='Due Date', + string="Due Date", required=True, readonly=True, - states={'draft': [('readonly', False)]}, + states={"draft": [("readonly", False)]}, ) date_receive = fields.Datetime( - string='Received Date', + string="Received Date", default=fields.Datetime.now, required=True, readonly=True, - states={'draft': [('readonly', False)]}, - ) - date_accept = fields.Datetime( - string='Accepted Date', - readonly=True, - ) - invoice_ref = fields.Char( - string='Invoice Reference', - copy=False, + states={"draft": [("readonly", False)]}, ) + date_accept = fields.Datetime(string="Accepted Date", readonly=True) + invoice_ref = fields.Char(string="Invoice Reference", copy=False) partner_id = fields.Many2one( - comodel_name='res.partner', - string='Vendor', + comodel_name="res.partner", + string="Vendor", required=True, change_default=True, - track_visibility='always', + track_visibility="always", readonly=True, - states={'draft': [('readonly', False)]}, + states={"draft": [("readonly", False)]}, ) responsible_id = fields.Many2one( - comodel_name='res.users', - string='Responsible Person', + comodel_name="res.users", + string="Responsible Person", default=lambda self: self.env.user, required=True, change_default=True, - track_visibility='always', + track_visibility="always", readonly=True, - states={'draft': [('readonly', False)]}, + states={"draft": [("readonly", False)]}, ) currency_id = fields.Many2one( - comodel_name='res.currency', - string='Currency', + comodel_name="res.currency", + string="Currency", default=lambda self: self.env.user.company_id.currency_id.id, required=True, readonly=True, ) state = fields.Selection( - [('draft', 'Draft'), - ('accept', 'Accepted'), - ('cancel', 'Cancelled')], - string='Status', + [("draft", "Draft"), ("accept", "Accepted"), ("cancel", "Cancelled")], + string="Status", readonly=True, index=True, copy=False, - default='draft', - track_visibility='onchange' + default="draft", + track_visibility="onchange", ) wa_line_ids = fields.One2many( - comodel_name='work.acceptance.line', - inverse_name='wa_id', - string='Work Acceptance Lines', - ) - notes = fields.Text( - string='Notes', + comodel_name="work.acceptance.line", + inverse_name="wa_id", + string="Work Acceptance Lines", ) + notes = fields.Text(string="Notes") product_id = fields.Many2one( - comodel_name='product.product', - related='wa_line_ids.product_id', - string='Product', + comodel_name="product.product", + related="wa_line_ids.product_id", + string="Product", readonly=False, ) user_id = fields.Many2one( - comodel_name='res.users', - string='Work Acceptance Representative', + comodel_name="res.users", + string="Work Acceptance Representative", default=lambda self: self.env.user, index=True, - track_visibility='onchange', + track_visibility="onchange", ) company_id = fields.Many2one( - comodel_name='res.company', - string='Company', + comodel_name="res.company", + string="Company", default=lambda self: self.env.user.company_id.id, required=True, index=True, readonly=True, - states={'draft': [('readonly', False)]}, + states={"draft": [("readonly", False)]}, ) purchase_id = fields.Many2one( - comodel_name='purchase.order', - string='Purchase Order', - readonly=True, + comodel_name="purchase.order", string="Purchase Order", readonly=True ) @api.model def create(self, vals): - if vals.get('name', 'New') == 'New': - vals['name'] = self.env['ir.sequence'].next_by_code( - 'work.acceptance') or '/' + if vals.get("name", "New") == "New": + vals["name"] = ( + self.env["ir.sequence"].next_by_code("work.acceptance") or "/" + ) return super(WorkAcceptance, self).create(vals) @api.multi @@ -122,99 +106,77 @@ def button_accept(self, force=False): self._unlink_zero_quantity() po_lines = self.purchase_id.order_line for po_line in po_lines: - if po_line.product_id.type not in ['product', 'consu']: + if po_line.product_id.type not in ["product", "consu"]: po_line.qty_received = self.wa_line_ids.filtered( - lambda l: l.purchase_line_id == po_line).product_qty - self.write({'state': 'accept', 'date_accept': fields.Datetime.now()}) + lambda l: l.purchase_line_id == po_line + ).product_qty + self.write({"state": "accept", "date_accept": fields.Datetime.now()}) @api.multi def button_draft(self): - self.write({'state': 'draft'}) + self.write({"state": "draft"}) @api.multi def button_cancel(self): - self.write({'state': 'cancel'}) + self.write({"state": "cancel"}) def _unlink_zero_quantity(self): wa_line_zero_quantity = self.wa_line_ids.filtered( - lambda l: l.product_qty == 0.0) + lambda l: l.product_qty == 0.0 + ) wa_line_zero_quantity.unlink() class WorkAcceptanceLine(models.Model): - _name = 'work.acceptance.line' - _description = 'Work Acceptance Line' - _order = 'id' + _name = "work.acceptance.line" + _description = "Work Acceptance Line" + _order = "id" - name = fields.Text( - string='Description', - required=True - ) - product_qty = fields.Float( - string='Quantity', - required=True, - ) + name = fields.Text(string="Description", required=True) + product_qty = fields.Float(string="Quantity", required=True) product_id = fields.Many2one( - comodel_name='product.product', - string='Product', - required=True, + comodel_name="product.product", string="Product", required=True ) product_uom = fields.Many2one( - comodel_name='uom.uom', - string='Product Unit of Measure', - required=True, - ) - price_unit = fields.Float( - string='Unit Price', - required=True, - ) - price_subtotal = fields.Monetary( - compute='_compute_amount', - string='Subtotal', + comodel_name="uom.uom", string="Product Unit of Measure", required=True ) + price_unit = fields.Float(string="Unit Price", required=True) + price_subtotal = fields.Monetary(compute="_compute_amount", string="Subtotal") wa_id = fields.Many2one( - comodel_name='work.acceptance', - string='WA Reference', + comodel_name="work.acceptance", + string="WA Reference", index=True, required=True, - ondelete='cascade' + ondelete="cascade", ) partner_id = fields.Many2one( - comodel_name='res.partner', - related='wa_id.partner_id', - string='Partner', + comodel_name="res.partner", + related="wa_id.partner_id", + string="Partner", readonly=True, ) responsible_id = fields.Many2one( - comodel_name='res.users', - related='wa_id.responsible_id', - string='Responsible Person', + comodel_name="res.users", + related="wa_id.responsible_id", + string="Responsible Person", readonly=True, ) currency_id = fields.Many2one( - related='wa_id.currency_id', - string='Currency', - readonly=True, + related="wa_id.currency_id", string="Currency", readonly=True ) date_due = fields.Datetime( - related='wa_id.date_due', - string='Due Date', - readonly=True, + related="wa_id.date_due", string="Due Date", readonly=True ) date_receive = fields.Datetime( - related='wa_id.date_receive', - string='Received Date', - readonly=True, + related="wa_id.date_receive", string="Received Date", readonly=True ) date_accept = fields.Datetime( - related='wa_id.date_accept', - string='Accepted Date', - readonly=True, + related="wa_id.date_accept", string="Accepted Date", readonly=True ) purchase_line_id = fields.Many2one( - comodel_name='purchase.order.line', - string='Purchase Order Line', - ondelete='set null', + comodel_name="purchase.order.line", + string="Purchase Order Line", + ondelete="set null", index=True, readonly=True, ) diff --git a/purchase_work_acceptance/tests/test_purchase_work_acceptance.py b/purchase_work_acceptance/tests/test_purchase_work_acceptance.py index 992452658d5..4610903ae99 100644 --- a/purchase_work_acceptance/tests/test_purchase_work_acceptance.py +++ b/purchase_work_acceptance/tests/test_purchase_work_acceptance.py @@ -3,96 +3,132 @@ from odoo import fields from odoo.exceptions import ValidationError -from odoo.tests.common import TransactionCase, Form +from odoo.tests.common import Form, TransactionCase class TestPurchaseWorkAcceptance(TransactionCase): def setUp(self): super(TestPurchaseWorkAcceptance, self).setUp() # Create Product - self.service_product = self.env.ref('product.product_product_1') - self.product_product = self.env.ref('product.product_product_6') + self.service_product = self.env.ref("product.product_product_1") + self.product_product = self.env.ref("product.product_product_6") # Create Vendor - self.res_partner = self.env.ref('base.res_partner_3') + self.res_partner = self.env.ref("base.res_partner_3") # Create Employee - self.employee = self.env.ref('base.user_demo') + self.employee = self.env.ref("base.user_demo") # Create Date self.date_now = fields.Datetime.now() def test_00_wa_button(self): - work_acceptance = self.env['work.acceptance'].create({ - 'partner_id': self.res_partner.id, - 'responsible_id': self.employee.id, - 'date_due': self.date_now, - 'date_receive': self.date_now, - 'company_id': self.env.ref('base.main_company').id, - 'wa_line_ids': [ - (0, 0, {'product_id': self.service_product.id, - 'name': self.service_product.name, - 'price_unit': self.service_product.standard_price, - 'product_qty': 3.0, - 'product_uom': self.service_product.uom_id.id, - })] - }) + work_acceptance = self.env["work.acceptance"].create( + { + "partner_id": self.res_partner.id, + "responsible_id": self.employee.id, + "date_due": self.date_now, + "date_receive": self.date_now, + "company_id": self.env.ref("base.main_company").id, + "wa_line_ids": [ + ( + 0, + 0, + { + "product_id": self.service_product.id, + "name": self.service_product.name, + "price_unit": self.service_product.standard_price, + "product_qty": 3.0, + "product_uom": self.service_product.uom_id.id, + }, + ) + ], + } + ) work_acceptance.button_accept() - self.assertEqual(work_acceptance.state, 'accept') + self.assertEqual(work_acceptance.state, "accept") work_acceptance.button_cancel() - self.assertEqual(work_acceptance.state, 'cancel') + self.assertEqual(work_acceptance.state, "cancel") work_acceptance.button_draft() - self.assertEqual(work_acceptance.state, 'draft') + self.assertEqual(work_acceptance.state, "draft") def test_01_action_view_wa(self): # Create Purchase Order - purchase_order = self.env['purchase.order'].create({ - 'partner_id': self.res_partner.id, - 'order_line': [ - (0, 0, {'product_id': self.service_product.id, - 'product_uom': self.service_product.uom_id.id, - 'name': self.service_product.name, - 'price_unit': self.service_product.standard_price, - 'date_planned': self.date_now, - 'product_qty': 42.0})]}) + purchase_order = self.env["purchase.order"].create( + { + "partner_id": self.res_partner.id, + "order_line": [ + ( + 0, + 0, + { + "product_id": self.service_product.id, + "product_uom": self.service_product.uom_id.id, + "name": self.service_product.name, + "price_unit": self.service_product.standard_price, + "date_planned": self.date_now, + "product_qty": 42.0, + }, + ) + ], + } + ) purchase_order.button_confirm() - self.assertEqual(purchase_order.state, 'purchase') + self.assertEqual(purchase_order.state, "purchase") res = purchase_order.with_context(create_wa=True).action_view_wa() - ctx = res.get('context') - work_acceptance = Form(self.env['work.acceptance'].with_context(ctx)) - self.assertEqual(work_acceptance.state, 'draft') + ctx = res.get("context") + work_acceptance = Form(self.env["work.acceptance"].with_context(ctx)) + self.assertEqual(work_acceptance.state, "draft") def test_02_flow_product(self): # Create Purchase Order - purchase_order = self.env['purchase.order'].create({ - 'partner_id': self.res_partner.id, - 'order_line': [ - (0, 0, {'product_id': self.product_product.id, - 'product_uom': self.product_product.uom_id.id, - 'name': self.product_product.name, - 'price_unit': self.product_product.standard_price, - 'date_planned': self.date_now, - 'product_qty': 42.0})] - }) + purchase_order = self.env["purchase.order"].create( + { + "partner_id": self.res_partner.id, + "order_line": [ + ( + 0, + 0, + { + "product_id": self.product_product.id, + "product_uom": self.product_product.uom_id.id, + "name": self.product_product.name, + "price_unit": self.product_product.standard_price, + "date_planned": self.date_now, + "product_qty": 42.0, + }, + ) + ], + } + ) purchase_order.button_confirm() - self.assertEqual(purchase_order.state, 'purchase') + self.assertEqual(purchase_order.state, "purchase") self.assertEqual(purchase_order.picking_count, 1) # Create Work Acceptance - work_acceptance = self.env['work.acceptance'].create({ - 'purchase_id': purchase_order.id, - 'partner_id': self.res_partner.id, - 'responsible_id': self.employee.id, - 'date_due': self.date_now, - 'date_receive': self.date_now, - 'company_id': self.env.ref('base.main_company').id, - 'wa_line_ids': [ - (0, 0, {'purchase_line_id': purchase_order.order_line[0].id, - 'product_id': purchase_order.order_line[0].product_id.id, - 'name': purchase_order.order_line[0].name, - 'price_unit': purchase_order.order_line[0].price_unit, - 'product_uom': purchase_order.order_line[0].product_uom.id, - 'product_qty': 42.0})] - }) + work_acceptance = self.env["work.acceptance"].create( + { + "purchase_id": purchase_order.id, + "partner_id": self.res_partner.id, + "responsible_id": self.employee.id, + "date_due": self.date_now, + "date_receive": self.date_now, + "company_id": self.env.ref("base.main_company").id, + "wa_line_ids": [ + ( + 0, + 0, + { + "purchase_line_id": purchase_order.order_line[0].id, + "product_id": purchase_order.order_line[0].product_id.id, + "name": purchase_order.order_line[0].name, + "price_unit": purchase_order.order_line[0].price_unit, + "product_uom": purchase_order.order_line[0].product_uom.id, + "product_qty": 42.0, + }, + ) + ], + } + ) work_acceptance.button_accept() - self.assertEqual(work_acceptance.state, 'accept') + self.assertEqual(work_acceptance.state, "accept") self.assertEqual(purchase_order.wa_count, 1) # Received Products picking = purchase_order.picking_ids[0] @@ -106,12 +142,14 @@ def test_02_flow_product(self): picking.move_ids_without_package[0].quantity_done = 42.0 picking.button_validate() # Create Vendor Bill - invoice = self.env['account.invoice'].create({ - 'partner_id': self.res_partner.id, - 'purchase_id': purchase_order.id, - 'account_id': self.res_partner.property_account_payable_id.id, - 'type': 'in_invoice', - }) + invoice = self.env["account.invoice"].create( + { + "partner_id": self.res_partner.id, + "purchase_id": purchase_order.id, + "account_id": self.res_partner.property_account_payable_id.id, + "type": "in_invoice", + } + ) invoice.purchase_order_change() invoice.wa_id = work_acceptance with self.assertRaises(ValidationError): @@ -122,50 +160,70 @@ def test_02_flow_product(self): def test_03_flow_service(self): # Create Purchase Order - purchase_order = self.env['purchase.order'].create({ - 'partner_id': self.res_partner.id, - 'order_line': [ - (0, 0, {'product_id': self.service_product.id, - 'product_uom': self.service_product.uom_id.id, - 'name': self.service_product.name, - 'price_unit': self.service_product.standard_price, - 'date_planned': self.date_now, - 'product_qty': 30.0})] - }) + purchase_order = self.env["purchase.order"].create( + { + "partner_id": self.res_partner.id, + "order_line": [ + ( + 0, + 0, + { + "product_id": self.service_product.id, + "product_uom": self.service_product.uom_id.id, + "name": self.service_product.name, + "price_unit": self.service_product.standard_price, + "date_planned": self.date_now, + "product_qty": 30.0, + }, + ) + ], + } + ) purchase_order.button_confirm() - self.assertEqual(purchase_order.state, 'purchase') + self.assertEqual(purchase_order.state, "purchase") # Create Work Acceptance - work_acceptance = self.env['work.acceptance'].create({ - 'purchase_id': purchase_order.id, - 'partner_id': self.res_partner.id, - 'responsible_id': self.employee.id, - 'date_due': self.date_now, - 'date_receive': self.date_now, - 'company_id': self.env.ref('base.main_company').id, - 'wa_line_ids': [ - (0, 0, {'purchase_line_id': purchase_order.order_line[0].id, - 'product_id': purchase_order.order_line[0].product_id.id, - 'name': purchase_order.order_line[0].name, - 'price_unit': purchase_order.order_line[0].price_unit, - 'product_uom': purchase_order.order_line[0].product_uom.id, - 'product_qty': 30.0})] - }) + work_acceptance = self.env["work.acceptance"].create( + { + "purchase_id": purchase_order.id, + "partner_id": self.res_partner.id, + "responsible_id": self.employee.id, + "date_due": self.date_now, + "date_receive": self.date_now, + "company_id": self.env.ref("base.main_company").id, + "wa_line_ids": [ + ( + 0, + 0, + { + "purchase_line_id": purchase_order.order_line[0].id, + "product_id": purchase_order.order_line[0].product_id.id, + "name": purchase_order.order_line[0].name, + "price_unit": purchase_order.order_line[0].price_unit, + "product_uom": purchase_order.order_line[0].product_uom.id, + "product_qty": 30.0, + }, + ) + ], + } + ) work_acceptance.button_accept() - self.assertEqual(work_acceptance.state, 'accept') + self.assertEqual(work_acceptance.state, "accept") self.assertEqual(purchase_order.wa_count, 1) # Create Vendor Bill purchase_order.with_context(create_bill=True).action_view_invoice() - wizard = self.env['select.work.acceptance.wizard'].create({ - 'wa_id': work_acceptance.id, - }) + wizard = self.env["select.work.acceptance.wizard"].create( + {"wa_id": work_acceptance.id} + ) wizard.button_create_vendor_bill() - invoice = self.env['account.invoice'].create({ - 'partner_id': self.res_partner.id, - 'purchase_id': purchase_order.id, - 'account_id': self.res_partner.property_account_payable_id.id, - 'type': 'in_invoice', - }) + invoice = self.env["account.invoice"].create( + { + "partner_id": self.res_partner.id, + "purchase_id": purchase_order.id, + "account_id": self.res_partner.property_account_payable_id.id, + "type": "in_invoice", + } + ) invoice.wa_id = work_acceptance invoice.purchase_order_change() - self.assertEqual(invoice.state, 'draft') + self.assertEqual(invoice.state, "draft") invoice.action_invoice_open() diff --git a/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py b/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py index 0b3e0be2fa2..185fec1f8f0 100644 --- a/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py +++ b/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py @@ -1,41 +1,41 @@ # Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError class SelectWorkAcceptanceWizard(models.TransientModel): - _name = 'select.work.acceptance.wizard' - _description = 'Select Work Acceptance Wizard' + _name = "select.work.acceptance.wizard" + _description = "Select Work Acceptance Wizard" - require_wa = fields.Boolean( - default=lambda self: self._get_require_wa(), - ) + require_wa = fields.Boolean(default=lambda self: self._get_require_wa()) wa_id = fields.Many2one( - comodel_name='work.acceptance', - string='Work Acceptance', + comodel_name="work.acceptance", + string="Work Acceptance", domain=lambda self: [ - ('state', '=', 'accept'), - ('purchase_id', '=', self._context.get('active_id'))] + ("state", "=", "accept"), + ("purchase_id", "=", self._context.get("active_id")), + ], ) def _get_require_wa(self): return self.env.user.has_group( - 'purchase_work_acceptance.group_enforce_wa_on_invoice') + "purchase_work_acceptance.group_enforce_wa_on_invoice" + ) @api.multi def button_create_vendor_bill(self): - order = self.env['purchase.order'].browse(self._context.get('active_id')) + order = self.env["purchase.order"].browse(self._context.get("active_id")) if any(invoice.wa_id == self.wa_id for invoice in order.invoice_ids): - raise ValidationError(_('%s was used in some bill.') % self.wa_id.name) - action = self.env.ref('account.action_vendor_bill_template') + raise ValidationError(_("%s was used in some bill.") % self.wa_id.name) + action = self.env.ref("account.action_vendor_bill_template") result = action.read()[0] - result['context'] = { - 'type': 'in_invoice', - 'default_wa_id': self.wa_id.id, - 'default_purchase_id': self._context.get('active_id'), + result["context"] = { + "type": "in_invoice", + "default_wa_id": self.wa_id.id, + "default_purchase_id": self._context.get("active_id"), } - res = self.env.ref('account.invoice_supplier_form', False) - result['views'] = [(res and res.id or False, 'form')] + res = self.env.ref("account.invoice_supplier_form", False) + result["views"] = [(res and res.id or False, "form")] return result From 35c27fd2406857833c94f3c52863e9571057bf84 Mon Sep 17 00:00:00 2001 From: ps-tubtim Date: Wed, 11 Mar 2020 16:43:32 +0700 Subject: [PATCH 004/210] [MIG] purchase_work_acceptance: Migration to 13.0 --- purchase_work_acceptance/__manifest__.py | 4 +- .../data/work_acceptance_sequence.xml | 6 +- purchase_work_acceptance/models/__init__.py | 2 +- .../{account_invoice.py => account_move.py} | 32 +- purchase_work_acceptance/models/purchase.py | 15 +- .../models/stock_picking.py | 2 - .../models/work_acceptance.py | 5 +- .../readme/CONTRIBUTORS.rst | 4 +- purchase_work_acceptance/readme/USAGE.rst | 2 +- .../security/security.xml | 18 +- .../tests/test_purchase_work_acceptance.py | 44 ++- .../views/account_invoice_views.xml | 22 -- .../views/account_move_views.xml | 21 ++ .../views/purchase_views.xml | 49 +-- .../views/res_config_settings_views.xml | 77 +++-- .../views/stock_picking_views.xml | 19 +- .../views/work_acceptance_views.xml | 283 ++++++++++++------ .../wizard/select_work_acceptance_wizard.py | 10 +- .../select_work_acceptance_wizard_views.xml | 36 +-- 19 files changed, 382 insertions(+), 269 deletions(-) rename purchase_work_acceptance/models/{account_invoice.py => account_move.py} (71%) delete mode 100644 purchase_work_acceptance/views/account_invoice_views.xml create mode 100644 purchase_work_acceptance/views/account_move_views.xml diff --git a/purchase_work_acceptance/__manifest__.py b/purchase_work_acceptance/__manifest__.py index bbb2e5ae961..b3d36daad34 100644 --- a/purchase_work_acceptance/__manifest__.py +++ b/purchase_work_acceptance/__manifest__.py @@ -5,7 +5,7 @@ "name": "Purchase Work Acceptance", "version": "13.0.1.0.0", "category": "Purchase Management", - "author": "Ecosoft, " "Odoo Community Association (OCA)", + "author": "Ecosoft, Odoo Community Association (OCA)", "license": "AGPL-3", "website": "https://github.com/OCA/purchase-workflow", "depends": ["purchase_stock"], @@ -13,7 +13,7 @@ "data/work_acceptance_sequence.xml", "security/ir.model.access.csv", "security/security.xml", - "views/account_invoice_views.xml", + "views/account_move_views.xml", "views/purchase_views.xml", "views/res_config_settings_views.xml", "views/stock_picking_views.xml", diff --git a/purchase_work_acceptance/data/work_acceptance_sequence.xml b/purchase_work_acceptance/data/work_acceptance_sequence.xml index 12cfb883d7b..0fa20f65037 100644 --- a/purchase_work_acceptance/data/work_acceptance_sequence.xml +++ b/purchase_work_acceptance/data/work_acceptance_sequence.xml @@ -1,14 +1,12 @@ - + - Work Acceptance work.acceptance WA 5 - + - diff --git a/purchase_work_acceptance/models/__init__.py b/purchase_work_acceptance/models/__init__.py index ec77fa9ef3e..eed2998d2ca 100644 --- a/purchase_work_acceptance/models/__init__.py +++ b/purchase_work_acceptance/models/__init__.py @@ -1,6 +1,6 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from . import account_invoice +from . import account_move from . import purchase from . import res_config_settings from . import stock_picking diff --git a/purchase_work_acceptance/models/account_invoice.py b/purchase_work_acceptance/models/account_move.py similarity index 71% rename from purchase_work_acceptance/models/account_invoice.py rename to purchase_work_acceptance/models/account_move.py index 7988398e1a5..a7034707ee6 100644 --- a/purchase_work_acceptance/models/account_invoice.py +++ b/purchase_work_acceptance/models/account_move.py @@ -5,8 +5,8 @@ from odoo.exceptions import ValidationError -class AccountInvoice(models.Model): - _inherit = "account.invoice" +class AccountMove(models.Model): + _inherit = "account.move" require_wa = fields.Boolean(compute="_compute_require_wa") wa_id = fields.Many2one( @@ -21,30 +21,20 @@ class AccountInvoice(models.Model): "according to the quantity and unit price of the work acceptance.", ) - @api.multi def _compute_require_wa(self): self.require_wa = self.env.user.has_group( "purchase_work_acceptance.group_enforce_wa_on_invoice" ) - def _prepare_invoice_line_from_po_line(self, line): - res = super()._prepare_invoice_line_from_po_line(line) - wa_line = self.wa_id.wa_line_ids.filtered(lambda l: l.purchase_line_id == line) - if wa_line: - res["quantity"] = wa_line.product_qty - res["uom_id"] = wa_line.product_uom - return res - - @api.onchange("purchase_id") - def purchase_order_change(self): - res = super().purchase_order_change() + @api.onchange("purchase_vendor_bill_id", "purchase_id") + def _onchange_purchase_auto_complete(self): + res = super()._onchange_purchase_auto_complete() if self.wa_id: - self.reference = self.wa_id.invoice_ref + self.ref = self.wa_id.invoice_ref self.currency_id = self.wa_id.currency_id return res - @api.multi - def action_invoice_open(self): + def action_post(self): for rec in self: if rec.wa_id: wa_line = {} @@ -60,7 +50,7 @@ def action_invoice_open(self): wa_line[line.product_id.id] = qty invoice_line = {} for line in rec.invoice_line_ids: - qty = line.uom_id._compute_quantity( + qty = line.product_uom_id._compute_quantity( line.quantity, line.product_id.uom_id ) if qty > 0.0: @@ -72,8 +62,8 @@ def action_invoice_open(self): if wa_line != invoice_line: raise ValidationError( _( - "You cannot validate a bill if " - "Quantity not equal accepted quantity" + "You cannot validate a bill if Quantity not equal " + "accepted quantity" ) ) - return super().action_invoice_open() + return super().action_post() diff --git a/purchase_work_acceptance/models/purchase.py b/purchase_work_acceptance/models/purchase.py index 22a69507957..86598c517e6 100644 --- a/purchase_work_acceptance/models/purchase.py +++ b/purchase_work_acceptance/models/purchase.py @@ -1,7 +1,7 @@ # Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import _, api, fields, models +from odoo import _, fields, models class PurchaseOrder(models.Model): @@ -27,7 +27,6 @@ def _compute_wa_ids(self): ) order.wa_count = len(order.wa_ids) - @api.multi def action_view_wa(self): self.ensure_one() act = self.env.ref("purchase_work_acceptance.action_work_acceptance") @@ -67,7 +66,6 @@ def action_view_wa(self): result["res_id"] = self.wa_ids.id or False return result - @api.multi def action_view_invoice(self): if self.env.context.get("create_bill", False) and self.env.user.has_group( "purchase_work_acceptance.group_enable_wa_on_invoice" @@ -78,14 +76,13 @@ def action_view_invoice(self): return { "name": _("Select Work Acceptance"), "type": "ir.actions.act_window", - "view_type": "form", "view_mode": "form", "res_model": "select.work.acceptance.wizard", "views": [(wizard.id, "form")], "view_id": wizard.id, "target": "new", } - return super(PurchaseOrder, self).action_view_invoice() + return super().action_view_invoice() class PurchaseOrderLine(models.Model): @@ -104,3 +101,11 @@ def _get_product_qty(self): for wa_line in self.wa_line_ids if wa_line.wa_id.state != "cancel" ) + + def _prepare_account_move_line(self, move): + res = super()._prepare_account_move_line(move) + if move.wa_id: + wa_line = self.wa_line_ids.filtered(lambda l: l.wa_id == move.wa_id) + res["quantity"] = wa_line.product_qty + res["product_uom_id"] = wa_line.product_uom + return res diff --git a/purchase_work_acceptance/models/stock_picking.py b/purchase_work_acceptance/models/stock_picking.py index 2b4b0d0d406..814d69832b9 100644 --- a/purchase_work_acceptance/models/stock_picking.py +++ b/purchase_work_acceptance/models/stock_picking.py @@ -19,13 +19,11 @@ class Picking(models.Model): ], ) - @api.multi def _compute_require_wa(self): self.require_wa = self.env.user.has_group( "purchase_work_acceptance.group_enforce_wa_on_in" ) - @api.multi def button_validate(self): if self.wa_id: order = self.env["purchase.order"].browse(self._context.get("active_id")) diff --git a/purchase_work_acceptance/models/work_acceptance.py b/purchase_work_acceptance/models/work_acceptance.py index ca4a2375131..419c735c729 100644 --- a/purchase_work_acceptance/models/work_acceptance.py +++ b/purchase_work_acceptance/models/work_acceptance.py @@ -83,7 +83,7 @@ class WorkAcceptance(models.Model): company_id = fields.Many2one( comodel_name="res.company", string="Company", - default=lambda self: self.env.user.company_id.id, + default=lambda self: self.env.company.id, required=True, index=True, readonly=True, @@ -101,7 +101,6 @@ def create(self, vals): ) return super(WorkAcceptance, self).create(vals) - @api.multi def button_accept(self, force=False): self._unlink_zero_quantity() po_lines = self.purchase_id.order_line @@ -112,11 +111,9 @@ def button_accept(self, force=False): ).product_qty self.write({"state": "accept", "date_accept": fields.Datetime.now()}) - @api.multi def button_draft(self): self.write({"state": "draft"}) - @api.multi def button_cancel(self): self.write({"state": "cancel"}) diff --git a/purchase_work_acceptance/readme/CONTRIBUTORS.rst b/purchase_work_acceptance/readme/CONTRIBUTORS.rst index 0ef1f84c3fd..ea63aa7bc15 100644 --- a/purchase_work_acceptance/readme/CONTRIBUTORS.rst +++ b/purchase_work_acceptance/readme/CONTRIBUTORS.rst @@ -1 +1,3 @@ -* Pimolnat Suntian +* `Ecosoft `__: + + * Pimolnat Suntian diff --git a/purchase_work_acceptance/readme/USAGE.rst b/purchase_work_acceptance/readme/USAGE.rst index a9b4a125112..7025c3dcfa3 100644 --- a/purchase_work_acceptance/readme/USAGE.rst +++ b/purchase_work_acceptance/readme/USAGE.rst @@ -23,4 +23,4 @@ ** Control Vendor Bill by Work Acceptance ** #. After once the products and/or services have been accepted, Click 'Create Bill' -#. You will be prompted to select a Work Acceptance. Select it and Click 'Create Vendor Bill' +#. You will be prompted to select a Work Acceptance. Select it and Click 'Post' diff --git a/purchase_work_acceptance/security/security.xml b/purchase_work_acceptance/security/security.xml index 2c0f7f4257b..769ccab3829 100644 --- a/purchase_work_acceptance/security/security.xml +++ b/purchase_work_acceptance/security/security.xml @@ -1,29 +1,23 @@ - + - Enable WA on Purchase Order - + - Enable WA on Goods Receipt - + - Enforce WA on Goods Receipt - + - Enable WA on Vendor Bill - + - Enforce WA on Vendor Bill - + - diff --git a/purchase_work_acceptance/tests/test_purchase_work_acceptance.py b/purchase_work_acceptance/tests/test_purchase_work_acceptance.py index 4610903ae99..f7edd17b456 100644 --- a/purchase_work_acceptance/tests/test_purchase_work_acceptance.py +++ b/purchase_work_acceptance/tests/test_purchase_work_acceptance.py @@ -142,21 +142,20 @@ def test_02_flow_product(self): picking.move_ids_without_package[0].quantity_done = 42.0 picking.button_validate() # Create Vendor Bill - invoice = self.env["account.invoice"].create( - { - "partner_id": self.res_partner.id, - "purchase_id": purchase_order.id, - "account_id": self.res_partner.property_account_payable_id.id, - "type": "in_invoice", - } - ) - invoice.purchase_order_change() + f = Form(self.env["account.move"].with_context(default_type="in_invoice")) + f.partner_id = purchase_order.partner_id + f.purchase_id = purchase_order + # f.wa_id = work_acceptance + invoice = f.save() invoice.wa_id = work_acceptance + invoice_line = invoice.invoice_line_ids[0] with self.assertRaises(ValidationError): - invoice.invoice_line_ids[0].quantity = 6.0 - invoice.action_invoice_open() - invoice.invoice_line_ids[0].quantity = 42.0 - invoice.action_invoice_open() + invoice_line.with_context(check_move_validity=False).write( + {"quantity": 6.0} + ) + invoice.action_post() # Warn when quantity not equal to WA + invoice_line.quantity = 42.0 + invoice.action_post() def test_03_flow_service(self): # Create Purchase Order @@ -214,16 +213,11 @@ def test_03_flow_service(self): wizard = self.env["select.work.acceptance.wizard"].create( {"wa_id": work_acceptance.id} ) - wizard.button_create_vendor_bill() - invoice = self.env["account.invoice"].create( - { - "partner_id": self.res_partner.id, - "purchase_id": purchase_order.id, - "account_id": self.res_partner.property_account_payable_id.id, - "type": "in_invoice", - } - ) - invoice.wa_id = work_acceptance - invoice.purchase_order_change() + wiz = wizard.button_create_vendor_bill() + f = Form(self.env["account.move"].with_context(wiz.get("context", {}))) + f.purchase_id = purchase_order + invoice = f.save() + invoice._onchange_purchase_auto_complete() self.assertEqual(invoice.state, "draft") - invoice.action_invoice_open() + invoice.action_post() + self.assertEqual(invoice.state, "posted") diff --git a/purchase_work_acceptance/views/account_invoice_views.xml b/purchase_work_acceptance/views/account_invoice_views.xml deleted file mode 100644 index 2ae663e94a0..00000000000 --- a/purchase_work_acceptance/views/account_invoice_views.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - account.invoice.supplier.form - account.invoice - - - - - - - - - - diff --git a/purchase_work_acceptance/views/account_move_views.xml b/purchase_work_acceptance/views/account_move_views.xml new file mode 100644 index 00000000000..6e520e37761 --- /dev/null +++ b/purchase_work_acceptance/views/account_move_views.xml @@ -0,0 +1,21 @@ + + + + account.move.form + account.move + + + + + + + + + diff --git a/purchase_work_acceptance/views/purchase_views.xml b/purchase_work_acceptance/views/purchase_views.xml index fafc580ee81..1b0b8afca4d 100644 --- a/purchase_work_acceptance/views/purchase_views.xml +++ b/purchase_work_acceptance/views/purchase_views.xml @@ -1,37 +1,44 @@ - + - purchase.order.form.inherit purchase.order - + - - + - - {'column_invisible': [('parent.state', 'not in', ('purchase', 'done'))], 'readonly': ['|', ('product_type', 'in', ('consu', 'product')), ('wa_line_ids', '!=', ())]} + + {'column_invisible': [('parent.state', 'not in', ('purchase', 'done'))], 'readonly': ['|', ('product_type', 'in', ('consu', 'product')), ('wa_line_ids', '!=', ())]} - diff --git a/purchase_work_acceptance/views/res_config_settings_views.xml b/purchase_work_acceptance/views/res_config_settings_views.xml index d9e977eab09..aa0e278ac5a 100644 --- a/purchase_work_acceptance/views/res_config_settings_views.xml +++ b/purchase_work_acceptance/views/res_config_settings_views.xml @@ -1,37 +1,75 @@ - + - res.config.settings.view.form.inherit.purchase res.config.settings - - + + - +

Work Acceptance

-
+
- +
-
@@ -490,7 +490,7 @@

Maintainers

promote its widespread use.

Current maintainer:

ps-tubtim

-

This module is part of the OCA/purchase-workflow project on GitHub.

+

This module is part of the OCA/purchase-workflow project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

From fd38246fa1fbbe958cf44ebe73df5f058bb9a648 Mon Sep 17 00:00:00 2001 From: Saran440 Date: Mon, 13 Feb 2023 09:48:40 +0700 Subject: [PATCH 060/210] [FIX] hook function create_invoice --- .../wizard/select_work_acceptance_wizard.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py b/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py index ba89d3d59d4..3687bc77cf2 100644 --- a/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py +++ b/purchase_work_acceptance/wizard/select_work_acceptance_wizard.py @@ -32,6 +32,13 @@ def _compute_wa_ids(self): "invoice", self.env.context.get("active_id") ) + def _get_purchase_order_with_context(self, order_id): + return ( + self.env["purchase.order"] + .browse(order_id) + .with_context(create_bill=False, wa_id=self.wa_id.id) + ) + def button_create_vendor_bill(self): self.ensure_one() order_id = self._context.get("active_id") @@ -40,9 +47,5 @@ def button_create_vendor_bill(self): raise ValidationError( _("%s was already used by some bill") % self.wa_id.name ) - order = self.env["purchase.order"].browse(order_id) - return ( - order.with_context(create_bill=False, wa_id=self.wa_id.id) - .sudo() - .action_create_invoice() - ) + order = self._get_purchase_order_with_context(order_id) + return order.sudo().action_create_invoice() From e6f38c2eacf6ee5b2f5e4988dad2344cd20baf5b Mon Sep 17 00:00:00 2001 From: Saran440 Date: Fri, 17 Mar 2023 11:04:11 +0700 Subject: [PATCH 061/210] [IMP] purchase_work_acceptance: add purchase in wa view --- purchase_work_acceptance/views/work_acceptance_views.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/purchase_work_acceptance/views/work_acceptance_views.xml b/purchase_work_acceptance/views/work_acceptance_views.xml index 78e10c54519..c8beb7f8214 100644 --- a/purchase_work_acceptance/views/work_acceptance_views.xml +++ b/purchase_work_acceptance/views/work_acceptance_views.xml @@ -43,6 +43,7 @@ + Date: Tue, 18 Apr 2023 11:06:08 +0000 Subject: [PATCH 062/210] purchase_work_acceptance 15.0.1.0.1 --- purchase_work_acceptance/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/purchase_work_acceptance/__manifest__.py b/purchase_work_acceptance/__manifest__.py index 9e64b42caee..f0675a7a14b 100644 --- a/purchase_work_acceptance/__manifest__.py +++ b/purchase_work_acceptance/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Purchase Work Acceptance", - "version": "15.0.1.0.0", + "version": "15.0.1.0.1", "category": "Purchase Management", "author": "Ecosoft, Odoo Community Association (OCA)", "license": "AGPL-3", From 55914e643d77cfe2973cc4daffd4892302e480eb Mon Sep 17 00:00:00 2001 From: Saran440 Date: Wed, 12 Apr 2023 13:54:08 +0700 Subject: [PATCH 063/210] [ENH] purchase_work_acceptance: compute search wa_acceted field for filter --- purchase_work_acceptance/models/purchase.py | 14 +++++- .../tests/test_purchase_work_acceptance.py | 5 +++ .../views/purchase_views.xml | 44 ++++++++++++++++++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/purchase_work_acceptance/models/purchase.py b/purchase_work_acceptance/models/purchase.py index aa4df11246d..9ac59c32320 100644 --- a/purchase_work_acceptance/models/purchase.py +++ b/purchase_work_acceptance/models/purchase.py @@ -2,6 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import _, api, fields, models +from odoo.exceptions import UserError class PurchaseOrder(models.Model): @@ -19,7 +20,11 @@ class PurchaseOrder(models.Model): string="WA Lines", readonly=True, ) - wa_accepted = fields.Boolean(string="WA Accepted", compute="_compute_wa_accepted") + wa_accepted = fields.Boolean( + string="WA Accepted", + compute="_compute_wa_accepted", + search="_search_wa_accepted", + ) def _compute_wa_ids(self): for order in self: @@ -113,6 +118,13 @@ def _compute_wa_accepted(self): ) order.wa_accepted = not any(lines) + @api.model + def _search_wa_accepted(self, operator, value): + if operator not in ["=", "!="] or not isinstance(value, bool): + raise UserError(_("Operation not supported")) + recs = self.search([]).filtered(lambda l: l.wa_accepted is value) + return [("id", "in", recs.ids)] + def _prepare_invoice(self): invoice_vals = super()._prepare_invoice() invoice_vals["wa_id"] = self.env.context.get("wa_id") diff --git a/purchase_work_acceptance/tests/test_purchase_work_acceptance.py b/purchase_work_acceptance/tests/test_purchase_work_acceptance.py index 9ed2d9205e2..a6686f0b93a 100644 --- a/purchase_work_acceptance/tests/test_purchase_work_acceptance.py +++ b/purchase_work_acceptance/tests/test_purchase_work_acceptance.py @@ -352,3 +352,8 @@ def test_07_hide_wa_button(self): work_acceptance.button_accept() purchase_order._compute_wa_accepted() self.assertEqual(purchase_order.wa_accepted, True) + # Search wa accepted + purchase_order._search_wa_accepted("=", True) + # Search with not `=` or `!=` + with self.assertRaises(UserError): + purchase_order._search_wa_accepted(">", True) diff --git a/purchase_work_acceptance/views/purchase_views.xml b/purchase_work_acceptance/views/purchase_views.xml index 3a48fa6cc4f..8d245f906d5 100644 --- a/purchase_work_acceptance/views/purchase_views.xml +++ b/purchase_work_acceptance/views/purchase_views.xml @@ -1,6 +1,48 @@ - + + + request.quotation.select + purchase.order + + + + + + + + + + + + purchase.order.select + purchase.order + + + + + + + + + + purchase.order.form.inherit purchase.order From d029790ffe59b38a9208c03de7de3ab5fe25cf10 Mon Sep 17 00:00:00 2001 From: Saran440 Date: Fri, 28 Apr 2023 10:21:25 +0700 Subject: [PATCH 064/210] [FIX] purchase_work_acceptance: show invoice ref in WA tree view --- purchase_work_acceptance/views/work_acceptance_views.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/purchase_work_acceptance/views/work_acceptance_views.xml b/purchase_work_acceptance/views/work_acceptance_views.xml index c8beb7f8214..5d6dcc89589 100644 --- a/purchase_work_acceptance/views/work_acceptance_views.xml +++ b/purchase_work_acceptance/views/work_acceptance_views.xml @@ -141,6 +141,7 @@ + + From 464b37a79990d5d3b587858218d3cb908aed4a8c Mon Sep 17 00:00:00 2001 From: oca-ci Date: Mon, 5 Jun 2023 15:01:41 +0000 Subject: [PATCH 065/210] [UPD] Update purchase_work_acceptance.pot --- .../i18n/purchase_work_acceptance.pot | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/purchase_work_acceptance/i18n/purchase_work_acceptance.pot b/purchase_work_acceptance/i18n/purchase_work_acceptance.pot index 4bab597ef14..bdfacb36f85 100644 --- a/purchase_work_acceptance/i18n/purchase_work_acceptance.pot +++ b/purchase_work_acceptance/i18n/purchase_work_acceptance.pot @@ -384,6 +384,12 @@ msgstr "" msgid "Number of unread messages" msgstr "" +#. module: purchase_work_acceptance +#: code:addons/purchase_work_acceptance/models/purchase.py:0 +#, python-format +msgid "Operation not supported" +msgstr "" + #. module: purchase_work_acceptance #: model:ir.model.fields,field_description:purchase_work_acceptance.field_work_acceptance_line__partner_id msgid "Partner" @@ -607,6 +613,8 @@ msgstr "" #. module: purchase_work_acceptance #: model:ir.model.fields,field_description:purchase_work_acceptance.field_purchase_order__wa_accepted +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.purchase_order_view_search +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_purchase_order_filter msgid "WA Accepted" msgstr "" @@ -616,6 +624,12 @@ msgstr "" msgid "WA Lines" msgstr "" +#. module: purchase_work_acceptance +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.purchase_order_view_search +#: model_terms:ir.ui.view,arch_db:purchase_work_acceptance.view_purchase_order_filter +msgid "WA Not Accepted" +msgstr "" + #. module: purchase_work_acceptance #: model:ir.model.fields,field_description:purchase_work_acceptance.field_account_bank_statement_line__wa_id #: model:ir.model.fields,field_description:purchase_work_acceptance.field_account_move__wa_id From 1708c8b77f1148b47c6013dd12971bdee1110021 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Mon, 5 Jun 2023 15:10:07 +0000 Subject: [PATCH 066/210] purchase_work_acceptance 15.0.1.1.0 --- purchase_work_acceptance/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/purchase_work_acceptance/__manifest__.py b/purchase_work_acceptance/__manifest__.py index f0675a7a14b..bea0572b863 100644 --- a/purchase_work_acceptance/__manifest__.py +++ b/purchase_work_acceptance/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Purchase Work Acceptance", - "version": "15.0.1.0.1", + "version": "15.0.1.1.0", "category": "Purchase Management", "author": "Ecosoft, Odoo Community Association (OCA)", "license": "AGPL-3", From 8d132c9dc59b39f8e179923cde0d9c93b1b80632 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Sun, 3 Sep 2023 15:46:12 +0000 Subject: [PATCH 067/210] [UPD] README.rst --- purchase_work_acceptance/README.rst | 15 ++++--- .../static/description/index.html | 44 ++++++++++--------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/purchase_work_acceptance/README.rst b/purchase_work_acceptance/README.rst index 3ea9c301f5d..4a17079675d 100644 --- a/purchase_work_acceptance/README.rst +++ b/purchase_work_acceptance/README.rst @@ -2,10 +2,13 @@ Purchase Work Acceptance ======================== -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:1ce800fe59b40b1f33a33e12ed713848d5d0638f103c27afa2ad2c11c415b2ee + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png :target: https://odoo-community.org/page/development-status @@ -19,11 +22,11 @@ Purchase Work Acceptance .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png :target: https://translation.odoo-community.org/projects/purchase-workflow-15-0/purchase-workflow-15-0-purchase_work_acceptance :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/142/15.0 - :alt: Try me on Runbot +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/purchase-workflow&target_branch=15.0 + :alt: Try me on Runboat -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| This module introduces the ability to define a quantity control point on Receipts and Vendor Bills by Work Acceptance. Only the products and services that have been included in a Work Acceptance can be @@ -109,7 +112,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us smashing it by providing a detailed and welcomed +If you spotted it first, help us to smash it by providing a detailed and welcomed `feedback `_. Do not contact contributors directly about support or help with technical issues. diff --git a/purchase_work_acceptance/static/description/index.html b/purchase_work_acceptance/static/description/index.html index b12c193679d..1cafbc511ab 100644 --- a/purchase_work_acceptance/static/description/index.html +++ b/purchase_work_acceptance/static/description/index.html @@ -1,20 +1,20 @@ - + - + Purchase Work Acceptance + + +
+

Purchase stock price unit sync

+ + +

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runbot

+

This module allows to sync picking cost prices with purchase order line +price when moves are already done.

+

Can be used with product_cost_price_avco_sync.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/purchase-workflow project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/purchase_stock_price_unit_sync/tests/__init__.py b/purchase_stock_price_unit_sync/tests/__init__.py new file mode 100644 index 00000000000..40febbe558a --- /dev/null +++ b/purchase_stock_price_unit_sync/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import test_purchase_stock_price_unit_sync diff --git a/purchase_stock_price_unit_sync/tests/test_purchase_stock_price_unit_sync.py b/purchase_stock_price_unit_sync/tests/test_purchase_stock_price_unit_sync.py new file mode 100644 index 00000000000..d74ed924e79 --- /dev/null +++ b/purchase_stock_price_unit_sync/tests/test_purchase_stock_price_unit_sync.py @@ -0,0 +1,46 @@ +# Copyright 2019 Tecnativa - Carlos Dauden +# Copyright 2019 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields +from odoo.tests.common import SavepointCase + + +class TestProductCostPriceAvcoSync(SavepointCase): + + @classmethod + def setUpClass(cls): + super(TestProductCostPriceAvcoSync, cls).setUpClass() + cls.partner = cls.env['res.partner'].create({ + 'customer': True, + 'supplier': True, + 'name': 'Test Partner', + }) + cls.product = cls.env['product.product'].create({ + 'name': 'Product for test', + 'type': 'product', + 'tracking': 'none', + 'property_cost_method': 'average', + 'standard_price': 7.0, + }) + + cls.order = cls.env['purchase.order'].create( + {'partner_id': cls.partner.id, + 'order_line': [ + (0, 0, { + 'name': 'Test line', + 'product_qty': 10.0, + 'product_id': cls.product.id, + 'product_uom': cls.product.uom_id.id, + 'date_planned': fields.Date.today(), + 'price_unit': 8.0}), + ]}) + + def test_sync_cost_price(self): + self.order.button_confirm() + picking = self.order.picking_ids[:1] + move = picking.move_lines[:1] + move.quantity_done = move.product_uom_qty + picking.action_done() + self.assertAlmostEqual(move.price_unit, 8.0, 2) + self.order.order_line[:1].price_unit = 6.0 + self.assertAlmostEqual(move.price_unit, 6.0, 2) From 4198dd9a516ea6f090a737c4407da1061ca37e2a Mon Sep 17 00:00:00 2001 From: Carlos Dauden Date: Thu, 9 Jan 2020 10:31:27 +0100 Subject: [PATCH 076/210] [MIG] purchase_stock_price_unit_sync: Migration to 12.0 [UPD] Update purchase_stock_price_unit_sync.pot --- purchase_stock_price_unit_sync/README.rst | 10 +++++----- purchase_stock_price_unit_sync/__manifest__.py | 4 ++-- .../i18n/purchase_stock_price_unit_sync.pot | 2 +- .../static/description/index.html | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/purchase_stock_price_unit_sync/README.rst b/purchase_stock_price_unit_sync/README.rst index d96ade7b095..51447cdd2d7 100644 --- a/purchase_stock_price_unit_sync/README.rst +++ b/purchase_stock_price_unit_sync/README.rst @@ -14,13 +14,13 @@ Purchase stock price unit sync :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github - :target: https://github.com/OCA/purchase-workflow/tree/11.0/purchase_stock_price_unit_sync + :target: https://github.com/OCA/purchase-workflow/tree/12.0/purchase_stock_price_unit_sync :alt: OCA/purchase-workflow .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/purchase-workflow-11-0/purchase-workflow-11-0-purchase_stock_price_unit_sync + :target: https://translation.odoo-community.org/projects/purchase-workflow-12-0/purchase-workflow-12-0-purchase_stock_price_unit_sync :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/142/11.0 + :target: https://runbot.odoo-community.org/runbot/142/12.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -41,7 +41,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -74,6 +74,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/purchase-workflow `_ project on GitHub. +This module is part of the `OCA/purchase-workflow `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/purchase_stock_price_unit_sync/__manifest__.py b/purchase_stock_price_unit_sync/__manifest__.py index a093a60f1eb..f6784a71638 100644 --- a/purchase_stock_price_unit_sync/__manifest__.py +++ b/purchase_stock_price_unit_sync/__manifest__.py @@ -4,13 +4,13 @@ { 'name': 'Purchase stock price unit sync', 'summary': 'Update cost price in stock moves already done', - 'version': '11.0.1.0.0', + 'version': '12.0.1.0.0', 'category': 'Purchase', 'website': 'https://github.com/OCA/purchase-workflow', 'author': 'Tecnativa, Odoo Community Association (OCA)', 'license': 'AGPL-3', 'installable': True, 'depends': [ - 'purchase', + 'purchase_stock', ], } diff --git a/purchase_stock_price_unit_sync/i18n/purchase_stock_price_unit_sync.pot b/purchase_stock_price_unit_sync/i18n/purchase_stock_price_unit_sync.pot index 676a9476da2..16a9b9ac8e1 100644 --- a/purchase_stock_price_unit_sync/i18n/purchase_stock_price_unit_sync.pot +++ b/purchase_stock_price_unit_sync/i18n/purchase_stock_price_unit_sync.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 11.0\n" +"Project-Id-Version: Odoo Server 12.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: <>\n" "Language-Team: \n" diff --git a/purchase_stock_price_unit_sync/static/description/index.html b/purchase_stock_price_unit_sync/static/description/index.html index 06960d26983..6fcf636c185 100644 --- a/purchase_stock_price_unit_sync/static/description/index.html +++ b/purchase_stock_price_unit_sync/static/description/index.html @@ -367,7 +367,7 @@

Purchase stock price unit sync

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runbot

+

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runbot

This module allows to sync picking cost prices with purchase order line price when moves are already done.

Can be used with product_cost_price_avco_sync.

@@ -388,7 +388,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -419,7 +419,7 @@

Maintainers

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

-

This module is part of the OCA/purchase-workflow project on GitHub.

+

This module is part of the OCA/purchase-workflow project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

From c79bb45f4d51fcf6b55e49c4dc9b0fd9f41d2fcb Mon Sep 17 00:00:00 2001 From: sergio-teruel Date: Thu, 17 Sep 2020 16:16:45 +0200 Subject: [PATCH 077/210] [IMP] purchase_stock_price_unit_sync: black, isort --- .../__manifest__.py | 20 +++---- .../models/purchase_order.py | 20 ++++--- .../test_purchase_stock_price_unit_sync.py | 55 +++++++++++-------- 3 files changed, 52 insertions(+), 43 deletions(-) diff --git a/purchase_stock_price_unit_sync/__manifest__.py b/purchase_stock_price_unit_sync/__manifest__.py index f6784a71638..1b1bfa81c41 100644 --- a/purchase_stock_price_unit_sync/__manifest__.py +++ b/purchase_stock_price_unit_sync/__manifest__.py @@ -2,15 +2,13 @@ # Copyright 2018 Tecnativa - Sergio Teruel # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). { - 'name': 'Purchase stock price unit sync', - 'summary': 'Update cost price in stock moves already done', - 'version': '12.0.1.0.0', - 'category': 'Purchase', - 'website': 'https://github.com/OCA/purchase-workflow', - 'author': 'Tecnativa, Odoo Community Association (OCA)', - 'license': 'AGPL-3', - 'installable': True, - 'depends': [ - 'purchase_stock', - ], + "name": "Purchase stock price unit sync", + "summary": "Update cost price in stock moves already done", + "version": "12.0.1.0.0", + "category": "Purchase", + "website": "https://github.com/OCA/purchase-workflow", + "author": "Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "depends": ["purchase_stock",], } diff --git a/purchase_stock_price_unit_sync/models/purchase_order.py b/purchase_stock_price_unit_sync/models/purchase_order.py index 6c53c4fbeef..ed77ba22fa1 100644 --- a/purchase_stock_price_unit_sync/models/purchase_order.py +++ b/purchase_stock_price_unit_sync/models/purchase_order.py @@ -5,18 +5,22 @@ class PurchaseOrderLine(models.Model): - _inherit = 'purchase.order.line' + _inherit = "purchase.order.line" def write(self, vals): res = super().write(vals) - if ('price_unit' in vals or 'discount' in vals) and ( - not self.env.context.get('skip_stock_price_unit_sync')): + if ("price_unit" in vals or "discount" in vals) and ( + not self.env.context.get("skip_stock_price_unit_sync") + ): self.stock_price_unit_sync() return res def stock_price_unit_sync(self): - for line in self.filtered(lambda l: l.state in ['purchase', 'done']): - line.move_ids.write({ - 'price_unit': line.with_context(skip_stock_price_unit_sync=True - )._get_stock_move_price_unit(), - }) + for line in self.filtered(lambda l: l.state in ["purchase", "done"]): + line.move_ids.write( + { + "price_unit": line.with_context( + skip_stock_price_unit_sync=True + )._get_stock_move_price_unit(), + } + ) diff --git a/purchase_stock_price_unit_sync/tests/test_purchase_stock_price_unit_sync.py b/purchase_stock_price_unit_sync/tests/test_purchase_stock_price_unit_sync.py index d74ed924e79..e1d292bebb8 100644 --- a/purchase_stock_price_unit_sync/tests/test_purchase_stock_price_unit_sync.py +++ b/purchase_stock_price_unit_sync/tests/test_purchase_stock_price_unit_sync.py @@ -6,34 +6,41 @@ class TestProductCostPriceAvcoSync(SavepointCase): - @classmethod def setUpClass(cls): super(TestProductCostPriceAvcoSync, cls).setUpClass() - cls.partner = cls.env['res.partner'].create({ - 'customer': True, - 'supplier': True, - 'name': 'Test Partner', - }) - cls.product = cls.env['product.product'].create({ - 'name': 'Product for test', - 'type': 'product', - 'tracking': 'none', - 'property_cost_method': 'average', - 'standard_price': 7.0, - }) + cls.partner = cls.env["res.partner"].create( + {"customer": True, "supplier": True, "name": "Test Partner",} + ) + cls.product = cls.env["product.product"].create( + { + "name": "Product for test", + "type": "product", + "tracking": "none", + "property_cost_method": "average", + "standard_price": 7.0, + } + ) - cls.order = cls.env['purchase.order'].create( - {'partner_id': cls.partner.id, - 'order_line': [ - (0, 0, { - 'name': 'Test line', - 'product_qty': 10.0, - 'product_id': cls.product.id, - 'product_uom': cls.product.uom_id.id, - 'date_planned': fields.Date.today(), - 'price_unit': 8.0}), - ]}) + cls.order = cls.env["purchase.order"].create( + { + "partner_id": cls.partner.id, + "order_line": [ + ( + 0, + 0, + { + "name": "Test line", + "product_qty": 10.0, + "product_id": cls.product.id, + "product_uom": cls.product.uom_id.id, + "date_planned": fields.Date.today(), + "price_unit": 8.0, + }, + ), + ], + } + ) def test_sync_cost_price(self): self.order.button_confirm() From d754db7ec909fb0d4eae7488f1933a36471b7798 Mon Sep 17 00:00:00 2001 From: sergio-teruel Date: Thu, 17 Sep 2020 16:16:46 +0200 Subject: [PATCH 078/210] [MIG] purchase_stock_price_unit_sync: Migration to v13.0 [UPD] Update purchase_stock_price_unit_sync.pot --- purchase_stock_price_unit_sync/README.rst | 10 +++++----- purchase_stock_price_unit_sync/__manifest__.py | 4 ++-- .../i18n/purchase_stock_price_unit_sync.pot | 7 +++---- .../models/purchase_order.py | 4 ++-- .../static/description/index.html | 6 +++--- .../tests/test_purchase_stock_price_unit_sync.py | 16 ++++++++++------ 6 files changed, 25 insertions(+), 22 deletions(-) diff --git a/purchase_stock_price_unit_sync/README.rst b/purchase_stock_price_unit_sync/README.rst index 51447cdd2d7..cb64d0109e5 100644 --- a/purchase_stock_price_unit_sync/README.rst +++ b/purchase_stock_price_unit_sync/README.rst @@ -14,13 +14,13 @@ Purchase stock price unit sync :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github - :target: https://github.com/OCA/purchase-workflow/tree/12.0/purchase_stock_price_unit_sync + :target: https://github.com/OCA/purchase-workflow/tree/13.0/purchase_stock_price_unit_sync :alt: OCA/purchase-workflow .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/purchase-workflow-12-0/purchase-workflow-12-0-purchase_stock_price_unit_sync + :target: https://translation.odoo-community.org/projects/purchase-workflow-13-0/purchase-workflow-13-0-purchase_stock_price_unit_sync :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/142/12.0 + :target: https://runbot.odoo-community.org/runbot/142/13.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -41,7 +41,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -74,6 +74,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/purchase-workflow `_ project on GitHub. +This module is part of the `OCA/purchase-workflow `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/purchase_stock_price_unit_sync/__manifest__.py b/purchase_stock_price_unit_sync/__manifest__.py index 1b1bfa81c41..a4895b56906 100644 --- a/purchase_stock_price_unit_sync/__manifest__.py +++ b/purchase_stock_price_unit_sync/__manifest__.py @@ -4,11 +4,11 @@ { "name": "Purchase stock price unit sync", "summary": "Update cost price in stock moves already done", - "version": "12.0.1.0.0", + "version": "13.0.1.0.0", "category": "Purchase", "website": "https://github.com/OCA/purchase-workflow", "author": "Tecnativa, Odoo Community Association (OCA)", "license": "AGPL-3", "installable": True, - "depends": ["purchase_stock",], + "depends": ["purchase_stock"], } diff --git a/purchase_stock_price_unit_sync/i18n/purchase_stock_price_unit_sync.pot b/purchase_stock_price_unit_sync/i18n/purchase_stock_price_unit_sync.pot index 16a9b9ac8e1..7cb3c725358 100644 --- a/purchase_stock_price_unit_sync/i18n/purchase_stock_price_unit_sync.pot +++ b/purchase_stock_price_unit_sync/i18n/purchase_stock_price_unit_sync.pot @@ -1,12 +1,12 @@ # Translation of Odoo Server. # This file contains the translation of the following modules: -# * purchase_stock_price_unit_sync +# * purchase_stock_price_unit_sync # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 12.0\n" +"Project-Id-Version: Odoo Server 13.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: <>\n" +"Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -17,4 +17,3 @@ msgstr "" #: model:ir.model,name:purchase_stock_price_unit_sync.model_purchase_order_line msgid "Purchase Order Line" msgstr "" - diff --git a/purchase_stock_price_unit_sync/models/purchase_order.py b/purchase_stock_price_unit_sync/models/purchase_order.py index ed77ba22fa1..756a175428c 100644 --- a/purchase_stock_price_unit_sync/models/purchase_order.py +++ b/purchase_stock_price_unit_sync/models/purchase_order.py @@ -17,9 +17,9 @@ def write(self, vals): def stock_price_unit_sync(self): for line in self.filtered(lambda l: l.state in ["purchase", "done"]): - line.move_ids.write( + line.move_ids.mapped("stock_valuation_layer_ids").write( { - "price_unit": line.with_context( + "unit_cost": line.with_context( skip_stock_price_unit_sync=True )._get_stock_move_price_unit(), } diff --git a/purchase_stock_price_unit_sync/static/description/index.html b/purchase_stock_price_unit_sync/static/description/index.html index 6fcf636c185..b3a345606e6 100644 --- a/purchase_stock_price_unit_sync/static/description/index.html +++ b/purchase_stock_price_unit_sync/static/description/index.html @@ -367,7 +367,7 @@

Purchase stock price unit sync

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runbot

+

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runbot

This module allows to sync picking cost prices with purchase order line price when moves are already done.

Can be used with product_cost_price_avco_sync.

@@ -388,7 +388,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -419,7 +419,7 @@

Maintainers

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

-

This module is part of the OCA/purchase-workflow project on GitHub.

+

This module is part of the OCA/purchase-workflow project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/purchase_stock_price_unit_sync/tests/test_purchase_stock_price_unit_sync.py b/purchase_stock_price_unit_sync/tests/test_purchase_stock_price_unit_sync.py index e1d292bebb8..bbc91523913 100644 --- a/purchase_stock_price_unit_sync/tests/test_purchase_stock_price_unit_sync.py +++ b/purchase_stock_price_unit_sync/tests/test_purchase_stock_price_unit_sync.py @@ -9,16 +9,20 @@ class TestProductCostPriceAvcoSync(SavepointCase): @classmethod def setUpClass(cls): super(TestProductCostPriceAvcoSync, cls).setUpClass() - cls.partner = cls.env["res.partner"].create( - {"customer": True, "supplier": True, "name": "Test Partner",} + cls.partner = cls.env["res.partner"].create({"name": "Test Partner"}) + cls.product_category = cls.env["product.category"].create( + { + "name": "Category property_cost_method average", + "property_cost_method": "average", + } ) cls.product = cls.env["product.product"].create( { "name": "Product for test", "type": "product", "tracking": "none", - "property_cost_method": "average", - "standard_price": 7.0, + "categ_id": cls.product_category.id, + "standard_price": 1, } ) @@ -48,6 +52,6 @@ def test_sync_cost_price(self): move = picking.move_lines[:1] move.quantity_done = move.product_uom_qty picking.action_done() - self.assertAlmostEqual(move.price_unit, 8.0, 2) + self.assertAlmostEqual(move.stock_valuation_layer_ids[:1].unit_cost, 8.0, 2) self.order.order_line[:1].price_unit = 6.0 - self.assertAlmostEqual(move.price_unit, 6.0, 2) + self.assertAlmostEqual(move.stock_valuation_layer_ids[:1].unit_cost, 6.0, 2) From 4b01dc585f06750c2d6b63db8cf6cd1b6435af1f Mon Sep 17 00:00:00 2001 From: david Date: Thu, 14 Oct 2021 12:31:16 +0200 Subject: [PATCH 079/210] [IMP][FIX] purchase_stock_price_unit_sync: handle kit cases If we receive a kit, we shouldn't write the kit purchase price on the components price units. TT32040 purchase_stock_price_unit_sync 13.0.1.0.1 --- purchase_stock_price_unit_sync/__manifest__.py | 2 +- .../models/purchase_order.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/purchase_stock_price_unit_sync/__manifest__.py b/purchase_stock_price_unit_sync/__manifest__.py index a4895b56906..7d30c01e002 100644 --- a/purchase_stock_price_unit_sync/__manifest__.py +++ b/purchase_stock_price_unit_sync/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Purchase stock price unit sync", "summary": "Update cost price in stock moves already done", - "version": "13.0.1.0.0", + "version": "13.0.1.0.1", "category": "Purchase", "website": "https://github.com/OCA/purchase-workflow", "author": "Tecnativa, Odoo Community Association (OCA)", diff --git a/purchase_stock_price_unit_sync/models/purchase_order.py b/purchase_stock_price_unit_sync/models/purchase_order.py index 756a175428c..e29f25f563f 100644 --- a/purchase_stock_price_unit_sync/models/purchase_order.py +++ b/purchase_stock_price_unit_sync/models/purchase_order.py @@ -17,6 +17,18 @@ def write(self, vals): def stock_price_unit_sync(self): for line in self.filtered(lambda l: l.state in ["purchase", "done"]): + # When the affected product is a kit we do nothing, which is the + # default behavior on the standard: the move is exploded into moves + # for the components and those get the default price_unit for the + # time being. We avoid a hard dependency as well. + if hasattr(line.product_id, "bom_ids") and self.env[ + "mrp.bom" + ].sudo()._bom_find( + product=line.product_id, + company_id=line.company_id.id, + bom_type="phantom", + ): + continue line.move_ids.mapped("stock_valuation_layer_ids").write( { "unit_cost": line.with_context( From 4a6d692519c0f722b8b6ba88b39ebde086dfe1b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?= Date: Wed, 9 Mar 2022 14:32:46 +0100 Subject: [PATCH 080/210] [MIG] purchase_stock_price_unit_sync: Migration to 14.0 TT35009 --- purchase_stock_price_unit_sync/README.rst | 10 +++++----- purchase_stock_price_unit_sync/__manifest__.py | 2 +- .../models/purchase_order.py | 2 +- purchase_stock_price_unit_sync/readme/CONTRIBUTORS.rst | 4 ++-- .../static/description/index.html | 8 ++++---- .../tests/test_purchase_stock_price_unit_sync.py | 4 ++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/purchase_stock_price_unit_sync/README.rst b/purchase_stock_price_unit_sync/README.rst index cb64d0109e5..3bc08d2fa08 100644 --- a/purchase_stock_price_unit_sync/README.rst +++ b/purchase_stock_price_unit_sync/README.rst @@ -14,13 +14,13 @@ Purchase stock price unit sync :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github - :target: https://github.com/OCA/purchase-workflow/tree/13.0/purchase_stock_price_unit_sync + :target: https://github.com/OCA/purchase-workflow/tree/14.0/purchase_stock_price_unit_sync :alt: OCA/purchase-workflow .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/purchase-workflow-13-0/purchase-workflow-13-0-purchase_stock_price_unit_sync + :target: https://translation.odoo-community.org/projects/purchase-workflow-14-0/purchase-workflow-14-0-purchase_stock_price_unit_sync :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/142/13.0 + :target: https://runbot.odoo-community.org/runbot/142/14.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -41,7 +41,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -74,6 +74,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/purchase-workflow `_ project on GitHub. +This module is part of the `OCA/purchase-workflow `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/purchase_stock_price_unit_sync/__manifest__.py b/purchase_stock_price_unit_sync/__manifest__.py index 7d30c01e002..92265c35096 100644 --- a/purchase_stock_price_unit_sync/__manifest__.py +++ b/purchase_stock_price_unit_sync/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Purchase stock price unit sync", "summary": "Update cost price in stock moves already done", - "version": "13.0.1.0.1", + "version": "14.0.1.0.0", "category": "Purchase", "website": "https://github.com/OCA/purchase-workflow", "author": "Tecnativa, Odoo Community Association (OCA)", diff --git a/purchase_stock_price_unit_sync/models/purchase_order.py b/purchase_stock_price_unit_sync/models/purchase_order.py index e29f25f563f..0fc933ee7a1 100644 --- a/purchase_stock_price_unit_sync/models/purchase_order.py +++ b/purchase_stock_price_unit_sync/models/purchase_order.py @@ -1,4 +1,4 @@ -# Copyright 2019 Carlos Dauden - Tecnativa +# Copyright 2019 Tecnativa - Carlos Dauden # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo import models diff --git a/purchase_stock_price_unit_sync/readme/CONTRIBUTORS.rst b/purchase_stock_price_unit_sync/readme/CONTRIBUTORS.rst index 22e2c955617..66d11c82502 100644 --- a/purchase_stock_price_unit_sync/readme/CONTRIBUTORS.rst +++ b/purchase_stock_price_unit_sync/readme/CONTRIBUTORS.rst @@ -1,4 +1,4 @@ * `Tecnativa `_: - * Carlos Dauden - * Sergio Teruel + * Carlos Dauden + * Sergio Teruel diff --git a/purchase_stock_price_unit_sync/static/description/index.html b/purchase_stock_price_unit_sync/static/description/index.html index b3a345606e6..826bb972112 100644 --- a/purchase_stock_price_unit_sync/static/description/index.html +++ b/purchase_stock_price_unit_sync/static/description/index.html @@ -3,7 +3,7 @@ - + Purchase stock price unit sync + + +
+

Price recalculation in purchases orders

+ + +

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runbot

+

This module adds one button on purchase orders (below the lines) that:

+
    +
  • Recalculates the prices of the order lines that contain a product in them.
  • +
+

It is launched manually as a button to get the user to decide if he/she wants to +recalculate prices when vendor is changed or after duplicating a purchase order +to update or not purchase information.

+

Table of contents

+ +
+

Usage

+
    +
  1. Go to Purchase -> Products > Products and create some record and set differente prices to vendors in Purchase tab, for example: Vendor 1: 10 and Vendor 2: 20.
  2. +
  3. Go to Purchase -> Orders > Requests for Quotation and create some record and set Vendor 1.
  4. +
  5. Add a line with the previously created product.
  6. +
  7. The unit price of the product is 10.
  8. +
  9. Change vendor to Vendor 2.
  10. +
  11. Click on the “Update lines info” button.
  12. +
  13. The unit price of the product is 20.
  14. +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+
    +
  • Tecnativa:
      +
    • Víctor Martínez
    • +
    • Pedro M. Baeza
    • +
    +
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

victoralmau

+

This module is part of the OCA/purchase-workflow project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/purchase_order_price_recalculation/tests/__init__.py b/purchase_order_price_recalculation/tests/__init__.py new file mode 100644 index 00000000000..3f6b4227301 --- /dev/null +++ b/purchase_order_price_recalculation/tests/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from . import test_purchase_order_price_recalculation diff --git a/purchase_order_price_recalculation/tests/test_purchase_order_price_recalculation.py b/purchase_order_price_recalculation/tests/test_purchase_order_price_recalculation.py new file mode 100644 index 00000000000..93f37ac5a54 --- /dev/null +++ b/purchase_order_price_recalculation/tests/test_purchase_order_price_recalculation.py @@ -0,0 +1,42 @@ +# Copyright 2022 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) + +from odoo.tests import Form, common + + +class TestPurchaseOrderPriceRecalculation(common.SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.partner_a = cls.env["res.partner"].create({"name": "Test partner A"}) + cls.partner_b = cls.env["res.partner"].create({"name": "Test partner B"}) + cls.product = cls.env["product.product"].create( + { + "name": "Test product", + "seller_ids": [ + (0, 0, {"name": cls.partner_a.id, "price": 10}), + (0, 0, {"name": cls.partner_b.id, "price": 20}), + ], + } + ) + cls.order = cls._create_order(cls, cls.partner_a) + + def _create_order(self, partner): + order_form = Form(self.env["purchase.order"]) + order_form.partner_id = partner + with order_form.order_line.new() as line_form: + line_form.product_id = self.product + line_form.product_qty = 1 + return order_form.save() + + def test_order_update_lines_info(self): + product_line = self.order.order_line + self.assertEqual(product_line.price_unit, 10) + # Test form + order_form = Form(self.order) + order_form.partner_id = self.partner_b + # Update partner + self.order.partner_id = self.partner_b + self.assertEqual(product_line.price_unit, 10) + self.order.update_lines_info() + self.assertEqual(product_line.price_unit, 20) diff --git a/purchase_order_price_recalculation/views/purchase_order_view.xml b/purchase_order_price_recalculation/views/purchase_order_view.xml new file mode 100644 index 00000000000..b310c841b05 --- /dev/null +++ b/purchase_order_price_recalculation/views/purchase_order_view.xml @@ -0,0 +1,19 @@ + + + + purchase.order + + + + + + From 88148d020fe917e30a71c7647dfe72e7e77e6fbc Mon Sep 17 00:00:00 2001 From: Francesco Foresti Date: Wed, 16 Nov 2022 17:33:19 +0000 Subject: [PATCH 112/210] Added translation using Weblate (Italian) --- purchase_order_price_recalculation/i18n/it.po | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 purchase_order_price_recalculation/i18n/it.po diff --git a/purchase_order_price_recalculation/i18n/it.po b/purchase_order_price_recalculation/i18n/it.po new file mode 100644 index 00000000000..e05819377e9 --- /dev/null +++ b/purchase_order_price_recalculation/i18n/it.po @@ -0,0 +1,47 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_order_price_recalculation +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: purchase_order_price_recalculation +#: model:ir.model.fields,field_description:purchase_order_price_recalculation.field_purchase_order__display_name +msgid "Display Name" +msgstr "" + +#. module: purchase_order_price_recalculation +#: model:ir.model.fields,field_description:purchase_order_price_recalculation.field_purchase_order__id +msgid "ID" +msgstr "" + +#. module: purchase_order_price_recalculation +#: model:ir.model.fields,field_description:purchase_order_price_recalculation.field_purchase_order____last_update +msgid "Last Modified on" +msgstr "" + +#. module: purchase_order_price_recalculation +#: model:ir.model,name:purchase_order_price_recalculation.model_purchase_order +msgid "Purchase Order" +msgstr "" + +#. module: purchase_order_price_recalculation +#: model_terms:ir.ui.view,arch_db:purchase_order_price_recalculation.purchase_order_form +msgid "" +"This will update all the line prices based on the vendor currently set. Do " +"you want to continue?" +msgstr "" + +#. module: purchase_order_price_recalculation +#: model_terms:ir.ui.view,arch_db:purchase_order_price_recalculation.purchase_order_form +msgid "Update lines info" +msgstr "" From 38ec7e972efb8c82d94cd4d7d2b97181791dccc6 Mon Sep 17 00:00:00 2001 From: Francesco Foresti Date: Wed, 16 Nov 2022 17:33:26 +0000 Subject: [PATCH 113/210] Translated using Weblate (Italian) Currently translated at 100.0% (6 of 6 strings) Translation: purchase-workflow-14.0/purchase-workflow-14.0-purchase_order_price_recalculation Translate-URL: https://translation.odoo-community.org/projects/purchase-workflow-14-0/purchase-workflow-14-0-purchase_order_price_recalculation/it/ --- purchase_order_price_recalculation/i18n/it.po | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/purchase_order_price_recalculation/i18n/it.po b/purchase_order_price_recalculation/i18n/it.po index e05819377e9..001a47c5360 100644 --- a/purchase_order_price_recalculation/i18n/it.po +++ b/purchase_order_price_recalculation/i18n/it.po @@ -6,33 +6,35 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2022-11-16 19:44+0000\n" +"Last-Translator: Francesco Foresti \n" "Language-Team: none\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.14.1\n" #. module: purchase_order_price_recalculation #: model:ir.model.fields,field_description:purchase_order_price_recalculation.field_purchase_order__display_name msgid "Display Name" -msgstr "" +msgstr "Nome da visualizzare" #. module: purchase_order_price_recalculation #: model:ir.model.fields,field_description:purchase_order_price_recalculation.field_purchase_order__id msgid "ID" -msgstr "" +msgstr "ID" #. module: purchase_order_price_recalculation #: model:ir.model.fields,field_description:purchase_order_price_recalculation.field_purchase_order____last_update msgid "Last Modified on" -msgstr "" +msgstr "Ultima modifica il" #. module: purchase_order_price_recalculation #: model:ir.model,name:purchase_order_price_recalculation.model_purchase_order msgid "Purchase Order" -msgstr "" +msgstr "Ordine di acquisto" #. module: purchase_order_price_recalculation #: model_terms:ir.ui.view,arch_db:purchase_order_price_recalculation.purchase_order_form @@ -40,8 +42,10 @@ msgid "" "This will update all the line prices based on the vendor currently set. Do " "you want to continue?" msgstr "" +"Questo aggiornerà i prezzi di tutte le righe sulla base del fornitore " +"impostato in questo momento. Vuoi continuare?" #. module: purchase_order_price_recalculation #: model_terms:ir.ui.view,arch_db:purchase_order_price_recalculation.purchase_order_form msgid "Update lines info" -msgstr "" +msgstr "Aggiorna info righe" From 92386bbe392febf07d25071c7e263f77b83a7d3b Mon Sep 17 00:00:00 2001 From: mymage Date: Thu, 23 Mar 2023 10:53:45 +0000 Subject: [PATCH 114/210] Translated using Weblate (Italian) Currently translated at 100.0% (6 of 6 strings) Translation: purchase-workflow-14.0/purchase-workflow-14.0-purchase_order_price_recalculation Translate-URL: https://translation.odoo-community.org/projects/purchase-workflow-14-0/purchase-workflow-14-0-purchase_order_price_recalculation/it/ [UPD] README.rst --- purchase_order_price_recalculation/README.rst | 15 ++++--- purchase_order_price_recalculation/i18n/it.po | 6 +-- .../static/description/index.html | 40 ++++++++++--------- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/purchase_order_price_recalculation/README.rst b/purchase_order_price_recalculation/README.rst index b757c0d5fe4..543e78d9674 100644 --- a/purchase_order_price_recalculation/README.rst +++ b/purchase_order_price_recalculation/README.rst @@ -2,10 +2,13 @@ Price recalculation in purchases orders ======================================= -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:990cd9a9f28aac588b8afdc0bcfb334edc4b5e6c94c6d2a39f056f32f13cfebc + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status @@ -19,11 +22,11 @@ Price recalculation in purchases orders .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png :target: https://translation.odoo-community.org/projects/purchase-workflow-14-0/purchase-workflow-14-0-purchase_order_price_recalculation :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/142/14.0 - :alt: Try me on Runbot +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/purchase-workflow&target_branch=14.0 + :alt: Try me on Runboat -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| This module adds one button on purchase orders (below the lines) that: @@ -54,7 +57,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us smashing it by providing a detailed and welcomed +If you spotted it first, help us to smash it by providing a detailed and welcomed `feedback `_. Do not contact contributors directly about support or help with technical issues. diff --git a/purchase_order_price_recalculation/i18n/it.po b/purchase_order_price_recalculation/i18n/it.po index 001a47c5360..462dd5690bf 100644 --- a/purchase_order_price_recalculation/i18n/it.po +++ b/purchase_order_price_recalculation/i18n/it.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2022-11-16 19:44+0000\n" -"Last-Translator: Francesco Foresti \n" +"PO-Revision-Date: 2023-03-23 13:24+0000\n" +"Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" "MIME-Version: 1.0\n" @@ -19,7 +19,7 @@ msgstr "" #. module: purchase_order_price_recalculation #: model:ir.model.fields,field_description:purchase_order_price_recalculation.field_purchase_order__display_name msgid "Display Name" -msgstr "Nome da visualizzare" +msgstr "Nome visualizzato" #. module: purchase_order_price_recalculation #: model:ir.model.fields,field_description:purchase_order_price_recalculation.field_purchase_order__id diff --git a/purchase_order_price_recalculation/static/description/index.html b/purchase_order_price_recalculation/static/description/index.html index 3240b8c6639..100a763ea8d 100644 --- a/purchase_order_price_recalculation/static/description/index.html +++ b/purchase_order_price_recalculation/static/description/index.html @@ -1,20 +1,20 @@ - + - + Price recalculation in purchases orders + + +
+

Purchase Order Product Attachment Mgmt

+ + +

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runbot

+

This module allows to get all attachments from all products of a purchase on a view.

+

Table of contents

+ +
+

Usage

+
    +
  1. Go to Purchase -> Orders > Purchase Orders and create or edit some record.
  2. +
  3. The smart-button “Attachments” display the attachments of the product lines.
  4. +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+
    +
  • Tecnativa:
      +
    • Víctor Martínez
    • +
    • Pedro M. Baeza
    • +
    +
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

victoralmau

+

This module is part of the OCA/purchase-workflow project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/purchase_order_product_attachment_mgmt/tests/__init__.py b/purchase_order_product_attachment_mgmt/tests/__init__.py new file mode 100644 index 00000000000..4d931d95937 --- /dev/null +++ b/purchase_order_product_attachment_mgmt/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) + +from . import test_purchase_order_product_attachment_mgmt diff --git a/purchase_order_product_attachment_mgmt/tests/test_purchase_order_product_attachment_mgmt.py b/purchase_order_product_attachment_mgmt/tests/test_purchase_order_product_attachment_mgmt.py new file mode 100644 index 00000000000..3c844e9a562 --- /dev/null +++ b/purchase_order_product_attachment_mgmt/tests/test_purchase_order_product_attachment_mgmt.py @@ -0,0 +1,48 @@ +# Copyright 2022 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import base64 + +from odoo.tests import Form, common + + +class TestPurchaseOrderProductAttachmentMgmt(common.SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.partner = cls.env["res.partner"].create({"name": "Mr Odoo"}) + cls.product_a = cls.env["product.product"].create({"name": "Test Product A"}) + cls.product_b = cls.env["product.product"].create({"name": "Test Product B"}) + cls.purchase_order = cls._create_purchase_order(cls) + + def _create_purchase_order(self): + order_form = Form(self.env["purchase.order"]) + order_form.partner_id = self.partner + with order_form.order_line.new() as line_form: + line_form.product_id = self.product_a + with order_form.order_line.new() as line_form: + line_form.product_id = self.product_b + return order_form.save() + + def _create_attachment(self, product): + return self.env["ir.attachment"].create( + { + "name": "Test file %s" % product.name, + "res_model": product._name, + "res_id": product.id, + "datas": base64.b64encode(b"\xff data"), + } + ) + + def test_purchase_order_documents(self): + attachment_a = self._create_attachment(self.product_a) + action = self.purchase_order.action_see_purchase_order_attachments() + attachments = self.env["ir.attachment"].search(action["domain"]) + self.assertIn(attachment_a.id, attachments.ids) + self.assertIn(self.product_a.id, attachments.mapped("res_id")) + self.assertNotIn(self.product_b.id, attachments.mapped("res_id")) + attachment_b = self._create_attachment(self.product_b) + action = self.purchase_order.action_see_purchase_order_attachments() + attachments = self.env["ir.attachment"].search(action["domain"]) + self.assertIn(attachment_b.id, attachments.ids) + self.assertIn(self.product_a.id, attachments.mapped("res_id")) + self.assertIn(self.product_b.id, attachments.mapped("res_id")) diff --git a/purchase_order_product_attachment_mgmt/views/purchase_order_view.xml b/purchase_order_product_attachment_mgmt/views/purchase_order_view.xml new file mode 100644 index 00000000000..b854939e450 --- /dev/null +++ b/purchase_order_product_attachment_mgmt/views/purchase_order_view.xml @@ -0,0 +1,29 @@ + + + + purchase.order.form + purchase.order + + + +