[MERGE] forward port of branch 8.0 up to 42ecf5e

This commit is contained in:
Denis Ledoux
2015-08-26 14:05:17 +02:00
21 changed files with 147 additions and 44 deletions
+7
View File
@@ -2163,6 +2163,13 @@ class account_tax(osv.osv):
total += r['amount']
return res
def _fix_tax_included_price(self, cr, uid, price, prod_taxes, line_taxes):
"""Subtract tax amount from price when corresponding "price included" taxes do not apply"""
incl_tax = [tax for tax in prod_taxes if tax.id not in line_taxes and tax.price_include]
if incl_tax:
return self._unit_compute_inv(cr, uid, incl_tax, price)[0]['price_unit']
return price
def _unit_compute_inv(self, cr, uid, taxes, price_unit, product=None, partner=None):
taxes = self._applicable(cr, uid, taxes, price_unit, product, partner)
res = []
+1 -1
View File
@@ -737,7 +737,7 @@ class account_invoice(models.Model):
if self.currency_id != company_currency:
currency = self.currency_id.with_context(date=self.date_invoice or fields.Date.context_today(self))
line['currency_id'] = currency.id
line['amount_currency'] = line['price']
line['amount_currency'] = currency.round(line['price'])
line['price'] = currency.compute(line['price'], company_currency)
else:
line['currency_id'] = False
+2 -2
View File
@@ -23,11 +23,11 @@
<field name="tax_ids" widget="one2many_list">
<tree string="Tax Mapping" editable="bottom">
<field name="tax_src_id" domain="[('parent_id','=',False)]"/>
<field name="tax_dest_id" domain="[('parent_id','=',False)]"/>
<field name="tax_dest_id" domain="[('parent_id','=',False), ('price_include', '=', False)]"/>
</tree>
<form string="Tax Mapping">
<field name="tax_src_id" domain="[('parent_id','=',False)]"/>
<field name="tax_dest_id" domain="[('parent_id','=',False)]"/>
<field name="tax_dest_id" domain="[('parent_id','=',False), ('price_include', '=', False)]"/>
</form>
</field>
<separator string="Accounts Mapping"/>
+1 -1
View File
@@ -449,7 +449,7 @@ class pos_session(osv.osv):
bank_statement_ids.append(statement_id)
values.update({
'name': self.pool['ir.sequence'].next_by_code(cr, uid, 'pos.session'),
'name': self.pool['ir.sequence'].next_by_code(cr, uid, 'pos.session', context=context),
'statement_ids' : [(6, 0, bank_statement_ids)],
'config_id': config_id
})
+1 -1
View File
@@ -47,7 +47,7 @@ class pos_details(report_sxw.rml_parse):
user_ids = form['user_ids'] or self._get_all_users()
company_id = user_obj.browse(self.cr, self.uid, self.uid).company_id.id
pos_ids = pos_obj.search(self.cr, self.uid, [('date_order','>=',form['date_start'] + ' 00:00:00'),('date_order','<=',form['date_end'] + ' 23:59:59'),('user_id','in',user_ids),('state','in',['done','paid','invoiced']),('company_id','=',company_id)])
for pos in pos_obj.browse(self.cr, self.uid, pos_ids):
for pos in pos_obj.browse(self.cr, self.uid, pos_ids, context=self.localcontext):
for pol in pos.lines:
result = {
'code': pol.product_id.default_code,
+1
View File
@@ -1217,6 +1217,7 @@ class purchase_order_line(osv.osv):
taxes = account_tax.browse(cr, uid, map(lambda x: x.id, product.supplier_taxes_id))
fpos = fiscal_position_id and account_fiscal_position.browse(cr, uid, fiscal_position_id, context=context) or False
taxes_ids = account_fiscal_position.map_tax(cr, uid, fpos, taxes)
price = self.pool['account.tax']._fix_tax_included_price(cr, uid, price, product.supplier_taxes_id, taxes_ids)
res['value'].update({'price_unit': price, 'taxes_id': taxes_ids})
return res
+1
View File
@@ -20,3 +20,4 @@
##############################################################################
from . import test_purchase_to_invoice
from . import test_onchange_product_id
@@ -0,0 +1,44 @@
from openerp.tests.common import TransactionCase
class TestOnchangeProductId(TransactionCase):
"""Test that when an included tax is mapped by a fiscal position, the included tax must be
subtracted to the price of the product.
"""
def setUp(self):
super(TestOnchangeProductId, self).setUp()
self.fiscal_position_model = self.registry('account.fiscal.position')
self.fiscal_position_tax_model = self.registry('account.fiscal.position.tax')
self.tax_model = self.registry('account.tax')
self.pricelist_model = self.registry('product.pricelist')
self.res_partner_model = self.registry('res.partner')
self.product_tmpl_model = self.registry('product.template')
self.product_model = self.registry('product.product')
self.product_uom_model = self.registry('product.uom')
self.so_line_model = self.registry('purchase.order.line')
def test_onchange_product_id(self):
cr, uid = self.cr, self.uid
uom_id = self.product_uom_model.search(cr, uid, [('name', '=', 'Unit(s)')])[0]
pricelist = self.pricelist_model.search(cr, uid, [('name', '=', 'Public Pricelist')])[0]
partner_id = self.res_partner_model.create(cr, uid, dict(name="George"))
tax_include_id = self.tax_model.create(cr, uid, dict(name="Include tax",
type='percent',
amount='0.21',
price_include=True))
tax_exclude_id = self.tax_model.create(cr, uid, dict(name="Exclude tax",
type='percent',
amount='0.00'))
product_tmpl_id = self.product_tmpl_model.create(cr, uid, dict(name="Voiture",
list_price='121',
supplier_taxes_id=[(6, 0, [tax_include_id])]))
product_id = self.product_model.create(cr, uid, dict(product_tmpl_id=product_tmpl_id))
fp_id = self.fiscal_position_model.create(cr, uid, dict(name="fiscal position",
sequence=1))
fp_tax_id = self.fiscal_position_tax_model.create(cr, uid, dict(position_id=fp_id,
tax_src_id=tax_include_id,
tax_dest_id=tax_exclude_id))
res = self.so_line_model.onchange_product_id(cr, uid, [], pricelist, product_id, 1.0, uom_id, partner_id,
fiscal_position_id=fp_id)
self.assertEquals(100, res['value']['price_unit'], "The included tax must be subtracted to the price")
+5 -3
View File
@@ -1052,7 +1052,7 @@ class sale_order_line(osv.osv):
date_order=order['date_order'],
fiscal_position=order['fiscal_position'][0] if order['fiscal_position'] else False,
flag=False, # Force name update
context=context
context=dict(context or {}, company_id=values.get('company_id'))
)['value']
if defaults.get('tax_id'):
defaults['tax_id'] = [[6, 0, defaults['tax_id']]]
@@ -1108,8 +1108,8 @@ class sale_order_line(osv.osv):
# The superuser is used by website_sale in order to create a sale order. We need to make
# sure we only select the taxes related to the company of the partner. This should only
# apply if the partner is linked to a company.
if uid == SUPERUSER_ID and partner.company_id:
taxes = product_obj.taxes_id.filtered(lambda r: r.company_id == partner.company_id)
if uid == SUPERUSER_ID and context.get('company_id'):
taxes = product_obj.taxes_id.filtered(lambda r: r.company_id.id == context['company_id'])
else:
taxes = product_obj.taxes_id
result['tax_id'] = self.pool['account.fiscal.position'].map_tax(cr, uid, fpos, taxes)
@@ -1162,6 +1162,8 @@ class sale_order_line(osv.osv):
product, qty or 1.0, partner_id, ctx)[pricelist]
else:
price = Product.price_get(cr, uid, [product], ptype='list_price', context=ctx_product)[product] or False
if update_tax:
price = self.pool['account.tax']._fix_tax_included_price(cr, uid, price, product_obj.taxes_id, result['tax_id'])
if context.get('uom_qty_change', False):
result, domain = {}, {}
result.update({'price_unit': price})
+6 -5
View File
@@ -141,17 +141,17 @@
<group>
<group>
<field name="product_id"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom, 'company_id': parent.company_id}"
groups="base.group_user"
on_change="product_id_change(parent.pricelist_id, product_id, product_uom_qty, False, product_uos_qty, False, name, parent.partner_id, False, True, parent.date_order, False, parent.fiscal_position, False, context)"/>
<label for="product_uom_qty"/>
<div>
<field
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom, 'uom_qty_change':True}"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom, 'uom_qty_change':True, 'company_id': parent.company-id}"
name="product_uom_qty" class="oe_inline"
on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, False, False, parent.date_order, False, parent.fiscal_position, True, context)"/>
<field name="product_uom" groups="product.group_uom" class="oe_inline oe_no_button"
context="{'company_id': parent.company_id}"
on_change="product_uom_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, False, False, parent.date_order, context)"/>
</div>
<label for="product_uos_qty" groups="product.group_uos"/>
@@ -184,14 +184,15 @@
<field name="state" invisible="1"/>
<field name="th_weight" invisible="1"/>
<field name="product_id"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom, 'company_id': parent.company_id}"
groups="base.group_user"
on_change="product_id_change(parent.pricelist_id, product_id, product_uom_qty, False, product_uos_qty, False, name, parent.partner_id, False, True, parent.date_order, False, parent.fiscal_position, False, context)"/>
<field name="name"/>
<field name="product_uom_qty"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom, 'company_id': parent.company_id}"
on_change="product_id_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, product_uos_qty, product_uos, name, parent.partner_id, False, False, parent.date_order, False, parent.fiscal_position, True, context)"/>
<field name="product_uom"
context="{'company_id': parent.company_id}"
on_change="product_uom_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, product_uos_qty, product_uos, name, parent.partner_id, False, False, parent.date_order, context)"
groups="product.group_uom" options='{"no_open": True}'/>
<field name="product_uos_qty" groups="product.group_uos" invisible="1"/>
+1
View File
@@ -20,3 +20,4 @@
##############################################################################
from . import test_sale_to_invoice
from . import test_product_id_change
@@ -0,0 +1,41 @@
from openerp.tests.common import TransactionCase
class TestProductIdChange(TransactionCase):
"""Test that when an included tax is mapped by a fiscal position, the included tax must be
subtracted to the price of the product.
"""
def setUp(self):
super(TestProductIdChange, self).setUp()
self.fiscal_position_model = self.registry('account.fiscal.position')
self.fiscal_position_tax_model = self.registry('account.fiscal.position.tax')
self.tax_model = self.registry('account.tax')
self.pricelist_model = self.registry('product.pricelist')
self.res_partner_model = self.registry('res.partner')
self.product_tmpl_model = self.registry('product.template')
self.product_model = self.registry('product.product')
self.so_line_model = self.registry('sale.order.line')
def test_product_id_change(self):
cr, uid = self.cr, self.uid
pricelist = self.pricelist_model.search(cr, uid, [('name', '=', 'Public Pricelist')])[0]
partner_id = self.res_partner_model.create(cr, uid, dict(name="George"))
tax_include_id = self.tax_model.create(cr, uid, dict(name="Include tax",
type='percent',
amount='0.21',
price_include=True))
tax_exclude_id = self.tax_model.create(cr, uid, dict(name="Exclude tax",
type='percent',
amount='0.00'))
product_tmpl_id = self.product_tmpl_model.create(cr, uid, dict(name="Voiture",
list_price='121',
taxes_id=[(6, 0, [tax_include_id])]))
product_id = self.product_model.create(cr, uid, dict(product_tmpl_id=product_tmpl_id))
fp_id = self.fiscal_position_model.create(cr, uid, dict(name="fiscal position",
sequence=1))
fp_tax_id = self.fiscal_position_tax_model.create(cr, uid, dict(position_id=fp_id,
tax_src_id=tax_include_id,
tax_dest_id=tax_exclude_id))
res = self.so_line_model.product_id_change(cr, uid, [], pricelist, product_id, partner_id=partner_id,
fiscal_position=fp_id)
self.assertEquals(100, res['value']['price_unit'], "The included tax must be subtracted to the price")
+2 -2
View File
@@ -40,7 +40,7 @@
parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position,
False, parent.warehouse_id, context)
</attribute>
<attribute name="context">{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':False}</attribute>
<attribute name="context">{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':False, 'company_id': parent.company_id}</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/tree//field[@name='product_id']" position="attributes">
<attribute name="on_change">product_id_change_with_wh(
@@ -76,7 +76,7 @@
</xpath>
<xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/group/group/field[@name='tax_id']" position="before">
<field name="product_tmpl_id" invisible="1"/>
<field name="product_packaging" context="{'default_product_tmpl_id': product_tmpl_id, 'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}" on_change="product_packaging_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, parent.partner_id, product_packaging, True, context)" domain="[('product_tmpl_id','=',product_tmpl_id)]" groups="product.group_stock_packaging" />
<field name="product_packaging" context="{'default_product_tmpl_id': product_tmpl_id, 'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom, 'company_id': parent.company_id}" on_change="product_packaging_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, parent.partner_id, product_packaging, True, context)" domain="[('product_tmpl_id','=',product_tmpl_id)]" groups="product.group_stock_packaging" />
</xpath>
<xpath expr="//page[@string='Order Lines']/field[@name='order_line']/tree[@string='Sales Order Lines']/field[@name='sequence']" position="after">
<field name="delay" invisible="1"/>
+3 -9
View File
@@ -848,7 +848,7 @@ class survey_user_input(osv.Model):
'survey_id': fields.many2one('survey.survey', 'Survey', required=True,
readonly=1, ondelete='restrict'),
'date_create': fields.datetime('Creation Date', required=True,
readonly=1),
readonly=1, copy=False),
'deadline': fields.datetime("Deadline",
help="Date by which the person can open the survey and submit answers",
oldname="date_deadline"),
@@ -861,7 +861,7 @@ class survey_user_input(osv.Model):
'Status',
readonly=True),
'test_entry': fields.boolean('Test entry', readonly=1),
'token': fields.char("Identification token", readonly=1, required=1),
'token': fields.char("Identification token", readonly=1, required=1, copy=False),
# Optional Identification data
'partner_id': fields.many2one('res.partner', 'Partner', readonly=1),
@@ -872,7 +872,7 @@ class survey_user_input(osv.Model):
'Last displayed page'),
# The answers !
'user_input_line_ids': fields.one2many('survey.user_input_line',
'user_input_id', 'Answers'),
'user_input_id', 'Answers', copy=True),
# URLs used to display the answers
'result_url': fields.related('survey_id', 'result_url', type='char',
@@ -895,9 +895,6 @@ class survey_user_input(osv.Model):
('deadline_in_the_past', 'CHECK (deadline >= date_create)', 'The deadline cannot be in the past')
]
def copy_data(self, cr, uid, id, default=None, context=None):
raise UserError(_('You cannot duplicate this element!'))
def do_clean_emptys(self, cr, uid, automatic=False, context=None):
''' Remove empty user inputs that have been created manually
(used as a cronjob declared in data/survey_cron.xml) '''
@@ -1026,9 +1023,6 @@ class survey_user_input_line(osv.Model):
vals.update({'quizz_mark': self.__get_mark(cr, uid, value_suggested)})
return super(survey_user_input_line, self).write(cr, uid, ids, vals, context=context)
def copy_data(self, cr, uid, id, default=None, context=None):
raise UserError(_('You cannot duplicate this element!'))
def save_lines(self, cr, uid, user_input_id, question, post, answer_tag,
context=None):
''' Save answers to questions, depending on question type
+2 -1
View File
@@ -46,7 +46,8 @@ class WebsiteMail(http.Controller):
partner_ids = _object._find_partner_from_emails(
cr, SUPERUSER_ID, _id, [email], context=context, check_followers=True)
if not partner_ids or not partner_ids[0]:
partner_ids = [partner_obj.create(cr, SUPERUSER_ID, {'name': email, 'email': email}, context=context)]
name = email.split('@')[0]
partner_ids = [partner_obj.create(cr, SUPERUSER_ID, {'name': name, 'email': email}, context=context)]
# add or remove follower
if _message_is_follower:
+1 -1
View File
@@ -184,7 +184,7 @@ class sale_quote(http.Controller):
res = request.registry.get('sale.order.line').product_id_change(request.cr, SUPERUSER_ID, order_id,
False, option.product_id.id, option.quantity, option.uom_id.id, option.quantity, option.uom_id.id,
option.name, order.partner_id.id, False, True, time.strftime('%Y-%m-%d'),
False, order.fiscal_position.id, True, request.context)
False, order.fiscal_position.id, True, dict(request.context or {}, company_id=order.company_id.id))
vals = res.get('value', {})
if 'tax_id' in vals:
vals['tax_id'] = [(6, 0, vals['tax_id'])]
@@ -43,7 +43,7 @@
</page>
</xpath>
<xpath expr="//field[@name='project_id']" position="before">
<field name="template_id" on_change="onchange_template_id(template_id, partner_id, fiscal_position, pricelist_id)"/>
<field name="template_id" context="{'company_id': company_id}" on_change="onchange_template_id(template_id, partner_id, fiscal_position, pricelist_id, context)"/>
</xpath>
<xpath expr="//field[@name='client_order_ref']" position="after">
<field name="require_payment"/>
+1
View File
@@ -245,6 +245,7 @@ class website_sale(http.Controller):
if category:
category = category_obj.browse(cr, uid, int(category), context=context)
category = category if category.exists() else False
attrib_list = request.httprequest.args.getlist('attrib')
attrib_values = [map(int,v.split("-")) for v in attrib_list if v]
+1 -1
View File
@@ -57,7 +57,7 @@ class sale_order(osv.Model):
partner_id=so.partner_id.id,
fiscal_position=so.fiscal_position.id,
qty=qty,
context=context
context=dict(context or {}, company_id=so.company_id.id)
)['value']
if line_id:
+18 -2
View File
@@ -626,9 +626,9 @@ instead of a single view its ``arch`` field is composed of any number of
<field name="model">idea.category</field>
<field name="inherit_id" ref="id_category_list"/>
<field name="arch" type="xml">
<!-- find field description inside tree, and add the field
<!-- find field description and add the field
idea_ids after it -->
<xpath expr="/tree/field[@name='description']" position="after">
<xpath expr="//field[@name='description']" position="after">
<field name="idea_ids" string="Number of ideas"/>
</xpath>
</field>
@@ -652,6 +652,22 @@ instead of a single view its ``arch`` field is composed of any number of
alters the attributes of the matched element using special
``attribute`` elements in the ``xpath``'s body
.. tip::
When matching a single element, the ``position`` attribute can be set directly
on the element to be found. Both inheritances below will give the same result.
.. code-block:: xml
<xpath expr="//field[@name='description']" position="after">
<field name="idea_ids" />
</xpath>
<field name="description" position="after">
<field name="idea_ids" />
</field>
.. exercise:: Alter existing content
* Using model inheritance, modify the existing *Partner* model to add an
+7 -14
View File
@@ -19,6 +19,7 @@
#
##############################################################################
import logging
import pytz
import time
from datetime import datetime, timedelta
@@ -212,22 +213,14 @@ class ir_sequence(models.Model):
def _interpolation_dict():
if self.env.context.get('ir_sequence_date'):
t = time.strptime(self.env.context.get('ir_sequence_date'), '%Y-%m-%d')
t = datetime.strptime(self.env.context.get('ir_sequence_date'), '%Y-%m-%d')
else:
t = time.localtime() # Actually, the server is always in UTC.
return {
'year': time.strftime('%Y', t),
'month': time.strftime('%m', t),
'day': time.strftime('%d', t),
'y': time.strftime('%y', t),
'doy': time.strftime('%j', t),
'woy': time.strftime('%W', t),
'weekday': time.strftime('%w', t),
'h24': time.strftime('%H', t),
'h12': time.strftime('%I', t),
'min': time.strftime('%M', t),
'sec': time.strftime('%S', t),
t = datetime.now(pytz.timezone(self.env.context.get('tz') or 'UTC'))
sequences = {
'year': '%Y', 'month': '%m', 'day': '%d', 'y': '%y', 'doy': '%j', 'woy': '%W',
'weekday': '%w', 'h24': '%H', 'h12': '%I', 'min': '%M', 'sec': '%S'
}
return {key: t.strftime(sequence) for key, sequence in sequences.iteritems()}
d = _interpolation_dict()
try: