diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index 146212f3e2d..627db50a12d 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -978,7 +978,7 @@ class AccountInvoice(models.Model): values['invoice_line_ids'] = self._refund_cleanup_lines(invoice.invoice_line_ids) - tax_lines = filter(lambda l: l.manual, invoice.tax_line_ids) + tax_lines = invoice.tax_line_ids values['tax_line_ids'] = self._refund_cleanup_lines(tax_lines) if journal_id: diff --git a/addons/account/wizard/account_invoice_refund.py b/addons/account/wizard/account_invoice_refund.py index 3467b2e74a6..b45e4a5970c 100644 --- a/addons/account/wizard/account_invoice_refund.py +++ b/addons/account/wizard/account_invoice_refund.py @@ -58,7 +58,6 @@ class AccountInvoiceRefund(models.TransientModel): date = form.date or False description = form.description or inv.name refund = inv.refund(form.date_invoice, date, description, inv.journal_id.id) - refund.compute_taxes() created_inv.append(refund.id) if mode in ('cancel', 'modify'): diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 6db76a52243..e56e012533a 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -562,7 +562,7 @@ class PosOrder(models.Model): 'location_id': location_id, 'location_dest_id': destination_id, } - pos_qty = any([x.qty >= 0 for x in order.lines]) + pos_qty = any([x.qty > 0 for x in order.lines]) if pos_qty: order_picking = Picking.create(picking_vals.copy()) neg_qty = any([x.qty < 0 for x in order.lines]) diff --git a/addons/point_of_sale/views/pos_session_view.xml b/addons/point_of_sale/views/pos_session_view.xml index d6fb4cc6953..5dfe4acdb1e 100644 --- a/addons/point_of_sale/views/pos_session_view.xml +++ b/addons/point_of_sale/views/pos_session_view.xml @@ -154,7 +154,7 @@ - + diff --git a/addons/sale/sale_analytic.py b/addons/sale/sale_analytic.py index 622d2520c63..0f07cff230f 100644 --- a/addons/sale/sale_analytic.py +++ b/addons/sale/sale_analytic.py @@ -13,7 +13,19 @@ class SaleOrderLine(models.Model): lines = {} if not domain: # To filter on analyic lines linked to an expense - domain = [('so_line', 'in', self.ids), ('amount', '<=', 0.0)] + expense_type_id = self.env.ref('account.data_account_type_expenses', raise_if_not_found=False) + expense_type_id = expense_type_id and expense_type_id.id + domain = [ + ('so_line', 'in', self.ids), + '|', + ('amount', '<', 0), + '&', + ('amount', '=', 0), + '|', + ('move_id', '=', False), + ('move_id.account_id.user_type_id', '=', expense_type_id) + ] + data = self.env['account.analytic.line'].read_group( domain, ['so_line', 'unit_amount', 'product_uom_id'], ['product_uom_id', 'so_line'], lazy=False diff --git a/addons/sale_timesheet/models/sale_timesheet.py b/addons/sale_timesheet/models/sale_timesheet.py index 8d2085aecc9..bd312081201 100644 --- a/addons/sale_timesheet/models/sale_timesheet.py +++ b/addons/sale_timesheet/models/sale_timesheet.py @@ -251,7 +251,20 @@ class SaleOrderLine(models.Model): def _compute_analytic(self, domain=None): if not domain: # To filter on analyic lines linked to an expense - domain = [('so_line', 'in', self.ids), '|', ('amount', '<=', 0.0), ('project_id', '!=', False)] + expense_type_id = self.env.ref('account.data_account_type_expenses', raise_if_not_found=False) + expense_type_id = expense_type_id and expense_type_id.id + domain = [ + ('so_line', 'in', self.ids), + '|', + '|', + ('amount', '<', 0.0), + ('project_id', '!=', False), + '&', + ('amount', '=', 0), + '|', + ('move_id', '=', False), + ('move_id.account_id.user_type_id', '=', expense_type_id) + ] return super(SaleOrderLine, self)._compute_analytic(domain=domain) @api.model diff --git a/doc/cla/individual/ttpphuctran.md b/doc/cla/individual/ttpphuctran.md new file mode 100644 index 00000000000..2cbbdd58851 --- /dev/null +++ b/doc/cla/individual/ttpphuctran.md @@ -0,0 +1,11 @@ +Vietnam, 2017-04-10 + +I hereby agree to the terms of the Odoo Individual Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Tran Thanh Phuc ttp.phuctran@gmail.com https://github.com/ttpphuctran diff --git a/openerp/addons/base/ir/ir_rule.py b/openerp/addons/base/ir/ir_rule.py index 5e571c1347b..99366eebe8e 100644 --- a/openerp/addons/base/ir/ir_rule.py +++ b/openerp/addons/base/ir/ir_rule.py @@ -101,9 +101,8 @@ class IrRule(models.Model): group_domains = defaultdict(list) # {group: list of domains} for rule in rules.sudo(): dom = expression.normalize_domain(rule_domain[rule.id]) - for group in rule.groups: - if group in user.groups_id: - group_domains[group].append(dom) + if rule.groups & user.groups_id: + group_domains[rule.groups[0]].append(dom) if not rule.groups: global_domains.append(dom) diff --git a/openerp/addons/test_new_api/ir.model.access.csv b/openerp/addons/test_new_api/ir.model.access.csv index a8d921c30ae..3d078fd4427 100644 --- a/openerp/addons/test_new_api/ir.model.access.csv +++ b/openerp/addons/test_new_api/ir.model.access.csv @@ -13,3 +13,4 @@ access_test_function_counter,access_test_function_counter,model_test_old_api_fun access_domain_bool,access_domain_bool,model_domain_bool,,1,1,1,1 access_test_new_api_foo,access_test_new_api_foo,model_test_new_api_foo,,1,1,1,1 access_test_new_api_bar,access_test_new_api_bar,model_test_new_api_bar,,1,1,1,1 +access_test_new_api_recursive,access_test_new_api_recursive,model_test_new_api_recursive,,1,1,1,1 diff --git a/openerp/addons/test_new_api/models.py b/openerp/addons/test_new_api/models.py index 620202c0576..284196c3a88 100644 --- a/openerp/addons/test_new_api/models.py +++ b/openerp/addons/test_new_api/models.py @@ -321,3 +321,19 @@ class Bar(models.Model): def _compute_foo(self): for bar in self: bar.foo = self.env['test_new_api.foo'].search([('name', '=', bar.name)], limit=1) + + +class ComputeRecursive(models.Model): + _name = 'test_new_api.recursive' + + name = fields.Char(required=True) + parent = fields.Many2one('test_new_api.recursive') + display_name = fields.Char(compute='_compute_display_name', store=True) + + @api.depends('name', 'parent.display_name') + def _compute_display_name(self): + for rec in self: + if rec.parent: + rec.display_name = rec.parent.display_name + " / " + rec.name + else: + rec.display_name = rec.name diff --git a/openerp/addons/test_new_api/tests/test_new_fields.py b/openerp/addons/test_new_api/tests/test_new_fields.py index 323c2c2c31d..70cfc50faae 100644 --- a/openerp/addons/test_new_api/tests/test_new_fields.py +++ b/openerp/addons/test_new_api/tests/test_new_fields.py @@ -180,6 +180,29 @@ class TestNewFields(common.TransactionCase): cath.parent = finn self.assertEqual(ewan.display_name, "Gabriel / Finnley / Catherine / Ewan") + def test_12_recursive_recompute(self): + """ test recomputation on recursively dependent field """ + a = self.env['test_new_api.recursive'].create({'name': 'A'}) + b = self.env['test_new_api.recursive'].create({'name': 'B', 'parent': a.id}) + c = self.env['test_new_api.recursive'].create({'name': 'C', 'parent': b.id}) + d = self.env['test_new_api.recursive'].create({'name': 'D', 'parent': c.id}) + self.assertEqual(a.display_name, 'A') + self.assertEqual(b.display_name, 'A / B') + self.assertEqual(c.display_name, 'A / B / C') + self.assertEqual(d.display_name, 'A / B / C / D') + + b.parent = False + self.assertEqual(a.display_name, 'A') + self.assertEqual(b.display_name, 'B') + self.assertEqual(c.display_name, 'B / C') + self.assertEqual(d.display_name, 'B / C / D') + + b.name = 'X' + self.assertEqual(a.display_name, 'A') + self.assertEqual(b.display_name, 'X') + self.assertEqual(c.display_name, 'X / C') + self.assertEqual(d.display_name, 'X / C / D') + def test_12_cascade(self): """ test computed field depending on computed field """ message = self.env.ref('test_new_api.message_0_0') diff --git a/openerp/fields.py b/openerp/fields.py index 4d01054be0b..dabf83f0923 100644 --- a/openerp/fields.py +++ b/openerp/fields.py @@ -639,7 +639,8 @@ class Field(object): if field in fields: self.recursive = True - continue + if not i: + continue # self directly depends on self, give up # add trigger on field and its inverses to recompute self model._field_triggers.add(field, (self, '.'.join(path[:i] or ['id'])))