[MERGE] forward port branch 11.0 up to e8f630e44d
This commit is contained in:
@@ -1212,6 +1212,11 @@ class AccountMoveLine(models.Model):
|
|||||||
account_move_line.payment_id.write({'invoice_ids': [(3, invoice.id, None)]})
|
account_move_line.payment_id.write({'invoice_ids': [(3, invoice.id, None)]})
|
||||||
rec_move_ids += account_move_line.matched_debit_ids
|
rec_move_ids += account_move_line.matched_debit_ids
|
||||||
rec_move_ids += account_move_line.matched_credit_ids
|
rec_move_ids += account_move_line.matched_credit_ids
|
||||||
|
if self.env.context.get('invoice_id'):
|
||||||
|
current_invoice = self.env['account.invoice'].browse(self.env.context['invoice_id'])
|
||||||
|
rec_move_ids = rec_move_ids.filtered(
|
||||||
|
lambda r: (r.debit_move_id + r.credit_move_id) & current_invoice.move_id.line_ids
|
||||||
|
)
|
||||||
return rec_move_ids.unlink()
|
return rec_move_ids.unlink()
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
|
|||||||
@@ -633,7 +633,7 @@ var StatementModel = BasicModel.extend({
|
|||||||
handles = [handle];
|
handles = [handle];
|
||||||
} else {
|
} else {
|
||||||
_.each(this.lines, function (line, handle) {
|
_.each(this.lines, function (line, handle) {
|
||||||
if (!line.reconciled && !line.balance.amount && line.reconciliation_proposition.length) {
|
if (!line.reconciled && line.balance && !line.balance.amount && line.reconciliation_proposition.length) {
|
||||||
handles.push(handle);
|
handles.push(handle);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -625,6 +625,42 @@ class TestReconciliation(AccountingTestCase):
|
|||||||
full_rec_payable = full_rec_move.line_ids.filtered(lambda l: l.account_id == self.account_rsa)
|
full_rec_payable = full_rec_move.line_ids.filtered(lambda l: l.account_id == self.account_rsa)
|
||||||
self.assertEqual(full_rec_payable.balance, 18.75)
|
self.assertEqual(full_rec_payable.balance, 18.75)
|
||||||
|
|
||||||
|
def test_unreconcile(self):
|
||||||
|
# Use case:
|
||||||
|
# 2 invoices paid with a single payment. Unreconcile the payment with one invoice, the
|
||||||
|
# other invoice should remain reconciled.
|
||||||
|
inv1 = self.create_invoice(invoice_amount=10, currency_id=self.currency_usd_id)
|
||||||
|
inv2 = self.create_invoice(invoice_amount=20, currency_id=self.currency_usd_id)
|
||||||
|
payment = self.env['account.payment'].create({
|
||||||
|
'payment_type': 'inbound',
|
||||||
|
'payment_method_id': self.env.ref('account.account_payment_method_manual_in').id,
|
||||||
|
'partner_type': 'customer',
|
||||||
|
'partner_id': self.partner_agrolait_id,
|
||||||
|
'amount': 100,
|
||||||
|
'currency_id': self.currency_usd_id,
|
||||||
|
'journal_id': self.bank_journal_usd.id,
|
||||||
|
})
|
||||||
|
payment.post()
|
||||||
|
credit_aml = payment.move_line_ids.filtered('credit')
|
||||||
|
|
||||||
|
# Check residual before assignation
|
||||||
|
self.assertAlmostEquals(inv1.residual, 10)
|
||||||
|
self.assertAlmostEquals(inv2.residual, 20)
|
||||||
|
|
||||||
|
# Assign credit and residual
|
||||||
|
inv1.assign_outstanding_credit(credit_aml.id)
|
||||||
|
inv2.assign_outstanding_credit(credit_aml.id)
|
||||||
|
self.assertAlmostEquals(inv1.residual, 0)
|
||||||
|
self.assertAlmostEquals(inv2.residual, 0)
|
||||||
|
|
||||||
|
# Unreconcile one invoice at a time and check residual
|
||||||
|
credit_aml.with_context(invoice_id=inv1.id).remove_move_reconcile()
|
||||||
|
self.assertAlmostEquals(inv1.residual, 10)
|
||||||
|
self.assertAlmostEquals(inv2.residual, 0)
|
||||||
|
credit_aml.with_context(invoice_id=inv2.id).remove_move_reconcile()
|
||||||
|
self.assertAlmostEquals(inv1.residual, 10)
|
||||||
|
self.assertAlmostEquals(inv2.residual, 20)
|
||||||
|
|
||||||
def test_partial_reconcile_currencies_02(self):
|
def test_partial_reconcile_currencies_02(self):
|
||||||
####
|
####
|
||||||
# Day 1: Invoice Cust/001 to customer (expressed in USD)
|
# Day 1: Invoice Cust/001 to customer (expressed in USD)
|
||||||
|
|||||||
@@ -175,3 +175,10 @@ class PaymentTransaction(models.Model):
|
|||||||
})
|
})
|
||||||
|
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
|
def _post_process_after_done(self, **kwargs):
|
||||||
|
# set invoice id in payment transaction when payment being done from sale order
|
||||||
|
res = super(PaymentTransaction, self)._post_process_after_done()
|
||||||
|
if kwargs.get('invoice_id'):
|
||||||
|
self.account_invoice_id = kwargs['invoice_id']
|
||||||
|
return res
|
||||||
|
|||||||
@@ -28,6 +28,12 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
|||||||
// Keys from a barcode scanner are usually processed as quick as possible,
|
// Keys from a barcode scanner are usually processed as quick as possible,
|
||||||
// but some scanners can use an intercharacter delay (we support <= 50 ms)
|
// but some scanners can use an intercharacter delay (we support <= 50 ms)
|
||||||
max_time_between_keys_in_ms: session.max_time_between_keys_in_ms || 55,
|
max_time_between_keys_in_ms: session.max_time_between_keys_in_ms || 55,
|
||||||
|
// To be able to receive the barcode value, an input must be focused.
|
||||||
|
// On mobile devices, this causes the virtual keyboard to open.
|
||||||
|
// Unfortunately it is not possible to avoid this behavior...
|
||||||
|
// To avoid keyboard flickering at each detection of a barcode value,
|
||||||
|
// we want to keep it open for a while (800 ms).
|
||||||
|
inputTimeOut: 800,
|
||||||
|
|
||||||
init: function() {
|
init: function() {
|
||||||
mixins.PropertiesMixin.init.call(this);
|
mixins.PropertiesMixin.init.call(this);
|
||||||
@@ -38,6 +44,30 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
|||||||
// Bind event handler once the DOM is loaded
|
// Bind event handler once the DOM is loaded
|
||||||
// TODO: find a way to be active only when there are listeners on the bus
|
// TODO: find a way to be active only when there are listeners on the bus
|
||||||
$(_.bind(this.start, this, false));
|
$(_.bind(this.start, this, false));
|
||||||
|
|
||||||
|
// Mobile device detection
|
||||||
|
var isMobile = navigator.userAgent.match(/Android/i) ||
|
||||||
|
navigator.userAgent.match(/webOS/i) ||
|
||||||
|
navigator.userAgent.match(/iPhone/i) ||
|
||||||
|
navigator.userAgent.match(/iPad/i) ||
|
||||||
|
navigator.userAgent.match(/iPod/i) ||
|
||||||
|
navigator.userAgent.match(/BlackBerry/i) ||
|
||||||
|
navigator.userAgent.match(/Windows Phone/i);
|
||||||
|
this.isChromeMobile = isMobile && window.chrome;
|
||||||
|
|
||||||
|
// Creates an input who will receive the barcode scanner value.
|
||||||
|
if (this.isChromeMobile) {
|
||||||
|
this.$barcodeInput = $('<input/>', {
|
||||||
|
name: 'barcode',
|
||||||
|
type: 'text',
|
||||||
|
css: {
|
||||||
|
'position': 'absolute',
|
||||||
|
'opacity': 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__removeBarcodeField = _.debounce(this._removeBarcodeField, this.inputTimeOut);
|
||||||
},
|
},
|
||||||
|
|
||||||
handle_buffered_keys: function() {
|
handle_buffered_keys: function() {
|
||||||
@@ -109,7 +139,7 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
|||||||
e.key === "ArrowUp" || e.key === "ArrowDown" ||
|
e.key === "ArrowUp" || e.key === "ArrowDown" ||
|
||||||
e.key === "Escape" || e.key === "Tab" ||
|
e.key === "Escape" || e.key === "Tab" ||
|
||||||
e.key === "Backspace" || e.key === "Delete" ||
|
e.key === "Backspace" || e.key === "Delete" ||
|
||||||
/F\d\d?/.test(e.key)) {
|
e.key === "Unidentified" || /F\d\d?/.test(e.key)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@@ -167,8 +197,84 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to detect the barcode value by listening all keydown events:
|
||||||
|
* Checks if a dom element who may contains text value has the focus.
|
||||||
|
* If not, it's probably because these events are triggered by a barcode scanner.
|
||||||
|
* To be able to handle this value, a focused input will be created.
|
||||||
|
*
|
||||||
|
* This function also has the responsibility to detect the end of the barcode value.
|
||||||
|
* (1) In most of cases, an optional key (tab or enter) is sent to mark the end of the value.
|
||||||
|
* So, we direclty handle the value.
|
||||||
|
* (2) If no end key is configured, we have to calculate the delay between each keydowns.
|
||||||
|
* 'max_time_between_keys_in_ms' depends of the device and may be configured.
|
||||||
|
* Exceeded this timeout, we consider that the barcode value is entirely sent.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {jQuery.Event} e keydown event
|
||||||
|
*/
|
||||||
|
_listenBarcodeScanner: function (e) {
|
||||||
|
if (!$('input:text:focus, textarea:focus, [contenteditable]:focus').length) {
|
||||||
|
$('body').append(this.$barcodeInput);
|
||||||
|
this.$barcodeInput.focus();
|
||||||
|
}
|
||||||
|
if (this.$barcodeInput.is(":focus")) {
|
||||||
|
// Handle buffered keys immediately if the keypress marks the end
|
||||||
|
// of a barcode or after x milliseconds without a new keypress.
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
// On chrome mobile, e.which only works for some special characters like ENTER or TAB.
|
||||||
|
if (String.fromCharCode(e.which).match(this.suffix)) {
|
||||||
|
this._handleBarcodeValue(e);
|
||||||
|
} else {
|
||||||
|
this.timeout = setTimeout(this._handleBarcodeValue.bind(this, e),
|
||||||
|
this.max_time_between_keys_in_ms);
|
||||||
|
}
|
||||||
|
// if the barcode input doesn't receive keydown for a while, remove it.
|
||||||
|
this.__removeBarcodeField();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the barcode value from the temporary input element.
|
||||||
|
* This checks this value and trigger it on the bus.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {jQuery.Event} keydown event
|
||||||
|
*/
|
||||||
|
_handleBarcodeValue: function (e) {
|
||||||
|
var barcodeValue = this.$barcodeInput.val();
|
||||||
|
if (barcodeValue.match(this.regexp)) {
|
||||||
|
core.bus.trigger('barcode_scanned', barcodeValue, $(e.target).parent()[0]);
|
||||||
|
this.$barcodeInput.val('');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the temporary input created to store the barcode value.
|
||||||
|
* If nothing happens, this input will be removed, so the focus will be lost
|
||||||
|
* and the virtual keyboard on mobile devices will be closed.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_removeBarcodeField: function () {
|
||||||
|
if (this.$barcodeInput) {
|
||||||
|
// Reset the value and remove from the DOM.
|
||||||
|
this.$barcodeInput.val('').remove();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
start: function(prevent_key_repeat){
|
start: function(prevent_key_repeat){
|
||||||
$('body').bind("keypress", this.__handler);
|
// Chrome Mobile isn't triggering keypress event.
|
||||||
|
// This is marked as Legacy in the DOM-Level-3 Standard.
|
||||||
|
// See: https://www.w3.org/TR/uievents/#legacy-keyboardevent-event-types
|
||||||
|
// This fix is only applied for Google Chrome Mobile but it should work for
|
||||||
|
// all other cases.
|
||||||
|
// In master, we could remove the behavior with keypress and only use keydown.
|
||||||
|
if (this.isChromeMobile) {
|
||||||
|
$('body').on("keydown", this._listenBarcodeScanner.bind(this));
|
||||||
|
} else {
|
||||||
|
$('body').bind("keypress", this.__handler);
|
||||||
|
}
|
||||||
if (prevent_key_repeat === true) {
|
if (prevent_key_repeat === true) {
|
||||||
$('body').bind("keydown", this.__keydown_handler);
|
$('body').bind("keydown", this.__keydown_handler);
|
||||||
$('body').bind('keyup', this.__keyup_handler);
|
$('body').bind('keyup', this.__keyup_handler);
|
||||||
|
|||||||
@@ -622,9 +622,11 @@ class Import(models.TransientModel):
|
|||||||
# versions, for both data and pattern
|
# versions, for both data and pattern
|
||||||
user_format = pycompat.to_native(options.get('%s_format' % field['type']))
|
user_format = pycompat.to_native(options.get('%s_format' % field['type']))
|
||||||
for num, line in enumerate(data):
|
for num, line in enumerate(data):
|
||||||
|
if line[index]:
|
||||||
|
line[index] = line[index].strip()
|
||||||
if line[index]:
|
if line[index]:
|
||||||
try:
|
try:
|
||||||
line[index] = dt.strftime(dt.strptime(pycompat.to_native(line[index].strip()), user_format), server_format)
|
line[index] = dt.strftime(dt.strptime(pycompat.to_native(line[index]), user_format), server_format)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise ValueError(_("Column %s contains incorrect values. Error in line %d: %s") % (name, num + 1, e))
|
raise ValueError(_("Column %s contains incorrect values. Error in line %d: %s") % (name, num + 1, e))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class MailAlias(models.AbstractModel):
|
|||||||
_inherit = 'mail.alias.mixin'
|
_inherit = 'mail.alias.mixin'
|
||||||
|
|
||||||
def _alias_check_contact_on_record(self, record, message, message_dict, alias):
|
def _alias_check_contact_on_record(self, record, message, message_dict, alias):
|
||||||
if alias.alias_contact == 'employees' and record.ids:
|
if alias.alias_contact == 'employees':
|
||||||
email_from = tools.decode_message_header(message, 'From')
|
email_from = tools.decode_message_header(message, 'From')
|
||||||
email_address = tools.email_split(email_from)[0]
|
email_address = tools.email_split(email_from)[0]
|
||||||
employee = self.env['hr.employee'].search([('work_email', 'ilike', email_address)], limit=1)
|
employee = self.env['hr.employee'].search([('work_email', 'ilike', email_address)], limit=1)
|
||||||
|
|||||||
@@ -604,7 +604,7 @@ msgstr "Bankverbindlichkeiten"
|
|||||||
#: model:account.account,name:l10n_ch.1_ch_coa_2160
|
#: model:account.account,name:l10n_ch.1_ch_coa_2160
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_2160
|
#: model:account.account.template,name:l10n_ch.ch_coa_2160
|
||||||
msgid "Dettes envers l'actionnaire"
|
msgid "Dettes envers l'actionnaire"
|
||||||
msgstr ""
|
msgstr "Gesellschafterverbindlichkeiten"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_3806
|
#: model:account.account,name:l10n_ch.1_ch_coa_3806
|
||||||
@@ -612,7 +612,7 @@ msgstr ""
|
|||||||
#: model:account.account.template,name:l10n_ch.ch_coa_3806
|
#: model:account.account.template,name:l10n_ch.ch_coa_3806
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4906
|
#: model:account.account.template,name:l10n_ch.ch_coa_4906
|
||||||
msgid "Différences de change"
|
msgid "Différences de change"
|
||||||
msgstr ""
|
msgstr "Währungsdifferenzen"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_2261
|
#: model:account.account,name:l10n_ch.1_ch_coa_2261
|
||||||
@@ -624,7 +624,7 @@ msgstr "Beschlossene Ausschüttungen"
|
|||||||
#: model:account.account,name:l10n_ch.1_ch_coa_4071
|
#: model:account.account,name:l10n_ch.1_ch_coa_4071
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4071
|
#: model:account.account.template,name:l10n_ch.ch_coa_4071
|
||||||
msgid "Droits de douanes à l'importation"
|
msgid "Droits de douanes à l'importation"
|
||||||
msgstr ""
|
msgstr "Einfuhrzölle"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_1109
|
#: model:account.account,name:l10n_ch.1_ch_coa_1109
|
||||||
@@ -648,7 +648,7 @@ msgstr "Abrechnungskonto MWST"
|
|||||||
#: model:account.account,name:l10n_ch.1_ch_coa_4009
|
#: model:account.account,name:l10n_ch.1_ch_coa_4009
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4009
|
#: model:account.account.template,name:l10n_ch.ch_coa_4009
|
||||||
msgid "Déductions obtenues sur achats"
|
msgid "Déductions obtenues sur achats"
|
||||||
msgstr ""
|
msgstr "Einkaufsrabatte"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_3009
|
#: model:account.account,name:l10n_ch.1_ch_coa_3009
|
||||||
@@ -714,7 +714,7 @@ msgstr "Unterhalt, Reparaturen, Ersatz mobile Sachanlagen"
|
|||||||
#: model:account.account,name:l10n_ch.1_ch_coa_1570
|
#: model:account.account,name:l10n_ch.1_ch_coa_1570
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_1570
|
#: model:account.account.template,name:l10n_ch.ch_coa_1570
|
||||||
msgid "Equipements et Installations"
|
msgid "Equipements et Installations"
|
||||||
msgstr ""
|
msgstr "Feste Einrichtungen und Installationen"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_3800
|
#: model:account.account,name:l10n_ch.1_ch_coa_3800
|
||||||
@@ -722,7 +722,7 @@ msgstr ""
|
|||||||
#: model:account.account.template,name:l10n_ch.ch_coa_3800
|
#: model:account.account.template,name:l10n_ch.ch_coa_3800
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4900
|
#: model:account.account.template,name:l10n_ch.ch_coa_4900
|
||||||
msgid "Escomptes"
|
msgid "Escomptes"
|
||||||
msgstr ""
|
msgstr "Erlösminderungen"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_4530
|
#: model:account.account,name:l10n_ch.1_ch_coa_4530
|
||||||
@@ -734,31 +734,31 @@ msgstr "Benzin"
|
|||||||
#: model:account.account,name:l10n_ch.1_ch_coa_3804
|
#: model:account.account,name:l10n_ch.1_ch_coa_3804
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_3804
|
#: model:account.account.template,name:l10n_ch.ch_coa_3804
|
||||||
msgid "Frais d'encaissement"
|
msgid "Frais d'encaissement"
|
||||||
msgstr "Frais d'encaissement"
|
msgstr "Inkassoaufwand"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_3807
|
#: model:account.account,name:l10n_ch.1_ch_coa_3807
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_3807
|
#: model:account.account.template,name:l10n_ch.ch_coa_3807
|
||||||
msgid "Frais d'expédition"
|
msgid "Frais d'expédition"
|
||||||
msgstr "Frais d'expédition"
|
msgstr "Versandkosten"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_4072
|
#: model:account.account,name:l10n_ch.1_ch_coa_4072
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4072
|
#: model:account.account.template,name:l10n_ch.ch_coa_4072
|
||||||
msgid "Frais de transport à l'achat"
|
msgid "Frais de transport à l'achat"
|
||||||
msgstr "Frais de transport à l'achat"
|
msgstr "Transportkosten"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_4070
|
#: model:account.account,name:l10n_ch.1_ch_coa_4070
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4070
|
#: model:account.account.template,name:l10n_ch.ch_coa_4070
|
||||||
msgid "Frêts à l'achat"
|
msgid "Frêts à l'achat"
|
||||||
msgstr ""
|
msgstr "Frachtkosten"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_4510
|
#: model:account.account,name:l10n_ch.1_ch_coa_4510
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4510
|
#: model:account.account.template,name:l10n_ch.ch_coa_4510
|
||||||
msgid "Gaz"
|
msgid "Gaz"
|
||||||
msgstr "Gaz"
|
msgstr "Gas"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_1770
|
#: model:account.account,name:l10n_ch.1_ch_coa_1770
|
||||||
@@ -992,7 +992,7 @@ msgstr "Beteiligungen"
|
|||||||
#: model:account.account,name:l10n_ch.1_ch_coa_4086
|
#: model:account.account,name:l10n_ch.1_ch_coa_4086
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4086
|
#: model:account.account.template,name:l10n_ch.ch_coa_4086
|
||||||
msgid "Pertes de matières"
|
msgid "Pertes de matières"
|
||||||
msgstr ""
|
msgstr "Warenschwund"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_3805
|
#: model:account.account,name:l10n_ch.1_ch_coa_3805
|
||||||
@@ -1125,13 +1125,13 @@ msgstr "Werbeaufwand"
|
|||||||
#: model:account.account,name:l10n_ch.1_ch_coa_3801
|
#: model:account.account,name:l10n_ch.1_ch_coa_3801
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_3801
|
#: model:account.account.template,name:l10n_ch.ch_coa_3801
|
||||||
msgid "Rabais et réduction de prix"
|
msgid "Rabais et réduction de prix"
|
||||||
msgstr ""
|
msgstr "Rabatte und Preisreduktionen"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_4901
|
#: model:account.account,name:l10n_ch.1_ch_coa_4901
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4901
|
#: model:account.account.template,name:l10n_ch.ch_coa_4901
|
||||||
msgid "Rabais et réductions de prix"
|
msgid "Rabais et réductions de prix"
|
||||||
msgstr ""
|
msgstr "Rabatte und Preisreduktionen"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_3802
|
#: model:account.account,name:l10n_ch.1_ch_coa_3802
|
||||||
@@ -1139,7 +1139,7 @@ msgstr ""
|
|||||||
#: model:account.account.template,name:l10n_ch.ch_coa_3802
|
#: model:account.account.template,name:l10n_ch.ch_coa_3802
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4092
|
#: model:account.account.template,name:l10n_ch.ch_coa_4092
|
||||||
msgid "Ristournes"
|
msgid "Ristournes"
|
||||||
msgstr ""
|
msgstr "Rückvergütungen"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_2940
|
#: model:account.account,name:l10n_ch.1_ch_coa_2940
|
||||||
@@ -1473,13 +1473,13 @@ msgstr "Wertschriften"
|
|||||||
#: model:account.account,name:l10n_ch.1_transfer_account_id
|
#: model:account.account,name:l10n_ch.1_transfer_account_id
|
||||||
#: model:account.account.template,name:l10n_ch.transfer_account_id
|
#: model:account.account.template,name:l10n_ch.transfer_account_id
|
||||||
msgid "Transferts internes"
|
msgid "Transferts internes"
|
||||||
msgstr ""
|
msgstr "Interne Verrechnungen"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_1280
|
#: model:account.account,name:l10n_ch.1_ch_coa_1280
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_1280
|
#: model:account.account.template,name:l10n_ch.ch_coa_1280
|
||||||
msgid "Travaux en cours"
|
msgid "Travaux en cours"
|
||||||
msgstr "Unfertige Erzeugnisse"
|
msgstr "Nicht fakturierte Dienstleistungen"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_3940
|
#: model:account.account,name:l10n_ch.1_ch_coa_3940
|
||||||
@@ -1491,19 +1491,19 @@ msgstr "Bestandesänderungen nicht fakturierte Dienstleistungen"
|
|||||||
#: model:account.account,name:l10n_ch.1_ch_coa_1287
|
#: model:account.account,name:l10n_ch.1_ch_coa_1287
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_1287
|
#: model:account.account.template,name:l10n_ch.ch_coa_1287
|
||||||
msgid "Variation de la valeur des travaux en cours"
|
msgid "Variation de la valeur des travaux en cours"
|
||||||
msgstr ""
|
msgstr "Bestandesänderungen nicht fakturierte Dienstleistungen"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_1277
|
#: model:account.account,name:l10n_ch.1_ch_coa_1277
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_1277
|
#: model:account.account.template,name:l10n_ch.ch_coa_1277
|
||||||
msgid "Variation de stock produits semi-ouvrés"
|
msgid "Variation de stock produits semi-ouvrés"
|
||||||
msgstr ""
|
msgstr "Bestandesänderungen unfertige Erzeugnisse"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_1267
|
#: model:account.account,name:l10n_ch.1_ch_coa_1267
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_1267
|
#: model:account.account.template,name:l10n_ch.ch_coa_1267
|
||||||
msgid "Variation de stocks de produits finis"
|
msgid "Variation de stocks de produits finis"
|
||||||
msgstr ""
|
msgstr "Bestandesänderungen fertige Erzeugnisse"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_1207
|
#: model:account.account,name:l10n_ch.1_ch_coa_1207
|
||||||
@@ -1511,13 +1511,13 @@ msgstr ""
|
|||||||
#: model:account.account.template,name:l10n_ch.ch_coa_1207
|
#: model:account.account.template,name:l10n_ch.ch_coa_1207
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4800
|
#: model:account.account.template,name:l10n_ch.ch_coa_4800
|
||||||
msgid "Variation des stocks de marchandises"
|
msgid "Variation des stocks de marchandises"
|
||||||
msgstr ""
|
msgstr "Bestandesänderungen Handelsware"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_4801
|
#: model:account.account,name:l10n_ch.1_ch_coa_4801
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4801
|
#: model:account.account.template,name:l10n_ch.ch_coa_4801
|
||||||
msgid "Variation des stocks de matières premières"
|
msgid "Variation des stocks de matières premières"
|
||||||
msgstr ""
|
msgstr "Bestandesänderungen Rohstoffe"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_3901
|
#: model:account.account,name:l10n_ch.1_ch_coa_3901
|
||||||
@@ -1535,7 +1535,7 @@ msgstr "Bestandesänderungen unfertige Erzeugnisse"
|
|||||||
#: model:account.account,name:l10n_ch.1_ch_coa_1217
|
#: model:account.account,name:l10n_ch.1_ch_coa_1217
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_1217
|
#: model:account.account.template,name:l10n_ch.ch_coa_1217
|
||||||
msgid "Variation des stocks des matières premières"
|
msgid "Variation des stocks des matières premières"
|
||||||
msgstr ""
|
msgstr "Bestandesänderungen Rohstoffe"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_4008
|
#: model:account.account,name:l10n_ch.1_ch_coa_4008
|
||||||
@@ -1543,7 +1543,7 @@ msgstr ""
|
|||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4008
|
#: model:account.account.template,name:l10n_ch.ch_coa_4008
|
||||||
#: model:account.account.template,name:l10n_ch.ch_coa_4080
|
#: model:account.account.template,name:l10n_ch.ch_coa_4080
|
||||||
msgid "Variations de stocks"
|
msgid "Variations de stocks"
|
||||||
msgstr ""
|
msgstr "Inventurdifferenzen"
|
||||||
|
|
||||||
#. module: l10n_ch
|
#. module: l10n_ch
|
||||||
#: model:account.account,name:l10n_ch.1_ch_coa_3200
|
#: model:account.account,name:l10n_ch.1_ch_coa_3200
|
||||||
|
|||||||
@@ -19,12 +19,18 @@ body.l10n_ch_isr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* content outside isr needs margins to not overlap header */
|
/* content outside isr needs margins to not overlap header */
|
||||||
body.l10n_ch_isr #content_outside_isr {
|
#content_outside_isr {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
padding-top: 150px;
|
padding-top: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ISR is intended for pre-printed paper, we don't want stylistic background */
|
||||||
|
.o_report_layout_background {
|
||||||
|
background: none;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body.l10n_ch_isr #isr {
|
body.l10n_ch_isr #isr {
|
||||||
|
|||||||
@@ -144,10 +144,6 @@ msgid ""
|
|||||||
"object.parent_id.subject) or (object.parent_id and "
|
"object.parent_id.subject) or (object.parent_id and "
|
||||||
"object.parent_id.record_name and 'Re: %s' % object.parent_id.record_name)}"
|
"object.parent_id.record_name and 'Re: %s' % object.parent_id.record_name)}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"${object.subject 或 (object.record_name 和 'Re: %s' % object.record_name) 或 "
|
|
||||||
"(object.parent_id and object.parent_id.subject 和 'Re: %s' % "
|
|
||||||
"object.parent_id.subject) 或 (object.parent_id 和 object.parent_id.record_name"
|
|
||||||
" 和 'Re: %s' % object.parent_id.record_name)}"
|
|
||||||
|
|
||||||
#. module: mail
|
#. module: mail
|
||||||
#. openerp-web
|
#. openerp-web
|
||||||
|
|||||||
@@ -508,22 +508,19 @@
|
|||||||
<filter string="My Equipments" name="my" domain="[('owner_user_id', '=', uid)]"/>
|
<filter string="My Equipments" name="my" domain="[('owner_user_id', '=', uid)]"/>
|
||||||
<filter string="Archived" domain="[('active', '=', False)]" name="inactive"/>
|
<filter string="Archived" domain="[('active', '=', False)]" name="inactive"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<filter string="Unread Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
|
|
||||||
<separator/>
|
|
||||||
<filter string="My Activities" name="activities_my"
|
<filter string="My Activities" name="activities_my"
|
||||||
domain="[('activity_ids.user_id', '=', uid)]"/>
|
domain="[('activity_ids.user_id', '=', uid)]"/>
|
||||||
<filter string="Today Activities" name="activities_today"
|
<separator/>
|
||||||
domain="[('activity_ids.date_deadline', '=', context_today().strftime('%Y-%m-%d'))]"/>
|
<filter string="Late Activities" name="activities_overdue"
|
||||||
<filter string="Upcoming Activities (7 days)" name="activities_week"
|
|
||||||
domain="['&', ('activity_ids.date_deadline', '>=', context_today().strftime('%Y-%m-%d')),
|
|
||||||
('activity_ids.date_deadline', '<=', (context_today()+datetime.timedelta(days=7)).strftime('%Y-%m-%d'))
|
|
||||||
]"/>
|
|
||||||
<filter string="Overdue Activities" name="activities_overdue"
|
|
||||||
domain="[('activity_ids.date_deadline', '<', context_today().strftime('%Y-%m-%d'))]"
|
domain="[('activity_ids.date_deadline', '<', context_today().strftime('%Y-%m-%d'))]"
|
||||||
help="Show all records which has next action date is before today"/>
|
help="Show all records which has next action date is before today"/>
|
||||||
<filter string="Upcoming Activities (All)" name="activities_upcoming_all"
|
<filter string="Today Activities" name="activities_today"
|
||||||
|
domain="[('activity_ids.date_deadline', '=', context_today().strftime('%Y-%m-%d'))]"/>
|
||||||
|
<filter string="Future Activities" name="activities_upcoming_all"
|
||||||
domain="[('activity_ids.date_deadline', '>', context_today().strftime('%Y-%m-%d'))
|
domain="[('activity_ids.date_deadline', '>', context_today().strftime('%Y-%m-%d'))
|
||||||
]"/>
|
]"/>
|
||||||
|
<separator/>
|
||||||
|
<filter string="Unread Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
|
||||||
<!-- <filter string="Archived" name="inactive" domain="[('active','=',False)]"/> -->
|
<!-- <filter string="Archived" name="inactive" domain="[('active','=',False)]"/> -->
|
||||||
<group expand='0' string='Group by...'>
|
<group expand='0' string='Group by...'>
|
||||||
<filter string='Technicians' name="technicians" domain="[]" context="{'group_by': 'technician_user_id'}"/>
|
<filter string='Technicians' name="technicians" domain="[]" context="{'group_by': 'technician_user_id'}"/>
|
||||||
|
|||||||
@@ -794,6 +794,8 @@ class MassMailing(models.Model):
|
|||||||
def _process_mass_mailing_queue(self):
|
def _process_mass_mailing_queue(self):
|
||||||
mass_mailings = self.search([('state', 'in', ('in_queue', 'sending')), '|', ('schedule_date', '<', fields.Datetime.now()), ('schedule_date', '=', False)])
|
mass_mailings = self.search([('state', 'in', ('in_queue', 'sending')), '|', ('schedule_date', '<', fields.Datetime.now()), ('schedule_date', '=', False)])
|
||||||
for mass_mailing in mass_mailings:
|
for mass_mailing in mass_mailings:
|
||||||
|
user = mass_mailing.write_uid or self.env.user
|
||||||
|
mass_mailing = mass_mailing.with_context(**user.sudo(user=user).context_get())
|
||||||
if len(mass_mailing.get_remaining_recipients()) > 0:
|
if len(mass_mailing.get_remaining_recipients()) > 0:
|
||||||
mass_mailing.state = 'sending'
|
mass_mailing.state = 'sending'
|
||||||
mass_mailing.send_mail()
|
mass_mailing.send_mail()
|
||||||
|
|||||||
@@ -686,6 +686,10 @@ class PaymentTransaction(models.Model):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def _post_process_after_done(self, **kwargs):
|
||||||
|
return True
|
||||||
|
|
||||||
# --------------------------------------------------
|
# --------------------------------------------------
|
||||||
# SERVER2SERVER RELATED METHODS
|
# SERVER2SERVER RELATED METHODS
|
||||||
# --------------------------------------------------
|
# --------------------------------------------------
|
||||||
|
|||||||
@@ -281,7 +281,7 @@
|
|||||||
<select name="country_id" class="form-control">
|
<select name="country_id" class="form-control">
|
||||||
<option value="">Country...</option>
|
<option value="">Country...</option>
|
||||||
<t t-foreach="countries or []" t-as="country">
|
<t t-foreach="countries or []" t-as="country">
|
||||||
<option t-att-value="country.id" t-att-selected="country.id == partner.country_id.id">
|
<option t-att-value="country.id" t-att-selected="country.id == int(country_id) if country_id else country.id == partner.country_id.id">
|
||||||
<t t-esc="country.name" />
|
<t t-esc="country.name" />
|
||||||
</option>
|
</option>
|
||||||
</t>
|
</t>
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ class PricelistItem(models.Model):
|
|||||||
'product.category', 'Product Category', ondelete='cascade',
|
'product.category', 'Product Category', ondelete='cascade',
|
||||||
help="Specify a product category if this rule only applies to products belonging to this category or its children categories. Keep empty otherwise.")
|
help="Specify a product category if this rule only applies to products belonging to this category or its children categories. Keep empty otherwise.")
|
||||||
min_quantity = fields.Integer(
|
min_quantity = fields.Integer(
|
||||||
'Min. Quantity', default=1,
|
'Min. Quantity', default=0,
|
||||||
help="For the rule to apply, bought/sold quantity must be greater "
|
help="For the rule to apply, bought/sold quantity must be greater "
|
||||||
"than or equal to the minimum quantity specified in this field.\n"
|
"than or equal to the minimum quantity specified in this field.\n"
|
||||||
"Expressed in the default unit of measure of the product.")
|
"Expressed in the default unit of measure of the product.")
|
||||||
|
|||||||
@@ -588,20 +588,16 @@ class SaleOrder(models.Model):
|
|||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
res = {}
|
res = {}
|
||||||
for line in self.order_line:
|
for line in self.order_line:
|
||||||
base_tax = 0
|
price_reduce = line.price_unit * (1.0 - line.discount / 100.0)
|
||||||
|
taxes = line.tax_id.compute_all(price_reduce, quantity=line.product_uom_qty, product=line.product_id, partner=self.partner_shipping_id)['taxes']
|
||||||
for tax in line.tax_id:
|
for tax in line.tax_id:
|
||||||
group = tax.tax_group_id
|
group = tax.tax_group_id
|
||||||
res.setdefault(group, {'amount': 0.0, 'base': 0.0})
|
res.setdefault(group, {'amount': 0.0, 'base': 0.0})
|
||||||
# FORWARD-PORT UP TO SAAS-17
|
# FORWARD-PORT UP TO SAAS-17
|
||||||
price_reduce = line.price_unit * (1.0 - line.discount / 100.0)
|
|
||||||
taxes = tax.compute_all(price_reduce + base_tax, quantity=line.product_uom_qty,
|
|
||||||
product=line.product_id, partner=self.partner_shipping_id)['taxes']
|
|
||||||
for t in taxes:
|
for t in taxes:
|
||||||
res[group]['amount'] += t['amount']
|
if t['id'] == tax.id:
|
||||||
res[group]['base'] += t['base']
|
res[group]['amount'] += t['amount']
|
||||||
if tax.include_base_amount:
|
res[group]['base'] += t['base']
|
||||||
base_tax += tax.compute_all(price_reduce + base_tax, quantity=1, product=line.product_id,
|
|
||||||
partner=self.partner_shipping_id)['taxes'][0]['amount']
|
|
||||||
res = sorted(res.items(), key=lambda l: l[0].sequence)
|
res = sorted(res.items(), key=lambda l: l[0].sequence)
|
||||||
res = [(l[0].name, l[1]['amount'], l[1]['base'], len(res)) for l in res]
|
res = [(l[0].name, l[1]['amount'], l[1]['base'], len(res)) for l in res]
|
||||||
return res
|
return res
|
||||||
|
|||||||
@@ -169,9 +169,6 @@
|
|||||||
<field name="portal_confirmation_options" class="o_light_label" widget="radio"
|
<field name="portal_confirmation_options" class="o_light_label" widget="radio"
|
||||||
attrs="{'required': [('portal_confirmation', '=', True)]}"/>
|
attrs="{'required': [('portal_confirmation', '=', True)]}"/>
|
||||||
</div>
|
</div>
|
||||||
<div attrs="{'invisible': [('portal_confirmation_options', '!=', 'pay')]}">
|
|
||||||
<button name='%(payment.action_payment_acquirer)d' icon="fa-arrow-right" type="action" string="Payment Acquirers" class="btn-link"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ Provide tools for sale-related payment
|
|||||||
'views/crm_team_views.xml',
|
'views/crm_team_views.xml',
|
||||||
'views/sale_order_views.xml',
|
'views/sale_order_views.xml',
|
||||||
'views/sale_portal_templates.xml',
|
'views/sale_portal_templates.xml',
|
||||||
|
'views/settings.xml',
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
'auto_install': False,
|
'auto_install': False,
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ class PaymentTransaction(models.Model):
|
|||||||
created_invoice.with_context(default_currency_id=self.currency_id.id).pay_and_reconcile(self.acquirer_id.journal_id, pay_amount=created_invoice.amount_total)
|
created_invoice.with_context(default_currency_id=self.currency_id.id).pay_and_reconcile(self.acquirer_id.journal_id, pay_amount=created_invoice.amount_total)
|
||||||
if created_invoice.payment_ids:
|
if created_invoice.payment_ids:
|
||||||
created_invoice.payment_ids[0].payment_transaction_id = self
|
created_invoice.payment_ids[0].payment_transaction_id = self
|
||||||
|
self._post_process_after_done(invoice_id=created_invoice)
|
||||||
else:
|
else:
|
||||||
_logger.warning('<%s> transaction completed, could not auto-generate invoice for %s (ID %s)',
|
_logger.warning('<%s> transaction completed, could not auto-generate invoice for %s (ID %s)',
|
||||||
self.acquirer_id.provider, self.sale_order_id.name, self.sale_order_id.id)
|
self.acquirer_id.provider, self.sale_order_id.name, self.sale_order_id.id)
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record id="res_config_settings_view_form" model="ir.ui.view">
|
||||||
|
<field name="name">res.config.settings.view.form.inherit.sale_payment</field>
|
||||||
|
<field name="model">res.config.settings</field>
|
||||||
|
<field name="inherit_id" ref="sale.res_config_settings_view_form" />
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='portal_confirmation_options']/.." position="after">
|
||||||
|
<div attrs="{'invisible': [('portal_confirmation_options', '!=', 'pay')]}">
|
||||||
|
<button name='%(payment.action_payment_acquirer)d' icon="fa-arrow-right" type="action" string="Payment Acquirers" class="btn-link"/>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
@@ -56,7 +56,16 @@ class Project(models.Model):
|
|||||||
class ProjectTask(models.Model):
|
class ProjectTask(models.Model):
|
||||||
_inherit = "project.task"
|
_inherit = "project.task"
|
||||||
|
|
||||||
sale_line_id = fields.Many2one('sale.order.line', 'Sales Order Item', domain="[('is_service', '=', True), ('order_partner_id', '=', partner_id), ('is_expense', '=', False)]")
|
@api.model
|
||||||
|
def _default_sale_line_id(self):
|
||||||
|
sale_line_id = False
|
||||||
|
if self._context.get('default_parent_id'):
|
||||||
|
sale_line_id = self.env['project.task'].browse(self._context['default_parent_id']).sale_line_id.id
|
||||||
|
if not sale_line_id and self._context.get('default_project_id'):
|
||||||
|
sale_line_id = self.env['project.project'].browse(self._context['default_project_id']).sale_line_id.id
|
||||||
|
return sale_line_id
|
||||||
|
|
||||||
|
sale_line_id = fields.Many2one('sale.order.line', 'Sales Order Item', default=_default_sale_line_id, domain="[('is_service', '=', True), ('order_partner_id', '=', partner_id), ('is_expense', '=', False)]")
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
@api.constrains('sale_line_id')
|
@api.constrains('sale_line_id')
|
||||||
@@ -82,6 +91,10 @@ class ProjectTask(models.Model):
|
|||||||
result = super(ProjectTask, self).write(values)
|
result = super(ProjectTask, self).write(values)
|
||||||
# reassign SO line on related timesheet lines
|
# reassign SO line on related timesheet lines
|
||||||
if 'sale_line_id' in values:
|
if 'sale_line_id' in values:
|
||||||
|
# subtasks should have the same SO line than their mother
|
||||||
|
self.sudo().mapped('child_ids').write({
|
||||||
|
'so_line': values['sale_line_id']
|
||||||
|
})
|
||||||
self.sudo().mapped('timesheet_ids').write({
|
self.sudo().mapped('timesheet_ids').write({
|
||||||
'so_line': values['sale_line_id']
|
'so_line': values['sale_line_id']
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -829,5 +829,6 @@ class Orderpoint(models.Model):
|
|||||||
'date_planned': date or self._get_date_planned(product_qty, datetime.today()),
|
'date_planned': date or self._get_date_planned(product_qty, datetime.today()),
|
||||||
'warehouse_id': self.warehouse_id,
|
'warehouse_id': self.warehouse_id,
|
||||||
'orderpoint_id': self,
|
'orderpoint_id': self,
|
||||||
|
'company_id': self.company_id,
|
||||||
'group_id': group or self.group_id,
|
'group_id': group or self.group_id,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ class AccountInvoiceLine(models.Model):
|
|||||||
|
|
||||||
def _get_anglo_saxon_price_unit(self):
|
def _get_anglo_saxon_price_unit(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
|
if not self.product_id:
|
||||||
|
return self.price_unit
|
||||||
return self.product_id._get_anglo_saxon_price_unit(uom=self.uom_id)
|
return self.product_id._get_anglo_saxon_price_unit(uom=self.uom_id)
|
||||||
|
|
||||||
def _get_price(self, company_currency, price_unit):
|
def _get_price(self, company_currency, price_unit):
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
<field name="name">Public access to user_input</field>
|
<field name="name">Public access to user_input</field>
|
||||||
<field name="model_id" ref="survey.model_survey_user_input"/>
|
<field name="model_id" ref="survey.model_survey_user_input"/>
|
||||||
<field name="domain_force">[('create_uid', '=', user.id)]</field>
|
<field name="domain_force">[('create_uid', '=', user.id)]</field>
|
||||||
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
|
<field name="groups" eval="[(4, ref('base.group_user')), (4, ref('base.group_portal')), (4, ref('base.group_public'))]"/>
|
||||||
<field eval="0" name="perm_unlink"/>
|
<field eval="0" name="perm_unlink"/>
|
||||||
<field eval="0" name="perm_write"/>
|
<field eval="0" name="perm_write"/>
|
||||||
<field eval="1" name="perm_read"/>
|
<field eval="1" name="perm_read"/>
|
||||||
|
|||||||
@@ -993,7 +993,7 @@ class Binary(http.Controller):
|
|||||||
'/web/content/<string:model>/<int:id>/<string:field>/<string:filename>'], type='http', auth="public")
|
'/web/content/<string:model>/<int:id>/<string:field>/<string:filename>'], type='http', auth="public")
|
||||||
def content_common(self, xmlid=None, model='ir.attachment', id=None, field='datas',
|
def content_common(self, xmlid=None, model='ir.attachment', id=None, field='datas',
|
||||||
filename=None, filename_field='datas_fname', unique=None, mimetype=None,
|
filename=None, filename_field='datas_fname', unique=None, mimetype=None,
|
||||||
download=None, data=None, token=None, access_token=None):
|
download=None, data=None, token=None, access_token=None, **kw):
|
||||||
status, headers, content = binary_content(
|
status, headers, content = binary_content(
|
||||||
xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename,
|
xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename,
|
||||||
filename_field=filename_field, download=download, mimetype=mimetype,
|
filename_field=filename_field, download=download, mimetype=mimetype,
|
||||||
|
|||||||
@@ -125,8 +125,8 @@
|
|||||||
and main_object.website_meta_description or website_meta_description"/>
|
and main_object.website_meta_description or website_meta_description"/>
|
||||||
<t t-set="meta_keywords" t-value="main_object and 'website_meta_keywords' in main_object
|
<t t-set="meta_keywords" t-value="main_object and 'website_meta_keywords' in main_object
|
||||||
and main_object.website_meta_keywords or website_meta_keywords"/>
|
and main_object.website_meta_keywords or website_meta_keywords"/>
|
||||||
<meta t-if="meta_description" name="description" t-att-content="meta_description"/>
|
<meta t-if="meta_description or editable" name="description" t-att-content="meta_description"/>
|
||||||
<meta t-if="meta_keywords" name="keywords" t-att-content="meta_keywords"/>
|
<meta t-if="meta_keywords or editable" name="keywords" t-att-content="meta_keywords"/>
|
||||||
|
|
||||||
<!-- OpenGraph tags for Facebook sharing -->
|
<!-- OpenGraph tags for Facebook sharing -->
|
||||||
<meta property="og:title" t-att-content="additional_title" />
|
<meta property="og:title" t-att-content="additional_title" />
|
||||||
|
|||||||
@@ -1301,7 +1301,8 @@
|
|||||||
<div t-esc="int(line.product_uom_qty) == line.product_uom_qty and int(line.product_uom_qty) or line.product_uom_qty" />
|
<div t-esc="int(line.product_uom_qty) == line.product_uom_qty and int(line.product_uom_qty) or line.product_uom_qty" />
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center td-price">
|
<td class="text-center td-price">
|
||||||
<span t-field="line.price_unit" style="white-space: nowrap;" t-options="{'widget': 'monetary','from_currency': website_sale_order.pricelist_id.currency_id,'display_currency': website.currency_id}" />
|
<span t-field="line.price_reduce_taxexcl" style="white-space: nowrap;" t-options="{'widget': 'monetary', 'from_currency': website_sale_order.pricelist_id.currency_id, 'display_currency': website.currency_id}" groups="sale.group_show_price_subtotal" />
|
||||||
|
<span t-field="line.price_reduce_taxinc" style="white-space: nowrap;" t-options="{'widget': 'monetary', 'from_currency': website_sale_order.pricelist_id.currency_id, 'display_currency': website.currency_id}" groups="sale.group_show_price_total" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ class SaleOrder(models.Model):
|
|||||||
@api.depends('order_line.price_unit', 'order_line.tax_id', 'order_line.discount', 'order_line.product_uom_qty')
|
@api.depends('order_line.price_unit', 'order_line.tax_id', 'order_line.discount', 'order_line.product_uom_qty')
|
||||||
def _compute_amount_delivery(self):
|
def _compute_amount_delivery(self):
|
||||||
for order in self:
|
for order in self:
|
||||||
order.amount_delivery = sum(order.order_line.filtered('is_delivery').mapped('price_subtotal'))
|
if self.env.user.has_group('sale.group_show_price_subtotal'):
|
||||||
|
order.amount_delivery = sum(order.order_line.filtered('is_delivery').mapped('price_subtotal'))
|
||||||
|
else:
|
||||||
|
order.amount_delivery = sum(order.order_line.filtered('is_delivery').mapped('price_total'))
|
||||||
|
|
||||||
@api.depends('order_line.is_delivery')
|
@api.depends('order_line.is_delivery')
|
||||||
def _compute_has_delivery(self):
|
def _compute_has_delivery(self):
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
Austria, 18th of March 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,
|
||||||
|
|
||||||
|
Andreas Perhab bigbear.ap@gmx.at https://github.com/bigbear3001
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
Switzerland, 2018-03-20
|
||||||
|
|
||||||
|
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,
|
||||||
|
|
||||||
|
Andreas Hochuli a.hochuli@hispeed.ch https://github.com/Highcooley
|
||||||
@@ -406,7 +406,7 @@ Source installation requires manually installing dependencies:
|
|||||||
|
|
||||||
$ sudo npm install -g less
|
$ sudo npm install -g less
|
||||||
|
|
||||||
- on Windows, `install nodejs <http://nodejs.org/download/>`_, reboot (to
|
- on Windows, `install nodejs <https://nodejs.org/en/download/>`_, reboot (to
|
||||||
update the :envvar:`PATH`) and install less:
|
update the :envvar:`PATH`) and install less:
|
||||||
|
|
||||||
.. code-block:: doscon
|
.. code-block:: doscon
|
||||||
|
|||||||
Reference in New Issue
Block a user