[MERGE] forward port branch saas-14 up to aca401c500
This commit is contained in:
@@ -360,7 +360,7 @@ class account_payment(models.Model):
|
||||
if rec.payment_type == 'outbound':
|
||||
sequence_code = 'account.payment.supplier.invoice'
|
||||
rec.name = self.env['ir.sequence'].with_context(ir_sequence_date=rec.payment_date).next_by_code(sequence_code)
|
||||
if not rec.name and self.payment_type != 'transfer':
|
||||
if not rec.name and rec.payment_type != 'transfer':
|
||||
raise UserError(_("You have to define a sequence for %s in your company.") % (sequence_code,))
|
||||
|
||||
# Create the journal entry
|
||||
|
||||
@@ -35,5 +35,5 @@ class AccountCommonReport(models.TransientModel):
|
||||
data['model'] = self.env.context.get('active_model', 'ir.ui.menu')
|
||||
data['form'] = self.read(['date_from', 'date_to', 'journal_ids', 'target_move'])[0]
|
||||
used_context = self._build_contexts(data)
|
||||
data['form']['used_context'] = dict(used_context, lang=self.env.context.get('lang', 'en_US'))
|
||||
data['form']['used_context'] = dict(used_context, lang=self.env.context.get('lang') or 'en_US')
|
||||
return self._print_report(data)
|
||||
|
||||
@@ -31,7 +31,7 @@ class BaseGengoTranslations(models.TransientModel):
|
||||
res['authorized_credentials'], gengo = self.gengo_authentication()
|
||||
if 'lang_id' in fields:
|
||||
res['lang_id'] = self.env['res.lang'].search([
|
||||
('code', '=', self.env.context.get('lang', 'en_US'))
|
||||
('code', '=', self.env.context.get('lang') or 'en_US')
|
||||
], limit=1).id
|
||||
return res
|
||||
|
||||
|
||||
@@ -650,16 +650,30 @@ class Meeting(models.Model):
|
||||
date_deadline = fields.Datetime.context_timestamp(self.with_context(tz=timezone), fields.Datetime.from_string(stop))
|
||||
|
||||
# convert into string the date and time, using user formats
|
||||
date_str = date.strftime(format_date)
|
||||
time_str = date.strftime(format_time)
|
||||
date_str = date.strftime(format_date).decode('utf-8')
|
||||
time_str = date.strftime(format_time).decode('utf-8')
|
||||
|
||||
if zallday:
|
||||
display_time = _("AllDay , %s") % (date_str)
|
||||
elif zduration < 24:
|
||||
duration = date + timedelta(hours=zduration)
|
||||
display_time = _("%s at (%s To %s) (%s)") % (date_str, time_str, duration.strftime(format_time), timezone)
|
||||
duration_time = duration.strftime(format_time).decode('utf-8')
|
||||
display_time = _(u"%s at (%s To %s) (%s)") % (
|
||||
date_str,
|
||||
time_str,
|
||||
duration_time,
|
||||
timezone,
|
||||
)
|
||||
else:
|
||||
display_time = _("%s at %s To\n %s at %s (%s)") % (date_str, time_str, date_deadline.strftime(format_date), date_deadline.strftime(format_time), timezone)
|
||||
dd_date = date_deadline.strftime(format_date).decode('utf-8')
|
||||
dd_time = date_deadline.strftime(format_time).decode('utf-8')
|
||||
display_time = _(u"%s at %s To\n %s at %s (%s)") % (
|
||||
date_str,
|
||||
time_str,
|
||||
dd_date,
|
||||
dd_time,
|
||||
timezone,
|
||||
)
|
||||
return display_time
|
||||
|
||||
def _get_duration(self, start, stop):
|
||||
|
||||
@@ -492,10 +492,13 @@ class HrExpenseSheet(models.Model):
|
||||
@api.one
|
||||
@api.depends('expense_line_ids', 'expense_line_ids.total_amount', 'expense_line_ids.currency_id')
|
||||
def _compute_amount(self):
|
||||
if len(self.expense_line_ids.mapped('currency_id')) < 2:
|
||||
self.total_amount = sum(self.expense_line_ids.mapped('total_amount'))
|
||||
else:
|
||||
self.total_amount = 0.0
|
||||
total_amount = 0.0
|
||||
for expense in self.expense_line_ids:
|
||||
total_amount += expense.currency_id.with_context(
|
||||
date=expense.date,
|
||||
company_id=expense.company_id.id
|
||||
).compute(expense.total_amount, self.currency_id)
|
||||
self.total_amount = total_amount
|
||||
|
||||
# FIXME: A 4 command is missing to explicitly declare the one2many relation
|
||||
# between the sheet and the lines when using 'default_expense_line_ids':[ids]
|
||||
|
||||
@@ -77,21 +77,19 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<t t-if="len(o.mapped('expense_line_ids').mapped('currency_id')) < 2">
|
||||
<div class="row">
|
||||
<div class="col-xs-4 pull-right">
|
||||
<table class="table table-condensed">
|
||||
<tr class="border-black">
|
||||
<td><strong>Total</strong></td>
|
||||
<td class="text-right">
|
||||
<span t-field="o.total_amount"
|
||||
t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-4 pull-right">
|
||||
<table class="table table-condensed">
|
||||
<tr class="border-black">
|
||||
<td><strong>Total</strong></td>
|
||||
<td class="text-right">
|
||||
<span t-field="o.total_amount"
|
||||
t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
<p>Certified honest and conform,<br/>(Date and signature).<br/><br/></p>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -537,7 +537,7 @@ class HrPayslip(models.Model):
|
||||
return res
|
||||
ttyme = datetime.fromtimestamp(time.mktime(time.strptime(date_from, "%Y-%m-%d")))
|
||||
employee = self.env['hr.employee'].browse(employee_id)
|
||||
locale = self.env.context.get('lang', 'en_US')
|
||||
locale = self.env.context.get('lang') or 'en_US'
|
||||
res['value'].update({
|
||||
'name': _('Salary Slip of %s for %s') % (employee.name, tools.ustr(babel.dates.format_date(date=ttyme, format='MMMM-y', locale=locale))),
|
||||
'company_id': employee.company_id.id,
|
||||
@@ -586,7 +586,7 @@ class HrPayslip(models.Model):
|
||||
date_to = self.date_to
|
||||
|
||||
ttyme = datetime.fromtimestamp(time.mktime(time.strptime(date_from, "%Y-%m-%d")))
|
||||
locale = self.env.context.get('lang', 'en_US')
|
||||
locale = self.env.context.get('lang') or 'en_US'
|
||||
self.name = _('Salary Slip of %s for %s') % (employee.name, tools.ustr(babel.dates.format_date(date=ttyme, format='MMMM-y', locale=locale)))
|
||||
self.company_id = employee.company_id
|
||||
|
||||
|
||||
@@ -55,14 +55,14 @@ class SaleOrderLine(models.Model):
|
||||
if uom.id != components[product]['uom']:
|
||||
from_uom = uom
|
||||
to_uom = self.env['product.uom'].browse(components[product]['uom'])
|
||||
qty = from_uom._compute_quantity(qty, to_uom_id=to_uom)
|
||||
qty = from_uom._compute_quantity(qty, to_uom)
|
||||
components[product]['qty'] += qty
|
||||
else:
|
||||
# To be in the uom reference of the product
|
||||
to_uom = self.env['product.product'].browse(product).uom_id
|
||||
if uom.id != to_uom.id:
|
||||
from_uom = uom
|
||||
qty = from_uom._compute_quantity(qty, to_uom_id=to_uom)
|
||||
qty = from_uom._compute_quantity(qty, to_uom)
|
||||
components[product] = {'qty': qty, 'uom': to_uom.id}
|
||||
return components
|
||||
|
||||
|
||||
@@ -6563,6 +6563,12 @@ msgstr ""
|
||||
msgid "You have to select a product unit of measure in the same category than the default unit of measure of the product"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock
|
||||
#: code:addons/stock/models/stock_location.py:92
|
||||
#, python-format
|
||||
msgid "You have to set a name for this location."
|
||||
msgstr ""
|
||||
|
||||
#. module: stock
|
||||
#: model:ir.ui.view,arch_db:stock.view_immediate_transfer
|
||||
msgid "You haven't set processed (<i>done</i>) quantities. Click <i>apply</i> and\n"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil import relativedelta
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
@@ -87,6 +88,8 @@ class Location(models.Model):
|
||||
name = location.name
|
||||
while location.location_id and location.usage != 'view':
|
||||
location = location.location_id
|
||||
if not name:
|
||||
raise UserError(_('You have to set a name for this location.'))
|
||||
name = location.name + "/" + name
|
||||
ret_list.append((orig_location.id, name))
|
||||
return ret_list
|
||||
|
||||
@@ -35,7 +35,7 @@ class WebsiteBlog(http.Controller):
|
||||
group['date_begin'] = start
|
||||
group['date_end'] = end
|
||||
|
||||
locale = request.context.get('lang', 'en_US')
|
||||
locale = request.context.get('lang') or 'en_US'
|
||||
start = pytz.UTC.localize(fields.Datetime.from_string(start))
|
||||
tzinfo = pytz.timezone(request.context.get('tz', 'utc') or 'utc')
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ class WebsiteEventController(http.Controller):
|
||||
def get_formated_date(self, event):
|
||||
start_date = fields.Datetime.from_string(event.date_begin).date()
|
||||
end_date = fields.Datetime.from_string(event.date_end).date()
|
||||
month = babel.dates.get_month_names('abbreviated', locale=event.env.context.get('lang', 'en_US'))[start_date.month]
|
||||
month = babel.dates.get_month_names('abbreviated', locale=event.env.context.get('lang') or 'en_US')[start_date.month]
|
||||
return ('%s %s%s') % (month, start_date.strftime("%e"), (end_date != start_date and ("-" + end_date.strftime("%e")) or ""))
|
||||
|
||||
@http.route('/event/get_country_event_list', type='http', auth='public', website=True)
|
||||
|
||||
@@ -221,11 +221,11 @@
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<p t-field="track.description"/>
|
||||
<div t-field="track.description"/>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<h3>About The Author</h3>
|
||||
<p t-field="track.partner_biography"/>
|
||||
<div t-field="track.partner_biography"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -143,7 +143,7 @@ class WebsiteSaleBackend(WebsiteBackend):
|
||||
sales_graph = [{
|
||||
'0': fields.Date.to_string(d) if not previous else fields.Date.to_string(d + timedelta(days=days_between)),
|
||||
# Respect read_group format in models.py
|
||||
'1': daily_sales_dict.get(babel.dates.format_date(d, format='dd MMM yyyy', locale=request.env.context.get('lang', 'en_US')), 0)
|
||||
'1': daily_sales_dict.get(babel.dates.format_date(d, format='dd MMM yyyy', locale=request.env.context.get('lang') or 'en_US'), 0)
|
||||
} for d in date_list]
|
||||
|
||||
return sales_graph
|
||||
|
||||
@@ -293,10 +293,8 @@ class WebsiteSlides(http.Controller):
|
||||
|
||||
@http.route(['/slides/add_slide'], type='json', auth='user', methods=['POST'], website=True)
|
||||
def create_slide(self, *args, **post):
|
||||
payload = request.httprequest.content_length
|
||||
# payload is total request content size so it's not exact size of file.
|
||||
# already add client validation this is for double check if client alter.
|
||||
if (payload / 1024 / 1024 > 25):
|
||||
file_size = len(post['datas']) * 3 / 4; # base64
|
||||
if (file_size / 1024.0 / 1024.0) > 25:
|
||||
return {'error': _('File is too big. File size cannot exceed 25MB')}
|
||||
|
||||
values = dict((fname, post[fname]) for fname in [
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
Belgium, 2017-09-25
|
||||
|
||||
Niboo agrees to the terms of the Odoo Corporate Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Samuel Lefever sam@niboo.be https://github.com/samuellefever
|
||||
|
||||
List of contributors:
|
||||
|
||||
Samuel Lefever sam@niboo.be https://github.com/samuellefever
|
||||
Pierre Faniel pierre@niboo.be https://github.com/PierreFaniel
|
||||
Jerome Guerriat jerome@niboo.be https://github.com/jguerriat
|
||||
Jeremy Van Driessche jeremy@niboo.be https://github.com/jvandri
|
||||
Gael Rabier gael@niboo.be https://github.com/gaelrabier
|
||||
Tobias Zehntner tobias@niboo.be https://github.com/twobeers83
|
||||
Alexandre Dutry alexandre@nboo.be https://github.com/AlexandreDz
|
||||
@@ -0,0 +1,11 @@
|
||||
Algeria, 2017-09-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,
|
||||
|
||||
Yasser Kaddour yasser.kaddour@gmail.com https://github.com/YasserKaddour
|
||||
@@ -786,7 +786,7 @@
|
||||
|
||||
<record id="DZD" model="res.currency">
|
||||
<field name="name">DZD</field>
|
||||
<field name="symbol">DZ</field>
|
||||
<field name="symbol">DA</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="active" eval="False"/>
|
||||
</record>
|
||||
|
||||
@@ -689,7 +689,7 @@ class TestAutoJoin(TransactionCase):
|
||||
self.assertIn('res_partner_bank', sql_query[0],
|
||||
"_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') first query incorrect main table")
|
||||
|
||||
expected = "%s::text like %s" % (unaccent('"res_partner_bank"."sanitized_acc_number"'), unaccent('%s'))
|
||||
expected = "%s like %s" % (unaccent('"res_partner_bank"."sanitized_acc_number"::text'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') first query incorrect where condition")
|
||||
|
||||
@@ -729,7 +729,7 @@ class TestAutoJoin(TransactionCase):
|
||||
self.assertIn('"res_partner_bank" as "res_partner__bank_ids"', sql_query[0],
|
||||
"_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') query incorrect join")
|
||||
|
||||
expected = "%s::text like %s" % (unaccent('"res_partner__bank_ids"."sanitized_acc_number"'), unaccent('%s'))
|
||||
expected = "%s like %s" % (unaccent('"res_partner__bank_ids"."sanitized_acc_number"::text'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') query incorrect where condition")
|
||||
|
||||
@@ -812,7 +812,7 @@ class TestAutoJoin(TransactionCase):
|
||||
self.assertIn('"res_country"', sql_query[0],
|
||||
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect main table")
|
||||
|
||||
expected = "%s::text like %s" % (unaccent('"res_country"."code"'), unaccent('%s'))
|
||||
expected = "%s like %s" % (unaccent('"res_country"."code"::text'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect where condition")
|
||||
|
||||
@@ -846,7 +846,7 @@ class TestAutoJoin(TransactionCase):
|
||||
self.assertIn('"res_country" as "res_country_state__country_id"', sql_query[0],
|
||||
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect join")
|
||||
|
||||
expected = "%s::text like %s" % (unaccent('"res_country_state__country_id"."code"'), unaccent('%s'))
|
||||
expected = "%s like %s" % (unaccent('"res_country_state__country_id"."code"::text'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 1 incorrect where condition")
|
||||
|
||||
@@ -880,7 +880,7 @@ class TestAutoJoin(TransactionCase):
|
||||
self.assertIn('"res_country" as "res_partner__state_id__country_id"', sql_query[0],
|
||||
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect join")
|
||||
|
||||
expected = "%s::text like %s" % (unaccent('"res_partner__state_id__country_id"."code"'), unaccent('%s'))
|
||||
expected = "%s like %s" % (unaccent('"res_partner__state_id__country_id"."code"::text'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect where condition")
|
||||
|
||||
@@ -910,7 +910,7 @@ class TestAutoJoin(TransactionCase):
|
||||
# Test produced queries that domains effectively present
|
||||
sql_query = self.query_list[0].get_sql()
|
||||
|
||||
expected = "%s::text like %s" % (unaccent('"res_partner__child_ids__bank_ids"."sanitized_acc_number"'), unaccent('%s'))
|
||||
expected = "%s like %s" % (unaccent('"res_partner__child_ids__bank_ids"."sanitized_acc_number"::text'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join on one2many with domains incorrect result")
|
||||
# TDE TODO: check first domain has a correct table name
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from collections import Counter
|
||||
import datetime
|
||||
import errno
|
||||
from os import utime
|
||||
import time
|
||||
|
||||
@@ -12,6 +14,21 @@ from odoo.tests import HttpCase
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
def _touch(filepath, asset, t=None):
|
||||
try:
|
||||
utime(filepath, (t, t) if t else None)
|
||||
except OSError as e:
|
||||
if e.errno in [errno.EPERM, errno.EACCES, errno.EROFS]:
|
||||
# Permission denied when touching the asset file, possibly read-only filesystem.
|
||||
# We alter the asset last modified time to simulate a change in the file
|
||||
now = datetime.datetime.now()
|
||||
asset.last_modified = now
|
||||
for sheet in asset.stylesheets:
|
||||
sheet.last_modified = now
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
class TestJavascriptAssetsBundle(TransactionCase):
|
||||
def setUp(self):
|
||||
super(TestJavascriptAssetsBundle, self).setUp()
|
||||
@@ -82,9 +99,9 @@ class TestJavascriptAssetsBundle(TransactionCase):
|
||||
version0 = bundle0.version
|
||||
|
||||
path = get_resource_path('test_assetsbundle', 'static', 'src', 'js', 'test_jsfile1.js')
|
||||
utime(path, None) # touch
|
||||
|
||||
bundle1 = self._get_asset(self.jsbundle_xmlid)
|
||||
_touch(path, bundle1)
|
||||
|
||||
bundle1.js()
|
||||
last_modified1 = bundle1.last_modified
|
||||
version1 = bundle1.version
|
||||
@@ -210,9 +227,9 @@ class TestJavascriptAssetsBundle(TransactionCase):
|
||||
version0 = bundle0.version
|
||||
|
||||
path = get_resource_path('test_assetsbundle', 'static', 'src', 'css', 'test_cssfile1.css')
|
||||
utime(path, None) # touch
|
||||
|
||||
bundle1 = self._get_asset(self.cssbundle_xmlid, env=self.env(context={'max_css_rules': 1}))
|
||||
_touch(path, bundle1)
|
||||
|
||||
bundle1.css()
|
||||
last_modified1 = bundle1.last_modified
|
||||
version1 = bundle1.version
|
||||
@@ -362,10 +379,12 @@ class TestAssetsBundleWithIRAMock(TransactionCase):
|
||||
self.env['ir.attachment']._patch_method('unlink', unlink)
|
||||
self.addCleanup(self.env['ir.attachment']._revert_method, 'unlink')
|
||||
|
||||
def _bundle(self, should_create, should_unlink):
|
||||
self.counter.clear()
|
||||
def _get_asset(self):
|
||||
files, remains = self.env['ir.qweb']._get_asset_content(self.lessbundle_xmlid, {})
|
||||
asset = AssetsBundle(self.lessbundle_xmlid, files, remains, env=self.env)
|
||||
return AssetsBundle(self.lessbundle_xmlid, files, remains, env=self.env)
|
||||
|
||||
def _bundle(self, asset, should_create, should_unlink):
|
||||
self.counter.clear()
|
||||
asset.to_html(debug='assets')
|
||||
self.assertEquals(self.counter['create'], int(should_create))
|
||||
self.assertEquals(self.counter['unlink'], int(should_unlink))
|
||||
@@ -375,16 +394,17 @@ class TestAssetsBundleWithIRAMock(TransactionCase):
|
||||
are correctly invalidated.
|
||||
"""
|
||||
# Compile for the first time
|
||||
self._bundle(True, False)
|
||||
self._bundle(self._get_asset(), True, False)
|
||||
|
||||
# Compile a second time, without changes
|
||||
self._bundle(False, False)
|
||||
self._bundle(self._get_asset(), False, False)
|
||||
|
||||
# Touch the file and compile a third time
|
||||
path = get_resource_path('test_assetsbundle', 'static', 'src', 'less', 'test_lessfile1.less')
|
||||
t = time.time() + 5
|
||||
utime(path, (t, t)) # touch
|
||||
self._bundle(True, True)
|
||||
asset = self._get_asset()
|
||||
_touch(path, asset, t=t)
|
||||
self._bundle(asset, True, True)
|
||||
|
||||
# Because we are in the same transaction since the beginning of the test, the first asset
|
||||
# created and the second one have the same write_date, but the file's last modified date
|
||||
@@ -394,4 +414,4 @@ class TestAssetsBundleWithIRAMock(TransactionCase):
|
||||
self.cr.execute("update ir_attachment set write_date=clock_timestamp() + interval '10 seconds' where id = (select max(id) from ir_attachment)")
|
||||
|
||||
# Compile a fourth time, without changes
|
||||
self._bundle(False, False)
|
||||
self._bundle(self._get_asset(), False, False)
|
||||
|
||||
Reference in New Issue
Block a user