diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index 4cddc629a26..4f1413f7ba3 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -608,7 +608,7 @@ class AccountInvoice(models.Model): credit_aml = self.pool.get('account.move.line').browse(cr, uid, credit_aml_id, context=context) inv = self.browse(cr, uid, id, context=context) if not credit_aml.currency_id and inv.currency_id != inv.company_id.currency_id: - credit_aml.with_context(allow_amount_currency=True).write({ + credit_aml.with_context(allow_amount_currency=True, check_move_validity=False).write({ 'amount_currency': inv.company_id.currency_id.with_context(date=credit_aml.date).compute(credit_aml.balance, inv.currency_id), 'currency_id': inv.currency_id.id}) if credit_aml.payment_id: diff --git a/addons/account/models/res_config.py b/addons/account/models/res_config.py index 778d5cd1460..3b2ff3ecb67 100644 --- a/addons/account/models/res_config.py +++ b/addons/account/models/res_config.py @@ -232,10 +232,8 @@ class AccountConfigSettings(models.TransientModel): def set_product_taxes(self): """ Set the product taxes if they have changed """ ir_values_obj = self.env['ir.values'] - if self.default_sale_tax_id: - ir_values_obj.sudo().set_default('product.template', "taxes_id", [self.default_sale_tax_id.id], for_all_users=True, company_id=self.company_id.id) - if self.default_purchase_tax_id: - ir_values_obj.sudo().set_default('product.template', "supplier_taxes_id", [self.default_purchase_tax_id.id], for_all_users=True, company_id=self.company_id.id) + ir_values_obj.sudo().set_default('product.template', "taxes_id", [self.default_sale_tax_id.id] if self.default_sale_tax_id else False, for_all_users=True, company_id=self.company_id.id) + ir_values_obj.sudo().set_default('product.template', "supplier_taxes_id", [self.default_purchase_tax_id.id] if self.default_purchase_tax_id else False, for_all_users=True, company_id=self.company_id.id) @api.multi def set_chart_of_accounts(self): diff --git a/addons/account/wizard/account_invoice_refund.py b/addons/account/wizard/account_invoice_refund.py index b45e4a5970c..56608722806 100644 --- a/addons/account/wizard/account_invoice_refund.py +++ b/addons/account/wizard/account_invoice_refund.py @@ -74,7 +74,7 @@ class AccountInvoiceRefund(models.TransientModel): for tmpline in refund.move_id.line_ids: if tmpline.account_id.id == inv.account_id.id: to_reconcile_lines += tmpline - to_reconcile_lines.filtered(lambda l: l.reconciled == False).reconcile() + to_reconcile_lines.filtered(lambda l: l.reconciled == False).reconcile() if mode == 'modify': invoice = inv.read( ['name', 'type', 'number', 'reference', diff --git a/addons/account_budget/report/analytic_account_budget_report.py b/addons/account_budget/report/analytic_account_budget_report.py index 265a76e6b3e..ffc5c0ad0e2 100644 --- a/addons/account_budget/report/analytic_account_budget_report.py +++ b/addons/account_budget/report/analytic_account_budget_report.py @@ -60,11 +60,16 @@ class analytic_account_budget_report(report_sxw.rml_parse): 'theo':0.00, 'pln':0.00, 'prac':0.00, - 'perc':0.00 + 'perc':0.00, + 'date_from': budget_name[0].date_from, + 'date_to': budget_name[0].date_to, } result.append(res) - - line_ids = c_b_lines_obj.search(self.cr, self.uid, [('id', 'in', b_line_ids), ('crossovered_budget_id','=',budget_ids[i][0])]) + domain_lines = [('id', 'in', b_line_ids), + ('crossovered_budget_id', '=', budget_ids[i][0]), + ('date_from', '<=', d_to), + ('date_to', '>=', d_from)] + line_ids = c_b_lines_obj.search(self.cr, self.uid, domain_lines) line_id = c_b_lines_obj.browse(self.cr, self.uid, line_ids) tot_theo = tot_pln = tot_prac = tot_perc = 0 diff --git a/addons/account_budget/report/budget_report.py b/addons/account_budget/report/budget_report.py index cc2274c2eea..3ff1f7d0927 100644 --- a/addons/account_budget/report/budget_report.py +++ b/addons/account_budget/report/budget_report.py @@ -66,8 +66,11 @@ class budget_report(report_sxw.rml_parse): 'perc': 0.00 } result.append(res) - - line_ids = c_b_lines_obj.search(self.cr, self.uid, [('id', 'in', budget_ids), ('analytic_account_id','=',an_ids[i][0])]) + domain_lines = [('id', 'in', budget_ids), + ('analytic_account_id','=',an_ids[i][0]), + ('date_from', '<=', d_to), + ('date_to', '>=', d_from)] + line_ids = c_b_lines_obj.search(self.cr, self.uid, domain_lines) line_id = c_b_lines_obj.browse(self.cr, self.uid, line_ids) tot_theo = tot_pln = tot_prac = tot_perc = 0.00 diff --git a/addons/account_budget/views/report_analyticaccountbudget.xml b/addons/account_budget/views/report_analyticaccountbudget.xml index dab987d6099..9f6e31aa258 100644 --- a/addons/account_budget/views/report_analyticaccountbudget.xml +++ b/addons/account_budget/views/report_analyticaccountbudget.xml @@ -32,6 +32,8 @@ Planned Amt Practical Amt Perc(%) + Start date + End Date @@ -42,6 +44,8 @@ % + + diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py index 97fecf300f8..01bc7c3dd8c 100644 --- a/addons/account_voucher/account_voucher.py +++ b/addons/account_voucher/account_voucher.py @@ -365,7 +365,7 @@ class account_voucher_line(models.Model): if product.description_purchase: values['name'] += '\n' + product.description_purchase else: - values['price_unit'] = product.lst_price + values['price_unit'] = price_unit or product.lst_price taxes = product.taxes_id or account.tax_ids if product.description_sale: values['name'] += '\n' + product.description_sale @@ -375,7 +375,7 @@ class account_voucher_line(models.Model): if company and currency: if company.currency_id != currency: if type == 'purchase': - values['price_unit'] = product.standard_price + values['price_unit'] = price_unit or product.standard_price values['price_unit'] = values['price_unit'] * currency.rate return {'value': values, 'domain': {}} diff --git a/addons/google_account/models/google_service.py b/addons/google_account/models/google_service.py index d707ee8d188..15ad409fe42 100644 --- a/addons/google_account/models/google_service.py +++ b/addons/google_account/models/google_service.py @@ -8,6 +8,7 @@ import urllib2 import werkzeug.urls from odoo import api, fields, models, registry, _ +from odoo.exceptions import UserError from odoo.http import request @@ -124,6 +125,9 @@ class GoogleService(models.TransientModel): client_id = Parameters.get_param('google_%s_client_id' % (service,), default=False) client_secret = Parameters.get_param('google_%s_client_secret' % (service,), default=False) + if not client_id or not client_secret: + raise UserError(_("The account for the Google service '%s' is not configured") % service) + headers = {"content-type": "application/x-www-form-urlencoded"} data = werkzeug.url_encode({ 'refresh_token': refresh_token, diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py index 862ac1c7854..8d0be728b2c 100644 --- a/addons/sale_stock/sale_stock.py +++ b/addons/sale_stock/sale_stock.py @@ -73,7 +73,7 @@ class SaleOrder(models.Model): @api.multi def action_cancel(self): - self.order_line.mapped('procurement_ids').cancel() + self.mapped('order_line').mapped('procurement_ids').cancel() super(SaleOrder, self).action_cancel() @api.multi diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index c35c73a9ba4..49c22a63a93 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -157,7 +157,8 @@ class StockMove(models.Model): @api.depends('product_id', 'product_uom', 'product_uom_qty') def _compute_product_qty(self): if self.product_uom: - self.product_qty = self.env['product.uom']._compute_qty_obj(self.product_uom, self.product_uom_qty, self.product_id.uom_id) + rounding_method = self._context.get('rounding_method', 'UP') + self.product_qty = self.env['product.uom']._compute_qty_obj(self.product_uom, self.product_uom_qty, self.product_id.uom_id, rounding_method=rounding_method) def _set_product_qty(self): """ The meaning of product_qty field changed lately and is now a functional field computing the quantity @@ -980,12 +981,12 @@ class StockMove(models.Model): # TDE CLEANME: remove context key + add as parameter if self.env.context.get('source_location_id'): defaults['location_id'] = self.env.context['source_location_id'] - new_move = self.copy(defaults) + new_move = self.with_context(rounding_method='HALF-UP').copy(defaults) # ctx = context.copy() # TDE CLEANME: used only in write in this file, to clean # ctx['do_not_propagate'] = True - self.with_context(do_not_propagate=True).write({'product_uom_qty': self.product_uom_qty - uom_qty}) + self.with_context(do_not_propagate=True, rounding_method='HALF-UP').write({'product_uom_qty': self.product_uom_qty - uom_qty}) if self.move_dest_id and self.propagate and self.move_dest_id.state not in ('done', 'cancel'): new_move_prop = self.move_dest_id.split(qty) diff --git a/doc/cla/individual/NothingCtrl.md b/doc/cla/individual/NothingCtrl.md new file mode 100644 index 00000000000..bf58b0034d3 --- /dev/null +++ b/doc/cla/individual/NothingCtrl.md @@ -0,0 +1,9 @@ +Vietnam, 2017-08-15 + +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, + +Duong Bao Thang nothingctrl@gmail.com https://github.com/NothingCtrl diff --git a/doc/reference/views.rst b/doc/reference/views.rst index 9449fe15fd9..45d58f62ec8 100644 --- a/doc/reference/views.rst +++ b/doc/reference/views.rst @@ -838,17 +838,13 @@ attributes: Possible children of the view element are: ``field`` - declares fields to aggregate or to use in kanban *logic*. If the field is - simply displayed in the kanban view, it does not need to be pre-declared. + declares fields to use in kanban *logic*. If the field is simply displayed in + the kanban view, it does not need to be pre-declared. Possible attributes are: ``name`` (required) the name of the field to fetch - ``sum``, ``avg``, ``min``, ``max``, ``count`` - displays the corresponding aggregation at the top of a kanban column, the - field's value is the label of the aggregation (a string). Only one - aggregate operation per field is supported. ``templates`` defines a list of :ref:`reference/qweb` templates. Cards definition may be diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 68ad0509011..2008084df62 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -384,7 +384,8 @@ class IrModelFields(models.Model): if field.state == 'manual' and field.ttype == 'many2many': rel_name = field.relation_table or model._fields[field.name].relation tables_to_drop.add(rel_name) - model._pop_field(field.name) + if field.state == 'manual': + model._pop_field(field.name) if tables_to_drop: # drop the relation tables that are not used by other fields diff --git a/openerp/models.py b/openerp/models.py index 1205c84e24c..bdd0e13c2c1 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -6034,13 +6034,16 @@ class BaseModel(object): return RecordCache(self) @api.model - def _in_cache_without(self, field): - """ Make sure ``self`` is present in cache (for prefetching), and return - the records of model ``self`` in cache that have no value for ``field`` - (:class:`Field` instance). + def _in_cache_without(self, field, limit=PREFETCH_MAX): + """ Return records to prefetch that have no value in cache for ``field`` + (:class:`Field` instance), including ``self``. + Return at most ``limit`` records. """ ids = filter(None, self._prefetch[self._name] - set(self.env.cache[field])) - return self.browse(ids) + recs = self.browse(ids) + if limit and len(recs) > limit: + recs = self + (recs - self)[:(limit - len(self))] + return recs @api.model def refresh(self):