[MERGE] forward port branch saas-11 up to 659fb5d
This commit is contained in:
@@ -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):
|
||||||
|
|||||||
@@ -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(){
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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.'''
|
||||||
|
|||||||
@@ -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'))]}"/>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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'])
|
||||||
|
|||||||
Reference in New Issue
Block a user