[MERGE] forward port branch 11.0 up to ee0ff262f0

This commit is contained in:
Christophe Simonis
2018-10-29 17:12:53 +01:00
18 changed files with 163 additions and 29 deletions
+1 -1
View File
@@ -107,7 +107,7 @@ class AccountInvoice(models.Model):
def _compute_residual(self):
residual = 0.0
residual_company_signed = 0.0
sign = self.type in ['in_refund', 'out_refund'] and -1 or 1
sign = self.type in ['in_invoice', 'out_refund'] and -1 or 1
for line in self.sudo().move_id.line_ids:
if line.account_id == self.account_id:
residual_company_signed += line.amount_residual
+1 -1
View File
@@ -198,7 +198,7 @@ class account_abstract_payment(models.AbstractModel):
total = 0.0
groups = groupby(invoices, lambda i: i.currency_id)
for payment_currency, payment_invoices in groups:
amount_total = sum([MAP_INVOICE_TYPE_PAYMENT_SIGN[i.type] * i.residual_signed for i in payment_invoices])
amount_total = sum(i.residual_signed for i in payment_invoices)
if payment_currency == currency:
total += amount_total
else:
+26
View File
@@ -464,6 +464,32 @@ class TestPayment(AccountingTestCase):
#check the invoice status
self.assertEqual(invoice.state, 'paid')
def test_payment_and_writeoff_out_refund(self):
# Use case:
# Company is in EUR, create a credit note for 100 EUR and register payment of 90.
# Mark invoice as fully paid with a write_off
# Check that all the aml are correctly created.
invoice = self.create_invoice(amount=100, type='out_refund', currency_id=self.currency_eur_id, partner=self.partner_agrolait.id)
# register payment on invoice
payment = self.payment_model.create({'payment_type': 'outbound',
'payment_method_id': self.env.ref('account.account_payment_method_manual_in').id,
'partner_type': 'customer',
'partner_id': self.partner_agrolait.id,
'amount': 90,
'payment_date': time.strftime('%Y') + '-07-15',
'payment_difference_handling': 'reconcile',
'writeoff_account_id': self.account_payable.id,
'journal_id': self.bank_journal_euro.id,
'invoice_ids': [(4, invoice.id, None)]
})
payment.post()
self.check_journal_items(payment.move_line_ids, [
{'account_id': self.account_eur.id, 'debit': 0.0, 'credit': 90.0, 'amount_currency': 0.0, 'currency_id': False},
{'account_id': self.account_payable.id, 'debit': 0.0, 'credit': 10.0, 'amount_currency': 0.0, 'currency_id': False},
{'account_id': self.account_receivable.id, 'debit': 100.0, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': False},
])
self.assertEqual(invoice.state, 'paid')
def test_payment_and_writeoff_in_other_currency_3(self):
# Use case related in revision 20935462a0cabeb45480ce70114ff2f4e91eaf79
# Invoice made in secondary currency for which the rate to the company currency
+1 -1
View File
@@ -81,7 +81,7 @@ class HrAttendance(models.Model):
('employee_id', '=', attendance.employee_id.id),
('check_out', '=', False),
('id', '!=', attendance.id),
])
], order='check_in desc', limit=1)
if no_check_out_attendances:
raise exceptions.ValidationError(_("Cannot create new attendance record for %(empl_name)s, the employee hasn't checked out since %(datetime)s") % {
'empl_name': attendance.employee_id.name,
+3
View File
@@ -486,10 +486,13 @@ var BasicComposer = Widget.extend({
},
send_message: function () {
var $button = this.$('.o_composer_button_send');
if (this.is_empty() || !this.do_check_attachment_upload()) {
return;
}
$button.prop('disabled', true);
clearTimeout(this.canned_timeout);
var self = this;
this.preprocess_message().then(function (message) {
+1 -3
View File
@@ -197,6 +197,7 @@
</span>
</p>
<div class="o_thread_message_content">
<t t-raw="message.body"/>
<t t-if="message.tracking_value_ids and message.tracking_value_ids.length &gt; 0">
<t t-if="message.subtype_description">
<p><t t-esc="message.subtype_description"/></p>
@@ -204,9 +205,6 @@
<t t-call="mail.ChatThread.MessageTracking"/>
</t>
<p t-if="options.display_subject and message.display_subject" class="o_mail_subject">Subject: <t t-esc="message.subject"/></p>
<t t-if="!(message.tracking_value_ids and message.tracking_value_ids.length &gt; 0)">
<t t-raw="message.body"/>
</t>
<t t-if="message.attachment_ids.length > 0">
<div t-if="message.images.length > 0" class="o_attachments_previews">
<t t-foreach="message.images" t-as="attachment">
+56
View File
@@ -613,6 +613,62 @@ QUnit.test('chatter: post, receive and star messages', function (assert) {
});
});
QUnit.test('chatter: post a message disable the send button', function(assert) {
assert.expect(3);
var bus = new Bus();
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form string="Partners">' +
'<sheet>' +
'<field name="foo"/>' +
'</sheet>' +
'<div class="oe_chatter">' +
'<field name="message_ids" widget="mail_thread"/>' +
'</div>' +
'</form>',
res_id: 2,
session: {},
mockRPC: function (route, args) {
if (args.method === 'message_get_suggested_recipients') {
return $.when({2: []});
}
return this._super(route, args);
},
intercepts: {
get_messages: function (ev) {
ev.stopPropagation();
ev.data.callback($.when([]));
},
post_message: function (ev) {
ev.stopPropagation();
assert.ok(form.$('.o_composer_button_send').prop("disabled"),
"Send button should be disabled when a message is being sent");
bus.trigger('new_message', {
id: 0,
model: ev.data.options.model,
res_id: ev.data.options.res_id,
});
},
get_bus: function (ev) {
ev.stopPropagation();
ev.data.callback(bus);
},
},
});
form.$('.o_chatter_button_new_message').click();
assert.notOk(form.$('.o_composer_button_send').prop('disabled'),
"Send button should be enabled when posting a message");
form.$('.oe_chatter .o_composer_text_field:first()').val("My first message");
form.$('.oe_chatter .o_composer_button_send').click();
form.$('.o_chatter_button_new_message').click();
assert.notOk(form.$('.o_composer_button_send').prop('disabled'),
"Send button should be enabled when posting another message");
form.destroy();
});
QUnit.test('chatter: post a message and switch in edit mode', function (assert) {
assert.expect(5);
@@ -2152,6 +2152,19 @@ td {
overflow: auto;
height: 120px;
}
.pos .modal-dialog .popup-textinput{
display: flex;
flex-direction: column;
}
.pos .modal-dialog .popup-textinput .title,
.pos .modal-dialog .popup-textinput .footer{
flex: none;
}
.pos .modal-dialog .popup-textinput textarea{
resize: none;
flex: auto;
margin: 0 20px 80px;
}
.pos .popup .title {
background: rgba(255,255,255,0.5);
margin: 0;
@@ -742,6 +742,9 @@ var Chrome = PosBaseWidget.extend(AbstractAction.prototype, {
if(err.message === 'XmlHttpRequestError '){
title = 'Network Failure (XmlHttpRequestError)';
body = 'The Point of Sale could not be loaded due to a network problem.\n Please check your internet connection.';
}else if(err.message === 'TLSError'){
title = 'Https connection to IoT Box failed';
body = 'Make sure you are using IoT Box v18.10 or higher.\n\n Navigate to ' + err.url + ' to accept the certificate of your IoT Box.';
}else if(err.code === 200){
title = err.data.message;
body = err.data.debug;
+12 -7
View File
@@ -192,11 +192,15 @@ var ProxyDevice = core.Class.extend(mixins.PropertiesMixin,{
// try harder when we remember a good proxy url
found_url = this.try_hard_to_connect(localStorage.hw_proxy_url, options)
.then(null,function(){
return self.find_proxy(options);
if (window.location.protocol != 'https:'){
return self.find_proxy(options);
}
});
}else{
// just find something quick
found_url = this.find_proxy(options);
if (window.location.protocol != 'https:'){
found_url = this.find_proxy(options);
}
}
success = found_url.then(function(url){
@@ -248,16 +252,17 @@ var ProxyDevice = core.Class.extend(mixins.PropertiesMixin,{
// try several time to connect to a known proxy url
try_hard_to_connect: function(url,options){
options = options || {};
var port = ':' + (options.port || '8069');
var protocol = window.location.protocol;
var port = ( !options.port && protocol == "https:") ? ':443' : ':' + (options.port || '8069');
this.set_connection_status('connecting');
if(url.indexOf('//') < 0){
url = 'http://'+url;
url = protocol + '//' + url;
}
if(url.indexOf(':',5) < 0){
url = url+port;
url = url + port;
}
// try real hard to connect to url, with a 1sec timeout and up to 'retries' retries
@@ -273,11 +278,11 @@ var ProxyDevice = core.Class.extend(mixins.PropertiesMixin,{
.done(function(){
done.resolve(url);
})
.fail(function(){
.fail(function(resp){
if(retries > 0){
try_real_hard_to_connect(url,retries-1,done);
}else{
done.reject();
done.reject(resp.statusText, url);
}
});
return done;
+15 -7
View File
@@ -127,13 +127,21 @@ exports.PosModel = Backbone.Model.extend({
progress: function(prog){
self.chrome.loading_progress(prog);
},
}).then(function(){
if(self.config.iface_scan_via_proxy){
self.barcode_reader.connect_to_proxy();
}
}).always(function(){
done.resolve();
});
}).then(
function(){
if(self.config.iface_scan_via_proxy){
self.barcode_reader.connect_to_proxy();
}
done.resolve();
},
function(statusText, url){
if (statusText == 'error' && window.location.protocol == 'https:') {
var error = {message: 'TLSError', url: url};
self.chrome.loading_error(error);
} else {
done.resolve();
}
});
return done;
},
+1 -1
View File
@@ -1117,7 +1117,7 @@
<div class="modal-dialog">
<div class="popup popup-textinput">
<p class="title"><t t-esc=" widget.options.title || '' " /></p>
<textarea rows="10" cols="40"><t t-esc="widget.options.value" /></textarea>
<textarea><t t-esc="widget.options.value" /></textarea>
<div class="footer">
<div class="button confirm">
Ok
+1 -1
View File
@@ -208,7 +208,7 @@ class BootstrapTranslator(nodes.NodeVisitor, object):
else:
opts = {}
def warner(msg):
def warner(msg, **kw):
self.builder.warn(msg, (self.builder.current_docname, node.line))
highlighted = self.builder.highlighter.highlight_block(
node.rawsource, lang, opts=opts, warn=warner, linenos=linenos,
+12
View File
@@ -0,0 +1,12 @@
India, 17, Sept - 2018
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,
Anil Kesariya anil.r.kesariya@gmail.com https://github.com/AnilKesariya
+11
View File
@@ -0,0 +1,11 @@
Mexico, 2018-10-24
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,
Luis Guzman ark@switnet.org https://github.com/ark74
+3 -4
View File
@@ -693,11 +693,10 @@ class Module(models.Model):
mod.write(updated_values)
else:
mod_path = modules.get_module_path(mod_name)
if not mod_path:
if not mod_path or not terp:
continue
if not terp or not terp.get('installable', True):
continue
mod = self.create(dict(name=mod_name, state='uninstalled', **values))
state = "uninstalled" if terp.get('installable', True) else "uninstallable"
mod = self.create(dict(name=mod_name, state=state, **values))
res[1] += 1
mod._update_dependencies(terp.get('depends', []))
@@ -14,7 +14,7 @@
'website': "http://www.yourcompany.com",
# Categories can be used to filter modules in modules listing
# Check https://github.com/odoo/odoo/blob/master/odoo/addons/base/module/module_data.xml
# Check https://github.com/odoo/odoo/blob/saas-11.3/odoo/addons/base/data/ir_module_category_data.xml
# for the full list
'category': 'Uncategorized',
'version': '0.1',
+2 -2
View File
@@ -56,8 +56,8 @@ class MigrationManager(object):
function. Theses files must respect a directory tree structure: A 'migrations' folder
which containt a folder by version. Version can be 'module' version or 'server.module'
version (in this case, the files will only be processed by this version of the server).
Python file names must start by `pre` or `post` and will be executed, respectively,
before and after the module initialisation. `end` scripts are run after all modules have
Python file names must start by `pre-` or `post-` and will be executed, respectively,
before and after the module initialisation. `end-` scripts are run after all modules have
been updated.
Example:
<moduledir>