[MERGE] forward port of branch saas-3 up to 8f13e83

This commit is contained in:
Christophe Simonis
2014-08-20 17:51:20 +02:00
19 changed files with 91 additions and 35 deletions
+2 -1
View File
@@ -1680,7 +1680,8 @@ class account_move_reconcile(osv.osv):
if not total: if not total:
self.pool.get('account.move.line').write(cr, uid, self.pool.get('account.move.line').write(cr, uid,
map(lambda x: x.id, rec.line_partial_ids), map(lambda x: x.id, rec.line_partial_ids),
{'reconcile_id': rec.id } {'reconcile_id': rec.id },
context=context
) )
return True return True
+9 -3
View File
@@ -802,11 +802,14 @@ class account_move_line(osv.osv):
if self.pool.get('res.currency').is_zero(cr, uid, currency_id, total): if self.pool.get('res.currency').is_zero(cr, uid, currency_id, total):
res = self.reconcile(cr, uid, merges+unmerge, context=context, writeoff_acc_id=writeoff_acc_id, writeoff_period_id=writeoff_period_id, writeoff_journal_id=writeoff_journal_id) res = self.reconcile(cr, uid, merges+unmerge, context=context, writeoff_acc_id=writeoff_acc_id, writeoff_period_id=writeoff_period_id, writeoff_journal_id=writeoff_journal_id)
return res return res
# marking the lines as reconciled does not change their validity, so there is no need
# to revalidate their moves completely.
reconcile_context = dict(context, novalidate=True)
r_id = move_rec_obj.create(cr, uid, { r_id = move_rec_obj.create(cr, uid, {
'type': type, 'type': type,
'line_partial_ids': map(lambda x: (4,x,False), merges+unmerge) 'line_partial_ids': map(lambda x: (4,x,False), merges+unmerge)
}, context=context) }, context=reconcile_context)
move_rec_obj.reconcile_partial_check(cr, uid, [r_id] + merges_rec, context=context) move_rec_obj.reconcile_partial_check(cr, uid, [r_id] + merges_rec, context=reconcile_context)
return True return True
def reconcile(self, cr, uid, ids, type='auto', writeoff_acc_id=False, writeoff_period_id=False, writeoff_journal_id=False, context=None): def reconcile(self, cr, uid, ids, type='auto', writeoff_acc_id=False, writeoff_period_id=False, writeoff_journal_id=False, context=None):
@@ -931,11 +934,14 @@ class account_move_line(osv.osv):
writeoff_line_ids = [writeoff_line_ids[1]] writeoff_line_ids = [writeoff_line_ids[1]]
ids += writeoff_line_ids ids += writeoff_line_ids
# marking the lines as reconciled does not change their validity, so there is no need
# to revalidate their moves completely.
reconcile_context = dict(context, novalidate=True)
r_id = move_rec_obj.create(cr, uid, { r_id = move_rec_obj.create(cr, uid, {
'type': type, 'type': type,
'line_id': map(lambda x: (4, x, False), ids), 'line_id': map(lambda x: (4, x, False), ids),
'line_partial_ids': map(lambda x: (3, x, False), ids) 'line_partial_ids': map(lambda x: (3, x, False), ids)
}) }, context=reconcile_context)
# the id of the move.reconcile is written in the move.line (self) by the create method above # the id of the move.reconcile is written in the move.line (self) by the create method above
# because of the way the line_id are defined: (4, x, False) # because of the way the line_id are defined: (4, x, False)
for id in ids: for id in ids:
+2 -2
View File
@@ -127,14 +127,14 @@ class account_invoice_line(osv.osv):
if line.get('invl_id', 0) == i_line.id and a == line['account_id']: if line.get('invl_id', 0) == i_line.id and a == line['account_id']:
uom = i_line.product_id.uos_id or i_line.product_id.uom_id uom = i_line.product_id.uos_id or i_line.product_id.uom_id
valuation_price_unit = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.product_id.standard_price, i_line.uos_id.id) valuation_price_unit = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.product_id.standard_price, i_line.uos_id.id)
if inv.currency_id.id != company_currency:
standard_price = self.pool.get('res.currency').compute(cr, uid, company_currency, inv.currency_id.id, standard_price, context={'date': inv.date_invoice})
if i_line.product_id.cost_method != 'standard' and i_line.purchase_line_id: if i_line.product_id.cost_method != 'standard' and i_line.purchase_line_id:
#for average/fifo/lifo costing method, fetch real cost price from incomming moves #for average/fifo/lifo costing method, fetch real cost price from incomming moves
stock_move_obj = self.pool.get('stock.move') stock_move_obj = self.pool.get('stock.move')
valuation_stock_move = stock_move_obj.search(cr, uid, [('purchase_line_id', '=', i_line.purchase_line_id.id)], limit=1, context=context) valuation_stock_move = stock_move_obj.search(cr, uid, [('purchase_line_id', '=', i_line.purchase_line_id.id)], limit=1, context=context)
if valuation_stock_move: if valuation_stock_move:
valuation_price_unit = stock_move_obj.browse(cr, uid, valuation_stock_move[0], context=context).price_unit valuation_price_unit = stock_move_obj.browse(cr, uid, valuation_stock_move[0], context=context).price_unit
if inv.currency_id.id != company_currency:
valuation_price_unit = self.pool.get('res.currency').compute(cr, uid, company_currency, inv.currency_id.id, valuation_price_unit, context={'date': inv.date_invoice})
if valuation_price_unit != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc: if valuation_price_unit != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc:
price_diff = round(i_line.price_unit - valuation_price_unit, account_prec) price_diff = round(i_line.price_unit - valuation_price_unit, account_prec)
line.update({'price': round(valuation_price_unit * line['quantity'], account_prec)}) line.update({'price': round(valuation_price_unit * line['quantity'], account_prec)})
+8 -4
View File
@@ -358,7 +358,7 @@ class account_voucher(osv.osv):
\n* The \'Posted\' status is used when user create voucher,a voucher number is generated and voucher entries are created in account \ \n* The \'Posted\' status is used when user create voucher,a voucher number is generated and voucher entries are created in account \
\n* The \'Cancelled\' status is used when user cancel voucher.'), \n* The \'Cancelled\' status is used when user cancel voucher.'),
'amount': fields.float('Total', digits_compute=dp.get_precision('Account'), required=True, readonly=True, states={'draft':[('readonly',False)]}), 'amount': fields.float('Total', digits_compute=dp.get_precision('Account'), required=True, readonly=True, states={'draft':[('readonly',False)]}),
'tax_amount':fields.float('Tax Amount', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}), 'tax_amount':fields.float('Tax Amount', digits_compute=dp.get_precision('Account'), readonly=True),
'reference': fields.char('Ref #', size=64, readonly=True, states={'draft':[('readonly',False)]}, help="Transaction reference number."), 'reference': fields.char('Ref #', size=64, readonly=True, states={'draft':[('readonly',False)]}, help="Transaction reference number."),
'number': fields.char('Number', size=32, readonly=True,), 'number': fields.char('Number', size=32, readonly=True,),
'move_id':fields.many2one('account.move', 'Account Entry'), 'move_id':fields.many2one('account.move', 'Account Entry'),
@@ -1323,10 +1323,14 @@ class account_voucher(osv.osv):
if voucher.payment_option == 'with_writeoff': if voucher.payment_option == 'with_writeoff':
account_id = voucher.writeoff_acc_id.id account_id = voucher.writeoff_acc_id.id
write_off_name = voucher.comment write_off_name = voucher.comment
elif voucher.type in ('sale', 'receipt'): elif voucher.partner_id:
account_id = voucher.partner_id.property_account_receivable.id if voucher.type in ('sale', 'receipt'):
account_id = voucher.partner_id.property_account_receivable.id
else:
account_id = voucher.partner_id.property_account_payable.id
else: else:
account_id = voucher.partner_id.property_account_payable.id # fallback on account of voucher
account_id = voucher.account_id.id
sign = voucher.type == 'payment' and -1 or 1 sign = voucher.type == 'payment' and -1 or 1
move_line = { move_line = {
'name': write_off_name or name, 'name': write_off_name or name,
@@ -159,7 +159,7 @@
<field name="res_model">account.voucher</field> <field name="res_model">account.voucher</field>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,form,graph</field> <field name="view_mode">tree,form,graph</field>
<field name="context">{'type':'general'}</field> <field name="context">{}</field>
<field name="view_id" eval="view_voucher_tree"/> <field name="view_id" eval="view_voucher_tree"/>
<field name="search_view_id" ref="view_voucher_filter"/> <field name="search_view_id" ref="view_voucher_filter"/>
</record> </record>
+1
View File
@@ -21,4 +21,5 @@ class auth_oauth_provider(osv.osv):
} }
_defaults = { _defaults = {
'enabled' : False, 'enabled' : False,
'css_class' : "zocial",
} }
@@ -27,7 +27,7 @@ class pos_order_report(osv.osv):
_description = "Point of Sale Orders Statistics" _description = "Point of Sale Orders Statistics"
_auto = False _auto = False
_columns = { _columns = {
'date': fields.date('Date Order', readonly=True), 'date': fields.datetime('Date Order', readonly=True),
'partner_id':fields.many2one('res.partner', 'Partner', readonly=True), 'partner_id':fields.many2one('res.partner', 'Partner', readonly=True),
'product_id':fields.many2one('product.product', 'Product', readonly=True), 'product_id':fields.many2one('product.product', 'Product', readonly=True),
'state': fields.selection([('draft', 'New'), ('paid', 'Closed'), ('done', 'Synchronized'), ('invoiced', 'Invoiced'), ('cancel', 'Cancelled')], 'state': fields.selection([('draft', 'New'), ('paid', 'Closed'), ('done', 'Synchronized'), ('invoiced', 'Invoiced'), ('cancel', 'Cancelled')],
+3
View File
@@ -684,6 +684,9 @@ class product_product(osv.osv):
unlink_ids = [] unlink_ids = []
unlink_product_tmpl_ids = [] unlink_product_tmpl_ids = []
for product in self.browse(cr, uid, ids, context=context): for product in self.browse(cr, uid, ids, context=context):
# Check if product still exists, in case it has been unlinked by unlinking its template
if not product.exists():
continue
tmpl_id = product.product_tmpl_id.id tmpl_id = product.product_tmpl_id.id
# Check if the product is last product of this template # Check if the product is last product of this template
other_product_ids = self.search(cr, uid, [('product_tmpl_id', '=', tmpl_id), ('id', '!=', product.id)], context=context) other_product_ids = self.search(cr, uid, [('product_tmpl_id', '=', tmpl_id), ('id', '!=', product.id)], context=context)
+1 -1
View File
@@ -126,7 +126,7 @@ class stock_partial_picking(osv.osv_memory):
# Overridden to inject the purchase price as true 'cost price' when processing # Overridden to inject the purchase price as true 'cost price' when processing
# incoming pickings. # incoming pickings.
def _product_cost_for_average_update(self, cr, uid, move): def _product_cost_for_average_update(self, cr, uid, move):
if move.picking_id.purchase_id: if move.picking_id.purchase_id and move.purchase_line_id:
return {'cost': move.purchase_line_id.price_unit, return {'cost': move.purchase_line_id.price_unit,
'currency': move.picking_id.purchase_id.currency_id.id} 'currency': move.picking_id.purchase_id.currency_id.id}
return super(stock_partial_picking, self)._product_cost_for_average_update(cr, uid, move) return super(stock_partial_picking, self)._product_cost_for_average_update(cr, uid, move)
+6 -6
View File
@@ -28,6 +28,12 @@ from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FO
import openerp.addons.decimal_precision as dp import openerp.addons.decimal_precision as dp
from openerp import workflow from openerp import workflow
class res_company(osv.Model):
_inherit = "res.company"
_columns = {
'sale_note': fields.text('Default Terms and Conditions', translate=True, help="Default terms and conditions for quotations."),
}
class sale_order(osv.osv): class sale_order(osv.osv):
_name = "sale.order" _name = "sale.order"
_inherit = ['mail.thread', 'ir.needaction_mixin'] _inherit = ['mail.thread', 'ir.needaction_mixin']
@@ -987,12 +993,6 @@ class sale_order_line(osv.osv):
raise osv.except_osv(_('Invalid Action!'), _('Cannot delete a sales order line which is in state \'%s\'.') %(rec.state,)) raise osv.except_osv(_('Invalid Action!'), _('Cannot delete a sales order line which is in state \'%s\'.') %(rec.state,))
return super(sale_order_line, self).unlink(cr, uid, ids, context=context) return super(sale_order_line, self).unlink(cr, uid, ids, context=context)
class res_company(osv.Model):
_inherit = "res.company"
_columns = {
'sale_note': fields.text('Default Terms and Conditions', translate=True, help="Default terms and conditions for quotations."),
}
class mail_compose_message(osv.Model): class mail_compose_message(osv.Model):
_inherit = 'mail.compose.message' _inherit = 'mail.compose.message'
+2
View File
@@ -277,6 +277,8 @@ class product_product(osv.osv):
if prodlot_id: if prodlot_id:
prodlot_clause = ' and prodlot_id = %s ' prodlot_clause = ' and prodlot_id = %s '
where += [prodlot_id] where += [prodlot_id]
elif 'prodlot_id' in context and not prodlot_id:
prodlot_clause = ' and prodlot_id is null '
# TODO: perhaps merge in one query. # TODO: perhaps merge in one query.
if 'in' in what: if 'in' in what:
+30
View File
@@ -37,6 +37,36 @@
!python {model: product.product}: | !python {model: product.product}: |
product = self.browse(cr, uid, ref('product_product_6'), context=context) product = self.browse(cr, uid, ref('product_product_6'), context=context)
assert product.qty_available == 10, "Stock is not updated." assert product.qty_available == 10, "Stock is not updated."
-
I update the current stock of the Ice-cream with 10 kgm without Production Lot.
-
!record {model: stock.change.product.qty, id: change_qty_nolot}:
location_id: location_monitor_small
new_quantity: 10
product_id: product_product_6
-
!python {model: stock.change.product.qty}: |
self.change_product_qty(cr, uid, [ref('change_qty_nolot')], context=dict(context, active_id=ref('product_product_6')))
-
I check available stock of Ice-cream after update stock.
-
!python {model: product.product}: |
product = self.browse(cr, uid, ref('product_product_6'), context=context)
assert product.qty_available == 20, "Real stock is not updated."
-
I revert 10kgm updated stock again with no production lot in order to level the stock
-
!record {model: stock.change.product.qty, id: change_qty_nolot_1}:
location_id: location_monitor_small
new_quantity: 0
product_id: product_product_6
-
!python {model: stock.change.product.qty}: |
self.change_product_qty(cr, uid, [ref('change_qty_nolot_1')], context=dict(context, active_id=ref('product_product_6')))
-
!python {model: product.product}: |
product = self.browse(cr, uid, ref('product_product_6'), context=context)
assert product.qty_available == 10, "Real stock is not updated."
- -
Stock user can merge inventory, so let's check data with giving the access rights of user. Stock user can merge inventory, so let's check data with giving the access rights of user.
- -
+2 -1
View File
@@ -860,7 +860,8 @@ class Proxy(http.Controller):
from werkzeug.test import Client from werkzeug.test import Client
from werkzeug.wrappers import BaseResponse from werkzeug.wrappers import BaseResponse
return Client(request.httprequest.app, BaseResponse).get(path).data base_url = request.httprequest.base_url
return Client(request.httprequest.app, BaseResponse).get(path, base_url=base_url).data
class Database(http.Controller): class Database(http.Controller):
+1 -1
View File
@@ -2810,7 +2810,7 @@ instance.web.form.FieldTextHtml = instance.web.form.AbstractField.extend(instanc
if (! this.get("effective_readonly")) { if (! this.get("effective_readonly")) {
self._updating_editor = false; self._updating_editor = false;
this.$textarea = this.$el.find('textarea'); this.$textarea = this.$el.find('textarea');
var width = ((this.node.attrs || {}).editor_width || '100%'); var width = ((this.node.attrs || {}).editor_width || 'auto');
var height = ((this.node.attrs || {}).editor_height || 250); var height = ((this.node.attrs || {}).editor_height || 250);
this.$textarea.cleditor({ this.$textarea.cleditor({
width: width, // width not including margins, borders or padding width: width, // width not including margins, borders or padding
@@ -258,7 +258,7 @@
if (!focus_field){ if (!focus_field){
focus_field = _.find(self.editor.form.fields_order, function(field){ return fields[field] && fields[field].$el.is(':visible:has(input)'); }); focus_field = _.find(self.editor.form.fields_order, function(field){ return fields[field] && fields[field].$el.is(':visible:has(input)'); });
} }
if (focus_field) fields[focus_field].$el.find('input').select(); if (focus_field && fields[focus_field]) fields[focus_field].$el.find('input').select();
return record.attributes; return record.attributes;
}); });
}).fail(function () { }).fail(function () {
+11 -9
View File
@@ -1266,16 +1266,18 @@
</t> </t>
<t t-name="FieldBinaryImage"> <t t-name="FieldBinaryImage">
<span class="oe_form_field oe_form_field_image" t-att-style="widget.node.attrs.style"> <span class="oe_form_field oe_form_field_image" t-att-style="widget.node.attrs.style">
<div class="oe_form_field_image_controls oe_edit_only"> <t t-if="!widget.get('effective_readonly')">
<t t-call="HiddenInputFile"> <div class="oe_form_field_image_controls oe_edit_only">
<t t-set="fileupload_id" t-value="widget.fileupload_id"/> <t t-call="HiddenInputFile">
Edit <t t-set="fileupload_id" t-value="widget.fileupload_id"/>
</t> Edit
<div class="oe_form_binary_progress" style="display: none"> </t>
<img t-att-src='_s + "/web/static/src/img/throbber.gif"' width="16" height="16"/> <div class="oe_form_binary_progress" style="display: none">
<b>Uploading ...</b> <img t-att-src='_s + "/web/static/src/img/throbber.gif"' width="16" height="16"/>
<b>Uploading ...</b>
</div>
</div> </div>
</div> </t>
</span> </span>
</t> </t>
<t t-name="FieldBinaryImage-img"> <t t-name="FieldBinaryImage-img">
@@ -1091,6 +1091,7 @@ openerp.web_calendar = function(instance) {
var self = this; var self = this;
var def = $.Deferred(); var def = $.Deferred();
var defaults = {}; var defaults = {};
var created = false;
_.each($.extend({}, this.data_template, data), function(val, field_name) { _.each($.extend({}, this.data_template, data), function(val, field_name) {
defaults['default_' + field_name] = val; defaults['default_' + field_name] = val;
@@ -1130,9 +1131,14 @@ openerp.web_calendar = function(instance) {
} }
}); });
pop.on('create_completed', self, function(id) { pop.on('create_completed', self, function(id) {
self.trigger('slowadded'); created = true;
self.trigger('slowadded');
}); });
def.then(function() { def.then(function() {
if (created) {
var parent = self.getParent();
parent.$calendar.fullCalendar('refetchEvents');
}
self.trigger('close'); self.trigger('close');
}); });
return def; return def;
+1 -1
View File
@@ -183,7 +183,7 @@
<field name="fax"/> <field name="fax"/>
<field name="user_ids" invisible="1"/> <field name="user_ids" invisible="1"/>
<field name="email" widget="email" attrs="{'required': [('user_ids','!=', [])]}"/> <field name="email" widget="email" attrs="{'required': [('user_ids','!=', [])]}"/>
<field name="title" domain="[('domain', '=', 'contact')]" options='{"no_open": True}'/> <field name="title" options='{"no_open": True}'/>
</group> </group>
</group> </group>
+2 -2
View File
@@ -1264,9 +1264,9 @@ class function(_column):
# if we already have a value, don't recompute it. # if we already have a value, don't recompute it.
# This happen if case of stored many2one fields # This happen if case of stored many2one fields
if values and not multi and name in values[0]: if values and not multi and name in values[0]:
result = {v['id']: v[name] for v in values} result = dict((v['id'], v[name]) for v in values)
elif values and multi and all(n in values[0] for n in name): elif values and multi and all(n in values[0] for n in name):
result = {v['id']: dict((n, v[n]) for n in name) for v in values} result = dict((v['id'], dict((n, v[n]) for n in name)) for v in values)
else: else:
result = self._fnct(obj, cr, uid, ids, name, self._arg, context) result = self._fnct(obj, cr, uid, ids, name, self._arg, context)
if multi: if multi: