[MERGE] forward port branch saas-11 up to 659fb5d

This commit is contained in:
Christophe Simonis
2016-11-22 13:28:15 +01:00
17 changed files with 52 additions and 33 deletions
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from openerp import api, fields, models, _ from openerp import api, fields, models, _
from math import copysign
class AccountAnalyticLine(models.Model): class AccountAnalyticLine(models.Model):
@@ -20,8 +21,12 @@ class AccountAnalyticLine(models.Model):
help='Utility field to express amount currency') help='Utility field to express amount currency')
currency_id = fields.Many2one('res.currency', related='move_id.currency_id', string='Account Currency', store=True, help="The related account currency if not equal to the company one.", readonly=True) currency_id = fields.Many2one('res.currency', related='move_id.currency_id', string='Account Currency', store=True, help="The related account currency if not equal to the company one.", readonly=True)
amount_currency = fields.Monetary(related='move_id.amount_currency', store=True, help="The amount expressed in the related account currency if not equal to the company one.", readonly=True) amount_currency = fields.Monetary(related='move_id.amount_currency', store=True, help="The amount expressed in the related account currency if not equal to the company one.", readonly=True)
analytic_amount_currency = fields.Monetary(string='Amount Currency', compute="_get_analytic_amount_currency", help="The amount expressed in the related account currency if not equal to the company one.", readonly=True)
partner_id = fields.Many2one('res.partner', related='account_id.partner_id', string='Partner', store=True, readonly=True) partner_id = fields.Many2one('res.partner', related='account_id.partner_id', string='Partner', store=True, readonly=True)
def _get_analytic_amount_currency(self):
self.analytic_amount_currency = abs(self.amount_currency) * copysign(1, self.amount)
@api.v8 @api.v8
@api.onchange('product_id', 'product_uom_id', 'unit_amount', 'currency_id') @api.onchange('product_id', 'product_uom_id', 'unit_amount', 'currency_id')
def on_change_unit_amount(self): def on_change_unit_amount(self):
+1 -1
View File
@@ -1263,7 +1263,7 @@ class AccountMoveLine(models.Model):
""" Prepare the values used to create() an account.analytic.line upon validation of an account.move.line having """ Prepare the values used to create() an account.analytic.line upon validation of an account.move.line having
an analytic account. This method is intended to be extended in other modules. an analytic account. This method is intended to be extended in other modules.
""" """
amount = (self.debit or 0.0) - (self.credit or 0.0) amount = (self.credit or 0.0) - (self.debit or 0.0)
return { return {
'name': self.name, 'name': self.name,
'date': self.date, 'date': self.date,
@@ -15,7 +15,8 @@
</xpath> </xpath>
<xpath expr="//field[@name='amount']" position="after"> <xpath expr="//field[@name='amount']" position="after">
<field name="company_currency_id" invisible="1"/> <field name="company_currency_id" invisible="1"/>
<field name="amount_currency"/> <field name="amount_currency" invisible="1"/>
<field name="analytic_amount_currency"/>
<field name="product_id"/> <field name="product_id"/>
<field name="product_uom_id" class="oe_inline"/> <field name="product_uom_id" class="oe_inline"/>
</xpath> </xpath>
@@ -280,7 +280,7 @@ var ScaleScreenWidget = ScreenWidget.extend({
return self.pos.proxy.scale_read().then(function(weight){ return self.pos.proxy.scale_read().then(function(weight){
self.set_weight(weight.weight); self.set_weight(weight.weight);
}); });
},{duration:50, repeat: true}); },{duration:150, repeat: true});
}, },
get_product: function(){ get_product: function(){
+1 -1
View File
@@ -90,5 +90,5 @@ class AccountInvoiceLine(models.Model):
prod_quantity = factor * quantity prod_quantity = factor * quantity
average_price_unit += self._compute_average_price(prod_qty_done, prod_quantity, prod_moves) average_price_unit += self._compute_average_price(prod_qty_done, prod_quantity, prod_moves)
price_unit = average_price_unit or price_unit price_unit = average_price_unit or price_unit
price_unit = uom_obj._compute_qty_obj(self.uom_id, price_unit, self.product_id.uom_id, round=False) price_unit = self.product_id.uom_id._compute_price(self.product_id.uom_id.id, price_unit, to_uom_id=self.uom_id.id)
return price_unit return price_unit
+1 -1
View File
@@ -379,7 +379,7 @@ class AccountInvoiceLine(models.Model):
# on the moves we encounter. # on the moves we encounter.
average_price_unit = self._compute_average_price(qty_done, quantity, moves) average_price_unit = self._compute_average_price(qty_done, quantity, moves)
price_unit = average_price_unit or price_unit price_unit = average_price_unit or price_unit
price_unit = uom_obj._compute_qty_obj(self.uom_id, price_unit, self.product_id.uom_id, round=False) price_unit = self.product_id.uom_id._compute_price(self.product_id.uom_id.id, price_unit, to_uom_id=self.uom_id.id)
return price_unit return price_unit
def _compute_average_price(self, qty_done, quantity, moves): def _compute_average_price(self, qty_done, quantity, moves):
+10 -3
View File
@@ -25,7 +25,6 @@ class Location(models.Model):
return res return res
name = fields.Char('Location Name', required=True, translate=True) name = fields.Char('Location Name', required=True, translate=True)
# TDE CLEAME: unnecessary field, use name_get instead
complete_name = fields.Char("Full Location Name", compute='_compute_complete_name', store=True) complete_name = fields.Char("Full Location Name", compute='_compute_complete_name', store=True)
active = fields.Boolean('Active', default=True, help="By unchecking the active field, you may hide a location without deleting it.") active = fields.Boolean('Active', default=True, help="By unchecking the active field, you may hide a location without deleting it.")
usage = fields.Selection([ usage = fields.Selection([
@@ -75,14 +74,22 @@ class Location(models.Model):
""" Forms complete name of location from parent location to child location. """ """ Forms complete name of location from parent location to child location. """
name = self.name name = self.name
current = self current = self
while current.location_id and current.usage != 'view': while current.location_id:
current = current.location_id current = current.location_id
name = '%s/%s' % (current.name, name) name = '%s/%s' % (current.name, name)
self.complete_name = name self.complete_name = name
@api.multi @api.multi
def name_get(self): def name_get(self):
return [(location.id, location.complete_name) for location in self] ret_list = []
for location in self:
orig_location = location
name = location.name
while location.location_id and location.usage != 'view':
location = location.location_id
name = location.name + "/" + name
ret_list.append((orig_location.id, name))
return ret_list
def get_putaway_strategy(self, product): def get_putaway_strategy(self, product):
''' Returns the location where the product has to be put, if any compliant putaway strategy is found. Otherwise returns None.''' ''' Returns the location where the product has to be put, if any compliant putaway strategy is found. Otherwise returns None.'''
+1 -1
View File
@@ -869,7 +869,7 @@ class Picking(models.Model):
moves_reassign = any(x.origin_returned_move_id or x.move_orig_ids for x in picking.move_lines if x.state not in ['done', 'cancel']) moves_reassign = any(x.origin_returned_move_id or x.move_orig_ids for x in picking.move_lines if x.state not in ['done', 'cancel'])
if moves_reassign and picking.location_id.usage not in ("supplier", "production", "inventory"): if moves_reassign and picking.location_id.usage not in ("supplier", "production", "inventory"):
# unnecessary to assign other quants than those involved with pack operations as they will be unreserved anyways. # unnecessary to assign other quants than those involved with pack operations as they will be unreserved anyways.
picking.with_context(reserve_only_ops=True, no_state_change=True).rereserve_quants(move_ids=todo_moves.ids) picking.with_context(reserve_only_ops=True, no_state_change=True).rereserve_quants(move_ids=picking.move_lines.ids)
picking.do_recompute_remaining_quantities() picking.do_recompute_remaining_quantities()
# split move lines if needed # split move lines if needed
@@ -202,6 +202,7 @@
<header> <header>
<button name="action_confirm" states="draft" string="Mark as Todo" type="object" class="oe_highlight" groups="base.group_user"/> <button name="action_confirm" states="draft" string="Mark as Todo" type="object" class="oe_highlight" groups="base.group_user"/>
<button name="action_assign" states="confirmed,waiting" string="Reserve" type="object" class="oe_highlight" groups="base.group_user"/> <button name="action_assign" states="confirmed,waiting" string="Reserve" type="object" class="oe_highlight" groups="base.group_user"/>
<button name="action_assign" states="partially_available" string="Recheck Availability" type="object" groups="base.group_user"/>
<button name="force_assign" states="confirmed,waiting,partially_available" string="Force Availability" type="object" groups="base.group_user"/> <button name="force_assign" states="confirmed,waiting,partially_available" string="Force Availability" type="object" groups="base.group_user"/>
<button name="do_new_transfer" states="draft,partially_available,assigned" string="Validate" groups="stock.group_stock_user" type="object" class="oe_highlight"/> <button name="do_new_transfer" states="draft,partially_available,assigned" string="Validate" groups="stock.group_stock_user" type="object" class="oe_highlight"/>
<button name="do_print_picking" string="Print" groups="stock.group_stock_user" type="object" attrs="{'invisible': [('state', 'not in', ('assigned', 'partially_available'))]}"/> <button name="do_print_picking" string="Print" groups="stock.group_stock_user" type="object" attrs="{'invisible': [('state', 'not in', ('assigned', 'partially_available'))]}"/>
+5 -2
View File
@@ -31,7 +31,11 @@ class account_invoice_line(osv.osv):
def _get_anglo_saxon_price_unit(self): def _get_anglo_saxon_price_unit(self):
self.ensure_one() self.ensure_one()
return self.product_id.standard_price price = self.product_id.standard_price
if not self.uom_id or self.product_id.uom_id == self.uom_id:
return price
else:
return self.product_id.uom_id._compute_price(self.product_id.uom_id.id, price, to_uom_id=self.uom_id.id)
def _get_price(self, cr, uid, inv, company_currency, i_line, price_unit): def _get_price(self, cr, uid, inv, company_currency, i_line, price_unit):
cur_obj = self.pool.get('res.currency') cur_obj = self.pool.get('res.currency')
@@ -107,7 +111,6 @@ class account_invoice(osv.osv):
] ]
return [] return []
#---------------------------------------------------------- #----------------------------------------------------------
# Stock Location # Stock Location
#---------------------------------------------------------- #----------------------------------------------------------
@@ -1208,7 +1208,7 @@ var One2ManyListView = X2ManyListView.extend({
this.dataset.x2m.internal_dataset_changed = false; this.dataset.x2m.internal_dataset_changed = false;
var self = this; var self = this;
return this.save_edition().done(function () { return this.save_edition(true).done(function () {
if (self._dataset_changed) { if (self._dataset_changed) {
self.dataset.trigger('dataset_changed'); self.dataset.trigger('dataset_changed');
} }
@@ -448,7 +448,7 @@ ListView.include(/** @lends instance.web.ListView# */{
/** /**
* @return {jQuery.Deferred} * @return {jQuery.Deferred}
*/ */
save_edition: function () { save_edition: function (cancel_onfail) {
var self = this; var self = this;
return self.saving_mutex.exec(function() { return self.saving_mutex.exec(function() {
if (!self.editor.is_editing()) { if (!self.editor.is_editing()) {
@@ -483,7 +483,9 @@ ListView.include(/** @lends instance.web.ListView# */{
return {created: created, record: record}; return {created: created, record: record};
}); });
}, function() { }, function() {
return self.cancel_edition(); if (cancel_onfail) {
return self.cancel_edition();
}
}); });
}); });
}); });
@@ -161,11 +161,6 @@ var FieldTextHtmlSimple = widget.extend({
return !this.get('value') || this.get('value') === "<p><br/></p>" || !this.get('value').match(/\S/); return !this.get('value') || this.get('value') === "<p><br/></p>" || !this.get('value').match(/\S/);
}, },
commit_value: function () { commit_value: function () {
// leave code view before saving
if (this.$content.prev('textarea').length === 1) {
var layoutInfo = { 'editor': function() { return this.$content; }.bind(this) };
$.summernote.pluginEvents.codeview(undefined, undefined, layoutInfo);
}
if (this.options['style-inline']) { if (this.options['style-inline']) {
transcoder.class_to_style(this.$content); transcoder.class_to_style(this.$content);
transcoder.font_to_img(this.$content); transcoder.font_to_img(this.$content);
@@ -379,11 +374,6 @@ var FieldTextHtml = widget.extend({
this._dirty_flag = false; this._dirty_flag = false;
return this.editor.save(); return this.editor.save();
} else if (this._dirty_flag && this.editor && this.editor.buildingBlock) { } else if (this._dirty_flag && this.editor && this.editor.buildingBlock) {
// leave code view before saving
if (this.$content.prev('textarea').length === 1) {
var layoutInfo = { 'editor': function() { return this.$content; }.bind(this) };
$.summernote.pluginEvents.codeview(undefined, undefined, layoutInfo);
}
this.editor.buildingBlock.clean_for_save(); this.editor.buildingBlock.clean_for_save();
this.internal_set_value( this.$content.html() ); this.internal_set_value( this.$content.html() );
} }
@@ -538,8 +538,6 @@ function prettify_html(html) {
} }
return result; return result;
} }
// Change Warning: called with dummy arguments to quit code view before saving
$.summernote.pluginEvents.codeview = function (event, editor, layoutInfo) { $.summernote.pluginEvents.codeview = function (event, editor, layoutInfo) {
if (layoutInfo.toolbar) { if (layoutInfo.toolbar) {
return eventHandler.modules.codeview.toggle(layoutInfo); return eventHandler.modules.codeview.toggle(layoutInfo);
+1 -1
View File
@@ -902,7 +902,7 @@ class IrActionsServer(models.Model):
self._cr.execute(""" self._cr.execute("""
INSERT INTO ir_logging(create_date, create_uid, type, dbname, name, level, message, path, line, func) INSERT INTO ir_logging(create_date, create_uid, type, dbname, name, level, message, path, line, func)
VALUES (NOW() at time zone 'UTC', %s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES (NOW() at time zone 'UTC', %s, %s, %s, %s, %s, %s, %s, %s, %s)
""", ('server', self._cr.dbname, __name__, level, message, "action", action.id, action.name)) """, (self._uid, 'server', self._cr.dbname, __name__, level, message, "action", action.id, action.name))
eval_context = super(IrActionsServer, self)._get_eval_context(action=action) eval_context = super(IrActionsServer, self)._get_eval_context(action=action)
model = self.env[action.model_id.model] model = self.env[action.model_id.model]
+17 -5
View File
@@ -5,7 +5,7 @@ import logging
from collections import defaultdict from collections import defaultdict
from difflib import get_close_matches from difflib import get_close_matches
from odoo import api, fields, models, tools, _ from odoo import api, fields, models, tools, SUPERUSER_ID, _
from odoo.exceptions import AccessError, UserError, ValidationError from odoo.exceptions import AccessError, UserError, ValidationError
from odoo.modules import get_module_path, get_module_resource from odoo.modules import get_module_path, get_module_resource
@@ -121,12 +121,21 @@ class IrTranslationImport(object):
# referencing non-existent data. # referencing non-existent data.
cr.execute("DELETE FROM %s WHERE res_id IS NULL AND module IS NOT NULL" % self._table) cr.execute("DELETE FROM %s WHERE res_id IS NULL AND module IS NOT NULL" % self._table)
# detect the xml_translate fields, where the src must be the same
env = api.Environment(cr, SUPERUSER_ID, {})
src_relevant_fields = []
for model in env:
for field_name, field in env[model]._fields.items():
if hasattr(field, 'translate') and callable(field.translate):
src_relevant_fields.append("%s,%s" % (model, field_name))
find_expr = """ find_expr = """
irt.lang = ti.lang irt.lang = ti.lang
AND irt.type = ti.type AND irt.type = ti.type
AND irt.name = ti.name AND irt.name = ti.name
AND ( AND (
(ti.type = 'model' AND ti.res_id = irt.res_id AND irt.src = ti.src) (ti.type = 'model' AND ti.res_id = irt.res_id AND ti.name IN %s AND irt.src = ti.src)
OR (ti.type = 'model' AND ti.res_id = irt.res_id AND ti.name NOT IN %s)
OR (ti.type = 'view' AND (irt.res_id IS NULL OR ti.res_id = irt.res_id) AND irt.src = ti.src) OR (ti.type = 'view' AND (irt.res_id IS NULL OR ti.res_id = irt.res_id) AND irt.src = ti.src)
OR (ti.type = 'field') OR (ti.type = 'field')
OR (ti.type = 'help') OR (ti.type = 'help')
@@ -142,20 +151,23 @@ class IrTranslationImport(object):
state = 'translated' state = 'translated'
FROM %s AS ti FROM %s AS ti
WHERE %s AND ti.value IS NOT NULL AND ti.value != '' WHERE %s AND ti.value IS NOT NULL AND ti.value != ''
""" % (self._model_table, self._table, find_expr)) """ % (self._model_table, self._table, find_expr),
(tuple(src_relevant_fields), tuple(src_relevant_fields)))
# Step 3: insert new translations # Step 3: insert new translations
cr.execute(""" INSERT INTO %s(name, lang, res_id, src, type, value, module, state, comments) cr.execute(""" INSERT INTO %s(name, lang, res_id, src, type, value, module, state, comments)
SELECT name, lang, res_id, src, type, value, module, state, comments SELECT name, lang, res_id, src, type, value, module, state, comments
FROM %s AS ti FROM %s AS ti
WHERE NOT EXISTS(SELECT 1 FROM ONLY %s AS irt WHERE %s); WHERE NOT EXISTS(SELECT 1 FROM ONLY %s AS irt WHERE %s);
""" % (self._model_table, self._table, self._model_table, find_expr)) """ % (self._model_table, self._table, self._model_table, find_expr),
(tuple(src_relevant_fields), tuple(src_relevant_fields)))
if self._debug: if self._debug:
cr.execute("SELECT COUNT(*) FROM ONLY %s" % self._model_table) cr.execute("SELECT COUNT(*) FROM ONLY %s" % self._model_table)
total = cr.fetchone()[0] total = cr.fetchone()[0]
cr.execute("SELECT COUNT(*) FROM ONLY %s AS irt, %s AS ti WHERE %s" % \ cr.execute("SELECT COUNT(*) FROM ONLY %s AS irt, %s AS ti WHERE %s" % \
(self._model_table, self._table, find_expr)) (self._model_table, self._table, find_expr),
(tuple(src_relevant_fields), tuple(src_relevant_fields)))
count = cr.fetchone()[0] count = cr.fetchone()[0]
_logger.debug("ir.translation.cursor: %d entries now in ir.translation, %d common entries with tmp", total, count) _logger.debug("ir.translation.cursor: %d entries now in ir.translation, %d common entries with tmp", total, count)
+1 -1
View File
@@ -358,7 +358,7 @@ class Users(models.Model):
if 'company_id' in values: if 'company_id' in values:
for user in self: for user in self:
# if partner is global we keep it that way # if partner is global we keep it that way
if user.partner_id.company_id.id != values['company_id']: if user.partner_id.company_id and user.partner_id.company_id.id != values['company_id']:
user.partner_id.write({'company_id': user.company_id.id}) user.partner_id.write({'company_id': user.company_id.id})
# clear default ir values when company changes # clear default ir values when company changes
self.env['ir.values'].get_defaults_dict.clear_cache(self.env['ir.values']) self.env['ir.values'].get_defaults_dict.clear_cache(self.env['ir.values'])