[MERGE] forward port branch saas-14 up to 5eb6e14e85

This commit is contained in:
Christophe Simonis
2018-04-06 13:43:57 +02:00
27 changed files with 168 additions and 58 deletions
+1
View File
@@ -1426,6 +1426,7 @@ class AccountInvoiceTax(models.Model):
base = fields.Monetary(string='Base', compute='_compute_base_amount', store=True)
# DO NOT FORWARD-PORT!!! ONLY FOR v10
@api.model
def create(self, vals):
inv_tax = super(AccountInvoiceTax, self).create(vals)
# Workaround to make sure the tax amount is rounded to the currency precision since the ORM
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import account_tax
import account_partial_reconcile
@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name' : 'Tax Cash Basis Edit Base Account',
'version' : '1.0',
'summary': 'Add a custom account to handle base amount lines',
'sequence': 5,
'description': """
Move the cash basis lines to another account.
""",
'category': 'Accounting',
'depends': ['account'],
'data': [
'views/account_tax_views.xml',
],
'installable': True,
'auto_install': True,
}
@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp import api, models
class AccountPartialReconcileCashBasis(models.Model):
_inherit = 'account.partial.reconcile'
def _get_tax_cash_basis_base_account(self, line, tax):
if tax.cash_basis_base_account_id:
return tax.cash_basis_base_account_id
return super(AccountPartialReconcileCashBasis, self)._get_tax_cash_basis_base_account(line, tax)
@@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
from openerp import api, fields, models
class AccountTax(models.Model):
_inherit = 'account.tax'
cash_basis_base_account_id = fields.Many2one('account.account', domain=[('deprecated', '=', False)],
string='Base Tax Received Account',
help='Account that will be set on lines created in cash basis journal entry and used to keep track of the tax base amount.')
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_tax_form_cash_basis_inherit" model="ir.ui.view">
<field name="name">tax.form.cash.basis.base.account.inherit</field>
<field name="model">account.tax</field>
<field name="inherit_id" ref="account.view_tax_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='cash_basis_account']" position="after">
<field name="cash_basis_base_account_id" attrs="{'invisible': [('use_cash_basis', '=', False)]}"/>
</xpath>
</field>
</record>
</data>
</openerp>
@@ -286,6 +286,9 @@ class AccountVoucher(models.Model):
#create one move line per voucher line where amount is not 0.0
if not line.price_subtotal:
continue
line_subtotal = line.price_subtotal
if self.voucher_type == 'sale':
line_subtotal = -1 * line.price_subtotal
# convert the amount set on the voucher line into the currency of the voucher's company
# this calls res_curreny.compute() with the right context,
# so that it will take either the rate on the voucher if it is relevant or will use the default behaviour
@@ -302,7 +305,7 @@ class AccountVoucher(models.Model):
'debit': abs(amount) if self.voucher_type == 'purchase' else 0.0,
'date': self.account_date,
'tax_ids': [(4,t.id) for t in line.tax_ids],
'amount_currency': line.price_subtotal if current_currency != company_currency else 0.0,
'amount_currency': line_subtotal if current_currency != company_currency else 0.0,
'currency_id': company_currency != current_currency and current_currency or False,
'payment_id': self._context.get('payment_id'),
}
@@ -41,11 +41,18 @@ var GreetingMessage = Widget.extend(BarcodeHandlerMixin, {
if (this.next_action != 'hr_attendance.hr_attendance_action_kiosk_mode' && this.next_action.tag != 'hr_attendance_kiosk_mode') {
this.stop_listening();
}
this.attendance = action.attendance;
// We receive the check in/out times in UTC
// This widget only deals with display, which should be in browser's TimeZone
this.attendance.check_in = this.attendance.check_in && moment.utc(this.attendance.check_in).local();
this.attendance.check_out = this.attendance.check_out && moment.utc(this.attendance.check_out).local();
this.previous_attendance_change_date = action.previous_attendance_change_date && moment.utc(action.previous_attendance_change_date).local();
// check in/out times displayed in the greeting message template.
this.attendance.check_in_time = (new Date((new Date(this.attendance.check_in)).valueOf() - (new Date()).getTimezoneOffset()*60*1000)).toTimeString().slice(0,8);
this.attendance.check_out_time = this.attendance.check_out && (new Date((new Date(this.attendance.check_out)).valueOf() - (new Date()).getTimezoneOffset()*60*1000)).toTimeString().slice(0,8);
this.previous_attendance_change_date = action.previous_attendance_change_date;
this.format_time = 'HH:mm:ss';
this.attendance.check_in_time = this.attendance.check_in && this.attendance.check_in.format(this.format_time);
this.attendance.check_out_time = this.attendance.check_out && this.attendance.check_out.format(this.format_time);
this.employee_name = action.employee_name;
},
@@ -57,13 +64,13 @@ var GreetingMessage = Widget.extend(BarcodeHandlerMixin, {
welcome_message: function() {
var self = this;
var now = new Date((new Date(this.attendance.check_in)).valueOf() - (new Date()).getTimezoneOffset()*60*1000);
var now = this.attendance.check_in.clone();
this.return_to_main_menu = setTimeout( function() { self.do_action(self.next_action, {clear_breadcrumbs: true}); }, 5000);
if (now.getHours() < 5) {
if (now.hours() < 5) {
this.$('.o_hr_attendance_message_message').append(_t("Good night"));
} else if (now.getHours() < 12) {
if (now.getHours() < 8 && Math.random() < 0.3) {
} else if (now.hours() < 12) {
if (now.hours() < 8 && Math.random() < 0.3) {
if (Math.random() < 0.75) {
this.$('.o_hr_attendance_message_message').append(_t("The early bird catches the worm"));
} else {
@@ -72,16 +79,16 @@ var GreetingMessage = Widget.extend(BarcodeHandlerMixin, {
} else {
this.$('.o_hr_attendance_message_message').append(_t("Good morning"));
}
} else if (now.getHours() < 17){
} else if (now.hours() < 17){
this.$('.o_hr_attendance_message_message').append(_t("Good afternoon"));
} else if (now.getHours() < 23){
} else if (now.hours() < 23){
this.$('.o_hr_attendance_message_message').append(_t("Good evening"));
} else {
this.$('.o_hr_attendance_message_message').append(_t("Good night"));
}
if(this.previous_attendance_change_date){
var last_check_out_date = new Date((new Date(this.previous_attendance_change_date)).valueOf() - (new Date()).getTimezoneOffset()*60*1000);
if(now.valueOf() - last_check_out_date.valueOf() > 1000*60*60*24*7){
var last_check_out_date = this.previous_attendance_change_date.clone();
if(now - last_check_out_date > 24*7*60*60*1000){
this.$('.o_hr_attendance_random_message').html(_t("Glad to have you back, it's been a while!"));
} else {
if(Math.random() < 0.02){
@@ -93,33 +100,33 @@ var GreetingMessage = Widget.extend(BarcodeHandlerMixin, {
farewell_message: function() {
var self = this;
var now = new Date((new Date(this.attendance.check_out)).valueOf() - (new Date()).getTimezoneOffset()*60*1000);
var now = this.attendance.check_out.clone();
this.return_to_main_menu = setTimeout( function() { self.do_action(self.next_action, {clear_breadcrumbs: true}); }, 5000);
if(this.previous_attendance_change_date){
var last_check_in_date = new Date((new Date(this.previous_attendance_change_date)).valueOf() - (new Date()).getTimezoneOffset()*60*1000);
if(now.valueOf() - last_check_in_date.valueOf() > 1000*60*60*12){
var last_check_in_date = this.previous_attendance_change_date.clone();
if(now - last_check_in_date > 1000*60*60*12){
this.$('.o_hr_attendance_warning_message').append(_t("Warning! Last check in was over 12 hours ago.<br/>If this isn't right, please contact Human Resources."));
clearTimeout(this.return_to_main_menu);
this.stop_listening();
} else if(now.valueOf() - last_check_in_date.valueOf() > 1000*60*60*8){
} else if(now - last_check_in_date > 1000*60*60*8){
this.$('.o_hr_attendance_random_message').html(_t("Another good day's work! See you soon!"));
}
}
if (now.getHours() < 12) {
if (now.hours() < 12) {
this.$('.o_hr_attendance_message_message').append(_t("Have a good day!"));
} else if (now.getHours() < 14) {
} else if (now.hours() < 14) {
this.$('.o_hr_attendance_message_message').append(_t("Have a nice lunch!"));
if (Math.random() < 0.05) {
this.$('.o_hr_attendance_random_message').html(_t("Eat breakfast as a king, lunch as a merchant and supper as a beggar"));
} else if (Math.random() < 0.06) {
this.$('.o_hr_attendance_random_message').html(_t("An apple a day keeps the doctor away"));
}
} else if (now.getHours() < 17) {
} else if (now.hours() < 17) {
this.$('.o_hr_attendance_message_message').append(_t("Have a good afternoon"));
} else {
if (now.getHours() < 18 && Math.random() < 0.2) {
if (now.hours() < 18 && Math.random() < 0.2) {
this.$('.o_hr_attendance_message_message').append(_t("Early to bed and early to rise, makes a man healthy, wealthy and wise"));
} else {
this.$('.o_hr_attendance_message_message').append(_t("Have a good evening"));
@@ -11,7 +11,7 @@
<record id="email_template_data_applicant_refuse" model="mail.template">
<field name="name">Applicant: Refuse</field>
<field name="subject">Application refused</field>
<field name="email_to">${object.email_from}</field>
<field name="email_to">${object.email_from | safe}</field>
<field name="partner_to">${object.partner_id and object.partner_id.id or ''}</field>
<field name="lang">${object.partner_id and object.partner_id.lang or ''}</field>
<field name="model_id" ref="hr_recruitment.model_hr_applicant"/>
@@ -27,7 +27,7 @@ Unfortunately, your profile does not match with our needs</p>
<record id="email_template_data_applicant_interest" model="mail.template">
<field name="name">Applicant: Interest</field>
<field name="subject">Application approved</field>
<field name="email_to">${object.email_from}</field>
<field name="email_to">${object.email_from | safe}</field>
<field name="partner_to">${object.partner_id and object.partner_id.id or ''}</field>
<field name="lang">${object.partner_id and object.partner_id.lang or ''}</field>
<field name="model_id" ref="hr_recruitment.model_hr_applicant"/>
+10 -10
View File
@@ -29,7 +29,7 @@
<record id="chart1181_en" model="account.account.template">
<field name="code">1181</field>
<field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="reconcile" eval="False"/>
<field name="name">GST receivable</field>
<field name="chart_template_id" ref="ca_en_chart_template_en"/>
@@ -37,7 +37,7 @@
<record id="chart1182_en" model="account.account.template">
<field name="code">1182</field>
<field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="reconcile" eval="False"/>
<field name="name">PST/QST receivable</field>
<field name="chart_template_id" ref="ca_en_chart_template_en"/>
@@ -45,7 +45,7 @@
<record id="chart11831_en" model="account.account.template">
<field name="code">11831</field>
<field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="reconcile" eval="False"/>
<field name="name">HST receivable - 13%</field>
<field name="chart_template_id" ref="ca_en_chart_template_en"/>
@@ -53,7 +53,7 @@
<record id="chart11832_en" model="account.account.template">
<field name="code">11832</field>
<field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="reconcile" eval="False"/>
<field name="name">HST receivable - 14%</field>
<field name="chart_template_id" ref="ca_en_chart_template_en"/>
@@ -61,7 +61,7 @@
<record id="chart11833_en" model="account.account.template">
<field name="code">11833</field>
<field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="reconcile" eval="False"/>
<field name="name">HST receivable - 15%</field>
<field name="chart_template_id" ref="ca_en_chart_template_en"/>
@@ -79,7 +79,7 @@
<record id="chart2131_en" model="account.account.template">
<field name="code">2131</field>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="reconcile" eval="False"/>
<field name="name">GST to pay</field>
<field name="chart_template_id" ref="ca_en_chart_template_en"/>
@@ -87,7 +87,7 @@
<record id="chart2132_en" model="account.account.template">
<field name="code">2132</field>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="reconcile" eval="False"/>
<field name="name">PST/QST to pay</field>
<field name="chart_template_id" ref="ca_en_chart_template_en"/>
@@ -95,7 +95,7 @@
<record id="chart21331_en" model="account.account.template">
<field name="code">21331</field>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="reconcile" eval="False"/>
<field name="name">HST to pay - 13%</field>
<field name="chart_template_id" ref="ca_en_chart_template_en"/>
@@ -103,7 +103,7 @@
<record id="chart21332_en" model="account.account.template">
<field name="code">21332</field>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="reconcile" eval="False"/>
<field name="name">HST to pay - 14%</field>
<field name="chart_template_id" ref="ca_en_chart_template_en"/>
@@ -111,7 +111,7 @@
<record id="chart21333_en" model="account.account.template">
<field name="code">21333</field>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
<field name="reconcile" eval="False"/>
<field name="name">HST to pay - 15%</field>
<field name="chart_template_id" ref="ca_en_chart_template_en"/>
@@ -6,6 +6,7 @@ from openerp.exceptions import UserError
class AccountBankStatement(models.Model):
_inherit = 'account.bank.statement'
@api.multi
def unlink(self):
for statement in self.filtered(lambda s: s.company_id._is_accounting_unalterable() and s.journal_id.journal_user):
raise UserError(_('You cannot modify anything on a bank statement (name: %s) that was created by point of sale operations.') % (statement.name,))
@@ -15,6 +16,7 @@ class AccountBankStatement(models.Model):
class AccountBankStatementLine(models.Model):
_inherit = 'account.bank.statement.line'
@api.multi
def unlink(self):
for line in self.filtered(lambda s: s.company_id._is_accounting_unalterable() and s.journal_id.journal_user):
raise UserError(_('You cannot modify anything on a bank statement line (name: %s) that was created by point of sale operations.') % (line.name,))
+10 -10
View File
@@ -40,16 +40,16 @@ class PaymentAcquirerStripe(models.Model):
stripe_tx_values = dict(tx_values)
temp_stripe_tx_values = {
'company': self.company_id.name,
'amount': tx_values.get('amount'),
'currency': tx_values.get('currency') and tx_values.get('currency').name or '',
'currency_id': tx_values.get('currency') and tx_values.get('currency').id or '',
'address_line1': tx_values['partner_address'],
'address_city': tx_values['partner_city'],
'address_country': tx_values['partner_country'] and tx_values['partner_country'].name or '',
'email': tx_values['partner_email'],
'address_zip': tx_values['partner_zip'],
'name': tx_values['partner_name'],
'phone': tx_values['partner_phone'],
'amount': tx_values['amount'], # Mandatory
'currency': tx_values['currency'].name, # Mandatory anyway
'currency_id': tx_values['currency'].id, # same here
'address_line1': tx_values.get('partner_address'), # Any info of the partner is not mandatory
'address_city': tx_values.get('partner_city'),
'address_country': tx_values.get('partner_country') and tx_values.get('partner_country').name or '',
'email': tx_values.get('partner_email'),
'address_zip': tx_values.get('partner_zip'),
'name': tx_values.get('partner_name'),
'phone': tx_values.get('partner_phone'),
}
temp_stripe_tx_values['returndata'] = stripe_tx_values.pop('return_url', '')
+1 -1
View File
@@ -33,7 +33,7 @@ class TestUi(odoo.tests.HttpCase):
# euro's. this will cause issues as the sales journal is in
# USD, because of this all products would have a different
# price
main_company.currency_id = env.ref('base.USD')
cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", [env.ref('base.USD').id, main_company.id])
test_sale_journal = journal_obj.create({'name': 'Sales Journal - Test',
'code': 'TSJ',
@@ -12,7 +12,7 @@ class AccountAnalyticAccount(models.Model):
@api.multi
def unlink(self):
if self.env['project.issue'].search_count([('project_id.analytic_account_id', 'in', self.ids)]):
if self.env['project.issue'].sudo().search_count([('project_id.analytic_account_id', 'in', self.ids)]):
raise UserError(_('Please remove existing issues in the project linked to the accounts you want to delete.'))
return super(AccountAnalyticAccount, self).unlink()
+2 -2
View File
@@ -321,8 +321,8 @@ class PurchaseOrder(models.Model):
def button_approve(self, force=False):
self.write({'state': 'purchase', 'date_approve': fields.Date.context_today(self)})
self._create_picking()
if self.company_id.po_lock == 'lock':
self.write({'state': 'done'})
self.filtered(
lambda p: p.company_id.po_lock == 'lock').write({'state': 'done'})
return {}
@api.multi
+1 -1
View File
@@ -53,7 +53,7 @@ class SaleOrder(models.Model):
# Search for invoices which have been 'cancelled' (filter_refund = 'modify' in
# 'account.invoice.refund')
# use like as origin may contains multiple references (e.g. 'SO01, SO02')
refunds = invoice_ids.search([('origin', 'like', order.name)]).filtered(lambda r: r.type in ['out_invoice', 'out_refund'])
refunds = invoice_ids.search([('origin', 'like', order.name), ('company_id', '=', order.company_id.id)]).filtered(lambda r: r.type in ['out_invoice', 'out_refund'])
invoice_ids |= refunds.filtered(lambda r: order.name in [origin.strip() for origin in r.origin.split(',')])
# Search for refunds as well
refund_ids = self.env['account.invoice'].browse()
@@ -45,7 +45,7 @@
<field name="view_type">form</field>
<field name="view_mode">pivot,graph</field>
<field name="search_view_id" ref="view_stock_level_forecast_filter"/>
<field name="context">{'search_default_pivot_by':1, 'search_default_graph_by':1, 'search_default_product_tmpl_id': active_id}</field>
<field name="context">{'search_default_product_tmpl_id': active_id}</field>
<field name="view_id" ref="view_stock_level_forecast_pivot"/>
</record>
@@ -55,7 +55,7 @@
<field name="view_type">form</field>
<field name="view_mode">pivot,graph</field>
<field name="search_view_id" ref="view_stock_level_forecast_filter"/>
<field name="context">{'search_default_pivot_by':1, 'search_default_graph_by':1, 'search_default_product_id': active_id}</field>
<field name="context">{'search_default_product_id': active_id}</field>
<field name="view_id" ref="view_stock_level_forecast_pivot"/>
</record>
</odoo>
+2
View File
@@ -103,3 +103,5 @@
overflow-x: initial;
}
}
@icon-font-path: "/web/static/lib/bootstrap/fonts/";
@@ -54,3 +54,5 @@ body.o_connected_user {
}
}
}
@icon-font-path: "/web/static/lib/bootstrap/fonts/";
+1 -1
View File
@@ -165,7 +165,7 @@ class BlogPost(models.Model):
blog_post.teaser = blog_post.teaser_manual
else:
content = html2plaintext(blog_post.content).replace('\n', ' ')
blog_post.teaser = ' '.join(filter(None, content.split(' '))[:50]) + '...'
blog_post.teaser = content[:150] + '...'
@api.multi
def _set_teaser(self):
@@ -101,6 +101,7 @@
<t t-call="website_blog.index">
<t t-set="head">
<link t-att-href="'/blog/%s/feed' % (blog.id)" type="application/atom+xml" rel="alternate" title="Atom Feed"/>
<meta t-if="len(active_tag_ids) > 0" name="robots" t-attf-content="#{len(active_tag_ids) > 1 and 'noindex,'} nofollow"/>
</t>
<div class="oe_structure"/>
<div class="container">
+1 -1
View File
@@ -12,7 +12,7 @@ class TestUi(odoo.tests.HttpCase):
# - that main demo company is gelocated in US
# - that this test awaits for hardcoded USDs amount
# we have to force company currency as USDs only for this test
self.env.ref('base.main_company').write({'currency_id': self.env.ref('base.USD').id})
self.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", [self.env.ref('base.USD').id, self.env.ref('base.main_company').id])
self.phantom_js("/", "odoo.__DEBUG__.services['web_tour.tour'].run('event_buy_tickets')", "odoo.__DEBUG__.services['web_tour.tour'].tours.event_buy_tickets.ready", login="admin")
def test_demo(self):
+1
View File
@@ -26,3 +26,4 @@ Stéphane Bidoul stephane.bidoul@acsone.eu https://github.com/sbidoul
Thomas Binsfeld thomas.binsfeld@acsone.eu https://github.com/ThomasBinsfeld
Benjamin Willig benjamin.willig@acsone.eu https://github.com/benwillig
François Honoré francois.honore@acsone.eu https://github.com/acsonefho
Denis Robinet denis.robinet@acsone.eu https://github.com/RobinetDenisAcsone
+15
View File
@@ -0,0 +1,15 @@
Belgium, 2018-04-06
WINK SA/NV 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,
Thomas Fossoul tfossoul@wink.be https://github.com/tfossoulw
List of contributors:
Thomas Fossoul tfossoul@wink.be https://github.com/tfossoulw
+11
View File
@@ -0,0 +1,11 @@
France, 2018-04-04,
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,
Thomas Lemaire thomas.lemaire@ndp-systemes.fr https://github.com/thomas-tankengine
+8 -6
View File
@@ -531,12 +531,14 @@ class ResConfigSettings(models.TransientModel, ResConfigModuleInstallationMixin)
IrValues.set_default(model, field, value)
# group fields: modify group / implied groups
for name, groups, implied_group in classified['group']:
if self[name]:
groups.write({'implied_ids': [(4, implied_group.id)]})
else:
groups.write({'implied_ids': [(3, implied_group.id)]})
implied_group.write({'users': [(3, user.id) for user in groups.mapped('users')]})
with self.env.norecompute():
for name, groups, implied_group in classified['group']:
if self[name]:
groups.write({'implied_ids': [(4, implied_group.id)]})
else:
groups.write({'implied_ids': [(3, implied_group.id)]})
implied_group.write({'users': [(3, user.id) for user in groups.mapped('users')]})
self.recompute()
# other fields: execute all methods that start with 'set_'
for method in dir(self):
+2 -1
View File
@@ -220,7 +220,8 @@ class rml_parse(object):
date = datetime(*value.timetuple()[:6])
if date_time:
# Convert datetime values to the expected client/context timezone
record = self.env['base'].with_context(self.localcontext)
env = odoo.api.Environment(self.cr, self.uid, {})
record = env['base'].with_context(self.localcontext)
date = fields.Datetime.context_timestamp(record, date)
return date.strftime(date_format.encode('utf-8'))