[MERGE] Forward-port of latest saas-2 bugfixes, up to rev. 9144 revid:dle@openerp.com-20140310133913-465x5t3n1bo7fu98

bzr revid: dle@openerp.com-20140310143600-kz7qjfe4p63s0a34
This commit is contained in:
Denis Ledoux 2014-03-10 15:36:00 +01:00
commit 74af3ac0fe
22 changed files with 119 additions and 51 deletions

View File

@ -1601,7 +1601,6 @@
<label for="value_amount" string="Amount To Pay" attrs="{'invisible':[('value','=','balance')]}"/> <label for="value_amount" string="Amount To Pay" attrs="{'invisible':[('value','=','balance')]}"/>
<div attrs="{'invisible':[('value','=','balance')]}"> <div attrs="{'invisible':[('value','=','balance')]}">
<field name="value_amount" class="oe_inline"/> <field name="value_amount" class="oe_inline"/>
<label string="%%" class="oe_inline" attrs="{'invisible':['!',('value','=','procent')]}" />
</div> </div>
</group> </group>
<group string="Due Date Computation"> <group string="Due Date Computation">

View File

@ -407,7 +407,7 @@ class crm_lead(format_address, osv.osv):
'probability = 0 %, select "Change Probability Automatically".\n' 'probability = 0 %, select "Change Probability Automatically".\n'
'Create a specific stage or edit an existing one by editing columns of your opportunity pipe.')) 'Create a specific stage or edit an existing one by editing columns of your opportunity pipe.'))
for stage_id, lead_ids in stages_leads.items(): for stage_id, lead_ids in stages_leads.items():
self.write(cr, uid, lead_ids, {'stage_id': stage_id}, context=context) self.write(cr, uid, lead_ids, {'stage_id': stage_id, 'date_closed': fields.datetime.now()}, context=context)
return True return True
def case_mark_won(self, cr, uid, ids, context=None): def case_mark_won(self, cr, uid, ids, context=None):
@ -428,7 +428,7 @@ class crm_lead(format_address, osv.osv):
'probability = 100 % and select "Change Probability Automatically".\n' 'probability = 100 % and select "Change Probability Automatically".\n'
'Create a specific stage or edit an existing one by editing columns of your opportunity pipe.')) 'Create a specific stage or edit an existing one by editing columns of your opportunity pipe.'))
for stage_id, lead_ids in stages_leads.items(): for stage_id, lead_ids in stages_leads.items():
self.write(cr, uid, lead_ids, {'stage_id': stage_id}, context=context) self.write(cr, uid, lead_ids, {'stage_id': stage_id, 'date_closed': fields.datetime.now()}, context=context)
return True return True
def case_escalate(self, cr, uid, ids, context=None): def case_escalate(self, cr, uid, ids, context=None):

View File

@ -58,7 +58,7 @@
<field name="view_mode">tree,calendar</field> <field name="view_mode">tree,calendar</field>
<field name="view_id" ref="crm_case_inbound_phone_tree_view"/> <field name="view_id" ref="crm_case_inbound_phone_tree_view"/>
<field name="domain">[]</field> <field name="domain">[]</field>
<field name="context">{'default_state': 'done'}</field> <field name="context">{'search_default_state': 'done', 'default_state': 'done'}</field>
<field name="search_view_id" ref="crm.view_crm_case_phonecalls_filter"/> <field name="search_view_id" ref="crm.view_crm_case_phonecalls_filter"/>
<field name="help" type="html"> <field name="help" type="html">
<p class="oe_view_nocontent_create"> <p class="oe_view_nocontent_create">

View File

@ -167,6 +167,7 @@
<search string="Search Phonecalls"> <search string="Search Phonecalls">
<field name="name" string="Phonecalls"/> <field name="name" string="Phonecalls"/>
<field name="date"/> <field name="date"/>
<field name="state"/>
<separator/> <separator/>
<filter icon="terp-gtk-go-back-rtl" string="To Do" name="current" domain="[('state','=','open')]"/> <filter icon="terp-gtk-go-back-rtl" string="To Do" name="current" domain="[('state','=','open')]"/>
<separator/> <separator/>

View File

@ -52,7 +52,7 @@ class report_event_registration(osv.osv):
# TOFIX this request won't select events that have no registration # TOFIX this request won't select events that have no registration
cr.execute(""" CREATE VIEW report_event_registration AS ( cr.execute(""" CREATE VIEW report_event_registration AS (
SELECT SELECT
e.id::char || '/' || coalesce(r.id::char,'') AS id, e.id::varchar || '/' || coalesce(r.id::varchar,'') AS id,
e.id AS event_id, e.id AS event_id,
e.user_id AS user_id, e.user_id AS user_id,
r.user_id AS user_id_registration, r.user_id AS user_id_registration,

View File

@ -263,6 +263,10 @@ class hr_expense_expense(osv.osv):
#convert eml into an osv-valid format #convert eml into an osv-valid format
lines = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, exp.employee_id.address_home_id, exp.date_confirm, context=context)), eml) lines = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, exp.employee_id.address_home_id, exp.date_confirm, context=context)), eml)
journal_id = move_obj.browse(cr, uid, move_id, context).journal_id
# post the journal entry if 'Skip 'Draft' State for Manual Entries' is checked
if journal_id.entry_posted:
move_obj.button_validate(cr, uid, [move_id], context)
move_obj.write(cr, uid, [move_id], {'line_id': lines}, context=context) move_obj.write(cr, uid, [move_id], {'line_id': lines}, context=context)
self.write(cr, uid, ids, {'account_move_id': move_id, 'state': 'done'}, context=context) self.write(cr, uid, ids, {'account_move_id': move_id, 'state': 'done'}, context=context)
return True return True

View File

@ -23,7 +23,7 @@ import time
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from openerp.osv import fields, osv from openerp.osv import fields, osv
from openerp.tools import config from openerp.tools import config, float_compare
from openerp.tools.translate import _ from openerp.tools.translate import _
class hr_payslip(osv.osv): class hr_payslip(osv.osv):
@ -86,6 +86,7 @@ class hr_payslip(osv.osv):
def process_sheet(self, cr, uid, ids, context=None): def process_sheet(self, cr, uid, ids, context=None):
move_pool = self.pool.get('account.move') move_pool = self.pool.get('account.move')
period_pool = self.pool.get('account.period') period_pool = self.pool.get('account.period')
precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Payroll')
timenow = time.strftime('%Y-%m-%d') timenow = time.strftime('%Y-%m-%d')
for slip in self.browse(cr, uid, ids, context=context): for slip in self.browse(cr, uid, ids, context=context):
@ -149,7 +150,7 @@ class hr_payslip(osv.osv):
line_ids.append(credit_line) line_ids.append(credit_line)
credit_sum += credit_line[2]['credit'] - credit_line[2]['debit'] credit_sum += credit_line[2]['credit'] - credit_line[2]['debit']
if debit_sum > credit_sum: if float_compare(credit_sum, debit_sum, precision_digits=precision) == -1:
acc_id = slip.journal_id.default_credit_account_id.id acc_id = slip.journal_id.default_credit_account_id.id
if not acc_id: if not acc_id:
raise osv.except_osv(_('Configuration Error!'),_('The Expense Journal "%s" has not properly configured the Credit Account!')%(slip.journal_id.name)) raise osv.except_osv(_('Configuration Error!'),_('The Expense Journal "%s" has not properly configured the Credit Account!')%(slip.journal_id.name))
@ -165,7 +166,7 @@ class hr_payslip(osv.osv):
}) })
line_ids.append(adjust_credit) line_ids.append(adjust_credit)
elif debit_sum < credit_sum: elif float_compare(debit_sum, credit_sum, precision_digits=precision) == -1:
acc_id = slip.journal_id.default_debit_account_id.id acc_id = slip.journal_id.default_debit_account_id.id
if not acc_id: if not acc_id:
raise osv.except_osv(_('Configuration Error!'),_('The Expense Journal "%s" has not properly configured the Debit Account!')%(slip.journal_id.name)) raise osv.except_osv(_('Configuration Error!'),_('The Expense Journal "%s" has not properly configured the Debit Account!')%(slip.journal_id.name))

View File

@ -138,7 +138,7 @@ class wizard_multi_charts_accounts(osv.osv_memory):
def _process_taxes_translations(self, cr, uid, obj_multi, company_id, langs, field, context=None): def _process_taxes_translations(self, cr, uid, obj_multi, company_id, langs, field, context=None):
obj_tax_template = self.pool.get('account.tax.template') obj_tax_template = self.pool.get('account.tax.template')
obj_tax = self.pool.get('account.tax') obj_tax = self.pool.get('account.tax')
in_ids = sorted([x.id for x in obj_multi.chart_template_id.tax_template_ids]) in_ids = [x.id for x in obj_multi.chart_template_id.tax_template_ids]
out_ids = obj_tax.search(cr, uid, [('company_id', '=', company_id)], order='id') out_ids = obj_tax.search(cr, uid, [('company_id', '=', company_id)], order='id')
return self.process_translations(cr, uid, langs, obj_tax_template, field, in_ids, obj_tax, out_ids, context=context) return self.process_translations(cr, uid, langs, obj_tax_template, field, in_ids, obj_tax, out_ids, context=context)

View File

@ -6,7 +6,7 @@
<record id="membership_0" model="product.product"> <record id="membership_0" model="product.product">
<field name="membership">True</field> <field name="membership">True</field>
<field eval="time.strftime('%Y-01-01')" name="membership_date_from"/> <field eval="time.strftime('%Y-01-01')" name="membership_date_from"/>
<field eval="time.strftime('%Y-12-01')" name="membership_date_to"/> <field eval="time.strftime('%Y-12-31')" name="membership_date_to"/>
<field name="name">Gold Membership</field> <field name="name">Gold Membership</field>
<field name="list_price">180</field> <field name="list_price">180</field>
<field name="categ_id" ref="product.product_category_1"/> <field name="categ_id" ref="product.product_category_1"/>
@ -16,7 +16,7 @@
<record id="membership_1" model="product.product"> <record id="membership_1" model="product.product">
<field name="membership">True</field> <field name="membership">True</field>
<field eval="time.strftime('%Y-01-01')" name="membership_date_from"/> <field eval="time.strftime('%Y-01-01')" name="membership_date_from"/>
<field eval="time.strftime('%Y-12-01')" name="membership_date_to"/> <field eval="time.strftime('%Y-12-31')" name="membership_date_to"/>
<field name="name">Silver Membership</field> <field name="name">Silver Membership</field>
<field name="categ_id" ref="product.product_category_1"/> <field name="categ_id" ref="product.product_category_1"/>
<field name="list_price">80</field> <field name="list_price">80</field>
@ -26,7 +26,7 @@
<record id="membership_2" model="product.product"> <record id="membership_2" model="product.product">
<field name="membership">True</field> <field name="membership">True</field>
<field eval="time.strftime('%Y-01-01')" name="membership_date_from"/> <field eval="time.strftime('%Y-01-01')" name="membership_date_from"/>
<field eval="time.strftime('%Y-12-01')" name="membership_date_to"/> <field eval="time.strftime('%Y-12-31')" name="membership_date_to"/>
<field name="name">Basic Membership</field> <field name="name">Basic Membership</field>
<field name="categ_id" ref="product.product_category_1"/> <field name="categ_id" ref="product.product_category_1"/>
<field name="list_price">40</field> <field name="list_price">40</field>

View File

@ -29,6 +29,7 @@ from openerp.tools import float_compare
from openerp.tools.translate import _ from openerp.tools.translate import _
from openerp import tools, SUPERUSER_ID from openerp import tools, SUPERUSER_ID
from openerp import SUPERUSER_ID from openerp import SUPERUSER_ID
from openerp.addons.product import _common
#---------------------------------------------------------- #----------------------------------------------------------
# Work Centers # Work Centers
@ -320,7 +321,7 @@ class mrp_bom(osv.osv):
""" """
routing_obj = self.pool.get('mrp.routing') routing_obj = self.pool.get('mrp.routing')
factor = factor / (bom.product_efficiency or 1.0) factor = factor / (bom.product_efficiency or 1.0)
factor = rounding(factor, bom.product_rounding) factor = _common.ceiling(factor, bom.product_rounding)
if factor < bom.product_rounding: if factor < bom.product_rounding:
factor = bom.product_rounding factor = bom.product_rounding
result = [] result = []
@ -376,6 +377,8 @@ class mrp_bom(osv.osv):
def rounding(f, r): def rounding(f, r):
# TODO for trunk: log deprecation warning
# _logger.warning("Deprecated rounding method, please use tools.float_round to round floats.")
import math import math
if not r: if not r:
return f return f

View File

@ -57,7 +57,8 @@ The following topics should be covered by this module:
'test/test_mrp_repair_b4inv.yml', 'test/test_mrp_repair_b4inv.yml',
'test/test_mrp_repair_afterinv.yml', 'test/test_mrp_repair_afterinv.yml',
'test/test_mrp_repair_cancel.yml', 'test/test_mrp_repair_cancel.yml',
'test/mrp_repair_report.yml' 'test/mrp_repair_report.yml',
'test/test_mrp_repair_fee.yml',
], ],
'installable': True, 'installable': True,
'auto_install': False, 'auto_install': False,

View File

@ -108,10 +108,12 @@ class mrp_repair(osv.osv):
return res return res
def _get_lines(self, cr, uid, ids, context=None): def _get_lines(self, cr, uid, ids, context=None):
result = {} return self.pool['mrp.repair'].search(
for line in self.pool.get('mrp.repair.line').browse(cr, uid, ids, context=context): cr, uid, [('operations', 'in', ids)], context=context)
result[line.repair_id.id] = True
return result.keys() def _get_fee_lines(self, cr, uid, ids, context=None):
return self.pool['mrp.repair'].search(
cr, uid, [('fees_lines', 'in', ids)], context=context)
_columns = { _columns = {
'name': fields.char('Repair Reference',size=24, required=True, states={'confirmed':[('readonly',True)]}), 'name': fields.char('Repair Reference',size=24, required=True, states={'confirmed':[('readonly',True)]}),
@ -160,18 +162,21 @@ class mrp_repair(osv.osv):
'repaired': fields.boolean('Repaired', readonly=True), 'repaired': fields.boolean('Repaired', readonly=True),
'amount_untaxed': fields.function(_amount_untaxed, string='Untaxed Amount', 'amount_untaxed': fields.function(_amount_untaxed, string='Untaxed Amount',
store={ store={
'mrp.repair': (lambda self, cr, uid, ids, c={}: ids, ['operations'], 10), 'mrp.repair': (lambda self, cr, uid, ids, c={}: ids, ['operations', 'fees_lines'], 10),
'mrp.repair.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10), 'mrp.repair.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10),
'mrp.repair.fee': (_get_fee_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10),
}), }),
'amount_tax': fields.function(_amount_tax, string='Taxes', 'amount_tax': fields.function(_amount_tax, string='Taxes',
store={ store={
'mrp.repair': (lambda self, cr, uid, ids, c={}: ids, ['operations'], 10), 'mrp.repair': (lambda self, cr, uid, ids, c={}: ids, ['operations', 'fees_lines'], 10),
'mrp.repair.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10), 'mrp.repair.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10),
'mrp.repair.fee': (_get_fee_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10),
}), }),
'amount_total': fields.function(_amount_total, string='Total', 'amount_total': fields.function(_amount_total, string='Total',
store={ store={
'mrp.repair': (lambda self, cr, uid, ids, c={}: ids, ['operations'], 10), 'mrp.repair': (lambda self, cr, uid, ids, c={}: ids, ['operations', 'fees_lines'], 10),
'mrp.repair.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10), 'mrp.repair.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10),
'mrp.repair.fee': (_get_fee_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10),
}), }),
} }

View File

@ -0,0 +1,23 @@
-
Testing total amount update function
-
I check the total amount of mrp_repair_rmrp1 is 100
-
!assert {model: mrp.repair, id: mrp_repair_rmrp1, string=amount_total should be 100}:
- amount_total == 100
-
I add a new fee line
-
!record {model: mrp.repair, id: mrp_repair_rmrp1}:
fees_lines:
- name: 'Assembly Service Cost'
product_id: product.product_assembly
product_uom_qty: 1.0
product_uom: product.product_uom_hour
price_unit: 12.0
to_invoice: True
-
I check the total amount of mrp_repair_rmrp1 is now 112
-
!assert {model: mrp.repair, id: mrp_repair_rmrp1, string=amount_total should be 112}:
- amount_total == 112

View File

@ -63,7 +63,6 @@ Print product labels with barcode.
], ],
'test': [ 'test': [
'product_pricelist_demo.yml', 'product_pricelist_demo.yml',
'test/product_uom.yml',
'test/product_pricelist.yml', 'test/product_pricelist.yml',
], ],
'installable': True, 'installable': True,

View File

@ -18,12 +18,18 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################## ##############################################################################
from openerp import tools
import math
def rounding(f, r): def rounding(f, r):
# TODO for trunk: log deprecation warning
# _logger.warning("Deprecated rounding method, please use tools.float_round to round floats.")
return tools.float_round(f, precision_rounding=r)
# TODO for trunk: add rounding method parameter to tools.float_round and use this method as hook
def ceiling(f, r):
if not r: if not r:
return f return f
return round(f / r) * r return math.ceil(f / r) * r
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -21,8 +21,7 @@
import time import time
from _common import rounding from openerp import tools
from openerp.osv import fields, osv from openerp.osv import fields, osv
from openerp.tools.translate import _ from openerp.tools.translate import _
@ -270,7 +269,8 @@ class product_pricelist(osv.osv):
if price is not False: if price is not False:
price_limit = price price_limit = price
price = price * (1.0+(rule.price_discount or 0.0)) price = price * (1.0+(rule.price_discount or 0.0))
price = rounding(price, rule.price_round) #TOFIX: rounding with tools.float_rouding if rule.price_round:
price = tools.float_round(price, precision_rounding=rule.price_round)
price += (rule.price_surcharge or 0.0) price += (rule.price_surcharge or 0.0)
if rule.price_min_margin: if rule.price_min_margin:
price = max(price, price_limit+rule.price_min_margin) price = max(price, price_limit+rule.price_min_margin)

View File

@ -22,7 +22,7 @@
import math import math
import re import re
from _common import rounding from _common import ceiling
from openerp import SUPERUSER_ID from openerp import SUPERUSER_ID
from openerp import tools from openerp import tools
@ -178,7 +178,7 @@ class product_uom(osv.osv):
return qty return qty
amount = qty / from_unit.factor amount = qty / from_unit.factor
if to_unit: if to_unit:
amount = rounding(amount * to_unit.factor, to_unit.rounding) amount = ceiling(amount * to_unit.factor, to_unit.rounding)
return amount return amount
def _compute_price(self, cr, uid, from_uom_id, price, to_uom_id=False): def _compute_price(self, cr, uid, from_uom_id, price, to_uom_id=False):

View File

@ -221,7 +221,6 @@
<kanban> <kanban>
<field name="color"/> <field name="color"/>
<field name="type"/> <field name="type"/>
<field name="image_small"/>
<field name="list_price"/> <field name="list_price"/>
<templates> <templates>
<t t-name="kanban-box"> <t t-name="kanban-box">

View File

@ -1,15 +0,0 @@
-
In order to test conversation of UOM,
-
I convert Grams into TON with price.
-
!python {model: product.uom}: |
from_uom_id = ref("product_uom_gram")
to_uom_id = ref("product_uom_ton")
price = 2
qty = 1020000
price = self._compute_price(cr, uid, from_uom_id, price, to_uom_id)
qty = self._compute_qty(cr, uid, from_uom_id, qty, to_uom_id)
assert qty == 1.02, "Qty is not correspond."
assert price == 2000000.0, "Price is not correspond."

View File

@ -0,0 +1,5 @@
from . import test_uom
fast_suite = [
test_uom,
]

View File

@ -0,0 +1,37 @@
from openerp.tests.common import TransactionCase
class TestUom(TransactionCase):
"""Tests for unit of measure conversion"""
def setUp(self):
super(TestUom, self).setUp()
self.product = self.registry('product.product')
self.uom = self.registry('product.uom')
self.imd = self.registry('ir.model.data')
def test_10_conversion(self):
cr, uid = self.cr, self.uid
gram_id = self.imd.get_object_reference(cr, uid, 'product', 'product_uom_gram')[1]
tonne_id = self.imd.get_object_reference(cr, uid, 'product', 'product_uom_ton')[1]
qty = self.uom._compute_qty(cr, uid, gram_id, 1020000, tonne_id)
self.assertEquals(qty, 1.02, "Converted quantity does not correspond.")
price = self.uom._compute_price(cr, uid, gram_id, 2, tonne_id)
self.assertEquals(price, 2000000.0, "Converted price does not correspond.")
def test_20_rounding(self):
cr, uid = self.cr, self.uid
unit_id = self.imd.get_object_reference(cr, uid, 'product', 'product_uom_unit')[1]
categ_unit_id = self.imd.get_object_reference(cr, uid, 'product', 'product_uom_categ_unit')[1]
score_id = self.uom.create(cr, uid, {
'name': 'Score',
'factor_inv': 20,
'uom_type': 'bigger',
'rounding': 1.0,
'category_id': categ_unit_id
})
qty = self.uom._compute_qty(cr, uid, unit_id, 2, score_id)
self.assertEquals(qty, 1, "Converted quantity should be rounded up.")

View File

@ -53,9 +53,9 @@ class product_product(osv.osv):
states = ('draft', 'open', 'paid') states = ('draft', 'open', 'paid')
sqlstr="""select sqlstr="""select
sum(l.price_unit * l.quantity)/sum(l.quantity) as avg_unit_price, sum(l.price_unit * l.quantity)/sum(nullif(l.quantity,0)) as avg_unit_price,
sum(l.quantity) as num_qty, sum(l.quantity) as num_qty,
sum(l.quantity * (l.price_subtotal/l.quantity)) as total, sum(l.quantity * (l.price_subtotal/(nullif(l.quantity,0)))) as total,
sum(l.quantity * pt.list_price) as sale_expected, sum(l.quantity * pt.list_price) as sale_expected,
sum(l.quantity * pt.standard_price) as normal_cost sum(l.quantity * pt.standard_price) as normal_cost
from account_invoice_line l from account_invoice_line l