diff --git a/addons/account/account.py b/addons/account/account.py index c2e6f3d1221..fbbbfd64537 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -31,7 +31,7 @@ import decimal_precision as dp from tools.translate import _ from tools.float_utils import float_round from openerp import SUPERUSER_ID - +import tools _logger = logging.getLogger(__name__) @@ -227,7 +227,7 @@ class account_account(osv.osv): while pos < len(args): if args[pos][0] == 'code' and args[pos][1] in ('like', 'ilike') and args[pos][2]: - args[pos] = ('code', '=like', str(args[pos][2].replace('%', ''))+'%') + args[pos] = ('code', '=like', tools.ustr(args[pos][2].replace('%', ''))+'%') if args[pos][0] == 'journal_id': if not args[pos][2]: del args[pos] @@ -682,7 +682,7 @@ class account_journal_view(osv.osv): _name = "account.journal.view" _description = "Journal View" _columns = { - 'name': fields.char('Journal View', size=64, required=True), + 'name': fields.char('Journal View', size=64, required=True, translate=True), 'columns_id': fields.one2many('account.journal.column', 'view_id', 'Columns') } _order = "name" @@ -1908,7 +1908,7 @@ class account_tax(osv.osv): 'ref_tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."), 'include_base_amount': fields.boolean('Included in base amount', help="Indicates if the amount of tax must be included in the base amount for the computation of the next taxes"), 'company_id': fields.many2one('res.company', 'Company', required=True), - 'description': fields.char('Tax Code',size=32), + 'description': fields.char('Tax Code'), 'price_include': fields.boolean('Tax Included in Price', help="Check this if the price you use on the product and invoices includes this tax."), 'type_tax_use': fields.selection([('sale','Sale'),('purchase','Purchase'),('all','All')], 'Tax Application', required=True) @@ -2518,7 +2518,7 @@ class account_account_template(osv.osv): 'reconcile': fields.boolean('Allow Reconciliation', help="Check this option if you want the user to reconcile entries in this account."), 'shortcut': fields.char('Shortcut', size=12), 'note': fields.text('Note'), - 'parent_id': fields.many2one('account.account.template', 'Parent Account Template', ondelete='cascade'), + 'parent_id': fields.many2one('account.account.template', 'Parent Account Template', ondelete='cascade', domain=[('type','=','view')]), 'child_parent_ids':fields.one2many('account.account.template', 'parent_id', 'Children'), 'tax_ids': fields.many2many('account.tax.template', 'account_account_template_tax_rel', 'account_id', 'tax_id', 'Default Taxes'), 'nocreate': fields.boolean('Optional create', help="If checked, the new chart of accounts will not contain this by default."), @@ -2536,20 +2536,6 @@ class account_account_template(osv.osv): (_check_recursion, 'Error!\nYou cannot create recursive account templates.', ['parent_id']), ] - def create(self, cr, uid, vals, context=None): - if 'parent_id' in vals: - parent = self.read(cr, uid, [vals['parent_id']], ['type']) - if parent and parent[0]['type'] != 'view': - raise osv.except_osv(_('Warning!'), _("You may only select a parent account of type 'View'.")) - return super(account_account_template, self).create(cr, uid, vals, context=context) - - def write(self, cr, uid, ids, vals, context=None): - if 'parent_id' in vals: - parent = self.read(cr, uid, [vals['parent_id']], ['type']) - if parent and parent[0]['type'] != 'view': - raise osv.except_osv(_('Warning!'), _("You may only select a parent account of type 'View'.")) - return super(account_account_template, self).write(cr, uid, ids, vals, context=context) - def name_get(self, cr, uid, ids, context=None): if not ids: return [] @@ -2828,7 +2814,7 @@ class account_tax_template(osv.osv): 'ref_base_sign': fields.float('Base Code Sign', help="Usually 1 or -1."), 'ref_tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."), 'include_base_amount': fields.boolean('Include in Base Amount', help="Set if the amount of tax must be included in the base amount before computing the next taxes."), - 'description': fields.char('Internal Name', size=32), + 'description': fields.char('Internal Name'), 'type_tax_use': fields.selection([('sale','Sale'),('purchase','Purchase'),('all','All')], 'Tax Use In', required=True,), 'price_include': fields.boolean('Tax Included in Price', help="Check this if the price you use on the product and invoices includes this tax."), } diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py index 9889eadf387..b4fc2388a68 100644 --- a/addons/account/account_bank_statement.py +++ b/addons/account/account_bank_statement.py @@ -457,6 +457,8 @@ class account_bank_statement(osv.osv): return res and res[0] or 0.0 def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None): + if not journal_id: + return {} balance_start = self._compute_balance_end_real(cr, uid, journal_id, context=context) journal_data = self.pool.get('account.journal').read(cr, uid, journal_id, ['default_debit_account_id', 'company_id'], context=context) diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index aff38d71cfe..a1c53eff4b1 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -508,8 +508,10 @@ class account_invoice(osv.osv): if journal_id: journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context) currency_id = journal.currency and journal.currency.id or journal.company_id.currency_id.id + company_id = journal.company_id.id result = {'value': { 'currency_id': currency_id, + 'company_id': company_id, } } return result @@ -1371,7 +1373,10 @@ class account_invoice_line(osv.osv): 'partner_id': fields.related('invoice_id','partner_id',type='many2one',relation='res.partner',string='Partner',store=True) } - def _default_account_id(self, cr, uid, ids, context=None): + def _default_account_id(self, cr, uid, context=None): + # XXX this gets the default account for the user's company, + # it should get the default account for the invoice's company + # however, the invoice's company does not reach this point prop = self.pool.get('ir.property').get(cr, uid, 'property_account_income_categ', 'product.category', context=context) return prop and prop.id or False @@ -1401,7 +1406,7 @@ class account_invoice_line(osv.osv): context = {} company_id = company_id if company_id != None else context.get('company_id',False) context = dict(context) - context.update({'company_id': company_id}) + context.update({'company_id': company_id, 'force_company': company_id}) if not partner_id: raise osv.except_osv(_('No Partner Defined !'),_("You must first select a partner !") ) if not product: @@ -1556,16 +1561,19 @@ class account_invoice_line(osv.osv): def onchange_account_id(self, cr, uid, ids, product_id, partner_id, inv_type, fposition_id, account_id): if not account_id: return {} - taxes = self.pool.get('account.account').browse(cr, uid, account_id).tax_ids + unique_tax_ids = [] fpos = fposition_id and self.pool.get('account.fiscal.position').browse(cr, uid, fposition_id) or False - tax_ids = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes) - - product_change_result = self.product_id_change(cr, uid, ids, product_id, False, type=inv_type, - partner_id=partner_id, fposition_id=fposition_id) - unique_tax_ids = set(tax_ids) - if product_change_result and 'value' in product_change_result and 'invoice_line_tax_id' in product_change_result['value']: - unique_tax_ids |= set(product_change_result['value']['invoice_line_tax_id']) - return {'value':{'invoice_line_tax_id': list(unique_tax_ids)}} + account = self.pool.get('account.account').browse(cr, uid, account_id) + if not product_id: + taxes = account.tax_ids + unique_tax_ids = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes) + else: + product_change_result = self.product_id_change(cr, uid, ids, product_id, False, type=inv_type, + partner_id=partner_id, fposition_id=fposition_id, + company_id=account.company_id.id) + if product_change_result and 'value' in product_change_result and 'invoice_line_tax_id' in product_change_result['value']: + unique_tax_ids = product_change_result['value']['invoice_line_tax_id'] + return {'value':{'invoice_line_tax_id': unique_tax_ids}} account_invoice_line() @@ -1650,14 +1658,13 @@ class account_invoice_tax(osv.osv): for line in inv.invoice_line: for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, (line.price_unit* (1-(line.discount or 0.0)/100.0)), line.quantity, line.product_id, inv.partner_id)['taxes']: - tax['price_unit'] = cur_obj.round(cr, uid, cur, tax['price_unit']) val={} val['invoice_id'] = inv.id val['name'] = tax['name'] val['amount'] = tax['amount'] val['manual'] = False val['sequence'] = tax['sequence'] - val['base'] = tax['price_unit'] * line['quantity'] + val['base'] = cur_obj.round(cr, uid, cur, tax['price_unit'] * line['quantity']) if inv.type in ('out_invoice','in_invoice'): val['base_code_id'] = tax['base_code_id'] diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 1c4d83106ca..4a587eee6fe 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -278,6 +278,7 @@
+
@@ -299,8 +300,8 @@ + + @@ -478,6 +479,7 @@
+
diff --git a/addons/event/res_partner_view.xml b/addons/event/res_partner_view.xml index 8e5ff480c2c..c3e8073a7ae 100644 --- a/addons/event/res_partner_view.xml +++ b/addons/event/res_partner_view.xml @@ -16,7 +16,7 @@ False - + @@ -24,7 +24,7 @@ - + diff --git a/addons/fetchmail/fetchmail.py b/addons/fetchmail/fetchmail.py index 70a05c6bd0e..e0023697594 100644 --- a/addons/fetchmail/fetchmail.py +++ b/addons/fetchmail/fetchmail.py @@ -195,7 +195,7 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS strip_attachments=(not server.attach), context=context) if res_id and server.action_id: - action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id]}) + action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id], 'active_model': context.get("thread_model", False)}) imap_server.store(num, '+FLAGS', '\\Seen') cr.commit() count += 1 @@ -220,7 +220,7 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS strip_attachments=(not server.attach), context=context) if res_id and server.action_id: - action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id]}) + action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id], 'active_model': context.get("thread_model", False)}) pop_server.dele(num) cr.commit() _logger.info("fetched/processed %s email(s) on %s server %s", numMsgs, server.type, server.name) diff --git a/addons/hr/hr_view.xml b/addons/hr/hr_view.xml index 6e23a714848..6253205eb7e 100644 --- a/addons/hr/hr_view.xml +++ b/addons/hr/hr_view.xml @@ -205,25 +205,6 @@ - - - kanban - - - - - tree - - - - - - - form - - - - @@ -372,14 +353,14 @@ - - - - +
+
+
+
diff --git a/addons/hr_evaluation/hr_evaluation_view.xml b/addons/hr_evaluation/hr_evaluation_view.xml index ca90e98e516..fb9d287ea77 100644 --- a/addons/hr_evaluation/hr_evaluation_view.xml +++ b/addons/hr_evaluation/hr_evaluation_view.xml @@ -178,7 +178,7 @@
-
@@ -333,7 +333,7 @@ - diff --git a/addons/mail/static/src/xml/mail_followers.xml b/addons/mail/static/src/xml/mail_followers.xml index cf31ab3e24c..203a7bce789 100644 --- a/addons/mail/static/src/xml/mail_followers.xml +++ b/addons/mail/static/src/xml/mail_followers.xml @@ -7,7 +7,6 @@ -->
-
@@ -18,7 +17,7 @@
-

+

· Invite partners
    diff --git a/addons/mail/tests/__init__.py b/addons/mail/tests/__init__.py index d63c5634cc3..2d48fa233c4 100644 --- a/addons/mail/tests/__init__.py +++ b/addons/mail/tests/__init__.py @@ -18,10 +18,11 @@ # along with this program. If not, see . # ############################################################################## -from . import test_mail +from . import test_mail, test_mail_access_rights checks = [ test_mail, + test_mail_access_rights, ] -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/mail/tests/test_mail_access_rights.py b/addons/mail/tests/test_mail_access_rights.py new file mode 100644 index 00000000000..104d7f28ffe --- /dev/null +++ b/addons/mail/tests/test_mail_access_rights.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (c) 2012-TODAY OpenERP S.A. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.addons.mail.tests import test_mail +from osv.orm import except_orm + + +class test_mail_access_rights(test_mail.TestMailMockups): + + def setUp(self): + super(test_mail_access_rights, self).setUp() + cr, uid = self.cr, self.uid + self.mail_group = self.registry('mail.group') + self.mail_message = self.registry('mail.message') + self.mail_notification = self.registry('mail.notification') + self.res_users = self.registry('res.users') + self.res_groups = self.registry('res.groups') + self.res_partner = self.registry('res.partner') + + # create a 'pigs' group that will be used through the various tests + self.group_pigs_id = self.mail_group.create(self.cr, self.uid, + {'name': 'Pigs', 'description': 'Fans of Pigs, unite !'}) + + # Find Employee group + group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user') + self.group_employee_id = group_employee_ref and group_employee_ref[1] or False + + # Create Bert (without groups) and Raoul( employee) + self.user_bert_id = self.res_users.create(cr, uid, {'name': 'Bert Tartopoils', 'login': 'bert', 'groups_id': [(6, 0, [])]}) + self.user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul', 'groups_id': [(6, 0, [self.group_employee_id])]}) + self.user_bert = self.res_users.browse(cr, uid, self.user_bert_id) + self.partner_bert_id = self.user_bert.partner_id.id + self.user_raoul = self.res_users.browse(cr, uid, self.user_raoul_id) + self.partner_raoul_id = self.user_raoul.partner_id.id + + def test_00_mail_message_read_access_rights(self): + """ Test basic mail_message read access rights. """ + cr, uid = self.cr, self.uid + partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id + user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id + + # Prepare groups: Pigs (employee), Jobs (public) + self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') + self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'}) + + # ---------------------------------------- + # CASE1: Bert, basic mail.message read access + # ---------------------------------------- + + # Do: create a new mail.message + message_id = self.mail_message.create(cr, uid, {'body': 'My Body'}) + # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc + self.assertRaises(except_orm, self.mail_message.read, + cr, user_bert_id, message_id) + # Do: message is pushed to Bert + notif_id = self.mail_notification.create(cr, uid, {'message_id': message_id, 'partner_id': partner_bert_id}) + # Test: Bert reads the message, ok because notification pushed + self.mail_message.read(cr, user_bert_id, message_id) + # Do: remove notification + self.mail_notification.unlink(cr, uid, notif_id) + # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc + self.assertRaises(except_orm, self.mail_message.read, + cr, self.user_bert_id, message_id) + # Do: Bert is now the author + self.mail_message.write(cr, uid, [message_id], {'author_id': partner_bert_id}) + # Test: Bert reads the message, ok because Bert is the author + self.mail_message.read(cr, user_bert_id, message_id) + # Do: Bert is not the author anymore + self.mail_message.write(cr, uid, [message_id], {'author_id': partner_raoul_id}) + # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc + self.assertRaises(except_orm, self.mail_message.read, + cr, user_bert_id, message_id) + # Do: message is attached to a document Bert can read, Jobs + self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_jobs_id}) + # Test: Bert reads the message, ok because linked to a doc he is allowed to read + self.mail_message.read(cr, user_bert_id, message_id) + # Do: message is attached to a document Bert cannot read, Pigs + self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_pigs_id}) + # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc + self.assertRaises(except_orm, self.mail_message.read, + cr, user_bert_id, message_id) + + def test_05_mail_message_search_access_rights(self): + """ Test mail_message search override about access rights. """ + self.assertTrue(1 == 1, 'Test not implemented, do not replace by return True') + + def test_10_mail_flow_access_rights(self): + """ Test a Chatter-looks alike flow. """ + cr, uid = self.cr, self.uid + partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id + user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id + + # Prepare groups: Pigs (employee), Jobs (public) + self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') + self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'}) + + # ---------------------------------------- + # CASE1: Bert, without groups + # ---------------------------------------- + # Do: Bert creates a group, should crash because perm_create only for employees + self.assertRaises(except_orm, + self.mail_group.create, + cr, user_bert_id, {'name': 'Bert\'s Group'}) + # Do: Bert reads Jobs basic fields, ok because public = read access on the group + self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['name', 'description']) + # Do: Bert browse Pigs, ok (no direct browse of partners) + self.mail_group.browse(cr, user_bert_id, self.group_jobs_id) + # Do: Bert reads Jobs messages, ok because read access on the group => read access on its messages + jobs_message_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_ids'])['message_ids'] + self.mail_message.read(cr, user_bert_id, jobs_message_ids) + # Do: Bert reads Jobs followers, ko because partner are accessible to employees or partner manager + jobs_followers_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_follower_ids'])['message_follower_ids'] + self.assertRaises(except_orm, + self.res_partner.read, + cr, user_bert_id, jobs_followers_ids) + # Do: Bert comments Jobs, ko because no write access on the group and not in the followers + self.assertRaises(except_orm, + self.mail_group.message_post, + cr, user_bert_id, self.group_jobs_id, body='I love Pigs') + # Do: add Bert to jobs followers + self.mail_group.message_subscribe(cr, uid, [self.group_jobs_id], [partner_bert_id]) + # Do: Bert comments Jobs, ok because he is now in the followers + self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs') + + # Do: Bert reads Pigs, should crash because mail.group security=groups only for employee group + self.assertRaises(except_orm, + self.mail_group.read, + cr, user_bert_id, self.group_pigs_id) + + # ---------------------------------------- + # CASE1: Raoul, employee + # ---------------------------------------- + # Do: Bert read Pigs, ok because public + self.mail_group.read(cr, user_raoul_id, self.group_pigs_id) + # Do: Bert read Jobs, ok because group_public_id = employee + self.mail_group.read(cr, user_raoul_id, self.group_jobs_id) diff --git a/addons/marketing_campaign/res_partner.py b/addons/marketing_campaign/res_partner.py index 98ac53b7b29..8ae1ab8645a 100644 --- a/addons/marketing_campaign/res_partner.py +++ b/addons/marketing_campaign/res_partner.py @@ -29,7 +29,13 @@ class res_partner(osv.osv): 'partner_id', 'Workitems', readonly=True), } - + + def copy(self, cr, uid, id, default={}, context=None): + default.update({ + 'workitem_ids': [], + }) + return super(res_partner, self).copy(cr, uid, id, default=default, context=context) + res_partner() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/marketing_campaign/res_partner_view.xml b/addons/marketing_campaign/res_partner_view.xml index 5b959625086..63c65ccd97f 100644 --- a/addons/marketing_campaign/res_partner_view.xml +++ b/addons/marketing_campaign/res_partner_view.xml @@ -12,7 +12,7 @@ False
    - + diff --git a/addons/membership/membership.py b/addons/membership/membership.py index 2a006814629..87af723f2f9 100644 --- a/addons/membership/membership.py +++ b/addons/membership/membership.py @@ -338,7 +338,7 @@ class Partner(osv.osv): -Paid Member: A member who has paid the membership amount."""), 'membership_start': fields.function( _membership_date, multi = 'membeship_start', - string = 'Start Membership Date', type = 'date', + string = 'Membership Start Date', type = 'date', store = { 'account.invoice': (_get_invoice_partner, ['state'], 10), 'membership.membership_line': (_get_partner_id, ['state'], 10, ), @@ -346,7 +346,7 @@ class Partner(osv.osv): }, help="Date from which membership becomes active."), 'membership_stop': fields.function( _membership_date, - string = 'Stop Membership Date', type='date', multi='membership_stop', + string = 'Membership End Date', type='date', multi='membership_stop', store = { 'account.invoice': (_get_invoice_partner, ['state'], 10), 'membership.membership_line': (_get_partner_id, ['state'], 10), diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 049c7c712fb..00a5790b67e 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -106,6 +106,7 @@ class mrp_routing_workcenter(osv.osv): """ _name = 'mrp.routing.workcenter' _description = 'Work Center Usage' + _order = 'sequence' _columns = { 'workcenter_id': fields.many2one('mrp.workcenter', 'Work Center', required=True), 'name': fields.char('Name', size=64, required=True), @@ -226,6 +227,7 @@ class mrp_bom(osv.osv): 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'mrp.bom', context=c), } _order = "sequence" + _parent_name = "bom_id" _sql_constraints = [ ('bom_qty_zero', 'CHECK (product_qty>0)', 'All product quantities must be greater than 0.\n' \ 'You should install the mrp_subproduct module if you want to manage extra products on BoMs !'), @@ -671,7 +673,7 @@ class mrp_production(osv.osv): for (production_id,name) in self.name_get(cr, uid, ids): production = self.browse(cr, uid, production_id) - if production.move_prod_id: + if production.move_prod_id and production.move_prod_id.location_id.id != production.location_dest_id.id: move_obj.write(cr, uid, [production.move_prod_id.id], {'location_id': production.location_dest_id.id}) self.action_ready_send_note(cr, uid, [production_id], context) @@ -829,7 +831,8 @@ class mrp_production(osv.osv): 'ref': wc.code, 'product_id': wc.product_id.id, 'unit_amount': wc_line.hour, - 'product_uom_id': wc.product_id.uom_id.id + 'product_uom_id': wc.product_id.id and wc.product_id.uom_id.id or False + } ) if wc.costs_journal_id and wc.costs_general_account_id: value = wc_line.cycle * wc.costs_cycle @@ -845,7 +848,8 @@ class mrp_production(osv.osv): 'ref': wc.code, 'product_id': wc.product_id.id, 'unit_amount': wc_line.cycle, - 'product_uom_id': wc.product_id.uom_id.id + 'product_uom_id': wc.product_id.id and wc.product_id.uom_id.id or False + } ) return amount diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index c003711ceb1..a198d736bbc 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -409,8 +409,9 @@
    - - + + +
    @@ -544,9 +545,7 @@ Bill of Materials Structure ir.actions.act_window mrp.bom - [('id','in',active_ids)] - tree - tree + [('bom_id', '=',active_ids)] @@ -675,7 +674,7 @@ - +