From ba3d3582bc00b544a897d2b83fa08975f23ae0bd Mon Sep 17 00:00:00 2001 From: "Denis Vermylen (dve)" Date: Mon, 25 Jul 2016 13:27:10 +0200 Subject: [PATCH] [MIG] purchase: Migrate to new API --- addons/purchase/__openerp__.py | 2 - addons/purchase/data/mail_template_data.xml | 2 +- addons/purchase/data/purchase_data.xml | 4 +- addons/purchase/data/purchase_data.yml | 5 +- addons/purchase/data/purchase_demo.xml | 4 +- addons/purchase/data/purchase_stock_demo.yml | 12 +- addons/purchase/models/account_invoice.py | 4 +- addons/purchase/models/mail_mail.py | 20 +-- addons/purchase/models/purchase.py | 35 ++--- addons/purchase/models/res_company.py | 10 +- addons/purchase/models/res_config.py | 99 ++++++------- addons/purchase/models/res_partner.py | 5 +- addons/purchase/models/stock.py | 135 ++++++++---------- .../report/purchase_order_templates.xml | 6 +- .../report/purchase_quotation_templates.xml | 6 +- addons/purchase/report/purchase_report.py | 78 +++++----- .../purchase/report/purchase_report_views.xml | 6 +- addons/purchase/report/purchase_reports.xml | 6 +- .../purchase/security/purchase_security.xml | 4 +- addons/purchase/test/average_price.yml | 60 ++++---- addons/purchase/test/costmethodchange.yml | 67 +++++---- addons/purchase/test/fifo_price.yml | 133 ++++++++--------- addons/purchase/test/fifo_returns.yml | 44 +++--- addons/purchase/test/process/cancel_order.yml | 13 +- .../purchase/test/process/run_scheduler.yml | 22 ++- .../purchase/test/stock_valuation_account.xml | 4 +- addons/purchase/test/ui/delete_order.yml | 14 +- addons/purchase/test/ui/duplicate_order.yml | 4 +- addons/purchase/tests/__init__.py | 2 +- addons/purchase/tests/test_create_picking.py | 2 +- .../tests/test_onchange_product_id.py | 7 +- addons/purchase/tests/test_purchase_order.py | 6 +- .../purchase/views/account_invoice_views.xml | 1 + addons/purchase/views/purchase_views.xml | 6 +- addons/purchase/views/res_company_views.xml | 8 +- addons/purchase/views/res_config_views.xml | 6 +- addons/purchase/views/res_partner_views.xml | 7 +- addons/purchase/views/stock_views.xml | 6 +- 38 files changed, 409 insertions(+), 446 deletions(-) diff --git a/addons/purchase/__openerp__.py b/addons/purchase/__openerp__.py index 2ab599c6852..5002fd853c2 100644 --- a/addons/purchase/__openerp__.py +++ b/addons/purchase/__openerp__.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - { 'name': 'Purchase Management', 'version': '1.2', @@ -51,7 +50,6 @@ Dashboard / Reports for Purchase Management will include: 'test/process/run_scheduler.yml', 'test/fifo_price.yml', 'test/fifo_returns.yml', - # 'test/costmethodchange.yml', 'test/process/cancel_order.yml', 'test/ui/duplicate_order.yml', 'test/ui/delete_order.yml', diff --git a/addons/purchase/data/mail_template_data.xml b/addons/purchase/data/mail_template_data.xml index bde408bffb4..d4644b4667b 100644 --- a/addons/purchase/data/mail_template_data.xml +++ b/addons/purchase/data/mail_template_data.xml @@ -1,7 +1,7 @@ - + RFQ - Send by Email diff --git a/addons/purchase/data/purchase_data.xml b/addons/purchase/data/purchase_data.xml index 7be98a3248a..2fdf518efae 100644 --- a/addons/purchase/data/purchase_data.xml +++ b/addons/purchase/data/purchase_data.xml @@ -1,5 +1,5 @@ - + @@ -53,4 +53,4 @@ - + diff --git a/addons/purchase/data/purchase_data.yml b/addons/purchase/data/purchase_data.yml index 1133dfc3f37..7286785b0d9 100644 --- a/addons/purchase/data/purchase_data.yml +++ b/addons/purchase/data/purchase_data.yml @@ -1,6 +1,5 @@ - - !python {model: stock.warehouse}: | + !python {model: stock.warehouse, id: stock.warehouse0}: | #enable purchase on main warehouse - main_warehouse = self.browse(cr, uid, ref('stock.warehouse0'), context=context) - self.write(cr, uid, main_warehouse.id, {'buy_to_resupply': True}, context=context) + self.write({'buy_to_resupply': True}) diff --git a/addons/purchase/data/purchase_demo.xml b/addons/purchase/data/purchase_demo.xml index d2154ba48b4..7d575957986 100644 --- a/addons/purchase/data/purchase_demo.xml +++ b/addons/purchase/data/purchase_demo.xml @@ -1,5 +1,5 @@ - + @@ -22,5 +22,5 @@ - + diff --git a/addons/purchase/data/purchase_stock_demo.yml b/addons/purchase/data/purchase_stock_demo.yml index a483c8301c6..d44d529b39c 100644 --- a/addons/purchase/data/purchase_stock_demo.yml +++ b/addons/purchase/data/purchase_stock_demo.yml @@ -1,12 +1,8 @@ - - !python {model: stock.warehouse}: | - pull_obj = self.pool.get('procurement.rule') + !python {model: stock.warehouse, id: False}: | + pull_obj = self.env['procurement.rule'] wh_to_assign = ['stock_warehouse_shop0'] for wh_ref in wh_to_assign: - warehouse = self.browse(cr, uid, ref('stock.' + wh_ref), context=context) + warehouse = self.browse(ref('stock.' + wh_ref)) #Force the rewriting of route and rule - self.write(cr, uid, warehouse.id, {'buy_to_resupply': True}, context=context) - - - - + warehouse.write({'buy_to_resupply': True}) diff --git a/addons/purchase/models/account_invoice.py b/addons/purchase/models/account_invoice.py index 6173924f9ba..19480fd5a16 100644 --- a/addons/purchase/models/account_invoice.py +++ b/addons/purchase/models/account_invoice.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp import api, fields, models, _ -from openerp.tools.float_utils import float_compare +from odoo import api, fields, models, _ +from odoo.tools.float_utils import float_compare class AccountInvoice(models.Model): diff --git a/addons/purchase/models/mail_mail.py b/addons/purchase/models/mail_mail.py index 29f893e736c..433ff1d66a5 100644 --- a/addons/purchase/models/mail_mail.py +++ b/addons/purchase/models/mail_mail.py @@ -1,14 +1,18 @@ -from openerp.osv import osv +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models -class mail_mail(osv.Model): +class MailMail(models.Model): _name = 'mail.mail' _inherit = 'mail.mail' - def _postprocess_sent_message(self, cr, uid, ids, context=None, mail_sent=True): - for mail in self.browse(cr, uid, ids, context=context): + @api.multi + def _postprocess_sent_message(self, mail_sent=True): + for mail in self: if mail_sent and mail.model == 'purchase.order': - obj = self.pool.get('purchase.order').browse(cr, uid, mail.res_id, context=context) - if obj.state == 'draft': - self.pool.get('purchase.order').signal_workflow(cr, uid, [mail.res_id], 'send_rfq') - return super(mail_mail, self)._postprocess_sent_message(cr, uid, ids, context=context, mail_sent=mail_sent) + purchase_order = self.env['purchase.order'].browse(mail.res_id) + if purchase_order.state == 'draft': + self.env['purchase.order'].signal_workflow([mail.res_id], 'send_rfq') + return super(MailMail, self)._postprocess_sent_message(mail_sent=mail_sent) diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index 34493ce3cda..7f5fb5dae09 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -3,14 +3,15 @@ from datetime import datetime from dateutil.relativedelta import relativedelta -from openerp import api, fields, models, _, SUPERUSER_ID -from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT -from openerp.tools.translate import _ -from openerp.tools.float_utils import float_is_zero, float_compare -import openerp.addons.decimal_precision as dp -from openerp.exceptions import UserError, AccessError -from openerp.tools.misc import formatLang -from openerp.addons.base.res.res_partner import WARNING_MESSAGE, WARNING_HELP + +from odoo import api, fields, models, SUPERUSER_ID, _ +from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT +from odoo.tools.float_utils import float_is_zero, float_compare +from odoo.exceptions import UserError, AccessError +from odoo.tools.misc import formatLang +from odoo.addons.base.res.res_partner import WARNING_MESSAGE, WARNING_HELP +import odoo.addons.decimal_precision as dp + class PurchaseOrder(models.Model): _name = "purchase.order" @@ -96,7 +97,7 @@ class PurchaseOrder(models.Model): 'cancel': [('readonly', True)], } - name = fields.Char('Order Reference', required=True, select=True, copy=False, default='New') + name = fields.Char('Order Reference', required=True, index=True, copy=False, default='New') origin = fields.Char('Source Document', copy=False,\ help="Reference of the document that generated this purchase order " "request (e.g. a sale order or an internal procurement request)") @@ -105,9 +106,9 @@ class PurchaseOrder(models.Model): "It's used to do the matching when you receive the " "products as this reference is usually written on the " "delivery order sent by your vendor.") - date_order = fields.Datetime('Order Date', required=True, states=READONLY_STATES, select=True, copy=False, default=fields.Datetime.now,\ + date_order = fields.Datetime('Order Date', required=True, states=READONLY_STATES, index=True, copy=False, default=fields.Datetime.now,\ help="Depicts the date where the Quotation should be validated and converted into a purchase order.") - date_approve = fields.Date('Approval Date', readonly=1, select=True, copy=False) + date_approve = fields.Date('Approval Date', readonly=1, index=True, copy=False) partner_id = fields.Many2one('res.partner', string='Vendor', required=True, states=READONLY_STATES, change_default=True, track_visibility='always') dest_address_id = fields.Many2one('res.partner', string='Drop Ship Address', states=READONLY_STATES,\ help="Put an address if you want to deliver directly from the vendor to the customer. "\ @@ -121,7 +122,7 @@ class PurchaseOrder(models.Model): ('purchase', 'Purchase Order'), ('done', 'Locked'), ('cancel', 'Cancelled') - ], string='Status', readonly=True, select=True, copy=False, default='draft', track_visibility='onchange') + ], string='Status', readonly=True, index=True, copy=False, default='draft', track_visibility='onchange') order_line = fields.One2many('purchase.order.line', 'order_id', string='Order Lines', states={'cancel': [('readonly', True)], 'done': [('readonly', True)]}, copy=True) notes = fields.Text('Terms and Conditions') @@ -137,7 +138,7 @@ class PurchaseOrder(models.Model): picking_ids = fields.Many2many('stock.picking', compute='_compute_picking', string='Receptions', copy=False) # There is no inverse function on purpose since the date may be different on each line - date_planned = fields.Datetime(string='Scheduled Date', compute='_compute_date_planned', store=True, select=True, oldname='minimum_planned_date') + date_planned = fields.Datetime(string='Scheduled Date', compute='_compute_date_planned', store=True, index=True, oldname='minimum_planned_date') amount_untaxed = fields.Monetary(string='Untaxed Amount', store=True, readonly=True, compute='_amount_all', track_visibility='always') amount_tax = fields.Monetary(string='Taxes', store=True, readonly=True, compute='_amount_all') @@ -149,7 +150,7 @@ class PurchaseOrder(models.Model): product_id = fields.Many2one('product.product', related='order_line.product_id', string='Product') create_uid = fields.Many2one('res.users', 'Responsible') - company_id = fields.Many2one('res.company', 'Company', required=True, select=1, states=READONLY_STATES, default=lambda self: self.env.user.company_id.id) + company_id = fields.Many2one('res.company', 'Company', required=True, index=True, states=READONLY_STATES, default=lambda self: self.env.user.company_id.id) picking_type_id = fields.Many2one('stock.picking.type', 'Deliver To', states=READONLY_STATES, required=True, default=_default_picking_type,\ help="This will determine picking type of incoming shipment") @@ -548,7 +549,7 @@ class PurchaseOrderLine(models.Model): name = fields.Text(string='Description', required=True) sequence = fields.Integer(string='Sequence', default=10) product_qty = fields.Float(string='Quantity', digits=dp.get_precision('Product Unit of Measure'), required=True) - date_planned = fields.Datetime(string='Scheduled Date', required=True, select=True) + date_planned = fields.Datetime(string='Scheduled Date', required=True, index=True) taxes_id = fields.Many2many('account.tax', string='Taxes', domain=['|', ('active', '=', False), ('active', '=', True)]) product_uom = fields.Many2one('product.uom', string='Product Unit of Measure', required=True) product_id = fields.Many2one('product.product', string='Product', domain=[('purchase_ok', '=', True)], change_default=True, required=True) @@ -559,7 +560,7 @@ class PurchaseOrderLine(models.Model): price_total = fields.Monetary(compute='_compute_amount', string='Total', store=True) price_tax = fields.Monetary(compute='_compute_amount', string='Tax', store=True) - order_id = fields.Many2one('purchase.order', string='Order Reference', select=True, required=True, ondelete='cascade') + order_id = fields.Many2one('purchase.order', string='Order Reference', index=True, required=True, ondelete='cascade') account_analytic_id = fields.Many2one('account.analytic.account', string='Analytic Account') analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tags') company_id = fields.Many2one('res.company', related='order_id.company_id', string='Company', store=True, readonly=True) @@ -776,6 +777,7 @@ class PurchaseOrderLine(models.Model): class ProcurementRule(models.Model): _inherit = 'procurement.rule' + @api.model def _get_action(self): return [('buy', _('Buy'))] + super(ProcurementRule, self)._get_action() @@ -1052,6 +1054,7 @@ class ProductProduct(models.Model): purchase_count = fields.Integer(compute='_purchase_count', string='# Purchases') + class ProductCategory(models.Model): _inherit = "product.category" diff --git a/addons/purchase/models/res_company.py b/addons/purchase/models/res_company.py index 6ee4d0664a3..49768923bdb 100644 --- a/addons/purchase/models/res_company.py +++ b/addons/purchase/models/res_company.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp import fields, models +from odoo import fields, models -class company(models.Model): +class Company(models.Model): _inherit = 'res.company' - po_lead = fields.Float(string='Purchase Lead Time', required=True,\ + po_lead = fields.Float(string='Purchase Lead Time', required=True, help="Margin of error for vendor lead times. When the system " "generates Purchase Orders for procuring products, " "they will be scheduled that many days earlier " @@ -21,8 +21,8 @@ class company(models.Model): po_double_validation = fields.Selection([ ('one_step', 'Confirm purchase orders in one step'), ('two_step', 'Get 2 levels of approvals to confirm a purchase order') - ], string="Levels of Approvals", default='one_step',\ + ], string="Levels of Approvals", default='one_step', help="Provide a double validation mechanism for purchases") - po_double_validation_amount = fields.Monetary(string='Double validation amount', default=5000,\ + po_double_validation_amount = fields.Monetary(string='Double validation amount', default=5000, help="Minimum amount for which a double validation is required") diff --git a/addons/purchase/models/res_config.py b/addons/purchase/models/res_config.py index db6006b8847..ce5244466d0 100644 --- a/addons/purchase/models/res_config.py +++ b/addons/purchase/models/res_config.py @@ -1,62 +1,57 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp import SUPERUSER_ID -from openerp.osv import fields, osv -from openerp.tools.translate import _ +from odoo import fields, models -class purchase_config_settings(osv.osv_memory): + +class PurchaseConfigSettings(models.TransientModel): _name = 'purchase.config.settings' _inherit = 'res.config.settings' - _columns = { - 'group_product_variant': fields.selection([ - (0, "No variants on products"), - (1, 'Products can have several attributes, defining variants (Example: size, color,...)') - ], "Product Variants", - help='Work with product variant allows you to define some variant of the same products, an ease the product management in the ecommerce for example', - implied_group='product.group_product_variant'), - 'group_uom':fields.selection([ - (0, 'Products have only one unit of measure (easier)'), - (1, 'Some products may be sold/puchased in different units of measure (advanced)') - ], "Units of Measure", - implied_group='product.group_uom', - help="""Allows you to select and maintain different units of measure for products."""), - 'group_costing_method':fields.selection([ - (0, 'Set a fixed cost price on each product'), - (1, "Use a 'Fixed', 'Real' or 'Average' price costing method") - ], "Costing Methods", - implied_group='stock_account.group_inventory_valuation', - help="""Allows you to compute product cost price based on average cost."""), - 'module_purchase_requisition': fields.selection([ - (0, 'Purchase propositions trigger draft purchase orders to a single supplier'), - (1, 'Allow using call for tenders to get quotes from multiple suppliers (advanced)') - ], "Calls for Tenders", - help="Calls for tenders are used when you want to generate requests for quotations to several vendors for a given set of products.\n" - "You can configure per product if you directly do a Request for Quotation " - "to one vendor or if you want a Call for Tenders to compare offers from several vendors."), - 'group_warning_purchase': fields.selection([ - (0, 'All the products and the customers can be used in purchase orders'), - (1, 'An informative or blocking warning can be set on a product or a customer') - ], "Warning", implied_group='purchase.group_warning_purchase'), - 'module_stock_dropshipping': fields.selection([ - (0, 'Suppliers always deliver to your warehouse(s)'), - (1, "Allow suppliers to deliver directly to your customers") - ], "Dropshipping", - help='\nCreates the dropship Route and add more complex tests\n' - '-This installs the module stock_dropshipping.'), - 'group_manage_vendor_price': fields.selection([ - (0, 'Manage vendor price on the product form'), - (1, 'Allow using and importing vendor pricelists') - ], "Vendor Price", - implied_group="purchase.group_manage_vendor_price"), - } + group_product_variant = fields.Selection([ + (0, "No variants on products"), + (1, 'Products can have several attributes, defining variants (Example: size, color,...)') + ], "Product Variants", + help='Work with product variant allows you to define some variant of the same products, an ease the product management in the ecommerce for example', + implied_group='product.group_product_variant') + group_uom = fields.Selection([ + (0, 'Products have only one unit of measure (easier)'), + (1, 'Some products may be sold/puchased in different units of measure (advanced)') + ], "Units of Measure", + implied_group='product.group_uom', + help="""Allows you to select and maintain different units of measure for products.""") + group_costing_method = fields.Selection([ + (0, 'Set a fixed cost price on each product'), + (1, "Use a 'Fixed', 'Real' or 'Average' price costing method") + ], "Costing Methods", + implied_group='stock_account.group_inventory_valuation', + help="""Allows you to compute product cost price based on average cost.""") + module_purchase_requisition = fields.Selection([ + (0, 'Purchase propositions trigger draft purchase orders to a single supplier'), + (1, 'Allow using call for tenders to get quotes from multiple suppliers (advanced)') + ], "Calls for Tenders", + help="Calls for tenders are used when you want to generate requests for quotations to several vendors for a given set of products.\n" + "You can configure per product if you directly do a Request for Quotation " + "to one vendor or if you want a Call for Tenders to compare offers from several vendors.") + group_warning_purchase = fields.Selection([ + (0, 'All the products and the customers can be used in purchase orders'), + (1, 'An informative or blocking warning can be set on a product or a customer') + ], "Warning", implied_group='purchase.group_warning_purchase') + module_stock_dropshipping = fields.Selection([ + (0, 'Suppliers always deliver to your warehouse(s)'), + (1, "Allow suppliers to deliver directly to your customers") + ], "Dropshipping", + help='\nCreates the dropship Route and add more complex tests\n' + '-This installs the module stock_dropshipping.') + group_manage_vendor_price = fields.Selection([ + (0, 'Manage vendor price on the product form'), + (1, 'Allow using and importing vendor pricelists') + ], "Vendor Price", + implied_group="purchase.group_manage_vendor_price") -class account_config_settings(osv.osv_memory): +class AccountConfigSettings(models.TransientModel): _inherit = 'account.config.settings' - _columns = { - 'group_analytic_account_for_purchases': fields.boolean('Analytic accounting for purchases', - implied_group='purchase.group_analytic_accounting', - help="Allows you to specify an analytic account on purchase order lines."), - } + group_analytic_account_for_purchases = fields.Boolean('Analytic accounting for purchases', + implied_group='purchase.group_analytic_accounting', + help="Allows you to specify an analytic account on purchase order lines.") diff --git a/addons/purchase/models/res_partner.py b/addons/purchase/models/res_partner.py index 969f1352393..8983a4b07b3 100644 --- a/addons/purchase/models/res_partner.py +++ b/addons/purchase/models/res_partner.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp import api, fields, models -from openerp.addons.base.res.res_partner import WARNING_MESSAGE, WARNING_HELP +from odoo import api, fields, models +from odoo.addons.base.res.res_partner import WARNING_MESSAGE, WARNING_HELP + class res_partner(models.Model): _name = 'res.partner' diff --git a/addons/purchase/models/stock.py b/addons/purchase/models/stock.py index a55a40d5c03..aa2b67c4750 100644 --- a/addons/purchase/models/stock.py +++ b/addons/purchase/models/stock.py @@ -1,20 +1,19 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp import api -from openerp.osv import fields, osv -from openerp.tools.translate import _ -from openerp.exceptions import UserError +from odoo import api, fields, models, _ +from odoo.exceptions import UserError -class stock_picking(osv.osv): + +class StockPicking(models.Model): _inherit = 'stock.picking' - _columns = { - 'purchase_id': fields.related('move_lines', 'purchase_line_id', 'order_id', string="Purchase Orders", - readonly=True, type="many2one", relation="purchase.order"), - } - def _prepare_values_extra_move(self, cr, uid, op, product, remaining_qty, context=None): - res = super(stock_picking, self)._prepare_values_extra_move(cr, uid, op, product, remaining_qty, context=context) + purchase_id = fields.Many2one('purchase.order', related='move_lines.purchase_line_id.order_id', + string="Purchase Orders", readonly=True) + + @api.model + def _prepare_values_extra_move(self, op, product, remaining_qty): + res = super(StockPicking, self)._prepare_values_extra_move(op, product, remaining_qty) for m in op.linked_move_operation_ids: if m.move_id.purchase_line_id and m.move_id.product_id == product: res['purchase_line_id'] = m.move_id.purchase_line_id.id @@ -23,7 +22,7 @@ class stock_picking(osv.osv): @api.model def _create_backorder(self, backorder_moves=[]): - res = super(stock_picking, self)._create_backorder(backorder_moves) + res = super(StockPicking, self)._create_backorder(backorder_moves) for picking in self: if picking.picking_type_id.code == 'incoming': backorder = self.search([('backorder_id', '=', picking.id)]) @@ -32,13 +31,12 @@ class stock_picking(osv.osv): subtype_id=self.env.ref('mail.mt_note').id) return res -class stock_move(osv.osv): + +class StockMove(models.Model): _inherit = 'stock.move' - _columns = { - 'purchase_line_id': fields.many2one('purchase.order.line', - 'Purchase Order Line', ondelete='set null', select=True, - readonly=True), - } + + purchase_line_id = fields.Many2one('purchase.order.line', + 'Purchase Order Line', ondelete='set null', index=True, readonly=True) @api.multi def get_price_unit(self): @@ -56,95 +54,88 @@ class stock_move(osv.osv): self.write({'price_unit': price_unit}) return price_unit return self.price_unit - return super(stock_move, self).get_price_unit() + return super(StockMove, self).get_price_unit() - def copy(self, cr, uid, id, default=None, context=None): + @api.multi + def copy(self, default=None): + self.ensure_one() default = default or {} - context = context or {} if not default.get('split_from'): #we don't want to propagate the link to the purchase order line except in case of move split default['purchase_line_id'] = False - return super(stock_move, self).copy(cr, uid, id, default, context) + return super(StockMove, self).copy(default) -class stock_warehouse(osv.osv): +class StockWarehouse(models.Model): _inherit = 'stock.warehouse' - _columns = { - 'buy_to_resupply': fields.boolean('Purchase to resupply this warehouse', - help="When products are bought, they can be delivered to this warehouse"), - 'buy_pull_id': fields.many2one('procurement.rule', 'Buy rule'), - } - _defaults = { - 'buy_to_resupply': True, - } - def _get_buy_pull_rule(self, cr, uid, warehouse, context=None): - route_obj = self.pool.get('stock.location.route') - data_obj = self.pool.get('ir.model.data') + buy_to_resupply = fields.Boolean('Purchase to resupply this warehouse', default=True, + help="When products are bought, they can be delivered to this warehouse") + buy_pull_id = fields.Many2one('procurement.rule', 'Buy rule') + + @api.multi + def _get_buy_pull_rule(self): try: - buy_route_id = data_obj.get_object_reference(cr, uid, 'purchase', 'route_warehouse0_buy')[1] + buy_route_id = self.env['ir.model.data'].get_object_reference('purchase', 'route_warehouse0_buy')[1] except: - buy_route_id = route_obj.search(cr, uid, [('name', 'like', _('Buy'))], context=context) - buy_route_id = buy_route_id and buy_route_id[0] or False + buy_route_id = self.env['stock.location.route'].search([('name', 'like', _('Buy'))]) + buy_route_id = buy_route_id[0].id if buy_route_id else False if not buy_route_id: - raise UserError(_('Can\'t find any generic Buy route.')) + raise UserError(_("Can't find any generic Buy route.")) return { - 'name': warehouse._format_routename(_(' Buy')), - 'location_id': warehouse.in_type_id.default_location_dest_id.id, + 'name': self._format_routename(_(' Buy')), + 'location_id': self.in_type_id.default_location_dest_id.id, 'route_id': buy_route_id, 'action': 'buy', - 'picking_type_id': warehouse.in_type_id.id, - 'warehouse_id': warehouse.id, + 'picking_type_id': self.in_type_id.id, + 'warehouse_id': self.id, 'group_propagation_option': 'none', } - def create_routes(self, cr, uid, ids, context=None): - pull_obj = self.pool.get('procurement.rule') - res = super(stock_warehouse, self).create_routes(cr, uid, ids, context=context) - warehouse = self.browse(cr, uid, ids, context=context)[0] - if warehouse.buy_to_resupply: - buy_pull_vals = self._get_buy_pull_rule(cr, uid, warehouse, context=context) - buy_pull_id = pull_obj.create(cr, uid, buy_pull_vals, context=context) - res['buy_pull_id'] = buy_pull_id + @api.multi + def create_routes(self): + res = super(StockWarehouse, self).create_routes() # super applies ensure_one() + if self.buy_to_resupply: + buy_pull_vals = self._get_buy_pull_rule() + buy_pull = self.env['procurement.rule'].create(buy_pull_vals) + res['buy_pull_id'] = buy_pull.id return res - def write(self, cr, uid, ids, vals, context=None): - pull_obj = self.pool.get('procurement.rule') - if isinstance(ids, (int, long)): - ids = [ids] - + @api.multi + def write(self, vals): if 'buy_to_resupply' in vals: if vals.get("buy_to_resupply"): - for warehouse in self.browse(cr, uid, ids, context=context): + for warehouse in self: if not warehouse.buy_pull_id: - buy_pull_vals = self._get_buy_pull_rule(cr, uid, warehouse, context=context) - buy_pull_id = pull_obj.create(cr, uid, buy_pull_vals, context=context) - vals['buy_pull_id'] = buy_pull_id + buy_pull_vals = self._get_buy_pull_rule() + buy_pull = self.env['procurement.rule'].create(buy_pull_vals) + vals['buy_pull_id'] = buy_pull.id else: - for warehouse in self.browse(cr, uid, ids, context=context): + for warehouse in self: if warehouse.buy_pull_id: - buy_pull_id = pull_obj.unlink(cr, uid, warehouse.buy_pull_id.id, context=context) - return super(stock_warehouse, self).write(cr, uid, ids, vals, context=None) + warehouse.buy_pull_id.unlink() + return super(StockWarehouse, self).write(vals) @api.multi def _get_all_routes(self): - routes = super(stock_warehouse, self).get_all_routes_for_wh() + routes = super(StockWarehouse, self).get_all_routes_for_wh() routes |= self.filtered(lambda self: self.buy_to_resupply and self.buy_pull_id and self.buy_pull_id.route_id).mapped('buy_pull_id').mapped('route_id') return routes - def _handle_renaming(self, cr, uid, ids, name, code, context=None): - res = super(stock_warehouse, self)._handle_renaming(cr, uid, ids, name, code, context=context) - warehouse = self.browse(cr, uid, ids[0], context=context) - pull_obj = self.pool.get('procurement.rule') + @api.multi + def _handle_renaming(self, name, code): + res = super(StockWarehouse, self)._handle_renaming(name, code) + warehouse = self[0] #change the buy procurement rule name if warehouse.buy_pull_id: - pull_obj.write(cr, uid, warehouse.buy_pull_id.id, {'name': warehouse.buy_pull_id.name.replace(warehouse.name, name, 1)}, context=context) + warehouse.buy_pull_id.write({'name': warehouse.buy_pull_id.name.replace(warehouse.name, name, 1)}) return res - def change_route(self, cr, uid, ids, context=None): - res = super(stock_warehouse, self).change_route(cr, uid, ids, context=context) - for warehouse in self.browse(cr, uid, ids[0], context=context): + @api.multi + def change_route(self): + res = super(StockWarehouse, self).change_route() + for warehouse in self: if warehouse.in_type_id.default_location_dest_id != warehouse.buy_pull_id.location_id: - self.pool.get('procurement.rule').write(cr, uid, warehouse.buy_pull_id.id, {'location_id': warehouse.in_type_id.default_location_dest_id.id}, context=context) + warehouse.buy_pull_id.write({'location_id': warehouse.in_type_id.default_location_dest_id.id}) return res diff --git a/addons/purchase/report/purchase_order_templates.xml b/addons/purchase/report/purchase_order_templates.xml index ad3896dd19d..51387d29c9e 100644 --- a/addons/purchase/report/purchase_order_templates.xml +++ b/addons/purchase/report/purchase_order_templates.xml @@ -1,6 +1,5 @@ - - + - - + diff --git a/addons/purchase/report/purchase_quotation_templates.xml b/addons/purchase/report/purchase_quotation_templates.xml index 765a108f306..d2855ccc023 100644 --- a/addons/purchase/report/purchase_quotation_templates.xml +++ b/addons/purchase/report/purchase_quotation_templates.xml @@ -1,6 +1,5 @@ - - + - - + diff --git a/addons/purchase/report/purchase_report.py b/addons/purchase/report/purchase_report.py index 268220edf29..d7134c7dc79 100644 --- a/addons/purchase/report/purchase_report.py +++ b/addons/purchase/report/purchase_report.py @@ -5,50 +5,52 @@ # Please note that these reports are not multi-currency !!! # -from openerp.osv import fields,osv -from openerp import tools +from odoo import fields, models +from odoo import tools -class purchase_report(osv.osv): + +class PurchaseReport(models.Model): _name = "purchase.report" _description = "Purchases Orders" _auto = False - _columns = { - 'date_order': fields.datetime('Order Date', readonly=True, help="Date on which this document has been created", oldname='date'), - 'state': fields.selection([('draft', 'Draft RFQ'), - ('sent', 'RFQ Sent'), - ('to approve', 'To Approve'), - ('purchase', 'Purchase Order'), - ('done', 'Done'), - ('cancel', 'Cancelled') - ],'Order Status', readonly=True), - 'product_id':fields.many2one('product.product', 'Product', readonly=True), - 'picking_type_id': fields.many2one('stock.warehouse', 'Warehouse', readonly=True), - 'partner_id':fields.many2one('res.partner', 'Vendor', readonly=True), - 'date_approve':fields.date('Date Approved', readonly=True), - 'product_uom' : fields.many2one('product.uom', 'Reference Unit of Measure', required=True), - 'company_id':fields.many2one('res.company', 'Company', readonly=True), - 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True), - 'user_id':fields.many2one('res.users', 'Responsible', readonly=True), - 'delay':fields.float('Days to Validate', digits=(16,2), readonly=True), - 'delay_pass':fields.float('Days to Deliver', digits=(16,2), readonly=True), - 'unit_quantity': fields.float('Product Quantity', readonly=True, oldname='quantity'), - 'price_total': fields.float('Total Price', readonly=True), - 'price_average': fields.float('Average Price', readonly=True, group_operator="avg"), - 'negociation': fields.float('Purchase-Standard Price', readonly=True, group_operator="avg"), - 'price_standard': fields.float('Products Value', readonly=True, group_operator="sum"), - 'nbr_lines': fields.integer('# of Lines', readonly=True, oldname='nbr'), - 'category_id': fields.many2one('product.category', 'Product Category', readonly=True), - 'product_tmpl_id': fields.many2one('product.template', 'Product Template', readonly=True), - 'country_id': fields.many2one('res.country', 'Partner Country', readonly=True), - 'fiscal_position_id': fields.many2one('account.fiscal.position', string='Fiscal Position', oldname='fiscal_position', readonly=True), - 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True), - 'commercial_partner_id': fields.many2one('res.partner', 'Commercial Entity', readonly=True), - 'weight': fields.float('Gross Weight', readonly=True), - 'volume': fields.float('Volume', readonly=True), - } _order = 'date_order desc, price_total desc' + + date_order = fields.Datetime('Order Date', readonly=True, help="Date on which this document has been created", oldname='date') + state = fields.Selection([ + ('draft', 'Draft RFQ'), + ('sent', 'RFQ Sent'), + ('to approve', 'To Approve'), + ('purchase', 'Purchase Order'), + ('done', 'Done'), + ('cancel', 'Cancelled') + ], 'Order Status', readonly=True) + product_id = fields.Many2one('product.product', 'Product', readonly=True) + picking_type_id = fields.Many2one('stock.warehouse', 'Warehouse', readonly=True) + partner_id = fields.Many2one('res.partner', 'Vendor', readonly=True) + date_approve = fields.Date('Date Approved', readonly=True) + product_uom = fields.Many2one('product.uom', 'Reference Unit of Measure', required=True) + company_id = fields.Many2one('res.company', 'Company', readonly=True) + currency_id = fields.Many2one('res.currency', 'Currency', readonly=True) + user_id = fields.Many2one('res.users', 'Responsible', readonly=True) + delay = fields.Float('Days to Validate', digits=(16, 2), readonly=True) + delay_pass = fields.Float('Days to Deliver', digits=(16, 2), readonly=True) + unit_quantity = fields.Float('Product Quantity', readonly=True, oldname='quantity') + price_total = fields.Float('Total Price', readonly=True) + price_average = fields.Float('Average Price', readonly=True, group_operator="avg") + negociation = fields.Float('Purchase-Standard Price', readonly=True, group_operator="avg") + price_standard = fields.Float('Products Value', readonly=True, group_operator="sum") + nbr_lines = fields.Integer('# of Lines', readonly=True, oldname='nbr') + category_id = fields.Many2one('product.category', 'Product Category', readonly=True) + product_tmpl_id = fields.Many2one('product.template', 'Product Template', readonly=True) + country_id = fields.Many2one('res.country', 'Partner Country', readonly=True) + fiscal_position_id = fields.Many2one('account.fiscal.position', string='Fiscal Position', oldname='fiscal_position', readonly=True) + account_analytic_id = fields.Many2one('account.analytic.account', 'Analytic Account', readonly=True) + commercial_partner_id = fields.Many2one('res.partner', 'Commercial Entity', readonly=True) + weight = fields.Float('Gross Weight', readonly=True) + volume = fields.Float('Volume', readonly=True) + def init(self, cr): - tools.sql.drop_view_if_exists(cr, 'purchase_report') + tools.sql.drop_view_if_exists(cr, 'purchase_report') # to remove, 2 lines below : create or replace. cr.execute(""" create or replace view purchase_report as ( WITH currency_rate as (%s) diff --git a/addons/purchase/report/purchase_report_views.xml b/addons/purchase/report/purchase_report_views.xml index e94277dcc87..f47a36e0a15 100644 --- a/addons/purchase/report/purchase_report_views.xml +++ b/addons/purchase/report/purchase_report_views.xml @@ -1,6 +1,5 @@ - - + product.month.pivot purchase.report @@ -95,5 +94,4 @@ - - + diff --git a/addons/purchase/report/purchase_reports.xml b/addons/purchase/report/purchase_reports.xml index 424a450cd9e..75bba974ed1 100644 --- a/addons/purchase/report/purchase_reports.xml +++ b/addons/purchase/report/purchase_reports.xml @@ -1,6 +1,5 @@ - - + - - + diff --git a/addons/purchase/security/purchase_security.xml b/addons/purchase/security/purchase_security.xml index 8625c90ac44..0544735c381 100644 --- a/addons/purchase/security/purchase_security.xml +++ b/addons/purchase/security/purchase_security.xml @@ -1,5 +1,5 @@ - + @@ -53,4 +53,4 @@ - + diff --git a/addons/purchase/test/average_price.yml b/addons/purchase/test/average_price.yml index 32e2cb9760b..a9a8c3585e2 100644 --- a/addons/purchase/test/average_price.yml +++ b/addons/purchase/test/average_price.yml @@ -28,8 +28,8 @@ - I confirm the first purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_average1")]) + !python {model: purchase.order, id: purchase_order_average1}: | + self.button_confirm() - I check the "Approved" status of purchase order 1 - @@ -38,16 +38,15 @@ - Process the reception of purchase order 1 - - !python {model: stock.picking}: | - pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_average1")).picking_ids - self.do_transfer(cr, uid, [pick_ids[0].id]) + !python {model: purchase.order, id: purchase_order_average1}: | + picking = self.picking_ids[0] + picking.do_transfer() - Check the standard price of the product (average icecream). - - !python {model: product.product}: | - product = self.browse(cr, uid, ref("product_average_icecream")) - assert product.qty_available == 10.0, 'Wrong quantity in stock after first reception' - assert product.standard_price == 60.0, 'Standard price should be the price of the first reception!' + !python {model: product.product, id: product_average_icecream}: | + assert self.qty_available == 10.0, 'Wrong quantity in stock after first reception' + assert self.standard_price == 60.0, 'Standard price should be the price of the first reception!' - I create a draft Purchase Order for second incoming shipment for 30 pieces at 80€ - @@ -63,19 +62,19 @@ - I confirm the second purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_average2")]) + !python {model: purchase.order, id: purchase_order_average2}: | + self.button_confirm() - Process the reception of purchase order 2 - - !python {model: stock.picking}: | - pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_average2")).picking_ids - self.do_transfer(cr, uid, [pick_ids[0].id]) + !python {model: purchase.order, id: purchase_order_average2}: | + picking = self.picking_ids[0] + picking.do_transfer() - Check the standard price - - !python {model: product.product}: | - assert self.browse(cr, uid, ref("product_average_icecream")).standard_price == 75.0, 'After second reception, we should have an average price of 75.0 on the product' + !python {model: product.product, id: product_average_icecream}: | + assert self.standard_price == 75.0, 'After second reception, we should have an average price of 75.0 on the product' - Create picking to send some goods - @@ -94,15 +93,15 @@ - I assign this outgoing shipment and process the delivery - - !python {model: stock.picking}: | - self.action_assign(cr, uid, [ref("outgoing_average_shipment")]) - self.do_transfer(cr, uid, [ref("outgoing_average_shipment")]) + !python {model: stock.picking, id: outgoing_average_shipment}: | + self.action_assign() + self.do_transfer() - Check the standard price (60 * 10 + 30 * 80) / 40 = 75.0 did not change - - !python {model: product.product}: | - assert self.browse(cr, uid, ref("product_average_icecream")).standard_price == 75.0, 'Standard price should not have changed with outgoing picking!' - assert self.browse(cr, uid, ref("product_average_icecream")).qty_available == 20.0, 'Pieces were not picked correctly as the quantity on hand is wrong' + !python {model: product.product, id: product_average_icecream}: | + assert self.standard_price == 75.0, 'Standard price should not have changed with outgoing picking!' + assert self.qty_available == 20.0, 'Pieces were not picked correctly as the quantity on hand is wrong' - Make a new purchase order with 500 g Average Ice Cream at a price of 0.2€/g - @@ -118,18 +117,17 @@ - I confirm the first purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_average3")]) + !python {model: purchase.order, id: purchase_order_average3}: | + self.button_confirm() - Process the reception of purchase order 3 in grams - - !python {model: stock.picking}: | - pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_average3")).picking_ids - self.do_transfer(cr, uid, [pick_ids[0].id]) + !python {model: purchase.order, id: purchase_order_average3}: | + picking = self.picking_ids[0] + picking.do_transfer() - Check price is (75.0*20 + 200*0.5) / 20.5 = 78.04878 - - !python {model: product.product}: | - product = self.browse(cr, uid, ref("product_average_icecream")) - assert product.qty_available == 20.5, 'Reception of purchase order in grams leads to wrong quantity in stock' - assert round(self.browse(cr, uid, ref("product_average_icecream")).standard_price, 2) == 78.05, 'Standard price as average price of third reception with other UoM incorrect! Got %s instead of 78.05' % (round(self.browse(cr, uid, ref("product_average_icecream")).standard_price, 2),) + !python {model: product.product, id: product_average_icecream}: | + assert self.qty_available == 20.5, 'Reception of purchase order in grams leads to wrong quantity in stock' + assert round(self.standard_price, 2) == 78.05, 'Standard price as average price of third reception with other UoM incorrect! Got %s instead of 78.05' % (round(self.standard_price, 2),) diff --git a/addons/purchase/test/costmethodchange.yml b/addons/purchase/test/costmethodchange.yml index cad69ecf3b5..c5b3da282f2 100644 --- a/addons/purchase/test/costmethodchange.yml +++ b/addons/purchase/test/costmethodchange.yml @@ -39,13 +39,13 @@ - I confirm the first purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_variable1")]) + !python {model: purchase.order, id: purchase_order_variable1}: | + self.button_confirm() - I confirm the second purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_variable2")]) + !python {model: purchase.order, id: purchase_order_variable2}: | + self.button_confirm() - I check the "Approved" status of purchase order 1 - @@ -54,30 +54,29 @@ - Process the reception of purchase order 1 - - !python {model: stock.partial.picking}: | - pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_variable1")).picking_ids - partial_id = self.create(cr, uid, {}, context={'active_model': 'stock.picking','active_ids': [pick_ids[0].id]}) - self.do_transfer(cr, uid, [partial_id]) + !python {model: stock.partial.picking, id: False}: | + pickings = self.env['purchase.order'].browse(ref("purchase_order_variable1")).picking_ids + partial = self.with_context({'active_model': 'stock.picking','active_ids': [pickings[0].id]}).create({}) + partial.do_transfer() - Check the standard price of the product (variable icecream). - - !python {model: product.product}: | - product = self.browse(cr, uid, ref("product_variable_icecream")) - assert product.qty_available == 10.0, 'Wrong quantity in stock after first reception' - assert product.standard_price == 60.0, 'Standard price should be the price of the first reception!' + !python {model: product.product, id: product_variable_icecream}: | + assert self.qty_available == 10.0, 'Wrong quantity in stock after first reception' + assert self.standard_price == 60.0, 'Standard price should be the price of the first reception!' - Process the reception of purchase order 2 - - !python {model: stock.partial.picking}: | - pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_variable2")).picking_ids - partial_id = self.create(cr, uid, {}, context={'active_model': 'stock.picking','active_ids': [pick_ids[0].id]}) - self.do_transfer(cr, uid, [partial_id]) + !python {model: stock.partial.picking, id: False}: | + pickings = self.env['purchase.order'].browse(ref("purchase_order_variable2")).picking_ids + partial = self.with_context({'active_model': 'stock.picking','active_ids': [pickings[0].id]}).create({}) + partial.do_transfer() - Check the standard price and change the product's cost method towards fifo - - !python {model: product.product}: | - assert self.browse(cr, uid, ref("product_variable_icecream")).standard_price == 75.0, 'After second reception, we should have an average price of 75.0 on the product' - self.write(cr, uid, [ref("product_variable_icecream")], {'cost_method': 'real'}, context=context) + !python {model: product.product, id: product_variable_icecream}: | + assert self.standard_price == 75.0, 'After second reception, we should have an average price of 75.0 on the product' + self.write({'cost_method': 'real'}) - Create picking to send some goods - @@ -99,15 +98,15 @@ - Process the delivery of the outgoing shipment - - !python {model: stock.partial.picking}: | - partial_id = self.create(cr, uid, {}, context={'active_model': 'stock.picking','active_ids': [ref("outgoing_variable_shipment")], 'default_type':'out'}) - self.do_transfer(cr, uid, [partial_id]) + !python {model: stock.partial.picking, id: False}: | + partial = self.with_context({'active_model': 'stock.picking','active_ids': [ref("outgoing_variable_shipment")], 'default_type':'out'}).create({}) + partial.do_transfer() - Check the standard price (60 * 10 + 30 * 80) / 40 = 75.0 did not change - - !python {model: product.product}: | - assert self.browse(cr, uid, ref("product_variable_icecream")).standard_price == 75.0, 'Standard price should not have changed with outgoing picking!' - assert self.browse(cr, uid, ref("product_variable_icecream")).qty_available == 20.0, 'Pieces were not picked correctly as the quantity on hand is wrong' + !python {model: product.product, id: product_variable_icecream}: | + assert self.standard_price == 75.0, 'Standard price should not have changed with outgoing picking!' + assert self.qty_available == 20.0, 'Pieces were not picked correctly as the quantity on hand is wrong' - I create a draft Purchase Order for third incoming shipment for 20 pieces at 60 euro - @@ -122,18 +121,18 @@ - I confirm this third purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_variable3")]) + !python {model: purchase.order, id: purchase_order_variable3}: | + self.button_confirm() - Process the reception of purchase order 3 - - !python {model: stock.partial.picking}: | - pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_variable3")).picking_ids - partial_id = self.create(cr, uid, {}, context={'active_model': 'stock.picking','active_ids': [pick_ids[0].id]}) - self.do_transfer(cr, uid, [partial_id]) + !python {model: stock.partial.picking, id: False}: | + pickings = self.env['purchase.order'].browse(ref("purchase_order_variable3")).picking_ids + partial = self.with_context({'active_model': 'stock.picking','active_ids': [pickings[0].id]}).create({}) + partial.do_transfer() - Change the cost method back to average and check price on product changed back to 70.0 = (20*60 + 10*60 + 30*80) / 60 - - !python {model: product.product}: | - self.write(cr, uid, [ref("product_variable_icecream")], {'cost_method': 'average'}, context=context) - assert self.browse(cr, uid, ref("product_variable_icecream")).standard_price == 70.0, 'After third reception and changing to average again, we should have an average price of 70.0 on the product' + !python {model: product.product, id: product_variable_icecream}: | + self.write({'cost_method': 'average'}) + assert self.standard_price == 70.0, 'After third reception and changing to average again, we should have an average price of 70.0 on the product' diff --git a/addons/purchase/test/fifo_price.yml b/addons/purchase/test/fifo_price.yml index 7c77dedf087..958e2fcb31b 100644 --- a/addons/purchase/test/fifo_price.yml +++ b/addons/purchase/test/fifo_price.yml @@ -36,8 +36,8 @@ - I confirm the first purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_fifo1")]) + !python {model: purchase.order, id: purchase_order_fifo1}: | + self.button_confirm() - I check the "Purchase" status of purchase order 1 - @@ -46,14 +46,14 @@ - Process the reception of purchase order 1 and set date - - !python {model: stock.picking}: | - picking_obj = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fifo1"), context=context).picking_ids[0] - picking_obj.do_transfer() + !python {model: purchase.order, id: purchase_order_fifo1}: | + picking = self.picking_ids[0] + picking.do_transfer() - Check the standard price of the product (fifo icecream), that should have not changed because the standard price is supposed to be updated only when goods are going out of the stock - - !python {model: product.product}: | - assert self.browse(cr, uid, ref("product_fifo_icecream")).standard_price == 70.0, 'Standard price should not have changed!' + !python {model: product.product, id: product_fifo_icecream}: | + assert self.standard_price == 70.0, 'Standard price should not have changed!' - I create a draft Purchase Order for second shipment for 30 kg at 80 euro - @@ -69,19 +69,19 @@ - I confirm the second purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_fifo2")]) + !python {model: purchase.order, id: purchase_order_fifo2}: | + self.button_confirm() - Process the reception of purchase order 2 - - !python {model: stock.picking}: | - picking_obj = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fifo2"), context=context).picking_ids[0] - picking_obj.do_transfer() + !python {model: purchase.order, id: purchase_order_fifo2}: | + picking = self.picking_ids[0] + picking.do_transfer() - Check the standard price of the product, that should have not changed because the standard price is supposed to be updated only when goods are going out of the stock - - !python {model: product.product}: | - assert self.browse(cr, uid, ref("product_fifo_icecream")).standard_price == 70.0, 'Standard price as fifo price of second reception incorrect!' + !python {model: product.product, id: product_fifo_icecream}: | + assert self.standard_price == 70.0, 'Standard price as fifo price of second reception incorrect!' - Let us send some goods - @@ -101,19 +101,18 @@ - I assign this outgoing shipment - - !python {model: stock.picking}: | - self.action_assign(cr, uid, [ref("outgoing_fifo_shipment")]) + !python {model: stock.picking, id: outgoing_fifo_shipment}: | + self.action_assign() - Process the delivery of the outgoing shipment - - !python {model: stock.picking}: | - pick_obj = self.pool.get('stock.picking').browse(cr, uid, ref("outgoing_fifo_shipment"), context=context) - pick_obj.do_transfer() + !python {model: stock.picking, id: outgoing_fifo_shipment}: | + self.do_transfer() - Check product standard price changed to 65.0 (because last outgoing shipment was made of 10 kg at 50€ and 10 kg at 80€) - - !python {model: product.product}: | - assert self.browse(cr, uid, ref("product_fifo_icecream")).standard_price == 65.0, "Product price not updated accordingly. %s found instead of 65" %(self.browse(cr, uid, ref("product_fifo_icecream")).standard_price,) + !python {model: product.product, id: product_fifo_icecream}: | + assert self.standard_price == 65.0, "Product price not updated accordingly. %s found instead of 65" % (self.standard_price,) - Do a delivery of an extra 500 g (delivery order) - @@ -133,19 +132,18 @@ - I assign this outgoing shipment - - !python {model: stock.picking}: | - self.action_assign(cr, uid, [ref("outgoing_fifo_shipment_uom")]) + !python {model: stock.picking, id: outgoing_fifo_shipment_uom}: | + self.action_assign() - Process the delivery of the outgoing shipment - - !python {model: stock.picking}: | - pick_obj = self.pool.get('stock.picking').browse(cr, uid, ref("outgoing_fifo_shipment_uom"), context=context) - pick_obj.do_transfer() + !python {model: stock.picking, id: outgoing_fifo_shipment_uom}: | + self.do_transfer() - Check product price changed to 80.0 (because last outgoing shipment was made of 0.5 kg at 80€) - - !python {model: product.product}: | - assert self.browse(cr, uid, ref("product_fifo_icecream")).standard_price == 80.0, "Product price not updated accordingly. %s found instead of 80" %(self.browse(cr, uid, ref("product_fifo_icecream")).standard_price,) + !python {model: product.product, id: product_fifo_icecream}: | + assert self.standard_price == 80.0, "Product price not updated accordingly. %s found instead of 80" % (self.standard_price,) - We will temporarily change the currency rate on the sixth of June to have the same results all year - @@ -179,14 +177,14 @@ - I confirm the purchase order in USD - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_fifo_usd")]) + !python {model: purchase.order, id: purchase_order_fifo_usd}: | + self.button_confirm() - Process the reception of purchase order with usd - - !python {model: stock.picking}: | - pick_obj = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fifo_usd"), context=context).picking_ids[0] - pick_obj.do_transfer() + !python {model: purchase.order, id: purchase_order_fifo_usd}: | + picking = self.picking_ids[0] + picking.do_transfer() - We create delivery order of 49.5 kg - @@ -206,19 +204,18 @@ - I assign this outgoing shipment - - !python {model: stock.picking}: | - self.action_assign(cr, uid, [ref("outgoing_fifo_shipment_cur")]) + !python {model: stock.picking, id: outgoing_fifo_shipment_cur}: | + self.action_assign() - Process the delivery of the outgoing shipment - - !python {model: stock.picking}: | - picking_obj = self.pool.get('stock.picking').browse(cr, uid, ref("outgoing_fifo_shipment_cur"), context=context) - picking_obj.do_transfer() + !python {model: stock.picking, id: outgoing_fifo_shipment_cur}: | + self.do_transfer() - Check rounded price is 102 euro (because last outgoing shipment was made of 19.5kg at 80€ and 30kg at $150 (rate=1.2834) - - !python {model: product.product}: | - assert round(self.browse(cr, uid, ref("product_fifo_icecream")).standard_price) == 102, "Product price not updated accordingly. %s found instead of 102 (rounded values)" %(round(self.browse(cr, uid, ref("product_fifo_icecream")).standard_price),) + !python {model: product.product, id: product_fifo_icecream}: | + assert round(self.standard_price) == 102, "Product price not updated accordingly. %s found instead of 102 (rounded values)" %(round(self.standard_price),) - Do a delivery of an extra 10 kg - @@ -238,21 +235,19 @@ - I assign this outgoing shipment - - !python {model: stock.picking}: | - self.action_assign(cr, uid, [ref("outgoing_fifo_shipment_ret")]) + !python {model: stock.picking, id: outgoing_fifo_shipment_ret}: | + self.action_assign() - Process the delivery of the outgoing shipment - - !python {model: stock.picking}: | - picking_obj = self.pool.get('stock.picking').browse(cr, uid, ref("outgoing_fifo_shipment_ret"), context=context) - picking_obj.do_transfer() + !python {model: stock.picking, id: outgoing_fifo_shipment_ret}: | + self.do_transfer() - Check rounded price is 150.0 / 1.2834 - - !python {model: product.product}: | - product = self.browse(cr, uid, ref("product_fifo_icecream")) - assert round(product.standard_price) == round(150.0 / 1.2834), "Product price not updated accordingly. %s found instead of %s" %(product.standard_price, round(150.0/1.2834)) - assert product.qty_available == 0.0, 'Wrong quantity in stock after first reception' + !python {model: product.product, id: product_fifo_icecream}: | + assert round(self.standard_price) == round(150.0 / 1.2834), "Product price not updated accordingly. %s found instead of %s" %(self.standard_price, round(150.0/1.2834)) + assert self.qty_available == 0.0, 'Wrong quantity in stock after first reception' - Let us create some outs to get negative stock for a new product using the same config - @@ -289,13 +284,12 @@ - Process the delivery of the first outgoing shipment - - !python {model: stock.picking}: | - picking_obj = self.browse(cr, uid, ref("outgoing_fifo_shipment_neg"), context=context) - picking_obj.do_transfer() + !python {model: stock.picking, id: outgoing_fifo_shipment_neg}: | + self.do_transfer() - The behavior of fifo/lifo is not garantee if the quants are created at the same second, so i just wait one second - - !python {model: stock.picking}: | + !python {model: stock.picking, id: False}: | import time time.sleep(1) - @@ -317,9 +311,8 @@ - Process the delivery of the outgoing shipments - - !python {model: stock.picking}: | - picking_obj1 = self.browse(cr, uid, ref("outgoing_fifo_shipment_neg2"), context=context) - picking_obj1.do_transfer() + !python {model: stock.picking, id: outgoing_fifo_shipment_neg2}: | + self.do_transfer() - Receive purchase order with 50 kg FIFO Ice Cream at 50 euro/kg @@ -336,20 +329,20 @@ - I confirm the first purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_fifo_neg")]) + !python {model: purchase.order, id: purchase_order_fifo_neg}: | + self.button_confirm() - Process the reception of purchase order 1 - - !python {model: stock.picking}: | - picking_obj = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fifo_neg"), context=context).picking_ids[0] - picking_obj.do_transfer() + !python {model: purchase.order, id: purchase_order_fifo_neg}: | + picking = self.picking_ids[0] + picking.do_transfer() - Assert price on product is still the old price as the out move has not been received fully yet - - !python {model: product.product}: | + !python {model: product.product, id: product_fifo_negative}: | - assert self.browse(cr, uid, ref("product_fifo_negative")).standard_price == 70, 'The product price should not have been updated' + assert self.standard_price == 70, 'The product price should not have been updated' - Receive purchase order with 60 kg FIFO Ice Cream at 80 euro/kg - @@ -365,16 +358,16 @@ - I confirm the second negative purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_fifo_neg2")]) + !python {model: purchase.order, id: purchase_order_fifo_neg2}: | + self.button_confirm() - Process the reception of purchase order 2 - - !python {model: stock.picking}: | - picking_obj = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fifo_neg2"), context=context).picking_ids[0] - picking_obj.do_transfer() + !python {model: purchase.order, id: purchase_order_fifo_neg2}: | + picking = self.picking_ids[0] + picking.do_transfer() - The price of the product should have changed back to 65.0 - - !python {model: product.product}: | - assert self.browse(cr, uid, ref("product_fifo_negative")).standard_price == 65.0, "Product price not updated accordingly. %s found instead of 65" %(self.browse(cr, uid, ref("product_fifo_negative")).standard_price,) + !python {model: product.product, id: product_fifo_negative}: | + assert self.standard_price == 65.0, "Product price not updated accordingly. %s found instead of 65" %(self.standard_price,) diff --git a/addons/purchase/test/fifo_returns.yml b/addons/purchase/test/fifo_returns.yml index e5fa0ce9de2..9004a36415d 100644 --- a/addons/purchase/test/fifo_returns.yml +++ b/addons/purchase/test/fifo_returns.yml @@ -41,44 +41,44 @@ - I confirm the first purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_fiforet1")]) + !python {model: purchase.order, id: purchase_order_fiforet1}: | + self.button_confirm() - Process the reception of purchase order 1 - - !python {model: stock.picking}: | - picking_obj = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fiforet1")).picking_ids[0] - self.do_transfer(cr,uid,[picking_obj.id], context=context) + !python {model: purchase.order, id: purchase_order_fiforet1}: | + picking = self.picking_ids[0] + picking.do_transfer() - Check the standard price of the product (fifo icecream) - - !python {model: product.product}: | - assert self.browse(cr, uid, ref("product_fiforet_icecream")).standard_price == 0.0, 'Standard price should not have changed!' + !python {model: product.product, id: product_fiforet_icecream}: | + assert self.standard_price == 0.0, 'Standard price should not have changed!' - I confirm the second purchase order - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_fiforet2")]) + !python {model: purchase.order, id: purchase_order_fiforet2}: | + self.button_confirm() - Process the reception of purchase order 2 - - !python {model: stock.picking}: | - picking_obj = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fiforet2")).picking_ids[0] - self.do_transfer(cr,uid,[picking_obj.id], context=context) + !python {model: purchase.order, id: purchase_order_fiforet2}: | + picking = self.picking_ids[0] + picking.do_transfer() - Return the goods of purchase order 2 - - !python {model: stock.return.picking}: | - pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fiforet2")).picking_ids - return_id = self.create(cr, uid, {}, context={'active_model':'stock.picking', 'active_id': pick_ids[0].id}) - return_picking_id, dummy = self._create_returns(cr, uid, [return_id], context={'active_id': pick_ids[0].id}) + !python {model: purchase.order, id: purchase_order_fiforet2}: | + picking = self.picking_ids[0] + return_id = self.env['stock.return.picking'].with_context(active_model='stock.picking', active_id=picking.id).create({}) + return_picking_id, dummy = return_id.with_context(active_id=picking.id)._create_returns() # Important to pass through confirmation and assignation - pick_obj = self.pool.get('stock.picking') - pick_obj.action_confirm(cr, uid, [return_picking_id]) - pick_obj.action_assign(cr, uid, [return_picking_id]) - pick_obj.do_transfer(cr, uid, [return_picking_id]) + return_picking = self.env['stock.picking'].browse(return_picking_id) + return_picking.action_confirm() + return_picking.action_assign() + return_picking.do_transfer() - Check the standard price of the product changed to 80.0 as we returned the quants of purchase order 2 - - !python {model: product.product}: | - assert self.browse(cr, uid, ref("product_fiforet_icecream")).standard_price == 80.0, 'Standard price should have changed to 80.0! %s found instead' % (self.browse(cr, uid, ref("product_fiforet_icecream")).standard_price,) + !python {model: product.product, id: product_fiforet_icecream}: | + assert self.standard_price == 80.0, 'Standard price should have changed to 80.0! %s found instead' % (self.standard_price,) diff --git a/addons/purchase/test/process/cancel_order.yml b/addons/purchase/test/process/cancel_order.yml index 6051f50c7fa..1ff1c0ee92e 100644 --- a/addons/purchase/test/process/cancel_order.yml +++ b/addons/purchase/test/process/cancel_order.yml @@ -8,8 +8,8 @@ - I confirm the purchase order. - - !python {model: purchase.order}: | - self.button_confirm(cr, uid, [ref("purchase_order_5")]) + !python {model: purchase.order, id: purchase_order_5}: | + self.button_confirm() - I check the "Approved" status after confirmed RFQ. - @@ -18,14 +18,13 @@ - First I cancel receptions related to this order if order shipped. - - !python {model: purchase.order}: | - order = self.browse(cr, uid, ref("purchase_order_5")) - self.pool.get('stock.picking').action_cancel(cr, uid, [picking.id for picking in order.picking_ids]) + !python {model: purchase.order, id: purchase_order_5}: | + self.env['stock.picking'].browse([picking.id for picking in self.picking_ids]).action_cancel() - Now I am able to cancel purchase order. - - !python {model: purchase.order}: | - self.button_cancel(cr, uid, [ref("purchase_order_5")]) + !python {model: purchase.order, id: purchase_order_5}: | + self.button_cancel() - I check that order is cancelled. - diff --git a/addons/purchase/test/process/run_scheduler.yml b/addons/purchase/test/process/run_scheduler.yml index 83255849b59..6ea17eaed48 100644 --- a/addons/purchase/test/process/run_scheduler.yml +++ b/addons/purchase/test/process/run_scheduler.yml @@ -11,8 +11,8 @@ - Add Buy route - - !python {model: product.product}: | - self.write(cr, uid, [ref("scheduler_product")], {"route_ids": [(4, ref("purchase.route_warehouse0_buy"))]}) + !python {model: product.product, id: scheduler_product}: | + self.write({"route_ids": [(4, ref("purchase.route_warehouse0_buy"))]}) - I create a procurement order. - @@ -24,19 +24,17 @@ - I run the scheduler. - - !python {model: procurement.order}: | - self.run_scheduler(cr, uid) + !python {model: procurement.order, id: False}: | + self.run_scheduler() - I check Generated RFQ. - - !python {model: procurement.order}: | - procurement = self.browse(cr, uid, ref('procurement_order_testcase0')) - assert procurement.purchase_line_id, 'RFQ should be generated!' + !python {model: procurement.order, id: procurement_order_testcase0}: | + assert self.purchase_line_id, 'RFQ should be generated!' - I delete the line from the purchase order and check that the move and the procurement are cancelled - - !python {model: procurement.order}: | - procurement = self.browse(cr, uid, ref('procurement_order_testcase0')) - procurement.purchase_line_id.unlink() - procurement.refresh() - assert procurement.state == 'exception', 'Procurement should be in exception' + !python {model: procurement.order, id: procurement_order_testcase0}: | + self.purchase_line_id.unlink() + self.refresh() + assert self.state == 'exception', 'Procurement should be in exception' diff --git a/addons/purchase/test/stock_valuation_account.xml b/addons/purchase/test/stock_valuation_account.xml index 3877775713e..41dff11daf2 100644 --- a/addons/purchase/test/stock_valuation_account.xml +++ b/addons/purchase/test/stock_valuation_account.xml @@ -1,5 +1,5 @@ - + @@ -16,4 +16,4 @@ - + diff --git a/addons/purchase/test/ui/delete_order.yml b/addons/purchase/test/ui/delete_order.yml index 9cde313ac1c..3b24ddaa8c4 100644 --- a/addons/purchase/test/ui/delete_order.yml +++ b/addons/purchase/test/ui/delete_order.yml @@ -8,24 +8,24 @@ - I try to delete confirmed order and check Error Message. - - !python {model: purchase.order}: | + !python {model: purchase.order, id: purchase_order_1}: | try: - self.unlink(cr, uid, [ref("purchase_order_1")]) + self.unlink() except Exception,e: pass - I delete a cancelled order. - - !python {model: purchase.order}: | - from openerp.exceptions import UserError + !python {model: purchase.order, id: purchase_order_7}: | + from odoo.exceptions import UserError try: - self.unlink(cr, uid, [ref("purchase_order_7")]) + self.unlink() except UserError: pass - I delete a draft order. - - !python {model: purchase.order}: | - self.unlink(cr, uid, [ref("purchase_order_5")]) + !python {model: purchase.order, id: purchase_order_5}: | + self.unlink() diff --git a/addons/purchase/test/ui/duplicate_order.yml b/addons/purchase/test/ui/duplicate_order.yml index d49cec22d73..0b9e640484a 100644 --- a/addons/purchase/test/ui/duplicate_order.yml +++ b/addons/purchase/test/ui/duplicate_order.yml @@ -3,5 +3,5 @@ - I duplicate order. - - !python {model: purchase.order}: | - self.copy(cr, uid, ref('purchase_order_1'), context) + !python {model: purchase.order, id: purchase_order_1}: | + self.copy() diff --git a/addons/purchase/tests/__init__.py b/addons/purchase/tests/__init__.py index 53b60c7dba4..9fe1b334ad2 100644 --- a/addons/purchase/tests/__init__.py +++ b/addons/purchase/tests/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from . import test_onchange_product_id, test_purchase_order, test_create_picking \ No newline at end of file +from . import test_onchange_product_id, test_purchase_order, test_create_picking diff --git a/addons/purchase/tests/test_create_picking.py b/addons/purchase/tests/test_create_picking.py index 5ea0b1b3bf7..228afb7b566 100644 --- a/addons/purchase/tests/test_create_picking.py +++ b/addons/purchase/tests/test_create_picking.py @@ -2,7 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from datetime import datetime -from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT +from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT from odoo.addons.product.tests import common diff --git a/addons/purchase/tests/test_onchange_product_id.py b/addons/purchase/tests/test_onchange_product_id.py index cd1c1795f3c..5a838fdbbdd 100644 --- a/addons/purchase/tests/test_onchange_product_id.py +++ b/addons/purchase/tests/test_onchange_product_id.py @@ -1,6 +1,9 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from datetime import datetime -from openerp.tests.common import TransactionCase -from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT +from odoo.tests.common import TransactionCase +from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT class TestOnchangeProductId(TransactionCase): """Test that when an included tax is mapped by a fiscal position, the included tax must be diff --git a/addons/purchase/tests/test_purchase_order.py b/addons/purchase/tests/test_purchase_order.py index 570759a9ab2..5f1c1f3f645 100644 --- a/addons/purchase/tests/test_purchase_order.py +++ b/addons/purchase/tests/test_purchase_order.py @@ -2,10 +2,10 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from datetime import datetime -from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT -from openerp.tests import common -from openerp.addons.account.tests.account_test_classes import AccountingTestCase +from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT +from odoo.addons.account.tests.account_test_classes import AccountingTestCase + class TestPurchaseOrder(AccountingTestCase): diff --git a/addons/purchase/views/account_invoice_views.xml b/addons/purchase/views/account_invoice_views.xml index d6f7c4e821d..7f4fc3bf4e0 100644 --- a/addons/purchase/views/account_invoice_views.xml +++ b/addons/purchase/views/account_invoice_views.xml @@ -1,3 +1,4 @@ + Vendor Bills diff --git a/addons/purchase/views/purchase_views.xml b/addons/purchase/views/purchase_views.xml index 0c82aba1a5b..14ec2e72259 100644 --- a/addons/purchase/views/purchase_views.xml +++ b/addons/purchase/views/purchase_views.xml @@ -1,6 +1,5 @@ - - + - - + diff --git a/addons/purchase/views/res_company_views.xml b/addons/purchase/views/res_company_views.xml index b1772a9e720..2b94a56a32b 100644 --- a/addons/purchase/views/res_company_views.xml +++ b/addons/purchase/views/res_company_views.xml @@ -1,6 +1,5 @@ - - - + + res.company.mrp.config @@ -17,5 +16,4 @@ - - + diff --git a/addons/purchase/views/res_config_views.xml b/addons/purchase/views/res_config_views.xml index a1039e89f86..ecdf91bf0f9 100644 --- a/addons/purchase/views/res_config_views.xml +++ b/addons/purchase/views/res_config_views.xml @@ -1,6 +1,5 @@ - - + purchase.res.config.view purchase.config.settings @@ -56,5 +55,4 @@ - - + diff --git a/addons/purchase/views/res_partner_views.xml b/addons/purchase/views/res_partner_views.xml index 1327cddad8b..0d9d340c097 100644 --- a/addons/purchase/views/res_partner_views.xml +++ b/addons/purchase/views/res_partner_views.xml @@ -1,5 +1,5 @@ - - + + res.partner.purchase.property.form.inherit @@ -105,5 +105,4 @@ - - + diff --git a/addons/purchase/views/stock_views.xml b/addons/purchase/views/stock_views.xml index c59cabfb05b..d7982554e7e 100644 --- a/addons/purchase/views/stock_views.xml +++ b/addons/purchase/views/stock_views.xml @@ -1,6 +1,5 @@ - - + stock.move.form stock.move @@ -23,5 +22,4 @@ - - +