[MERGE] forward port of branch 9.0 up to 100d604
This commit is contained in:
@@ -12,6 +12,7 @@ from . import test_chart_of_account
|
|||||||
from . import test_fiscal_position
|
from . import test_fiscal_position
|
||||||
from . import test_manual_reconciliation
|
from . import test_manual_reconciliation
|
||||||
from . import test_payment
|
from . import test_payment
|
||||||
|
from . import test_product_id_change
|
||||||
from . import test_reconciliation
|
from . import test_reconciliation
|
||||||
from . import test_search
|
from . import test_search
|
||||||
from . import test_tax
|
from . import test_tax
|
||||||
|
|||||||
@@ -1,50 +1,91 @@
|
|||||||
from openerp.tests.common import TransactionCase
|
from openerp.addons.account.tests.account_test_classes import AccountingTestCase
|
||||||
|
import time
|
||||||
|
|
||||||
class TestProductIdChange(TransactionCase):
|
class TestProductIdChange(AccountingTestCase):
|
||||||
"""Test that when an included tax is mapped by a fiscal position, the included tax must be
|
"""Test that when an included tax is mapped by a fiscal position, the included tax must be
|
||||||
subtracted to the price of the product.
|
subtracted to the price of the product.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestProductIdChange, self).setUp()
|
super(TestProductIdChange, self).setUp()
|
||||||
self.fiscal_position_model = self.registry('account.fiscal.position')
|
self.invoice_model = self.env['account.invoice']
|
||||||
self.fiscal_position_tax_model = self.registry('account.fiscal.position.tax')
|
self.fiscal_position_model = self.env['account.fiscal.position']
|
||||||
self.tax_model = self.registry('account.tax')
|
self.fiscal_position_tax_model = self.env['account.fiscal.position.tax']
|
||||||
self.pricelist_model = self.registry('product.pricelist')
|
self.tax_model = self.env['account.tax']
|
||||||
self.res_partner_model = self.registry('res.partner')
|
self.pricelist_model = self.env['product.pricelist']
|
||||||
self.product_tmpl_model = self.registry('product.template')
|
self.res_partner_model = self.env['res.partner']
|
||||||
self.product_model = self.registry('product.product')
|
self.product_tmpl_model = self.env['product.template']
|
||||||
self.invoice_line_model = self.registry('account.invoice.line')
|
self.product_model = self.env['product.product']
|
||||||
|
self.invoice_line_model = self.env['account.invoice.line']
|
||||||
|
self.account_receivable = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_receivable').id)], limit=1)
|
||||||
|
self.account_revenue = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1)
|
||||||
|
|
||||||
def test_product_id_change(self):
|
def test_product_id_change(self):
|
||||||
cr, uid = self.cr, self.uid
|
partner = self.res_partner_model.create(dict(name="George"))
|
||||||
partner_id = self.res_partner_model.create(cr, uid, dict(name="George"))
|
tax_include_sale = self.tax_model.create(dict(name="Include tax",
|
||||||
tax_include_id = self.tax_model.create(cr, uid, dict(name="Include tax",
|
type_tax_use='sale',
|
||||||
type='percent',
|
amount='21.00',
|
||||||
amount='0.21',
|
price_include=True))
|
||||||
price_include=True))
|
tax_include_purchase = self.tax_model.create(dict(name="Include tax",
|
||||||
tax_exclude_id = self.tax_model.create(cr, uid, dict(name="Exclude tax",
|
type_tax_use='purchase',
|
||||||
type='percent',
|
amount='21.00',
|
||||||
amount='0.00'))
|
price_include=True))
|
||||||
product_tmpl_id = self.product_tmpl_model.create(cr, uid, dict(name="Voiture",
|
tax_exclude_sale = self.tax_model.create(dict(name="Exclude tax",
|
||||||
list_price='121',
|
type_tax_use='sale',
|
||||||
standard_price='121',
|
amount='0.00'))
|
||||||
taxes_id=[(6, 0, [tax_include_id])],
|
tax_exclude_purchase = self.tax_model.create(dict(name="Exclude tax",
|
||||||
supplier_taxes_id=[(6, 0, [tax_include_id])]))
|
type_tax_use='purchase',
|
||||||
product_id = self.product_model.create(cr, uid, dict(product_tmpl_id=product_tmpl_id))
|
amount='0.00'))
|
||||||
product = self.product_model.browse(cr, uid, [product_id])
|
product_tmpl = self.product_tmpl_model.create(dict(name="Voiture",
|
||||||
fp_id = self.fiscal_position_model.create(cr, uid, dict(name="fiscal position",
|
list_price='121',
|
||||||
sequence=1))
|
standard_price='121',
|
||||||
fp_tax_id = self.fiscal_position_tax_model.create(cr, uid, dict(position_id=fp_id,
|
taxes_id=[(6, 0, [tax_include_sale.id])],
|
||||||
tax_src_id=tax_include_id,
|
supplier_taxes_id=[(6, 0, [tax_include_purchase.id])]))
|
||||||
tax_dest_id=tax_exclude_id))
|
product = self.product_model.create(dict(product_tmpl_id=product_tmpl.id))
|
||||||
|
fp = self.fiscal_position_model.create(dict(name="fiscal position", sequence=1))
|
||||||
|
fp_tax_sale = self.fiscal_position_tax_model.create(dict(position_id=fp.id,
|
||||||
|
tax_src_id=tax_include_sale.id,
|
||||||
|
tax_dest_id=tax_exclude_sale.id))
|
||||||
|
fp_tax_purchase = self.fiscal_position_tax_model.create(dict(position_id=fp.id,
|
||||||
|
tax_src_id=tax_include_purchase.id,
|
||||||
|
tax_dest_id=tax_exclude_purchase.id))
|
||||||
|
|
||||||
res = self.invoice_line_model.product_id_change(cr, uid, [], product.id, product.uom_id.id,
|
out_invoice = self.invoice_model.create({
|
||||||
qty=1, type='out_invoice', partner_id=partner_id,
|
'partner_id': partner.id,
|
||||||
fposition_id=fp_id)
|
'reference_type': 'none',
|
||||||
self.assertEquals(100, res['value']['price_unit'], "The included tax must be subtracted to the price")
|
'name': 'invoice to client',
|
||||||
|
'account_id': self.account_receivable.id,
|
||||||
|
'type': 'out_invoice',
|
||||||
|
'date_invoice': time.strftime('%Y') + '-06-26',
|
||||||
|
'fiscal_position_id': fp.id,
|
||||||
|
})
|
||||||
|
out_line = self.invoice_line_model.create({
|
||||||
|
'product_id': product.id,
|
||||||
|
'quantity': 1,
|
||||||
|
'price_unit': 121.0,
|
||||||
|
'invoice_id': out_invoice.id,
|
||||||
|
'name': 'something out',
|
||||||
|
'account_id': self.account_revenue.id,
|
||||||
|
})
|
||||||
|
|
||||||
res = self.invoice_line_model.product_id_change(cr, uid, [], product.id, product.uom_id.id,
|
in_invoice = self.invoice_model.create({
|
||||||
qty=1, type='in_invoice', partner_id=partner_id,
|
'partner_id': partner.id,
|
||||||
fposition_id=fp_id)
|
'reference_type': 'none',
|
||||||
self.assertEquals(100, res['value']['price_unit'], "The included tax must be subtracted to the price")
|
'name': 'invoice to supplier',
|
||||||
|
'account_id': self.account_receivable.id,
|
||||||
|
'type': 'in_invoice',
|
||||||
|
'date_invoice': time.strftime('%Y') + '-06-26',
|
||||||
|
'fiscal_position_id': fp.id,
|
||||||
|
})
|
||||||
|
in_line = self.invoice_line_model.create({
|
||||||
|
'product_id': product.id,
|
||||||
|
'quantity': 1,
|
||||||
|
'price_unit': 121.0,
|
||||||
|
'invoice_id': in_invoice.id,
|
||||||
|
'name': 'something in',
|
||||||
|
'account_id': self.account_revenue.id,
|
||||||
|
})
|
||||||
|
out_line._onchange_product_id()
|
||||||
|
self.assertEquals(100, out_line.price_unit, "The included tax must be subtracted to the price")
|
||||||
|
in_line._onchange_product_id()
|
||||||
|
self.assertEquals(100, in_line.price_unit, "The included tax must be subtracted to the price")
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ class LivechatController(http.Controller):
|
|||||||
username = kwargs.get("username", _("Visitor"))
|
username = kwargs.get("username", _("Visitor"))
|
||||||
channel = request.env['im_livechat.channel'].sudo().browse(channel_id)
|
channel = request.env['im_livechat.channel'].sudo().browse(channel_id)
|
||||||
info = request.env['im_livechat.channel'].get_livechat_info(channel.id, username=username)
|
info = request.env['im_livechat.channel'].get_livechat_info(channel.id, username=username)
|
||||||
return request.render('im_livechat.loader', {'info': info, 'web_session_required': True}) if info['available'] else False
|
js = request.render('im_livechat.loader', {'info': info, 'web_session_required': True})
|
||||||
|
return request.make_response(js, headers=[('Content-Type', 'application/javascript')])
|
||||||
|
|
||||||
@http.route('/im_livechat/init', type='json', auth="public")
|
@http.route('/im_livechat/init', type='json', auth="public")
|
||||||
def livechat_init(self, channel_id):
|
def livechat_init(self, channel_id):
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ class ImLivechatChannel(models.Model):
|
|||||||
@api.model
|
@api.model
|
||||||
def get_livechat_info(self, channel_id, username='Visitor'):
|
def get_livechat_info(self, channel_id, username='Visitor'):
|
||||||
info = {}
|
info = {}
|
||||||
info['available'] = len(self.browse(channel_id).get_available_users())
|
info['available'] = len(self.browse(channel_id).get_available_users()) > 0
|
||||||
if info['available']:
|
if info['available']:
|
||||||
info['server_url'] = self.env['ir.config_parameter'].get_param('web.base.url')
|
info['server_url'] = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||||
info['options'] = self.sudo().get_channel_infos(channel_id)
|
info['options'] = self.sudo().get_channel_infos(channel_id)
|
||||||
|
|||||||
@@ -143,7 +143,6 @@
|
|||||||
<t t-set="info" t-value="request.env['im_livechat.channel'].get_livechat_info(channel)"/>
|
<t t-set="info" t-value="request.env['im_livechat.channel'].get_livechat_info(channel)"/>
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
<t t-if="info['available']" t-translation="off">
|
|
||||||
document.addEventListener("DOMContentLoaded", function(event) {
|
document.addEventListener("DOMContentLoaded", function(event) {
|
||||||
<t t-if="web_session_required">
|
<t t-if="web_session_required">
|
||||||
odoo.define('web.session', function (require) {
|
odoo.define('web.session', function (require) {
|
||||||
@@ -154,6 +153,7 @@
|
|||||||
</t>
|
</t>
|
||||||
|
|
||||||
odoo.define('im_livechat.livesupport', function (require) {
|
odoo.define('im_livechat.livesupport', function (require) {
|
||||||
|
<t t-if="info['available']" t-translation="off">
|
||||||
var im_livechat = require('im_livechat.im_livechat');
|
var im_livechat = require('im_livechat.im_livechat');
|
||||||
var button = new im_livechat.LivechatButton(
|
var button = new im_livechat.LivechatButton(
|
||||||
$('body'),
|
$('body'),
|
||||||
@@ -162,9 +162,9 @@
|
|||||||
);
|
);
|
||||||
button.appendTo($('body'));
|
button.appendTo($('body'));
|
||||||
window.livechat_button = button;
|
window.livechat_button = button;
|
||||||
|
</t>
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</t>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,7 @@
|
|||||||
context="{
|
context="{
|
||||||
'default_composition_mode': 'mass_mail',
|
'default_composition_mode': 'mass_mail',
|
||||||
'default_partner_to': '${object.id or \'\'}',
|
'default_partner_to': '${object.id or \'\'}',
|
||||||
|
'default_active_domain': [['id', 'in', context.get('active_ids', [])]],
|
||||||
}"/>
|
}"/>
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|||||||
@@ -645,7 +645,7 @@ class pos_order(osv.osv):
|
|||||||
_order = "id desc"
|
_order = "id desc"
|
||||||
|
|
||||||
def _amount_line_tax(self, cr, uid, line, fiscal_position_id, context=None):
|
def _amount_line_tax(self, cr, uid, line, fiscal_position_id, context=None):
|
||||||
taxes = line.product_id.taxes_id.filtered(lambda t: t.company_id.id == line.order_id.company_id.id)
|
taxes = line.tax_ids.filtered(lambda t: t.company_id.id == line.order_id.company_id.id)
|
||||||
if fiscal_position_id:
|
if fiscal_position_id:
|
||||||
taxes = fiscal_position_id.map_tax(taxes)
|
taxes = fiscal_position_id.map_tax(taxes)
|
||||||
price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
|
price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
|
||||||
@@ -1399,7 +1399,7 @@ class pos_order_line(osv.osv):
|
|||||||
account_tax_obj = self.pool.get('account.tax')
|
account_tax_obj = self.pool.get('account.tax')
|
||||||
for line in self.browse(cr, uid, ids, context=context):
|
for line in self.browse(cr, uid, ids, context=context):
|
||||||
cur = line.order_id.pricelist_id.currency_id
|
cur = line.order_id.pricelist_id.currency_id
|
||||||
taxes = [ tax for tax in line.product_id.taxes_id if tax.company_id.id == line.order_id.company_id.id ]
|
taxes = [ tax for tax in line.tax_ids if tax.company_id.id == line.order_id.company_id.id ]
|
||||||
fiscal_position_id = line.order_id.fiscal_position_id
|
fiscal_position_id = line.order_id.fiscal_position_id
|
||||||
if fiscal_position_id:
|
if fiscal_position_id:
|
||||||
taxes = fiscal_position_id.map_tax(taxes)
|
taxes = fiscal_position_id.map_tax(taxes)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ odoo.define('point_of_sale.gui', function (require) {
|
|||||||
|
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var Model = require('web.DataModel');
|
var Model = require('web.DataModel');
|
||||||
|
var formats = require('web.formats');
|
||||||
|
|
||||||
var _t = core._t;
|
var _t = core._t;
|
||||||
|
|
||||||
@@ -411,8 +412,8 @@ var Gui = core.Class.extend({
|
|||||||
numpad_input: function(buffer, input, options) {
|
numpad_input: function(buffer, input, options) {
|
||||||
var newbuf = buffer.slice(0);
|
var newbuf = buffer.slice(0);
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var newbuf_float = instance.web.parse_value(newbuf, {type: "float"}, 0);
|
var newbuf_float = formats.parse_value(newbuf, {type: "float"}, 0);
|
||||||
var decimal_point = instance.web._t.database.parameters.decimal_point;
|
var decimal_point = _t.database.parameters.decimal_point;
|
||||||
|
|
||||||
if (input === decimal_point) {
|
if (input === decimal_point) {
|
||||||
if (options.firstinput) {
|
if (options.firstinput) {
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ var NumberPopupWidget = PopupWidget.extend({
|
|||||||
this._super(options);
|
this._super(options);
|
||||||
|
|
||||||
this.inputbuffer = '' + (options.value || '');
|
this.inputbuffer = '' + (options.value || '');
|
||||||
this.decimal_separator = instance.web._t.database.parameters.decimal_point;
|
this.decimal_separator = _t.database.parameters.decimal_point;
|
||||||
this.renderElement();
|
this.renderElement();
|
||||||
this.firstinput = true;
|
this.firstinput = true;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1706,7 +1706,7 @@ var PaymentScreenWidget = ScreenWidget.extend({
|
|||||||
'title': tip ? _t('Change Tip') : _t('Add Tip'),
|
'title': tip ? _t('Change Tip') : _t('Add Tip'),
|
||||||
'value': self.format_currency_no_symbol(value),
|
'value': self.format_currency_no_symbol(value),
|
||||||
'confirm': function(value) {
|
'confirm': function(value) {
|
||||||
order.set_tip(instance.web.parse_value(value, {type: "float"}, 0));
|
order.set_tip(formats.parse_value(value, {type: "float"}, 0));
|
||||||
self.order_changes();
|
self.order_changes();
|
||||||
self.render_paymentlines();
|
self.render_paymentlines();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ class PurchaseOrder(models.Model):
|
|||||||
picking_type_id = fields.Many2one('stock.picking.type', 'Deliver To', states=READONLY_STATES, required=True, default=_default_picking_type,\
|
picking_type_id = fields.Many2one('stock.picking.type', 'Deliver To', states=READONLY_STATES, required=True, default=_default_picking_type,\
|
||||||
help="This will determine picking type of incoming shipment")
|
help="This will determine picking type of incoming shipment")
|
||||||
default_location_dest_id_usage = fields.Selection(related='picking_type_id.default_location_dest_id.usage', string='Destination Location Type',\
|
default_location_dest_id_usage = fields.Selection(related='picking_type_id.default_location_dest_id.usage', string='Destination Location Type',\
|
||||||
help="Technical field used to display the Drop Ship Address")
|
help="Technical field used to display the Drop Ship Address", readonly=True)
|
||||||
group_id = fields.Many2one('procurement.group', string="Procurement Group")
|
group_id = fields.Many2one('procurement.group', string="Procurement Group")
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ var FieldTextHtml = widget.extend({
|
|||||||
return def;
|
return def;
|
||||||
},
|
},
|
||||||
get_url: function (_attr) {
|
get_url: function (_attr) {
|
||||||
var src = this.options.editor_url ? this.options.editor_url+"?" : "/web_editor/field/html?";
|
var src = this.options.editor_url || "/web_editor/field/html";
|
||||||
var datarecord = this.view.get_fields_values();
|
var datarecord = this.view.get_fields_values();
|
||||||
|
|
||||||
var attr = {
|
var attr = {
|
||||||
@@ -211,6 +211,9 @@ var FieldTextHtml = widget.extend({
|
|||||||
if (this.options.snippets) {
|
if (this.options.snippets) {
|
||||||
attr.snippets = this.options.snippets;
|
attr.snippets = this.options.snippets;
|
||||||
}
|
}
|
||||||
|
if (this.options.template) {
|
||||||
|
attr.template = this.options.template;
|
||||||
|
}
|
||||||
if (!this.get("effective_readonly")) {
|
if (!this.get("effective_readonly")) {
|
||||||
attr.enable_editor = 1;
|
attr.enable_editor = 1;
|
||||||
}
|
}
|
||||||
@@ -227,6 +230,10 @@ var FieldTextHtml = widget.extend({
|
|||||||
attr[k] = _attr[k];
|
attr[k] = _attr[k];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (src.indexOf('?') === -1) {
|
||||||
|
src += "?";
|
||||||
|
}
|
||||||
|
|
||||||
for (var k in attr) {
|
for (var k in attr) {
|
||||||
if (attr[k] !== null) {
|
if (attr[k] !== null) {
|
||||||
src += "&"+k+"="+(_.isBoolean(attr[k]) ? +attr[k] : attr[k]);
|
src += "&"+k+"="+(_.isBoolean(attr[k]) ? +attr[k] : attr[k]);
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
United States of America, 2015-10-22
|
||||||
|
|
||||||
|
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,
|
||||||
|
|
||||||
|
Stephen Medina stephen@lilmail.xyz https://github.com/stephen144
|
||||||
+3
-1
@@ -78,7 +78,7 @@ not be fetched by browsers. The ``src/css``, ``src/js`` and ``src/xml``
|
|||||||
sub-folders are conventional and not strictly necessary.
|
sub-folders are conventional and not strictly necessary.
|
||||||
|
|
||||||
``oepetstore/static/css/petstore.css``
|
``oepetstore/static/css/petstore.css``
|
||||||
currently empty, will hold the CSS_ for pet store content
|
Currently empty, will hold the CSS_ for pet store content
|
||||||
``oepetstore/static/xml/petstore.xml``
|
``oepetstore/static/xml/petstore.xml``
|
||||||
Mostly empty, will hold :ref:`reference/qweb` templates
|
Mostly empty, will hold :ref:`reference/qweb` templates
|
||||||
``oepetstore/static/js/petstore.js``
|
``oepetstore/static/js/petstore.js``
|
||||||
@@ -103,6 +103,8 @@ sub-folders are conventional and not strictly necessary.
|
|||||||
|
|
||||||
Which only prints a small message in the browser's console.
|
Which only prints a small message in the browser's console.
|
||||||
|
|
||||||
|
The files in the ``static`` folder, need to be defined within the module in order for them to be loaded correctly. Everything in ``src/xml`` is defined in ``__openerp__.py`` while the contents of ``src/css`` and ``src/js`` are defined in ``petstore.xml``, or a similar file.
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
All JavaScript files are concatenated and :term:`minified` to improve
|
All JavaScript files are concatenated and :term:`minified` to improve
|
||||||
|
|||||||
Reference in New Issue
Block a user