diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-05-02 19:36:16 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-05-02 19:36:16 +0200 |
| commit | 87e21ccdc5c181960fa0d137e3ed880673032ca9 (patch) | |
| tree | 5aa3efc5a04796733c242129d91343149839abcb | |
| parent | 3596e67afb72aac22d9a71ddf542cc5bbe00bce0 (diff) | |
| parent | 521414b1c106187ceac972ba7ae6f5c342959940 (diff) | |
[MERGE] forward port branch 11.0 up to 521414b1c10
73 files changed, 1078 insertions, 839 deletions
diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 0c4aebef0ab..a6288da6a22 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -102,8 +102,7 @@ class AccountMove(models.Model): partner_id = fields.Many2one('res.partner', compute='_compute_partner_id', string="Partner", store=True, readonly=True) amount = fields.Monetary(compute='_amount_compute', store=True) narration = fields.Text(string='Internal Note') - company_id = fields.Many2one('res.company', related='journal_id.company_id', string='Company', store=True, readonly=True, - default=lambda self: self.env.user.company_id) + company_id = fields.Many2one('res.company', related='journal_id.company_id', string='Company', store=True, readonly=True) matched_percentage = fields.Float('Percentage Matched', compute='_compute_matched_percentage', digits=0, store=True, readonly=True, help="Technical field used in cash basis method") # Dummy Account field to search on account.move by account_id dummy_account_id = fields.Many2one('account.account', related='line_ids.account_id', string='Account', store=False, readonly=True) @@ -1174,19 +1173,22 @@ class AccountMoveLine(models.Model): #create an empty move that will hold all the exchange rate adjustments exchange_move = False - if aml_to_balance_currency: + if aml_to_balance_currency and any([residual for dummy, residual in aml_to_balance_currency.values()]): exchange_move = self.env['account.move'].create( self.env['account.full.reconcile']._prepare_exchange_diff_move(move_date=maxdate, company=self[0].company_id)) for currency, values in aml_to_balance_currency.items(): aml_to_balance = values[0] total_amount_currency = values[1] - #eventually create journal entries to book the difference due to foreign currency's exchange rate that fluctuates - aml_recs, partial_recs = self.env['account.partial.reconcile'].create_exchange_rate_entry(aml_to_balance, 0.0, total_amount_currency, currency, exchange_move) + if total_amount_currency: + #eventually create journal entries to book the difference due to foreign currency's exchange rate that fluctuates + aml_recs, partial_recs = self.env['account.partial.reconcile'].create_exchange_rate_entry(aml_to_balance, 0.0, total_amount_currency, currency, exchange_move) - #add the exchange rate line and the exchange rate partial reconciliation in the et of the full reconcile - self |= aml_recs - partial_rec_set |= partial_recs + # add the exchange rate line and the exchange rate partial reconciliation in the et of the full reconcile + self |= aml_recs + partial_rec_set |= partial_recs + else: + aml_to_balance.reconcile() if exchange_move: exchange_move.post() @@ -1214,8 +1216,9 @@ class AccountMoveLine(models.Model): 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']) + aml_to_keep = current_invoice.move_id.line_ids | current_invoice.move_id.line_ids.mapped('full_reconcile_id.exchange_move_id.line_ids') rec_move_ids = rec_move_ids.filtered( - lambda r: (r.debit_move_id + r.credit_move_id) & current_invoice.move_id.line_ids + lambda r: (r.debit_move_id + r.credit_move_id) & aml_to_keep ) return rec_move_ids.unlink() diff --git a/addons/account/models/partner.py b/addons/account/models/partner.py index 40b1cd90ff5..4590fc250da 100644 --- a/addons/account/models/partner.py +++ b/addons/account/models/partner.py @@ -394,8 +394,7 @@ class ResPartner(models.Model): required=True) property_account_position_id = fields.Many2one('account.fiscal.position', company_dependent=True, string="Fiscal Position", - help="The fiscal position will determine taxes and accounts used for the partner.", oldname="property_account_position", - domain="[('company_id', 'in', [company_id, False])]") + help="The fiscal position will determine taxes and accounts used for the partner.", oldname="property_account_position") property_payment_term_id = fields.Many2one('account.payment.term', company_dependent=True, string='Customer Payment Terms', help="This payment term will be used instead of the default one for sales orders and customer invoices", oldname="property_payment_term") @@ -445,5 +444,9 @@ class ResPartner(models.Model): @api.onchange('company_id') def _onchange_company_id(self): + company = self.env['res.company'] if self.company_id: - return {'domain': {'property_account_position_id': [('company_id', 'in', [self.company_id.id, False])]}} + company = self.company_id + else: + company = self.env.user.company_id + return {'domain': {'property_account_position_id': [('company_id', 'in', [company.id, False])]}} diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js index 7b80e0bbaa7..0df19adea56 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_model.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js @@ -990,6 +990,7 @@ var StatementModel = BasicModel.extend({ var formatOptions = { currency_id: line.st_line.currency_id, }; + var amount = values.amount !== undefined ? values.amount : line.balance.amount; var prop = { 'id': _.uniqueId('createLine'), 'label': values.label || line.st_line.name, @@ -1002,8 +1003,7 @@ var StatementModel = BasicModel.extend({ 'debit': 0, 'credit': 0, 'base_amount': values.amount_type !== "percentage" ? - (values.amount || line.balance.amount) : - line.balance.amount * values.amount / 100, + (amount) : line.balance.amount * values.amount / 100, 'percent': values.amount_type === "percentage" ? values.amount : null, 'link': values.link, 'display': true, diff --git a/addons/account/tests/test_reconciliation.py b/addons/account/tests/test_reconciliation.py index 09945c6e15b..4a50c812620 100644 --- a/addons/account/tests/test_reconciliation.py +++ b/addons/account/tests/test_reconciliation.py @@ -661,6 +661,54 @@ class TestReconciliation(AccountingTestCase): self.assertAlmostEquals(inv1.residual, 10) self.assertAlmostEquals(inv2.residual, 20) + def test_unreconcile_exchange(self): + # Use case: + # - Company currency in EUR + # - Create 2 rates for USD: + # 1.0 on 2018-01-01 + # 0.5 on 2018-02-01 + # - Create an invoice on 2018-01-02 of 111 USD + # - Register a payment on 2018-02-02 of 111 USD + # - Unreconcile the payment + + self.env['res.currency.rate'].create({ + 'name': time.strftime('%Y') + '-07-01', + 'rate': 1.0, + 'currency_id': self.currency_usd_id, + 'company_id': self.env.ref('base.main_company').id + }) + self.env['res.currency.rate'].create({ + 'name': time.strftime('%Y') + '-08-01', + 'rate': 0.5, + 'currency_id': self.currency_usd_id, + 'company_id': self.env.ref('base.main_company').id + }) + inv = self.create_invoice(invoice_amount=111, 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': 111, + 'currency_id': self.currency_usd_id, + 'journal_id': self.bank_journal_usd.id, + 'payment_date': time.strftime('%Y') + '-08-01', + }) + payment.post() + credit_aml = payment.move_line_ids.filtered('credit') + + # Check residual before assignation + self.assertAlmostEquals(inv.residual, 111) + + # Assign credit, check exchange move and residual + inv.assign_outstanding_credit(credit_aml.id) + self.assertEqual(len(payment.move_line_ids.mapped('full_reconcile_id').exchange_move_id), 1) + self.assertAlmostEquals(inv.residual, 0) + + # Unreconcile invoice and check residual + credit_aml.with_context(invoice_id=inv.id).remove_move_reconcile() + self.assertAlmostEquals(inv.residual, 111) + def test_partial_reconcile_currencies_02(self): #### # Day 1: Invoice Cust/001 to customer (expressed in USD) diff --git a/addons/account_check_printing/models/account_payment.py b/addons/account_check_printing/models/account_payment.py index 4edf4517ba2..61ed7176ca1 100644 --- a/addons/account_check_printing/models/account_payment.py +++ b/addons/account_check_printing/models/account_payment.py @@ -34,7 +34,7 @@ class AccountRegisterPayments(models.TransientModel): res = super(AccountRegisterPayments, self)._prepare_payment_vals(invoices) if self.payment_method_id == self.env.ref('account_check_printing.account_payment_method_check'): res.update({ - 'check_manual_sequencing': self.check_manual_sequencing, + 'check_amount_in_words': self.check_amount_in_words, }) return res diff --git a/addons/barcodes/static/src/js/barcode_events.js b/addons/barcodes/static/src/js/barcode_events.js index 71e07030ffd..a2e5808f8be 100644 --- a/addons/barcodes/static/src/js/barcode_events.js +++ b/addons/barcodes/static/src/js/barcode_events.js @@ -53,7 +53,7 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, { navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i); - this.isChromeMobile = isMobile && window.chrome; + this.isChromeMobile = isMobile && navigator.userAgent.match(/Chrome/i); // Creates an input who will receive the barcode scanner value. if (this.isChromeMobile) { @@ -61,7 +61,9 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, { name: 'barcode', type: 'text', css: { - 'position': 'absolute', + 'position': 'fixed', + 'top': '50%', + 'transform': 'translateY(-50%)', 'opacity': 0, }, }); diff --git a/addons/base_vat_autocomplete/models/res_partner.py b/addons/base_vat_autocomplete/models/res_partner.py index 93d74c497f8..f62c2e53b8c 100644 --- a/addons/base_vat_autocomplete/models/res_partner.py +++ b/addons/base_vat_autocomplete/models/res_partner.py @@ -12,6 +12,9 @@ _logger = logging.getLogger(__name__) try: import stdnum.eu.vat as stdnum_vat + if not hasattr(stdnum_vat, "country_codes"): + # stdnum version >= 1.9 + stdnum_vat.country_codes = stdnum_vat._country_codes except ImportError: _logger.warning('Python `stdnum` library not found, unable to call VIES service to detect address based on VAT number.') stdnum_vat = None diff --git a/addons/delivery/models/stock_picking.py b/addons/delivery/models/stock_picking.py index 5b993bc68a1..d58c77972f1 100644 --- a/addons/delivery/models/stock_picking.py +++ b/addons/delivery/models/stock_picking.py @@ -159,6 +159,8 @@ class StockPicking(models.Model): def send_to_shipper(self): self.ensure_one() res = self.carrier_id.send_shipping(self)[0] + if self.carrier_id.free_over and self.sale_id._compute_amount_total_without_delivery() >= self.carrier_id.amount: + res['exact_price'] = 0.0 self.carrier_price = res['exact_price'] self.carrier_tracking_ref = res['tracking_number'] order_currency = self.sale_id.currency_id or self.company_id.currency_id diff --git a/addons/delivery/tests/test_delivery_cost.py b/addons/delivery/tests/test_delivery_cost.py index d027906ef6a..62ffc253328 100644 --- a/addons/delivery/tests/test_delivery_cost.py +++ b/addons/delivery/tests/test_delivery_cost.py @@ -30,7 +30,9 @@ class TestDeliveryCost(common.TransactionCase): self.free_delivery = self.env.ref('delivery.free_delivery_carrier') # as the tests hereunder assume all the prices in USD, we must ensure # that the company actually uses USD - self.env.user.company_id.write({'currency_id': self.env.ref('base.USD').id}) + self.env.cr.execute( + "UPDATE res_company SET currency_id = %s WHERE id = %s", + [self.env.ref('base.USD').id, self.env.user.company_id.id]) def test_00_delivery_cost(self): # In order to test Carrier Cost diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index 3e96acb2bb7..b86ed7b050d 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -418,6 +418,7 @@ class HrExpense(models.Model): expense_description = expense_description.replace(product_code.group(), '') products = self.env['product.product'].search([('default_code', 'ilike', product_code.group(1))]) or default_product product = products.filtered(lambda p: p.default_code == product_code.group(1)) or products[0] + account = product.product_tmpl_id._get_product_accounts()['expense'] pattern = '[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?' # Match the last occurence of a float in the string @@ -444,6 +445,8 @@ class HrExpense(models.Model): 'unit_amount': price, 'company_id': employee.company_id.id, }) + if account: + custom_values['account_id'] = account.id return super(HrExpense, self).message_new(msg_dict, custom_values) diff --git a/addons/l10n_be/i18n_extra/nl_BE.po b/addons/l10n_be/i18n_extra/nl_BE.po index 88d6c4b61ee..2a4b067ee33 100644 --- a/addons/l10n_be/i18n_extra/nl_BE.po +++ b/addons/l10n_be/i18n_extra/nl_BE.po @@ -18,935 +18,774 @@ msgstr "" "X-Generator: Poedit 1.8.12\n" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-00 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-00 msgid "0% Biens d'investissement" msgstr "0% Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-00-G #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-00-G msgid "0% Biens divers" msgstr "0% Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-OUT-00-CC #: model:account.tax.template,name:l10n_be.attn_VAT-OUT-00-CC msgid "0% Cocont." msgstr "0% Medecont." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-00-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-00-CC msgid "0% Cocont. - Biens d'investissement" msgstr "0% Medecont. - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-00-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-00-CC msgid "0% Cocont. M." msgstr "0% Medecont. G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-00-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-00-CC msgid "0% Cocont. S." msgstr "0% Medecont. D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-00-EU #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-00-EU msgid "0% EU - Biens d'investissement" msgstr "0% EU - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-00-EU-G #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-00-EU-G msgid "0% EU - Biens divers" msgstr "0% EU - Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-00-EU -#: model:account.tax,name:l10n_be.1_attn_VAT-OUT-00-EU-L #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-00-EU #: model:account.tax.template,name:l10n_be.attn_VAT-OUT-00-EU-L msgid "0% EU M." msgstr "0% EU G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-00-EU-S -#: model:account.tax,name:l10n_be.1_attn_VAT-OUT-00-EU-S #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-00-EU-S #: model:account.tax.template,name:l10n_be.attn_VAT-OUT-00-EU-S msgid "0% EU S." msgstr "0% EU D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-OUT-00-EU-T #: model:account.tax.template,name:l10n_be.attn_VAT-OUT-00-EU-T msgid "0% EU T." msgstr "0% EU. T." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-00 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-00 msgid "0% M." msgstr "0% G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-OUT-00-ROW #: model:account.tax.template,name:l10n_be.attn_VAT-OUT-00-ROW msgid "0% Non EU" msgstr "0% Non EU" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-00-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-00-ROW-CC msgid "0% Non EU - Biens d'investissement" msgstr "0% Niet EU - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-00-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-00-ROW-CC msgid "0% Non EU M." msgstr "0% Non EU G. " #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-00-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-00-ROW-CC msgid "0% Non EU S." msgstr "0% Non EU D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-00-S -#: model:account.tax,name:l10n_be.1_attn_VAT-OUT-00-S #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-00-S #: model:account.tax.template,name:l10n_be.attn_VAT-OUT-00-S msgid "0% S." msgstr "0% D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-OUT-12-L #: model:account.tax.template,name:l10n_be.attn_VAT-OUT-12-L msgid "12%" msgstr "12%" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-12 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-12 msgid "12% Biens d'investissement" msgstr "12% Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-G #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-G msgid "12% Biens divers" msgstr "12% Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-12-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-12-CC msgid "12% Cocont. - Biens d'investissement" msgstr "12% Medecont. - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-12-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-12-CC-C1 msgid "12% Cocont. Déductible - Biens d'investissement" msgstr "12% Medecont. Aftrekbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-12-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-12-CC-C1 msgid "12% Cocont. Déductible M." msgstr "12% Medecont. Aftrekbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-CC-C1 msgid "12% Cocont. Déductible S." msgstr "12% Medecont. Aftrekbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-12-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-12-CC msgid "12% Cocont. M." msgstr "12% Medecont. G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-12-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-12-CC-C2 msgid "12% Cocont. Récupérable - Biens d'investissement" msgstr "12% Medecont. Verhaalbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-12-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-12-CC-C2 msgid "12% Cocont. Récupérable M." msgstr "12% Medecont. Verhaalbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-CC-C2 msgid "12% Cocont. Récupérable S." msgstr "12% Medecont. Verhaalbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-CC msgid "12% Cocont. S." msgstr "12% Medecont. D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-12-EU #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-12-EU msgid "12% EU - Biens d'investissement" msgstr "12% EU - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-EU-G #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-EU-G msgid "12% EU - Biens divers" msgstr "12% EU - Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-12-EU-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-12-EU-C1 msgid "12% EU Déductible - Biens d'investissement" msgstr "12% EU Aftrekbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-EU-G-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-EU-G-C1 msgid "12% EU Déductible - Biens divers" msgstr "12% EU Aftrekbaar - Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-12-EU-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-12-EU-C1 msgid "12% EU Déductible M." msgstr "12% EU Aftrekbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-EU-S-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-EU-S-C1 msgid "12% EU Déductible S." msgstr "12% EU Aftrekbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-12-EU #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-12-EU msgid "12% EU M." msgstr "12% EU G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-12-EU-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-12-EU-C2 msgid "12% EU Récupérable - Biens d'investissement" msgstr "12% EU Verhaalbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-12-EU-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-12-EU-C2 msgid "12% EU Récupérable M." msgstr "12% EU Verhaalbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-EU-S-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-EU-S-C2 msgid "12% EU Récupérable S." msgstr "12% EU Verhaalbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-EU-S #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-EU-S msgid "12% EU S." msgstr "12% EU D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-12 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-12 msgid "12% M." msgstr "12% G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-12-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-12-ROW-CC msgid "12% Non EU - Biens d'investissement" msgstr "12% Niet EU - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-12-ROW-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-12-ROW-CC-C1 msgid "12% Non EU Déductible - Biens d'investissement" msgstr "12% Niet EU Aftrekbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-12-ROW-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-12-ROW-CC-C1 msgid "12% Non EU Déductible M." msgstr "12% Non EU Aftrekbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-ROW-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-ROW-CC-C1 msgid "12% Non EU Déductible S." msgstr "12% Niet EU Aftrekbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-12-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-12-ROW-CC msgid "12% Non EU M." msgstr "12% Niet EU G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-12-ROW-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-12-ROW-CC-C2 msgid "12% Non EU Récupérable - Biens d'investissement" msgstr "12% Niet EU Verhaalbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-12-ROW-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-12-ROW-CC-C2 msgid "12% Non EU Récupérable M." msgstr "12% Niet EU Verhaalbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-ROW-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-ROW-CC-C2 msgid "12% Non EU Récupérable S." msgstr "12% Non EU Verhaalbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-ROW-CC msgid "12% Non EU S." msgstr "12% Niet EU D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-S -#: model:account.tax,name:l10n_be.1_attn_VAT-OUT-12-S #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-S #: model:account.tax.template,name:l10n_be.attn_VAT-OUT-12-S msgid "12% S." msgstr "12% D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-OUT-21-L #: model:account.tax.template,name:l10n_be.attn_VAT-OUT-21-L msgid "21%" msgstr "21%" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-21 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-21 msgid "21% Biens d'investissement" msgstr "21% Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-G #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-G msgid "21% Biens divers" msgstr "21% Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-CC msgid "21% Cocont .S." msgstr "21% Medecont. D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-21-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-21-CC msgid "21% Cocont. - Biens d'investissement" msgstr "21% Medecont. - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-21-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-21-CC-C1 msgid "21% Cocont. Déductible - Biens d'investissement" msgstr "21% Medecont. Aftrekbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-21-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-21-CC-C1 msgid "21% Cocont. Déductible M." msgstr "21% Medecont. Aftrekbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-CC-C1 msgid "21% Cocont. Déductible S." msgstr "21% Medecont. Aftrekbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-21-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-21-CC msgid "21% Cocont. M." msgstr "21% Medecont. G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-21-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-21-CC-C2 msgid "21% Cocont. Récupérable - Biens d'investissement" msgstr "21% Medecont. Verhaalbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-21-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-21-CC-C2 msgid "21% Cocont. Récupérable M." msgstr "21% Medecont. Verhaalbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-CC-C2 msgid "21% Cocont. Récupérable S." msgstr "21% Medecont. Verhaalbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-21-EU #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-21-EU msgid "21% EU - Biens d'investissement" msgstr "21% EU - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-EU-G #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-EU-G msgid "21% EU - Biens divers" msgstr "21% EU - Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-21-EU-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-21-EU-C1 msgid "21% EU Déductible - Biens d'investissement" msgstr "21% EU Aftrekbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-EU-G-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-EU-G-C1 msgid "21% EU Déductible - Biens divers" msgstr "21% EU Aftrekbaar - Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-21-EU-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-21-EU-C1 msgid "21% EU Déductible M." msgstr "21% EU Aftrekbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-EU-S-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-EU-S-C1 msgid "21% EU Déductible S." msgstr "21% EU Aftrekbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-21-EU #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-21-EU msgid "21% EU M." msgstr "21% EU. G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-21-EU-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-21-EU-C2 msgid "21% EU Récupérable - Biens d'investissement" msgstr "21% EU Verhaalbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-EU-G-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-EU-G-C2 msgid "21% EU Récupérable - Biens divers" msgstr "21% EU Verhaalbaar - Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-21-EU-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-21-EU-C2 msgid "21% EU Récupérable M." msgstr "21% EU Verhaalbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-EU-S-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-EU-S-C2 msgid "21% EU Récupérable S." msgstr "21% EU Verhaalbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-EU-S #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-EU-S msgid "21% EU S." msgstr "21% EU D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-21 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-21 msgid "21% M." msgstr "21% G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-21-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-21-ROW-CC msgid "21% Non EU - Biens d'investissement" msgstr "21% Niet EU - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-21-ROW-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-21-ROW-CC-C1 msgid "21% Non EU Déductible - Biens d'investissement" msgstr "21% Non EU Aftrekbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-21-ROW-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-21-ROW-CC-C1 msgid "21% Non EU Déductible M." msgstr "21% Non EU Aftrekbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-ROW-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-ROW-CC-C1 msgid "21% Non EU Déductible S." msgstr "21% Non EU Aftrekbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-21-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-21-ROW-CC msgid "21% Non EU M." msgstr "21% Niet EU G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-21-ROW-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-21-ROW-CC-C2 msgid "21% Non EU Récupérable - Biens d'investissement" msgstr "21% Non EU Verhaalbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-21-ROW-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-21-ROW-CC-C2 msgid "21% Non EU Récupérable M." msgstr "21% Non EU Verhaalbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-ROW-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-ROW-CC-C2 msgid "21% Non EU Récupérable S." msgstr "21% Niet EU Verhaalbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-ROW-CC msgid "21% Non EU S." msgstr "21% Non EU D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-21-S -#: model:account.tax,name:l10n_be.1_attn_VAT-OUT-21-S #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-21-S #: model:account.tax.template,name:l10n_be.attn_VAT-OUT-21-S msgid "21% S." msgstr "21% D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_TVA-21-inclus-dans-prix #: model:account.tax.template,name:l10n_be.attn_TVA-21-inclus-dans-prix msgid "21% S. TTC" msgstr "21% D. (Inclusief BTW)" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-CAR-EXC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-CAR-EXC-C2 msgid "50% Déductible - Frais de voiture (Prix Excl.)" msgstr "50% Aftrekbaar - Autokosten (Prijs Excl.)" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-CAR-EXC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-CAR-EXC-C1 msgid "50% Non Déductible - Frais de voiture" msgstr "50% Niet Aftrekbaar - Autokosten" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-CAR-EXC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-CAR-EXC msgid "50% Non Déductible - Frais de voiture (Prix Excl.)" msgstr "50% Niet Aftrekbaar - Autokosten (Prijs Excl.)" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-06 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-06 msgid "6% Biens d'investissement" msgstr "6% Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-G #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-G msgid "6% Biens divers" msgstr "6% Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-06-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-06-CC msgid "6% Cocont. - Biens d'investissement" msgstr "6% Medecont. - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-06-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-06-CC-C1 msgid "6% Cocont. Déductible - Biens d'investissement" msgstr "6% Medecont. Aftrekbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-06-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06-CC-C1 msgid "6% Cocont. Déductible M." msgstr "6% Medecont. Aftrekbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-CC-C1 msgid "6% Cocont. Déductible S." msgstr "6% Medecont. Aftrekbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-06-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06-CC msgid "6% Cocont. M." msgstr "6% Medecont. G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-06-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-06-CC-C2 msgid "6% Cocont. Récupérable - Biens d'investissement" msgstr "6% Medecont. Verhaalbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-06-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06-CC-C2 msgid "6% Cocont. Récupérable M." msgstr "6% Medecont. Verhaalbaar G. " #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-CC-C2 msgid "6% Cocont. Récupérable S." msgstr "6% Medecont. Verhaalbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-CC msgid "6% Cocont. S." msgstr "6% Medecont. D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-06-EU #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-06-EU msgid "6% EU - Biens d'investissement" msgstr "6% EU - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-EU-G #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-EU-G msgid "6% EU - Biens divers" msgstr "6% EU - Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-06-EU-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-06-EU-C1 msgid "6% EU Déductible - Biens d'investissement" msgstr "6% EU Aftrekbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-EU-G-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-EU-G-C1 msgid "6% EU Déductible - Biens divers" msgstr "6% EU Aftrekbaar - Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-06-EU-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06-EU-C1 msgid "6% EU Déductible M." msgstr "6% EU Aftrekbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-EU-S-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-EU-S-C1 msgid "6% EU Déductible S." msgstr "6% EU Aftrekbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-06-EU #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06-EU msgid "6% EU M." msgstr "6% EU G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-06-EU-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-06-EU-C2 msgid "6% EU Récupérable - Biens d'investissement" msgstr "6% EU Verhaalbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-EU-G-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-EU-G-C2 msgid "6% EU Récupérable - Biens divers" msgstr "6% EU Verhaalbaar - Diverse goederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-06-EU-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06-EU-C2 msgid "6% EU Récupérable M." msgstr "6% EU Verhaalbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-EU-S-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-EU-S-C2 msgid "6% EU Récupérable S." msgstr "6% EU Verhaalbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-EU-S #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-EU-S msgid "6% EU S." msgstr "6% EU D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-06 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06 msgid "6% M." msgstr "6% G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-06-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-06-ROW-CC msgid "6% Non EU - Biens d'investissement" msgstr "6% Niet EU - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-06-ROW-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-06-ROW-CC-C1 msgid "6% Non EU Déductible - Biens d'investissement" msgstr "6% Niet EU Aftrekbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-06-ROW-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06-ROW-CC-C1 msgid "6% Non EU Déductible M." msgstr "6% Niet EU Aftrekbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-ROW-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-ROW-CC-C1 msgid "6% Non EU Déductible S." msgstr "6% Niet EU Aftrekbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-06-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06-ROW-CC msgid "6% Non EU M." msgstr "6% Niet EU G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V83-06-ROW-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V83-06-ROW-CC-C2 msgid "6% Non EU Récupérable - Biens d'investissement" msgstr "6% Non EU Verhaalbaar - Investeringsgoederen" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V81-06-ROW-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06-ROW-CC-C2 msgid "6% Non EU Récupérable M." msgstr "6% Niet EU Verhaalbaar G." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-ROW-CC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-ROW-CC-C2 msgid "6% Non EU Récupérable S." msgstr "6% Niet EU Verhaalbaar D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-ROW-CC #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-ROW-CC msgid "6% Non EU S." msgstr "6% Niet EU D." #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-06-S -#: model:account.tax,name:l10n_be.1_attn_VAT-OUT-06-S #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-06-S #: model:account.tax.template,name:l10n_be.attn_VAT-OUT-06-S msgid "6% S." msgstr "6% D." #. module: l10n_be -#: model:account.account,name:l10n_be.1_a601 #: model:account.account.template,name:l10n_be.a601 msgid "Achats de fournitures" msgstr "Aankopen van hulpstoffen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a604 #: model:account.account.template,name:l10n_be.a604 msgid "Achats de marchandises" msgstr "Aankopen van handelsgoederen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a600 #: model:account.account.template,name:l10n_be.a600 msgid "Achats de matières premières" msgstr "Aankopen van grondstoffen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a602 #: model:account.account.template,name:l10n_be.a602 msgid "Achats de services, travaux et études" msgstr "Aankopen van diensten, werk en studies" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a446 #: model:account.account.template,name:l10n_be.a446 msgid "Acomptes reçus" msgstr "Ontvangen voorschotten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a176 #: model:account.account.template,name:l10n_be.a176 msgid "Acomptes reçus sur commandes" msgstr "Ontvangen vooruitbetalingen op bestellingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a406 #: model:account.account.template,name:l10n_be.a406 msgid "Acomptes versés" msgstr "Vooruitbetalingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a360 #: model:account.account.template,name:l10n_be.a360 msgid "Acomptes versés sur achats pour stocks" msgstr "Vooruitbetalingen op aankopen voor aandelen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4550 #: model:account.account.template,name:l10n_be.a4550 msgid "Administrateurs, gérants et commissaires" msgstr "Bestuurders, zaakvoerders en commissarissen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2119 #: model:account.account.template,name:l10n_be.a2119 msgid "Amortissements sur concessions, brevets, etc..." msgstr "Afschrijvingen op consessies, octrooien, licenties, ..." #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2690 #: model:account.account.template,name:l10n_be.a2690 msgid "Amortissements sur frais d'aménagement des locaux pris en location" msgstr "Op inrichtingskosten gehuurde lokalen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2009 #: model:account.account.template,name:l10n_be.a2009 msgid "Amortissements sur frais de constitution et d'augmentation de capital" msgstr "Afschrijvingen op oprichtingskosten en kapitaalverhoging" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2109 #: model:account.account.template,name:l10n_be.a2109 msgid "Amortissements sur frais de recherche et de mise au point" msgstr "Afschrijving van kosten van onderzoek en ontwikkeling" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a24190 #: model:account.account.template,name:l10n_be.a24190 msgid "Amortissements sur matériel automobile" msgstr "Afschrijvingen op wagenuitrusting" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a24090 #: model:account.account.template,name:l10n_be.a24090 msgid "Amortissements sur mobilier" msgstr "Afschrijvingen op meubilair" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2529 #: model:account.account.template,name:l10n_be.a2529 msgid "Amortissements sur mobilier et matériel roulant en leasing" msgstr "Afschrijvingen op geleasd rollend materieel" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a614 #: model:account.account.template,name:l10n_be.a614 msgid "Annonces, publicité, propagande et documentation" msgstr "Advertenties, publiciteit, propaganda en documentatie" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a3100 #: model:account.account.template,name:l10n_be.a3100 msgid "Approvisionements et fournitures" msgstr "Materialen en benodigdheden" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4160 #: model:account.account.template,name:l10n_be.a4160 msgid "Associés" msgstr "Vennoten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a45932 #: model:account.account.template,name:l10n_be.a45932 msgid "Assurance groupe " msgstr "Groepsverzekering" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a45930 #: model:account.account.template,name:l10n_be.a45930 msgid "Assurance loi" msgstr "Wetsverzekering" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a45931 #: model:account.account.template,name:l10n_be.a45931 msgid "Assurance salaire garanti " msgstr "Verzekering gewaarborgd inkomen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a45933 #: model:account.account.template,name:l10n_be.a45933 msgid "Assurances individuelles" msgstr "Individuele verzekering" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a41671 #: model:account.account.template,name:l10n_be.a41671 msgid "Autres créances" msgstr "Overige vorderingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a174 -#: model:account.account,name:l10n_be.1_a424 #: model:account.account.template,name:l10n_be.a174 #: model:account.account.template,name:l10n_be.a424 msgid "Autres emprunts" msgstr "Overige leningen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4125 #: model:account.account.template,name:l10n_be.a4125 msgid "Autres impôts belges" msgstr "Overige Belgische belastingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a49102 -#: model:account.account,name:l10n_be.1_a740 #: model:account.account.template,name:l10n_be.a49102 #: model:account.account.template,name:l10n_be.a740 msgid "Autres produits d'exploitation" msgstr "Andere bedrijfsopbrengsten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4538 #: model:account.account.template,name:l10n_be.a4538 msgid "Autres précomptes retenus" msgstr "Andere ingehouden voorheffingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4161 #: model:account.account.template,name:l10n_be.a4161 msgid "Avances et prêts au personnel" msgstr "Voorschotten en leningen aan het personeel" @@ -1132,854 +971,701 @@ msgid "Belgium VAT Form: grid 88" msgstr "" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a140 #: model:account.account.template,name:l10n_be.a140 msgid "Bénéfice reporté" msgstr "Overgedragen winst" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a790 #: model:account.account.template,name:l10n_be.a790 msgid "Bénéfice reporté de l'exercice précédent" msgstr "Overgedragen winst van het vorige boekjaar" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a693 #: model:account.account.template,name:l10n_be.a693 msgid "Bénéfice à reporter" msgstr "Over te dragen winst" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4594 #: model:account.account.template,name:l10n_be.a4594 msgid "Caisse d'assurances sociales pour travailleurs indépendants" msgstr "Sociale kas voor zelfstandigen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a24105 #: model:account.account.template,name:l10n_be.a24105 msgid "Camions" msgstr "Vrachtwagens" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a1000 #: model:account.account.template,name:l10n_be.a1000 msgid "Capital" msgstr "Kapitaal" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a418 #: model:account.account.template,name:l10n_be.a418 msgid "Cautionnements versés en numéraires" msgstr "Borgtochten betaald in contanten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6600 #: model:account.account.template,name:l10n_be.a6600 msgid "Charges exceptionelles" msgstr "Uitzonderlijke kosten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6101 #: model:account.account.template,name:l10n_be.a6101 msgid "Charges locatives" msgstr "Huurlasten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a492 #: model:account.account.template,name:l10n_be.a492 msgid "Charges à imputer" msgstr "Toe te rekenen kosten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a490 #: model:account.account.template,name:l10n_be.a490 msgid "Charges à reporter" msgstr "Over te dragen kosten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a540 #: model:account.account.template,name:l10n_be.a540 msgid "Chèques à encaisser" msgstr "Te incasseren cheques" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4000 #: model:account.account.template,name:l10n_be.a4000 msgid "Clients" msgstr "Klanten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a370 #: model:account.account.template,name:l10n_be.a370 msgid "Commandes en cours d'exécution" msgstr "Lopende opdrachten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a49101 #: model:account.account.template,name:l10n_be.a49101 msgid "Commissions à obtenir" msgstr "Te ontvangen commissies" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a448 #: model:account.account.template,name:l10n_be.a448 msgid "Compensations fournisseurs" msgstr "Compensaties leveranciers" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4112 -#: model:account.account,name:l10n_be.1_a4512 #: model:account.account.template,name:l10n_be.a4112 #: model:account.account.template,name:l10n_be.a4512 msgid "Compte courant administration T.V.A." msgstr "Rekening Courant BTW-Administratie" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4163 #: model:account.account.template,name:l10n_be.a4163 msgid "Compte courant des administrateurs et gérants" msgstr "Rekening courant bestuurders en zaakvoerders" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4162 #: model:account.account.template,name:l10n_be.a4162 msgid "Compte courant des associés en S.P.R.L." msgstr "Rekening courant vennoten in B.V.B.A" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4990 #: model:account.account.template,name:l10n_be.a4990 msgid "Compte d'attente" msgstr "Wachtrekening" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2110 #: model:account.account.template,name:l10n_be.a2110 msgid "Concessions, brevets, licences, savoir-faire, marques, etc..." msgstr "Consessies, octrooien, licenties, ..." #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2501 #: model:account.account.template,name:l10n_be.a2501 msgid "Constructions" msgstr "Gebouwen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a621 #: model:account.account.template,name:l10n_be.a621 msgid "Cotisations patronales d'assurances sociales" msgstr "Werkgeversbijdragen voor sociale verzekeringen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a29000 #: model:account.account.template,name:l10n_be.a29000 msgid "Créances commerciales" msgstr "Handelsvorderingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a407 -#: model:account.account,name:l10n_be.1_a417 #: model:account.account.template,name:l10n_be.a407 #: model:account.account.template,name:l10n_be.a417 msgid "Créances douteuses" msgstr "Dubieuze debiteuren" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4164 #: model:account.account.template,name:l10n_be.a4164 msgid "Créances sur sociétés apparentées" msgstr "Vorderingen op gerelateerde bedrijven" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a1720 #: model:account.account.template,name:l10n_be.a1720 msgid "Dettes de location-financement de biens immobiliers" msgstr "Leasingschulden van onroerende goederen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a1721 #: model:account.account.template,name:l10n_be.a1721 msgid "Dettes de location-financement de biens mobiliers" msgstr "Leasingschulden van roerende goederen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a17300 #: model:account.account.template,name:l10n_be.a17300 msgid "Dettes en compte \\ Banque A" msgstr "Schulden op rekeningen \\Bank A" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4597 #: model:account.account.template,name:l10n_be.a4597 msgid "Dettes et provisions sociales diverses" msgstr "Diverse sociale schulden en provisies" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4500 #: model:account.account.template,name:l10n_be.a4500 msgid "Dettes fiscales estimées" msgstr "Geraamd bedrag der belastingschulden" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a1722 #: model:account.account.template,name:l10n_be.a1722 msgid "Dettes sur droits réels sur immeubles" msgstr "Schulden op zakelijke rechten op gebouwen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a654 -#: model:account.account,name:l10n_be.1_a754 #: model:account.account.template,name:l10n_be.a654 #: model:account.account.template,name:l10n_be.a754 msgid "Différences de change" msgstr "Wisselresultaten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4551 -#: model:account.account,name:l10n_be.1_a4560 #: model:account.account.template,name:l10n_be.a4551 #: model:account.account.template,name:l10n_be.a4560 msgid "Direction" msgstr "Directiepersoneel" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6302 #: model:account.account.template,name:l10n_be.a6302 msgid "Dotations aux amortissements sur immobilisations corporelles" msgstr "Afschrijvingen op materiële vaste activa" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6301 #: model:account.account.template,name:l10n_be.a6301 msgid "Dotations aux amortissements sur immobilisations incorporelles" msgstr "Afschrijvingen op immateriële vaste activa" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a755 #: model:account.account.template,name:l10n_be.a755 msgid "Ecarts de conversion des devises" msgstr "Resultaten uit de omrekening van vreemde valuta" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a175111 #: model:account.account.template,name:l10n_be.a175111 msgid "Effets à payer \\ Fournisseurs C.E.E." msgstr "Te betalen wissels: Leveranciers van de EEG" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a175110 #: model:account.account.template,name:l10n_be.a175110 msgid "Effets à payer \\ Fournisseurs belges" msgstr "Te betalen wissels: Belgische leveranciers" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a175112 #: model:account.account.template,name:l10n_be.a175112 msgid "Effets à payer \\ Fournisseurs importation" msgstr "Te betalen wissels: Import leveranciers" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4166 #: model:account.account.template,name:l10n_be.a4166 msgid "Emballages et matériel à rendre" msgstr "Terug te geven materiaal en verpakkingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4552 -#: model:account.account,name:l10n_be.1_a4561 #: model:account.account.template,name:l10n_be.a4552 #: model:account.account.template,name:l10n_be.a4561 msgid "Employés" msgstr "Bedienden" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a3200 #: model:account.account.template,name:l10n_be.a3200 msgid "En cours de fabrication" msgstr "Goederen in bewerking" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a611 #: model:account.account.template,name:l10n_be.a611 msgid "Entretien et réparation" msgstr "Onderhoud en herstellingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a653 #: model:account.account.template,name:l10n_be.a653 msgid "Escomptes clients" msgstr "" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a757 #: model:account.account.template,name:l10n_be.a757 msgid "Escomptes obtenus" msgstr "Bekomen kortingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4230 #: model:account.account.template,name:l10n_be.a4230 msgid "Etablissements de crédit" msgstr "Kredietinstellingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a430 #: model:account.account.template,name:l10n_be.a430 msgid "Etablissements de crédit. Emprunts en compte à terme fixe" msgstr "Kredietinstellingen - Leningen op rekeningen met vaste termijn" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a444 #: model:account.account.template,name:l10n_be.a444 msgid "Factures à recevoir" msgstr "Te ontvangen facturen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4220 #: model:account.account.template,name:l10n_be.a4220 msgid "Financement de biens immobiliers" msgstr "Financiering vastgoed" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4221 #: model:account.account.template,name:l10n_be.a4221 msgid "Financement de biens mobiliers" msgstr "Financiering roerend goed" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a440 #: model:account.account.template,name:l10n_be.a440 msgid "Fournisseurs" msgstr "Leveranciers" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a612 #: model:account.account.template,name:l10n_be.a612 msgid "Fournitures" msgstr "Diverse leveringen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a260 #: model:account.account.template,name:l10n_be.a260 msgid "Frais d'aménagements de locaux pris en location" msgstr "Inrichtingskosten gehuurde lokalen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a656 #: model:account.account.template,name:l10n_be.a656 msgid "Frais de banques, de chèques postaux" msgstr "Bank en chequekosten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2000 #: model:account.account.template,name:l10n_be.a2000 msgid "Frais de constitution et d'augmentation de capital" msgstr "Oprichtingskosten en kapitaalverhoging" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2100 #: model:account.account.template,name:l10n_be.a2100 msgid "Frais de recherche et de mise au point" msgstr "Kosten van onderzoek en ontwikkeling" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a3500 #: model:account.account.template,name:l10n_be.a3500 msgid "Immeubles destinés à la vente" msgstr "Onroerende goederen bestemd voor verkoop" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2800 #: model:account.account.template,name:l10n_be.a2800 msgid "Immobilisations Financières" msgstr "Financiële vaste activa" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4120 #: model:account.account.template,name:l10n_be.a4120 msgid "Impôts belges sur le résultat" msgstr "Belgische belastingen op het resultaat" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6700 #: model:account.account.template,name:l10n_be.a6700 msgid "Impôts et précomptes dus ou versés" msgstr "Verschuldigde of gestorte belastingen en voorheffingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4128 #: model:account.account.template,name:l10n_be.a4128 msgid "Impôts étrangers" msgstr "Buitenlandse belastingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6100 #: model:account.account.template,name:l10n_be.a6100 msgid "Loyers divers" msgstr "Diverse huren" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a3400 #: model:account.account.template,name:l10n_be.a3400 msgid "Marchandises" msgstr "Goederen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a300 #: model:account.account.template,name:l10n_be.a300 msgid "Matières premières" msgstr "Grondstoffen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a24011 #: model:account.account.template,name:l10n_be.a24011 msgid "Matériel de bureau de bâtiments administratifs et commerciaux" msgstr "Kantooruitrusting voor gebouwen met adminestratieve en commerciële functie" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a24010 #: model:account.account.template,name:l10n_be.a24010 msgid "Matériel de bureau de bâtiments industriels" msgstr "Kantooruitrusting voor gebouwen met industriële functie" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2521 #: model:account.account.template,name:l10n_be.a2521 msgid "Matériel roulant" msgstr "Rollend materieel" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2520 #: model:account.account.template,name:l10n_be.a2520 msgid "Mobilier" msgstr "Meubilair" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a24001 #: model:account.account.template,name:l10n_be.a24001 msgid "Mobilier des bâtiments administratifs et commerciaux" msgstr "Van administratieve en commerciële gebouwen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a24000 #: model:account.account.template,name:l10n_be.a24000 msgid "Mobilier des bâtiments industriels" msgstr "Van industriële gebouwen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a151 #: model:account.account.template,name:l10n_be.a151 msgid "Montants transférés aux résultats" msgstr "Bedragen komende van het resultaat" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4541 #: model:account.account.template,name:l10n_be.a4541 msgid "ONSS. 1er trimestre" msgstr "R.S.Z. 1ste kwartaal" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4542 #: model:account.account.template,name:l10n_be.a4542 msgid "ONSS. 2ème trimestre" msgstr "R.S.Z. 2de kwartaal" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4543 #: model:account.account.template,name:l10n_be.a4543 msgid "ONSS. 3ème trimestre" msgstr "R.S.Z. 3de kwartaal" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4544 #: model:account.account.template,name:l10n_be.a4544 msgid "ONSS. 4ème trimestre" msgstr "R.S.Z. 4de kwartaal" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4540 #: model:account.account.template,name:l10n_be.a4540 msgid "ONSS. Arriérés" msgstr "Achterstallige bijdragen RSZ" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4553 -#: model:account.account,name:l10n_be.1_a4562 #: model:account.account.template,name:l10n_be.a4553 #: model:account.account.template,name:l10n_be.a4562 msgid "Ouvriers" msgstr "Arbeiders" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a141 #: model:account.account.template,name:l10n_be.a141 msgid "Perte reportée" msgstr "Overgedragen verlies (-)" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a690 #: model:account.account.template,name:l10n_be.a690 msgid "Perte reportée de l'exercice précédent" msgstr "Overgedragen verlies van het vorige boekjaar" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a793 #: model:account.account.template,name:l10n_be.a793 msgid "Perte à reporter" msgstr "Over te dragen verlies" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2118 #: model:account.account.template,name:l10n_be.a2118 msgid "Plus-values actées sur concessions, brevets, etc..." msgstr "Gerealiseerde meerwaarden op consessies, octrooien, licenties, ..." #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2108 #: model:account.account.template,name:l10n_be.a2108 msgid "Plus-values actées sur frais de recherche et de mise au point" msgstr "Gerealiseerde meerwaarden op onderzoek en ontwikkeling" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2528 #: model:account.account.template,name:l10n_be.a2528 msgid "Plus-values actées sur mobilier et matériel roulant en leasing" msgstr "Gerealiseerde meerwaarden op geleasd rollend materieel" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a752 #: model:account.account.template,name:l10n_be.a752 msgid "Plus-values sur réalisations d'actifs circulants" msgstr "Meerwaarden op de realisatie van vlottende activa" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7051 #: model:account.account.template,name:l10n_be.a7051 msgid "Prestations de services dans les pays membres de la C.E.E." msgstr "Dienstverlening in lidstaten van de E.E.G." #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7050 #: model:account.account.template,name:l10n_be.a7050 msgid "Prestations de services en Belgique" msgstr "Dienstverlening in België" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7052 #: model:account.account.template,name:l10n_be.a7052 msgid "Prestations de services en vue de l'exportation" msgstr "Dienstverlening buiten de E.E.G. (export)" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a11 #: model:account.account.template,name:l10n_be.a11 msgid "Primes d'émission" msgstr "Uitgifte premies" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4930 #: model:account.account.template,name:l10n_be.a4930 msgid "Produits d'exploitation à reporter" msgstr "Over te dragen bedrijfsopbrengsten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a751 #: model:account.account.template,name:l10n_be.a751 msgid "Produits des actifs circulants" msgstr "Opbrengsten uit vlottende activa" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a756 #: model:account.account.template,name:l10n_be.a756 msgid "Produits des autres créances" msgstr "Diverse financiële opbrengsten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7600 #: model:account.account.template,name:l10n_be.a7600 msgid "Produits exceptionnels" msgstr "Uitzonderlijke opbrengsten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a3300 #: model:account.account.template,name:l10n_be.a3300 msgid "Produits finis" msgstr "Gereed product" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a404 -#: model:account.account,name:l10n_be.1_a414 #: model:account.account.template,name:l10n_be.a404 #: model:account.account.template,name:l10n_be.a414 msgid "Produits à recevoir" msgstr "Te innen opbrengsten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4590 #: model:account.account.template,name:l10n_be.a4590 msgid "Provision pour gratifications de fin d'année" msgstr "Voorziening voor eindejaarspremie" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a1600 #: model:account.account.template,name:l10n_be.a1600 msgid "Provisions pour risques et charges" msgstr "Voorzieningen voor risico's en kosten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4533 #: model:account.account.template,name:l10n_be.a4533 msgid "Précompte mobilier retenu sur intérêts payés" msgstr "Roerende voorheffing ingehouden op betaalde intresten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4530 #: model:account.account.template,name:l10n_be.a4530 msgid "Précompte professionnel retenu sur rémunérations" msgstr "Bedrijfsvoorheffing ingehouden op bezoldigingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a791 #: model:account.account.template,name:l10n_be.a791 msgid "Prélèvement sur le capital et les primes d'émission" msgstr "Onttrekking aan het kapitaal en aan de uitgiftepremies" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a780 #: model:account.account.template,name:l10n_be.a780 msgid "Prélèvements sur les impôts différés" msgstr "Onttrekking aan de uitgestelde belastingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a789 #: model:account.account.template,name:l10n_be.a789 msgid "Prélèvements sur les réserves immunisées" msgstr "Onttrekking aan de reserves" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a706 #: model:account.account.template,name:l10n_be.a706 msgid "Pénalités et dédits obtenus par l'entreprise" msgstr "Boeten en verbeurdverklaringen verkregen door de onderneming" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4168 #: model:account.account.template,name:l10n_be.a4168 msgid "Rabais, ristournes, remises à obtenir et autres avoirs non encore reçus" msgstr "Kortingen, rabatten en andere nog te ontvangen tegoeden" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7500 #: model:account.account.template,name:l10n_be.a7500 msgid "Revenus des actions" msgstr "Opbrengsten uit aandelen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7502 #: model:account.account.template,name:l10n_be.a7502 msgid "Revenus des créances à plus d'un an" msgstr "Inkomsten uit schuld > 1 jaar" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7501 #: model:account.account.template,name:l10n_be.a7501 msgid "Revenus des obligations" msgstr "Opbrengsten uit obligaties" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a49100 #: model:account.account.template,name:l10n_be.a49100 msgid "Ristournes, rabais à obtenir" msgstr "Te ontvangen kortingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a329 -#: model:account.account,name:l10n_be.1_a419 #: model:account.account.template,name:l10n_be.a329 #: model:account.account.template,name:l10n_be.a419 msgid "Réductions de valeur actées" msgstr "Geboekte waardeverminderingen (-)" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6320 #: model:account.account.template,name:l10n_be.a6320 msgid "Réductions de valeur sur commandes en cours d'exécution" msgstr "Waardeverminderingen op bestellingen in uitvoering" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6310 #: model:account.account.template,name:l10n_be.a6310 msgid "Réductions de valeur sur stocks" msgstr "Waardeverminderingen op voorraden" #. module: l10n_be -#: model:account.fiscal.position,name:l10n_be.1_fiscal_position_template_4 #: model:account.fiscal.position.template,name:l10n_be.fiscal_position_template_4 msgid "Régime Cocontractant" msgstr "Medecontractant" #. module: l10n_be -#: model:account.fiscal.position,name:l10n_be.1_fiscal_position_template_2 #: model:account.fiscal.position.template,name:l10n_be.fiscal_position_template_2 msgid "Régime Extra-Communautaire" msgstr "Export" #. module: l10n_be -#: model:account.fiscal.position,name:l10n_be.1_fiscal_position_template_3 #: model:account.fiscal.position.template,name:l10n_be.fiscal_position_template_3 msgid "Régime Intra-Communautaire" msgstr "Intra-Communautair" #. module: l10n_be -#: model:account.fiscal.position,name:l10n_be.1_fiscal_position_template_1 #: model:account.fiscal.position.template,name:l10n_be.fiscal_position_template_1 msgid "Régime National" msgstr "Nationaal" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V61 -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V61 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V61 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V61 msgid "Régularisation en faveur de l'état" msgstr "" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V62 -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V62 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V62 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V62 msgid "Régularisation en faveur du déclarant" msgstr "" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7710 #: model:account.account.template,name:l10n_be.a7710 msgid "Régularisations d'impôts dus ou versés" msgstr "Regularisering van verschuldigde of betaalde belastingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7711 #: model:account.account.template,name:l10n_be.a7711 msgid "Régularisations d'impôts estimés" msgstr "Regularisering van geraamde belastingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6200 #: model:account.account.template,name:l10n_be.a6200 msgid "Rémunérations: Administrateurs ou gérants" msgstr "Bezoldigingen: Bestuurders of zaakvoerders" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6204 #: model:account.account.template,name:l10n_be.a6204 msgid "Rémunérations: Autres membres du personnel" msgstr "Bezoldigingen: Andere personeelsleden, verbonden met een arbeidsovereenkomst" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6202 #: model:account.account.template,name:l10n_be.a6202 msgid "Rémunérations: Employés" msgstr "Bezoldigingen: Arbeiders" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6203 #: model:account.account.template,name:l10n_be.a6203 msgid "Rémunérations: Ouvriers" msgstr "Bezoldigingen: Bedienden" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a6201 #: model:account.account.template,name:l10n_be.a6201 msgid "Rémunérations: Personnel de direction" msgstr "Bezoldigingen: Directiepersoneel" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a130 #: model:account.account.template,name:l10n_be.a130 msgid "Réserve légale" msgstr "Wettelijke reserve" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a132 #: model:account.account.template,name:l10n_be.a132 msgid "Réserves immunisées" msgstr "Belastingvrije reserves" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a613 #: model:account.account.template,name:l10n_be.a613 msgid "Rétributions de tiers" msgstr "Vergoedingen aan derden" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a603 #: model:account.account.template,name:l10n_be.a603 msgid "Sous-traitances générales" msgstr "Algemene onderaannemingen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a753 #: model:account.account.template,name:l10n_be.a753 msgid "Subsides en capital et en intérêts" msgstr "Kapitaal- en interestsubsidies" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a150 #: model:account.account.template,name:l10n_be.a150 msgid "Subsides obtenus" msgstr "Verkregen subsidies" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a41670 #: model:account.account.template,name:l10n_be.a41670 msgid "Subsides à recevoir" msgstr "Te ontvangen subsidies" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a411059 #: model:account.account.template,name:l10n_be.a411059 msgid "T.V.A Déductible" msgstr "Aftrekbare BTW" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a64012 #: model:account.account.template,name:l10n_be.a64012 msgid "T.V.A. non déductible" msgstr "Niet aftrekbare BTW" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a451054 #: model:account.account.template,name:l10n_be.a451054 msgid "T.V.A. à payer" msgstr "Te betalen BTW" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a451056 #: model:account.account.template,name:l10n_be.a451056 msgid "T.V.A. à payer - Cocontractant" msgstr "Te betalen BTW - Medecontractant" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a451057 #: model:account.account.template,name:l10n_be.a451057 msgid "T.V.A. à payer - Import" msgstr "Te betalen BTW - Import" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a451055 #: model:account.account.template,name:l10n_be.a451055 msgid "T.V.A. à payer - Intra-communautaire" msgstr "Te betalen BTW - Intracommunautair" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-00 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-00-G -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-00-S -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-00 -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-00-L -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-00-S #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-00 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-00-G #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-00-S @@ -1990,10 +1676,6 @@ msgid "TVA 0%" msgstr "BTW 0%" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-00-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-00-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-00-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-00-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-00-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-00-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-00-CC @@ -2002,13 +1684,6 @@ msgid "TVA 0% Cocont." msgstr "BTW 0% Medecont." #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-00-EU -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-00-EU-G -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-00-EU-S -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-00-EU -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-00-EU-L -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-00-EU-S -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-00-EU-T #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-00-EU #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-00-EU-G #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-00-EU-S @@ -2020,10 +1695,6 @@ msgid "TVA 0% EU" msgstr "BTW 0% EU" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-00-ROW-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-00-ROW-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-00-ROW-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-00-ROW #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-00-ROW-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-00-ROW-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-00-ROW-CC @@ -2032,12 +1703,6 @@ msgid "TVA 0% Non EU" msgstr "BTW 0% Non EU" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-12 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-G -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-S -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-12 -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-12-L -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-12-S #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-12 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-G #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-S @@ -2048,9 +1713,6 @@ msgid "TVA 12%" msgstr "BTW 12%" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-12-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-12-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-12-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-12-CC @@ -2058,9 +1720,6 @@ msgid "TVA 12% Cocont." msgstr "BTW 12% Medecont." #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-12-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-12-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-12-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-12-CC-C1 @@ -2068,9 +1727,6 @@ msgid "TVA 12% Cocont. Déductible" msgstr "BTW 12% Medecont. Aftrekbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-12-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-12-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-12-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-12-CC-C2 @@ -2078,10 +1734,6 @@ msgid "TVA 12% Cocont. Récupérable" msgstr "BTW 12% Medecont. Verhaalbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-12-EU -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-EU-G -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-EU-S -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-12-EU #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-12-EU #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-EU-G #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-EU-S @@ -2090,10 +1742,6 @@ msgid "TVA 12% EU" msgstr "BTW 12% EU" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-12-EU-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-EU-G-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-EU-S-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-12-EU-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-12-EU-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-EU-G-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-EU-S-C1 @@ -2102,10 +1750,6 @@ msgid "TVA 12% EU Déductible" msgstr "BTW 12% EU Aftrekbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-12-EU-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-EU-G-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-EU-S-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-12-EU-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-12-EU-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-EU-G-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-EU-S-C2 @@ -2114,15 +1758,11 @@ msgid "TVA 12% EU Récupérable" msgstr "BTW 12% EU Verhaalbaar" #. module: l10n_be -#: model:account.tax,name:l10n_be.1_attn_VAT-IN-V82-12-EU-G-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-12-EU-G-C2 msgid "TVA 12% EU Récupérable - Biens divers" msgstr "BTW 12% EU Verhaalbaar - Diverse goederen" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-12-ROW-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-ROW-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-12-ROW-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-12-ROW-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-ROW-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-12-ROW-CC @@ -2130,9 +1770,6 @@ msgid "TVA 12% Non EU" msgstr "BTW 12% Niet EU" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-12-ROW-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-ROW-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-12-ROW-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-12-ROW-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-ROW-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-12-ROW-CC-C1 @@ -2140,9 +1777,6 @@ msgid "TVA 12% Non EU Déductible" msgstr "BTW 12% Niet EU Aftrekbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-12-ROW-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-12-ROW-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-12-ROW-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-12-ROW-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-12-ROW-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-12-ROW-CC-C2 @@ -2150,12 +1784,6 @@ msgid "TVA 12% Non EU Récupérable" msgstr "BTW 12% Niet EU Verhaalbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-21 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-G -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-S -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-21 -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-21-L -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-21-S #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-21 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-G #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-S @@ -2166,9 +1794,6 @@ msgid "TVA 21%" msgstr "BTW 21%" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-21-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-21-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-21-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-21-CC @@ -2176,9 +1801,6 @@ msgid "TVA 21% Cocont." msgstr "BTW 21% Medecont." #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-21-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-21-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-21-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-21-CC-C1 @@ -2186,9 +1808,6 @@ msgid "TVA 21% Cocont. Déductible" msgstr "BTW 21% Medecont. Aftrekbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-21-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-21-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-21-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-21-CC-C2 @@ -2196,10 +1815,6 @@ msgid "TVA 21% Cocont. Récupérable" msgstr "BTW 21% Medecont. Verhaalbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-21-EU -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-EU-G -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-EU-S -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-21-EU #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-21-EU #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-EU-G #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-EU-S @@ -2208,10 +1823,6 @@ msgid "TVA 21% EU" msgstr "BTW 21% EU" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-21-EU-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-EU-G-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-EU-S-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-21-EU-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-21-EU-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-EU-G-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-EU-S-C1 @@ -2220,10 +1831,6 @@ msgid "TVA 21% EU Déductible" msgstr "BTW 21% EU Aftrekbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-21-EU-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-EU-G-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-EU-S-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-21-EU-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-21-EU-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-EU-G-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-EU-S-C2 @@ -2232,9 +1839,6 @@ msgid "TVA 21% EU Récupérable" msgstr "BTW 21% EU Verhaalbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-21-ROW-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-ROW-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-21-ROW-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-21-ROW-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-ROW-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-21-ROW-CC @@ -2242,9 +1846,6 @@ msgid "TVA 21% Non EU" msgstr "BTW 21% Niet EU" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-21-ROW-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-ROW-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-21-ROW-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-21-ROW-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-ROW-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-21-ROW-CC-C1 @@ -2252,9 +1853,6 @@ msgid "TVA 21% Non EU Déductible" msgstr "BTW 21% Niet EU Aftrekbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-21-ROW-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-21-ROW-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-21-ROW-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-21-ROW-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-21-ROW-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-21-ROW-CC-C2 @@ -2262,30 +1860,21 @@ msgid "TVA 21% Non EU Récupérable" msgstr "BTW 21% Niet EU Verhaalbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_TVA-21-inclus-dans-prix #: model:account.tax.template,description:l10n_be.attn_TVA-21-inclus-dans-prix msgid "TVA 21% TTC" msgstr "VAT 21% (inclusief BTW)" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-CAR-EXC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-CAR-EXC-C2 msgid "TVA 50% Déductible - Frais de voiture (Prix Excl.)" msgstr "BTW 5°% Aftrekbaar - Auto kosten (Prijs Excl.)" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-CAR-EXC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-CAR-EXC msgid "TVA 50% Non Déductible - Frais de voiture (Prix Excl.)" msgstr "BTW 50% Niet Aftrekbaar - Auto kosten (Prijs Excl.)" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-06 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-G -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-S -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-06 -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-06-L -#: model:account.tax,description:l10n_be.1_attn_VAT-OUT-06-S #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-06 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-G #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-S @@ -2296,9 +1885,6 @@ msgid "TVA 6%" msgstr "BTW 6%" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-06-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-06-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-06-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-06-CC @@ -2306,9 +1892,6 @@ msgid "TVA 6% Cocont." msgstr "BTW 6% Medecont." #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-06-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-06-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-06-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-06-CC-C1 @@ -2316,9 +1899,6 @@ msgid "TVA 6% Cocont. Déductible" msgstr "BTW 6% Medecont. Aftrekbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-06-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-06-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-06-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-06-CC-C2 @@ -2326,10 +1906,6 @@ msgid "TVA 6% Cocont. Récupérable" msgstr "BTW 6% Medecont. Verhaalbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-06-EU -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-EU-G -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-EU-S -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-06-EU #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-06-EU #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-EU-G #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-EU-S @@ -2338,10 +1914,6 @@ msgid "TVA 6% EU" msgstr "BTW 6% EU" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-06-EU-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-EU-G-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-EU-S-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-06-EU-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-06-EU-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-EU-G-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-EU-S-C1 @@ -2350,10 +1922,6 @@ msgid "TVA 6% EU Déductible" msgstr "BTW 6% EU Aftrekbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-06-EU-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-EU-G-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-EU-S-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-06-EU-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-06-EU-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-EU-G-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-EU-S-C2 @@ -2362,9 +1930,6 @@ msgid "TVA 6% EU Récupérable" msgstr "BTW 6% EU Verhaalbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-06-ROW-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-ROW-CC -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-06-ROW-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-06-ROW-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-ROW-CC #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-06-ROW-CC @@ -2372,9 +1937,6 @@ msgid "TVA 6% Non EU" msgstr "BTW 6% Niet EU" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-06-ROW-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-ROW-CC-C1 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-06-ROW-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-06-ROW-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-ROW-CC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-06-ROW-CC-C1 @@ -2382,9 +1944,6 @@ msgid "TVA 6% Non EU Déductible" msgstr "BTW 6% Niet EU Aftrekbaar" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V81-06-ROW-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-06-ROW-CC-C2 -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V83-06-ROW-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V81-06-ROW-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-06-ROW-CC-C2 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V83-06-ROW-CC-C2 @@ -2392,73 +1951,61 @@ msgid "TVA 6% Non EU Récupérable" msgstr "BTW 6% Niet EU Verhaalbaar" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a4118 #: model:account.account.template,name:l10n_be.a4118 msgid "Taxe d'égalisation due" msgstr "Verschuldigde egalisatiebelasting" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a64000 #: model:account.account.template,name:l10n_be.a64000 msgid "Taxes sur autos et camions" msgstr "Verkeersbelasting bedrijfswagens" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a2500 #: model:account.account.template,name:l10n_be.a2500 msgid "Terrains" msgstr "Terreinen" #. module: l10n_be -#: model:account.account,name:l10n_be.1_trans #: model:account.account.template,name:l10n_be.trans msgid "Transferts" msgstr "Transferten" #. module: l10n_be -#: model:account.tax,description:l10n_be.1_attn_VAT-IN-V82-CAR-EXC-C1 #: model:account.tax.template,description:l10n_be.attn_VAT-IN-V82-CAR-EXC-C1 msgid "VAT 50% Non Déductible - Frais de voiture" msgstr "BTW 50% Niet Aftrekbaar - Auto kosten" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7001 #: model:account.account.template,name:l10n_be.a7001 msgid "Ventes dans les pays membres de la C.E.E. (marchandises)" msgstr "Verkopen: leden van de Europese gemeenschap (handelsgoederen)" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7011 #: model:account.account.template,name:l10n_be.a7011 msgid "Ventes dans les pays membres de la C.E.E. (produits finis)" msgstr "Verkopen: leden van de Europese gemeenschap (gereed product)" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7000 #: model:account.account.template,name:l10n_be.a7000 msgid "Ventes en Belgique (marchandises)" msgstr "Verkopen: België (handelsgoederen)" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7010 #: model:account.account.template,name:l10n_be.a7010 msgid "Ventes en Belgique (produits finis)" msgstr "Verkopen: België (gereed product)" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7002 #: model:account.account.template,name:l10n_be.a7002 msgid "Ventes à l'exportation (marchandises)" msgstr "Verkopen: export (handelsgoederen)" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a7012 #: model:account.account.template,name:l10n_be.a7012 msgid "Ventes à l'exportation (produits finis)" msgstr "Verkopen: export (gereed product)" #. module: l10n_be -#: model:account.account,name:l10n_be.1_a24100 #: model:account.account.template,name:l10n_be.a24100 msgid "Voitures" msgstr "Wagens" diff --git a/addons/l10n_do/models/chart_template.py b/addons/l10n_do/models/chart_template.py index 73e99589873..97d0833fef6 100644 --- a/addons/l10n_do/models/chart_template.py +++ b/addons/l10n_do/models/chart_template.py @@ -13,6 +13,49 @@ class WizardMultiChartsAccounts(models.TransientModel): return [ {'acc_name': _('Cash'), 'account_type': 'cash'}, {'acc_name': _('Caja Chica'), 'account_type': 'cash'}, + {'acc_name': _('Cheques Clientes'), 'account_type': 'cash'}, {'acc_name': _('Bank'), 'account_type': 'bank'} ] return super(WizardMultiChartsAccounts, self)._get_default_bank_account_ids() + + +class AccountChartTemplate(models.Model): + _inherit = "account.chart.template" + + @api.multi + def _prepare_all_journals(self, acc_template_ref, company, journals_dict=None): + """Create fiscal journals for buys""" + res = super(AccountChartTemplate, self)._prepare_all_journals( + acc_template_ref, company, journals_dict=journals_dict) + if not self == self.env.ref('l10n_do.do_chart_template'): + return res + for journal in res: + if journal['code'] == 'FACT': + journal['name'] = _('Compras Fiscales') + res += [{ + 'type': 'purchase', + 'name': _('Compras Informales'), + 'code': 'CINF', + 'company_id': company.id, + 'show_on_dashboard': True + }, { + 'type': 'purchase', + 'name': _('Gastos Menores'), + 'code': 'GASM', + 'company_id': company.id, + 'show_on_dashboard': True + }, { + 'type': 'purchase', + 'name': _('Compras al Exterior'), + 'code': 'CEXT', + 'company_id': company.id, + 'show_on_dashboard': True + }, { + 'type': 'purchase', + 'name': _('Gastos No Deducibles'), + 'code': 'GASTO', + 'company_id': company.id, + 'show_on_dashboard': True + }] + return res + diff --git a/addons/l10n_fr_certification/data/account_move.xml b/addons/l10n_fr_certification/data/account_move.xml index 2794e6364f9..c4d735d2b14 100644 --- a/addons/l10n_fr_certification/data/account_move.xml +++ b/addons/l10n_fr_certification/data/account_move.xml @@ -3,6 +3,7 @@ <field name="name">Data Inalterability Check</field> <field name="model_id" ref="account.model_account_move"/> <field name="type">ir.actions.server</field> + <field name="state">code</field> <field name="code"> action = env['account.move']._check_hash_integrity(env.user.company_id.id) </field> @@ -12,6 +13,7 @@ <field name="name">Get the certification now!</field> <field name="type">ir.actions.server</field> <field name="model_id" ref="account.model_res_company"/> + <field name="state">code</field> <field name="code"> db_uuid = env['ir.config_parameter'].sudo().get_param('database.uuid') action = {"type": "ir.actions.act_url", diff --git a/addons/l10n_fr_pos_cert/data/pos_inalterability.xml b/addons/l10n_fr_pos_cert/data/pos_inalterability.xml index ace4c3de24d..377204b73c6 100644 --- a/addons/l10n_fr_pos_cert/data/pos_inalterability.xml +++ b/addons/l10n_fr_pos_cert/data/pos_inalterability.xml @@ -8,6 +8,7 @@ <field name="name">Pos Orders Inalterability Check</field> <field name="model_id" ref="point_of_sale.model_pos_order"/> <field name="type">ir.actions.server</field> + <field name="state">code</field> <field name="code"> action = env['pos.order']._check_hash_integrity(env.user.company_id.id) </field> diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py index e49fbb61363..47e0c37408f 100644 --- a/addons/mail/models/mail_activity.py +++ b/addons/mail/models/mail_activity.py @@ -150,7 +150,8 @@ class MailActivity(models.Model): @api.onchange('recommended_activity_type_id') def _onchange_recommended_activity_type_id(self): - self.activity_type_id = self.recommended_activity_type_id + if self.recommended_activity_type_id: + self.activity_type_id = self.recommended_activity_type_id @api.multi def _check_access(self, operation): diff --git a/addons/mail/static/src/js/services/chat_manager.js b/addons/mail/static/src/js/services/chat_manager.js index 8ae45486e16..074d3d192d3 100644 --- a/addons/mail/static/src/js/services/chat_manager.js +++ b/addons/mail/static/src/js/services/chat_manager.js @@ -1279,7 +1279,15 @@ var ChatManager = AbstractService.extend({ _.each(_.keys(this.emojiSubstitutions), function (key) { var escapedKey = String(key).replace(/([.*+?=^!:${}()|[\]/\\])/g, '\\$1'); var regexp = new RegExp("(?:^|\\s|<[a-z]*>)(" + escapedKey + ")(?=\\s|$|</[a-z]*>)", "g"); + var msg_bak = msg.body; msg.body = msg.body.replace(regexp, ' <span class="o_mail_emoji">'+self.emojiSubstitutions[key]+'</span> '); + // Idiot-proof limit. If the user had the amazing idea of copy-pasting thousands of emojis, + // the image rendering can lead to memory overflow errors on some browsers (e.g. Chrome). + // Set an arbitrary limit to 200 from which we simply don't replace them (anyway, they are + // already replaced by the unicode counterpart). + if (_.str.count(msg.body, 'o_mail_emoji') > 200) { + msg.body = msg_bak; + } }); function propertyDescr(channel) { diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 64422c2c0d7..8b39d73d3ae 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -558,7 +558,7 @@ class MrpProduction(models.Model): order._cal_price(moves_to_do) moves_to_finish = order.move_finished_ids.filtered(lambda x: x.state not in ('done','cancel')) moves_to_finish._action_done() - #order.action_assign() + order.action_assign() consume_move_lines = moves_to_do.mapped('active_move_line_ids') for moveline in moves_to_finish.mapped('active_move_line_ids'): if moveline.product_id == order.product_id and moveline.move_id.has_tracking != 'none': diff --git a/addons/payment/models/__init__.py b/addons/payment/models/__init__.py index 3a1c7ce052a..ed704df85d1 100644 --- a/addons/payment/models/__init__.py +++ b/addons/payment/models/__init__.py @@ -3,3 +3,4 @@ from . import payment_acquirer from . import res_partner from . import account_payment +from . import chart_template diff --git a/addons/payment/models/chart_template.py b/addons/payment/models/chart_template.py new file mode 100644 index 00000000000..515103316be --- /dev/null +++ b/addons/payment/models/chart_template.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models, _ + + +class WizardMultiChartsAccounts(models.TransientModel): + _inherit = 'wizard.multi.charts.accounts' + + @api.multi + def _create_bank_journals_from_o2m(self, company, acc_template_ref): + res = super(WizardMultiChartsAccounts, self)._create_bank_journals_from_o2m(company, acc_template_ref) + + # Try to generate the missing journals + return res + self.env['payment.acquirer']._create_missing_journal_for_acquirers(company=company) diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py index a67aea945d7..2d07a174a7e 100644 --- a/addons/payment/models/payment_acquirer.py +++ b/addons/payment/models/payment_acquirer.py @@ -9,6 +9,7 @@ from odoo import api, exceptions, fields, models, _ from odoo.tools import consteq, float_round, image_resize_images, image_resize_image, ustr from odoo.addons.base.models import ir_module from odoo.exceptions import ValidationError +from odoo import api, SUPERUSER_ID _logger = logging.getLogger(__name__) @@ -21,6 +22,11 @@ def _partner_split_name(partner_name): return [' '.join(partner_name.split()[:-1]), ' '.join(partner_name.split()[-1:])] +def create_missing_journal_for_acquirers(cr, registry): + env = api.Environment(cr, SUPERUSER_ID, {}) + env['payment.acquirer']._create_missing_journal_for_acquirers() + + class PaymentAcquirer(models.Model): """ Acquirer Model. Each specific acquirer can extend the model by adding its own fields, using the acquirer_name as a prefix for the new fields. @@ -52,6 +58,9 @@ class PaymentAcquirer(models.Model): _description = 'Payment Acquirer' _order = 'website_published desc, sequence, name' + def _get_default_view_template_id(self): + return self.env.ref('payment.default_acquirer_button', raise_if_not_found=False) + name = fields.Char('Name', required=True, translate=True) description = fields.Html('Description') sequence = fields.Integer('Sequence', default=10, help="Determine the display order") @@ -62,7 +71,8 @@ class PaymentAcquirer(models.Model): 'res.company', 'Company', default=lambda self: self.env.user.company_id.id, required=True) view_template_id = fields.Many2one( - 'ir.ui.view', 'Form Button Template', required=True) + 'ir.ui.view', 'Form Button Template', required=True, + default=_get_default_view_template_id) registration_view_template_id = fields.Many2one( 'ir.ui.view', 'S2S Form Template', domain=[('type', '=', 'qweb')], help="Template for method registration") @@ -197,6 +207,58 @@ class PaymentAcquirer(models.Model): """ return dict(authorize=[], tokenize=[], fees=[]) + @api.multi + def _prepare_account_journal_vals(self): + '''Prepare the values to create the acquirer's journal. + :return: a dictionary to create a account.journal record. + ''' + self.ensure_one() + account_vals = self.env['account.journal']._prepare_liquidity_account( + self.name, self.company_id, None, 'bank') + account_vals['user_type_id'] = self.env.ref('account.data_account_type_current_assets').id + account_vals['reconcile'] = True + account = self.env['account.account'].create(account_vals) + return { + 'name': self.name, + 'code': self.name.upper(), + 'sequence': 999, + 'type': 'bank', + 'company_id': self.company_id.id, + 'default_debit_account_id': account.id, + 'default_credit_account_id': account.id, + # Show the journal on dashboard if the acquirer is published on the website. + 'show_on_dashboard': self.website_published, + # Don't show payment methods in the backend. + 'inbound_payment_method_ids': [], + 'outbound_payment_method_ids': [], + } + + @api.model + def _create_missing_journal_for_acquirers(self, company=None): + '''Create the journal for active acquirers. + We want one journal per acquirer. However, we can't create them during the 'create' of the payment.acquirer + because every acquirers are defined on the 'payment' module but is active only when installing their own module + (e.g. payment_paypal for Paypal). We can't do that in such modules because we have no guarantee the chart template + is already installed. + ''' + # Search for installed acquirers modules. + # If this method is triggered by a post_init_hook, the module is 'to install'. + # If the trigger comes from the chart template wizard, the modules are already installed. + acquirer_modules = self.env['ir.module.module'].search( + [('name', 'like', 'payment_%'), ('state', 'in', ('to install', 'installed'))]) + acquirer_names = [a.name.split('_')[1] for a in acquirer_modules] + + # Search for acquirers having no journal + company = company or self.env.user.company_id + acquirers = self.env['payment.acquirer'].search( + [('provider', 'in', acquirer_names), ('journal_id', '=', False), ('company_id', '=', company.id)]) + + journals = self.env['account.journal'] + for acquirer in acquirers.filtered(lambda l: not l.journal_id and l.company_id.chart_template_id): + acquirer.journal_id = self.env['account.journal'].create(acquirer._prepare_account_journal_vals()) + journals += acquirer.journal_id + return journals + @api.model def create(self, vals): image_resize_images(vals) @@ -209,7 +271,13 @@ class PaymentAcquirer(models.Model): @api.multi def toggle_website_published(self): - self.write({'website_published': not self.website_published}) + ''' When clicking on the website publish toggle button, the website_published is reversed and + the acquirer journal is set or not in favorite on the dashboard. + ''' + self.ensure_one() + self.website_published = not self.website_published + if self.journal_id: + self.journal_id.show_on_dashboard = self.website_published return True @api.multi diff --git a/addons/payment/views/payment_views.xml b/addons/payment/views/payment_views.xml index f3c8c0af16d..84d45c47eae 100644 --- a/addons/payment/views/payment_views.xml +++ b/addons/payment/views/payment_views.xml @@ -81,7 +81,7 @@ </page> <page string="Configuration"> <group name="acquirer_config"> - <field name="journal_id" context="{'default_type': 'bank'}" required="1"/> + <field name="journal_id" context="{'default_type': 'bank'}"/> <field name="capture_manually" attrs="{'invisible': [('authorize_implemented', '=', False)]}"/> <field name="save_token" widget="radio" attrs="{'invisible': ['|', ('token_implemented', '=', False), ('payment_flow', '=', 's2s')]}"/> <field name="fees_active" attrs="{'invisible': [('fees_implemented', '=', False)]}"/> @@ -113,7 +113,7 @@ </div> <field name="registration_view_template_id" groups="base.group_no_one"/> <field name="payment_icon_ids" widget="many2many_tags"/> - <field name="payment_flow" widget="radio"/> + <field name="payment_flow" widget="radio" attrs="{'invisible': [('token_implemented', '=', False)]}"/> </group> </page> </notebook> diff --git a/addons/payment_adyen/__init__.py b/addons/payment_adyen/__init__.py index 8c67f893b37..f2ff55f0433 100644 --- a/addons/payment_adyen/__init__.py +++ b/addons/payment_adyen/__init__.py @@ -3,3 +3,4 @@ from . import models from . import controllers +from odoo.addons.payment.models.payment_acquirer import create_missing_journal_for_acquirers diff --git a/addons/payment_adyen/__manifest__.py b/addons/payment_adyen/__manifest__.py index 1e26a8808ca..8b04a9834e2 100644 --- a/addons/payment_adyen/__manifest__.py +++ b/addons/payment_adyen/__manifest__.py @@ -13,4 +13,5 @@ 'data/payment_acquirer_data.xml', ], 'installable': True, + 'post_init_hook': 'create_missing_journal_for_acquirers', } diff --git a/addons/payment_authorize/__init__.py b/addons/payment_authorize/__init__.py index 8c67f893b37..f2ff55f0433 100644 --- a/addons/payment_authorize/__init__.py +++ b/addons/payment_authorize/__init__.py @@ -3,3 +3,4 @@ from . import models from . import controllers +from odoo.addons.payment.models.payment_acquirer import create_missing_journal_for_acquirers diff --git a/addons/payment_authorize/__manifest__.py b/addons/payment_authorize/__manifest__.py index 4a8eafa8b73..af6c1e946b9 100644 --- a/addons/payment_authorize/__manifest__.py +++ b/addons/payment_authorize/__manifest__.py @@ -13,4 +13,5 @@ 'data/payment_acquirer_data.xml', ], 'installable': True, + 'post_init_hook': 'create_missing_journal_for_acquirers', } diff --git a/addons/payment_buckaroo/__init__.py b/addons/payment_buckaroo/__init__.py index 8c67f893b37..f2ff55f0433 100644 --- a/addons/payment_buckaroo/__init__.py +++ b/addons/payment_buckaroo/__init__.py @@ -3,3 +3,4 @@ from . import models from . import controllers +from odoo.addons.payment.models.payment_acquirer import create_missing_journal_for_acquirers diff --git a/addons/payment_buckaroo/__manifest__.py b/addons/payment_buckaroo/__manifest__.py index 3e56a451c52..f08e9152473 100644 --- a/addons/payment_buckaroo/__manifest__.py +++ b/addons/payment_buckaroo/__manifest__.py @@ -13,4 +13,5 @@ 'data/payment_acquirer_data.xml', ], 'installable': True, + 'post_init_hook': 'create_missing_journal_for_acquirers', } diff --git a/addons/payment_ogone/__init__.py b/addons/payment_ogone/__init__.py index 8c67f893b37..f2ff55f0433 100644 --- a/addons/payment_ogone/__init__.py +++ b/addons/payment_ogone/__init__.py @@ -3,3 +3,4 @@ from . import models from . import controllers +from odoo.addons.payment.models.payment_acquirer import create_missing_journal_for_acquirers diff --git a/addons/payment_ogone/__manifest__.py b/addons/payment_ogone/__manifest__.py index 1fd1ee9c55b..3866d1e115b 100644 --- a/addons/payment_ogone/__manifest__.py +++ b/addons/payment_ogone/__manifest__.py @@ -13,4 +13,5 @@ 'data/payment_acquirer_data.xml', ], 'installable': True, + 'post_init_hook': 'create_missing_journal_for_acquirers', } diff --git a/addons/payment_paypal/__init__.py b/addons/payment_paypal/__init__.py index 8c67f893b37..f2ff55f0433 100644 --- a/addons/payment_paypal/__init__.py +++ b/addons/payment_paypal/__init__.py @@ -3,3 +3,4 @@ from . import models from . import controllers +from odoo.addons.payment.models.payment_acquirer import create_missing_journal_for_acquirers diff --git a/addons/payment_paypal/__manifest__.py b/addons/payment_paypal/__manifest__.py index 352b130e051..bf2e9e90b51 100644 --- a/addons/payment_paypal/__manifest__.py +++ b/addons/payment_paypal/__manifest__.py @@ -13,4 +13,5 @@ 'data/payment_acquirer_data.xml', ], 'installable': True, + 'post_init_hook': 'create_missing_journal_for_acquirers', } diff --git a/addons/payment_payumoney/__init__.py b/addons/payment_payumoney/__init__.py index 8c67f893b37..f2ff55f0433 100644 --- a/addons/payment_payumoney/__init__.py +++ b/addons/payment_payumoney/__init__.py @@ -3,3 +3,4 @@ from . import models from . import controllers +from odoo.addons.payment.models.payment_acquirer import create_missing_journal_for_acquirers diff --git a/addons/payment_payumoney/__manifest__.py b/addons/payment_payumoney/__manifest__.py index 794ba6b6de1..66f83456fcb 100644 --- a/addons/payment_payumoney/__manifest__.py +++ b/addons/payment_payumoney/__manifest__.py @@ -16,4 +16,5 @@ 'views/payment_payumoney_templates.xml', 'data/payment_acquirer_data.xml', ], + 'post_init_hook': 'create_missing_journal_for_acquirers', } diff --git a/addons/payment_sips/__init__.py b/addons/payment_sips/__init__.py index f7209b17100..c7d74c9c782 100644 --- a/addons/payment_sips/__init__.py +++ b/addons/payment_sips/__init__.py @@ -1,2 +1,3 @@ from . import models from . import controllers +from odoo.addons.payment.models.payment_acquirer import create_missing_journal_for_acquirers diff --git a/addons/payment_sips/__manifest__.py b/addons/payment_sips/__manifest__.py index 6039f962009..2764807c5ea 100644 --- a/addons/payment_sips/__manifest__.py +++ b/addons/payment_sips/__manifest__.py @@ -20,4 +20,5 @@ payments acquirer using Worldline SIPS.""", 'data/payment_acquirer_data.xml', ], 'installable': True, + 'post_init_hook': 'create_missing_journal_for_acquirers', } diff --git a/addons/payment_stripe/__init__.py b/addons/payment_stripe/__init__.py index 8c67f893b37..f2ff55f0433 100644 --- a/addons/payment_stripe/__init__.py +++ b/addons/payment_stripe/__init__.py @@ -3,3 +3,4 @@ from . import models from . import controllers +from odoo.addons.payment.models.payment_acquirer import create_missing_journal_for_acquirers diff --git a/addons/payment_stripe/__manifest__.py b/addons/payment_stripe/__manifest__.py index 6eb664791cb..247fe74859b 100644 --- a/addons/payment_stripe/__manifest__.py +++ b/addons/payment_stripe/__manifest__.py @@ -14,4 +14,5 @@ ], 'images': ['static/description/icon.png'], 'installable': True, + 'post_init_hook': 'create_missing_journal_for_acquirers', } diff --git a/addons/payment_transfer/__init__.py b/addons/payment_transfer/__init__.py index 8c67f893b37..f2ff55f0433 100644 --- a/addons/payment_transfer/__init__.py +++ b/addons/payment_transfer/__init__.py @@ -3,3 +3,4 @@ from . import models from . import controllers +from odoo.addons.payment.models.payment_acquirer import create_missing_journal_for_acquirers diff --git a/addons/payment_transfer/__manifest__.py b/addons/payment_transfer/__manifest__.py index 9f8704467dc..530fe49ede4 100644 --- a/addons/payment_transfer/__manifest__.py +++ b/addons/payment_transfer/__manifest__.py @@ -14,4 +14,5 @@ ], 'installable': True, 'auto_install': True, + 'post_init_hook': 'create_missing_journal_for_acquirers', } diff --git a/addons/payment_transfer/models/payment.py b/addons/payment_transfer/models/payment.py index 00a34ac0ad4..18c74d2246d 100644 --- a/addons/payment_transfer/models/payment.py +++ b/addons/payment_transfer/models/payment.py @@ -15,6 +15,19 @@ class TransferPaymentAcquirer(models.Model): provider = fields.Selection(selection_add=[('transfer', 'Wire Transfer')], default='transfer') + @api.model + def _create_missing_journal_for_acquirers(self, company=None): + # By default, the wire transfer method uses the default Bank journal. + company = company or self.env.user.company_id + acquirers = self.env['payment.acquirer'].search( + [('provider', '=', 'transfer'), ('journal_id', '=', False), ('company_id', '=', company.id)]) + + bank_journal = self.env['account.journal'].search( + [('type', '=', 'bank'), ('company_id', '=', company.id)], limit=1) + if bank_journal: + acquirers.write({'journal_id': bank_journal.id}) + return super(TransferPaymentAcquirer, self)._create_missing_journal_for_acquirers(company=company) + def transfer_get_form_action_url(self): return '/payment/transfer/feedback' diff --git a/addons/product/models/product.py b/addons/product/models/product.py index c0a892a3853..b00eaa33f62 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -230,9 +230,9 @@ class ProductProduct(models.Model): for supplier_info in self.seller_ids: if supplier_info.name.id == self._context.get('partner_id'): product_name = supplier_info.product_name or self.default_code + self.partner_ref = '%s%s' % (self.code and '[%s] ' % self.code or '', product_name) else: - product_name = self.name - self.partner_ref = '%s%s' % (self.code and '[%s] ' % self.code or '', product_name) + self.partner_ref = self.name_get()[0][1] @api.one @api.depends('image_variant', 'product_tmpl_id.image') @@ -431,7 +431,12 @@ class ProductProduct(models.Model): limit2 = (limit - len(products)) if limit else False products += self.search(args + [('name', operator, name), ('id', 'not in', products.ids)], limit=limit2) elif not products and operator in expression.NEGATIVE_TERM_OPERATORS: - products = self.search(args + ['&', ('default_code', operator, name), ('name', operator, name)], limit=limit) + domain = expression.OR([ + ['&', ('default_code', operator, name), ('name', operator, name)], + ['&', ('default_code', '=', False), ('name', operator, name)], + ]) + domain = expression.AND([args, domain]) + products = self.search(domain, limit=limit) if not products and operator in positive_operators: ptrn = re.compile('(\[(.*?)\])') res = ptrn.search(name) diff --git a/addons/product/tests/test_variants.py b/addons/product/tests/test_variants.py index 7917a0d4a2b..804bbc55c95 100644 --- a/addons/product/tests/test_variants.py +++ b/addons/product/tests/test_variants.py @@ -40,6 +40,15 @@ class TestVariantsSearch(TransactionCase): self.assertIn(self.product_shirt_template, search_value, 'Shirt should be found searching L') + def test_name_search(self): + self.product_slip_template = self.env['product.template'].create({ + 'name': 'Slip', + }) + res = self.env['product.product'].name_search('Shirt', [], 'not ilike', None) + res_ids = [r[0] for r in res] + self.assertIn(self.product_slip_template.product_variant_ids.id, res_ids, + 'Slip should be found searching \'not ilike\'') + class TestVariants(common.TestProductCommon): diff --git a/addons/purchase/models/account_invoice.py b/addons/purchase/models/account_invoice.py index 4847ddf11ee..7f170d4e814 100644 --- a/addons/purchase/models/account_invoice.py +++ b/addons/purchase/models/account_invoice.py @@ -168,6 +168,11 @@ class AccountInvoice(models.Model): valuation_price_unit = i_line.purchase_line_id.product_uom._compute_price(i_line.purchase_line_id.price_unit, i_line.uom_id) stock_move_obj = self.env['stock.move'] valuation_stock_move = stock_move_obj.search([('purchase_line_id', '=', i_line.purchase_line_id.id), ('state', '=', 'done')]) + if self.type == 'in_refund': + valuation_stock_move = valuation_stock_move.filtered(lambda m: m._is_out()) + elif self.type == 'in_invoice': + valuation_stock_move = valuation_stock_move.filtered(lambda m: m._is_in()) + if valuation_stock_move: valuation_price_unit_total = 0 valuation_total_qty = 0 diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index 994142c7362..08995f2aac6 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -92,7 +92,7 @@ class PurchaseOrder(models.Model): @api.depends('picking_ids', 'picking_ids.state') def _compute_is_shipped(self): for order in self: - if order.picking_ids and all([x.state == 'done' for x in order.picking_ids]): + if order.picking_ids and all([x.state in ['done', 'cancel'] for x in order.picking_ids]): order.is_shipped = True READONLY_STATES = { @@ -1054,7 +1054,7 @@ class ProcurementRule(models.Model): gpo = self.group_propagation_option group = (gpo == 'fixed' and self.group_id.id) or \ - (gpo == 'propagate' and 'group_id' in values and values['group_id'].id) or False + (gpo == 'propagate' and values.get('group_id') and values['group_id'].id) or False return { 'partner_id': partner.id, diff --git a/addons/purchase/tests/test_stockvaluation.py b/addons/purchase/tests/test_stockvaluation.py index cb5e4b2040e..f7e320a50ce 100644 --- a/addons/purchase/tests/test_stockvaluation.py +++ b/addons/purchase/tests/test_stockvaluation.py @@ -5,6 +5,7 @@ import time from datetime import datetime from odoo.tests.common import TransactionCase +from odoo.addons.account.tests.account_test_classes import AccountingTestCase from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT @@ -271,3 +272,139 @@ class TestStockValuation(TransactionCase): self.assertEqual(move2.price_unit, 100) self.assertEqual(move2.product_qty, 5) + +class TestStockValuationWithCOA(AccountingTestCase): + def setUp(self): + super(TestStockValuationWithCOA, self).setUp() + self.supplier_location = self.env.ref('stock.stock_location_suppliers') + self.stock_location = self.env.ref('stock.stock_location_stock') + self.partner_id = self.env.ref('base.res_partner_1') + self.product1 = self.env.ref('product.product_product_8') + Account = self.env['account.account'] + self.stock_input_account = Account.create({ + 'name': 'Stock Input', + 'code': 'StockIn', + 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, + }) + self.stock_output_account = Account.create({ + 'name': 'Stock Output', + 'code': 'StockOut', + 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, + }) + self.stock_valuation_account = Account.create({ + 'name': 'Stock Valuation', + 'code': 'Stock Valuation', + 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, + }) + self.stock_journal = self.env['account.journal'].create({ + 'name': 'Stock Journal', + 'code': 'STJTEST', + 'type': 'general', + }) + self.product1.categ_id.write({ + 'property_stock_account_input_categ_id': self.stock_input_account.id, + 'property_stock_account_output_categ_id': self.stock_output_account.id, + 'property_stock_valuation_account_id': self.stock_valuation_account.id, + 'property_stock_journal': self.stock_journal.id, + }) + + def test_fifo_anglosaxon_return(self): + self.env.user.company_id.anglo_saxon_accounting = True + self.product1.product_tmpl_id.cost_method = 'fifo' + self.product1.product_tmpl_id.valuation = 'real_time' + self.product1.product_tmpl_id.invoice_policy = 'delivery' + price_diff_account = self.env['account.account'].create({ + 'name': 'price diff account', + 'code': 'price diff account', + 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, + }) + self.product1.property_account_creditor_price_difference = price_diff_account + + # Receive 10@10 ; create the vendor bill + po1 = self.env['purchase.order'].create({ + 'partner_id': self.partner_id.id, + 'order_line': [ + (0, 0, { + 'name': self.product1.name, + 'product_id': self.product1.id, + 'product_qty': 10.0, + 'product_uom': self.product1.uom_po_id.id, + 'price_unit': 10.0, + 'date_planned': datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT), + }), + ], + }) + po1.button_confirm() + receipt_po1 = po1.picking_ids[0] + receipt_po1.move_lines.quantity_done = 10 + receipt_po1.button_validate() + + invoice_po1 = self.env['account.invoice'].create({ + 'partner_id': self.partner_id.id, + 'purchase_id': po1.id, + 'account_id': self.partner_id.property_account_payable_id.id, + 'type': 'in_invoice', + }) + invoice_po1.purchase_order_change() + invoice_po1.action_invoice_open() + + # Receive 10@20 ; create the vendor bill + po2 = self.env['purchase.order'].create({ + 'partner_id': self.partner_id.id, + 'order_line': [ + (0, 0, { + 'name': self.product1.name, + 'product_id': self.product1.id, + 'product_qty': 10.0, + 'product_uom': self.product1.uom_po_id.id, + 'price_unit': 20.0, + 'date_planned': datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT), + }), + ], + }) + po2.button_confirm() + receipt_po2 = po2.picking_ids[0] + receipt_po2.move_lines.quantity_done = 10 + receipt_po2.button_validate() + + invoice_po2 = self.env['account.invoice'].create({ + 'partner_id': self.partner_id.id, + 'purchase_id': po2.id, + 'account_id': self.partner_id.property_account_payable_id.id, + 'type': 'in_invoice', + }) + invoice_po2.purchase_order_change() + invoice_po2.action_invoice_open() + + # valuation of product1 should be 300 + self.assertEqual(self.product1.stock_value, 300) + + # return the second po + stock_return_picking = self.env['stock.return.picking']\ + .with_context(active_ids=receipt_po2.ids, active_id=receipt_po2.ids[0])\ + .create({}) + stock_return_picking.product_return_moves.quantity = 10 + stock_return_picking_action = stock_return_picking.create_returns() + return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id']) + return_pick.move_lines[0].move_line_ids[0].qty_done = 10 + return_pick.do_transfer() + + # valuation of product1 should be 200 as the first items will be sent out + self.assertEqual(self.product1.stock_value, 200) + + # create a credit note for po2 + creditnote_po2 = self.env['account.invoice'].create({ + 'partner_id': self.partner_id.id, + 'purchase_id': po2.id, + 'account_id': self.partner_id.property_account_payable_id.id, + 'type': 'in_refund', + }) + + creditnote_po2.purchase_order_change() + creditnote_po2.invoice_line_ids[0].quantity = 10 + creditnote_po2.action_invoice_open() + + # check the anglo saxon entries + price_diff_entry = self.env['account.move.line'].search([('account_id', '=', price_diff_account.id)]) + self.assertEqual(price_diff_entry.credit, 100) + diff --git a/addons/sale_payment/models/payment.py b/addons/sale_payment/models/payment.py index 8076addab09..831af37550f 100644 --- a/addons/sale_payment/models/payment.py +++ b/addons/sale_payment/models/payment.py @@ -3,6 +3,7 @@ import logging from odoo import api, fields, models, _ +from odoo.exceptions import UserError from odoo.tools import float_compare _logger = logging.getLogger(__name__) @@ -84,8 +85,16 @@ class PaymentTransaction(models.Model): # force_company needed for company_dependent fields ctx_company = {'company_id': self.sale_order_id.company_id.id, 'force_company': self.sale_order_id.company_id.id} - created_invoice = self.sale_order_id.with_context(**ctx_company).action_invoice_create() - created_invoice = self.env['account.invoice'].browse(created_invoice).with_context(**ctx_company) + + # We might fail to create the invoice because there is no invoiceable lines. This will + # raise a UserError and break the workflow. Better catch the error. + try: + created_invoice = self.sale_order_id.with_context(**ctx_company).action_invoice_create() + created_invoice = self.env['account.invoice'].browse(created_invoice).with_context(**ctx_company) + except UserError: + _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, exc_info=True) + return if created_invoice: _logger.info('<%s> transaction completed, auto-generated invoice %s (ID %s) for %s (ID %s)', diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 5ab7b982f2f..f3788f8592f 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -487,9 +487,19 @@ class StockMove(models.Model): } def _do_unreserve(self): - if any(move.state in ('done', 'cancel') for move in self): - raise UserError(_('Cannot unreserve a done move')) - self.mapped('move_line_ids').unlink() + moves_to_unreserve = self.env['stock.move'] + for move in self: + if move.state == 'cancel': + # We may have cancelled move in an open picking in a "propagate_cancel" scenario. + continue + if move.state == 'done': + if move.scrapped: + # We may have done move in an open picking in a scrap scenario. + continue + else: + raise UserError(_('Cannot unreserve a done move')) + moves_to_unreserve |= move + moves_to_unreserve.mapped('move_line_ids').unlink() return True def _push_apply(self): @@ -590,7 +600,7 @@ class StockMove(models.Model): # We are using propagate to False in order to not cancel destination moves merged in moves[0] moves_to_unlink.write({'propagate': False}) moves_to_unlink._action_cancel() - moves_to_unlink.unlink() + moves_to_unlink.sudo().unlink() return (self | self.env['stock.move'].concat(*moves_to_merge)) - moves_to_unlink def _get_relevant_state_among_moves(self): @@ -806,7 +816,12 @@ class StockMove(models.Model): } if quantity: uom_quantity = self.product_id.uom_id._compute_quantity(quantity, self.product_uom, rounding_method='HALF-UP') - vals = dict(vals, product_uom_qty=uom_quantity) + uom_quantity_back_to_product_uom = self.product_uom._compute_quantity(uom_quantity, self.product_id.uom_id, rounding_method='HALF-UP') + rounding = self.env['decimal.precision'].precision_get('Product Unit of Measure') + if float_compare(quantity, uom_quantity_back_to_product_uom, precision_digits=rounding) == 0: + vals = dict(vals, product_uom_qty=uom_quantity) + else: + vals = dict(vals, product_uom_qty=quantity, product_uom_id=self.product_id.uom_id.id) if reserved_quant: vals = dict( vals, @@ -836,11 +851,20 @@ class StockMove(models.Model): # is if the move's unit of measure's rounding does not allow fractional reservation. We chose # to convert `taken_quantity` to the move's unit of measure with a down rounding method and # then get it back in the quants unit of measure with an half-up rounding_method. This - # way, we'll never reserve more than allowed. - taken_quantity_move_uom = self.product_id.uom_id._compute_quantity(taken_quantity, self.product_uom, rounding_method='DOWN') - taken_quantity = self.product_uom._compute_quantity(taken_quantity_move_uom, self.product_id.uom_id, rounding_method='HALF-UP') + # way, we'll never reserve more than allowed. We do not apply this logic if + # `available_quantity` is brought by a chained move line. In this case, `_prepare_move_line_vals` + # will take care of changing the UOM to the UOM of the product. + if not strict: + taken_quantity_move_uom = self.product_id.uom_id._compute_quantity(taken_quantity, self.product_uom, rounding_method='DOWN') + taken_quantity = self.product_uom._compute_quantity(taken_quantity_move_uom, self.product_id.uom_id, rounding_method='HALF-UP') quants = [] + + if self.product_id.tracking == 'serial': + rounding = self.env['decimal.precision'].precision_get('Product Unit of Measure') + if float_compare(taken_quantity, int(taken_quantity), precision_digits=rounding) != 0: + taken_quantity = 0 + try: if not float_is_zero(taken_quantity, precision_rounding=self.product_id.uom_id.rounding): quants = self.env['stock.quant']._update_reserved_quantity( @@ -860,7 +884,7 @@ class StockMove(models.Model): to_update = self.move_line_ids.filtered(lambda m: m.product_id.tracking != 'serial' and m.location_id.id == reserved_quant.location_id.id and m.lot_id.id == reserved_quant.lot_id.id and m.package_id.id == reserved_quant.package_id.id and m.owner_id.id == reserved_quant.owner_id.id) if to_update: - to_update[0].with_context(bypass_reservation_update=True).product_uom_qty += self.product_id.uom_id._compute_quantity(quantity, self.product_uom, rounding_method='HALF-UP') + to_update[0].with_context(bypass_reservation_update=True).product_uom_qty += self.product_id.uom_id._compute_quantity(quantity, to_update.product_uom_id, rounding_method='HALF-UP') else: if self.product_id.tracking == 'serial': for i in range(0, int(quantity)): @@ -1017,8 +1041,8 @@ class StockMove(models.Model): # create the extra moves extra_move_quantity = float_round( self.quantity_done - self.product_uom_qty, - precision_rounding=self.product_uom.rounding, - rounding_method ='UP') + precision_rounding=rounding, + rounding_method='HALF-UP') extra_move_vals = self._prepare_extra_move_vals(extra_move_quantity) extra_move = self.copy(default=extra_move_vals) if extra_move.picking_id: @@ -1088,7 +1112,7 @@ class StockMove(models.Model): pass # If you were already putting stock.move.lots on the next one in the work order, transfer those to the new move - move.move_line_ids.filtered(lambda x: x.qty_done == 0.0).write({'move_id': new_move}) + move.move_line_ids.filtered(lambda x: x.qty_done == 0.0).write({'move_id': new_move, 'product_uom_qty': 0}) move.move_line_ids._action_done() # Check the consistency of the result packages; there should be an unique location across # the contained quants. diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py index c7f24401108..32e815b7af3 100644 --- a/addons/stock/tests/test_move.py +++ b/addons/stock/tests/test_move.py @@ -884,6 +884,47 @@ class StockMove(TransactionCase): move._action_done() self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.customer_location), 12.0) + def test_availability_7(self): + """ Check that, in the scenario where a move is in a bigger uom than the uom of the quants + and this uom only allows entire numbers, we only reserve quantity honouring the uom's + rounding even if the quantity is set across multiple quants. + """ + # on the dozen uom, set the rounding set 1.0 + self.uom_dozen.rounding = 1 + + # make 12 quants of 1 + for i in range(1, 13): + lot_id = self.env['stock.production.lot'].create({ + 'name': 'lot%s' % str(i), + 'product_id': self.product2.id, + }) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1.0, lot_id=lot_id) + + # the move should be reserved + move = self.env['stock.move'].create({ + 'name': 'test_availability_7', + 'location_id': self.stock_location.id, + 'location_dest_id': self.customer_location.id, + 'product_id': self.product2.id, + 'product_uom': self.uom_dozen.id, + 'product_uom_qty': 1, + }) + move._action_confirm() + move._action_assign() + self.assertEqual(move.state, 'assigned') + self.assertEqual(len(move.move_line_ids.mapped('product_uom_id')), 1) + self.assertEqual(move.move_line_ids.mapped('product_uom_id'), self.uom_unit) + + for move_line in move.move_line_ids: + move_line.qty_done = 1 + move._action_done() + + self.assertEqual(move.product_uom_qty, 1) + self.assertEqual(move.product_uom.id, self.uom_dozen.id) + self.assertEqual(move.state, 'done') + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.customer_location), 12.0) + self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.customer_location)), 12) + def test_unreserve_1(self): """ Check that unreserving a stock move sets the products reserved as available and set the state back to confirmed. @@ -1486,7 +1527,10 @@ class StockMove(TransactionCase): # the second move should not be reservable because of the rounding on the dozen move_pack_cust._action_assign() - self.assertEqual(move_pack_cust.state, 'waiting') + self.assertEqual(move_pack_cust.state, 'partially_available') + move_line_pack_cust = move_pack_cust.move_line_ids + self.assertEqual(move_line_pack_cust.product_uom_qty, 6) + self.assertEqual(move_line_pack_cust.product_uom_id.id, self.uom_unit.id) # move a dozen on the backorder to see how we handle the extra move backorder = self.env['stock.picking'].search([('backorder_id', '=', picking_stock_pack.id)]) @@ -1514,6 +1558,152 @@ class StockMove(TransactionCase): # the second move should now be reservable move_pack_cust._action_assign() self.assertEqual(move_pack_cust.state, 'assigned') + self.assertEqual(move_line_pack_cust.product_uom_qty, 12) + self.assertEqual(move_line_pack_cust.product_uom_id.id, self.uom_unit.id) + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, move_stock_pack.location_dest_id), 6) + + def test_link_assign_8(self): + """ Set the rounding of the dozen to 1.0, create a chain of two move for a dozen, the product + concerned is tracked by serial number. Check that the flow is ok. + """ + # on the dozen uom, set the rounding set 1.0 + self.uom_dozen.rounding = 1 + + # 6 units are available in stock + for i in range(1, 13): + lot_id = self.env['stock.production.lot'].create({ + 'name': 'lot%s' % str(i), + 'product_id': self.product2.id, + }) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1.0, lot_id=lot_id) + + # create pickings and moves for a pick -> pack mto scenario + picking_stock_pack = self.env['stock.picking'].create({ + 'location_id': self.stock_location.id, + 'location_dest_id': self.pack_location.id, + 'picking_type_id': self.env.ref('stock.picking_type_internal').id, + }) + move_stock_pack = self.env['stock.move'].create({ + 'name': 'test_link_assign_7', + 'location_id': self.stock_location.id, + 'location_dest_id': self.pack_location.id, + 'product_id': self.product2.id, + 'product_uom': self.uom_dozen.id, + 'product_uom_qty': 1.0, + 'picking_id': picking_stock_pack.id, + }) + picking_pack_cust = self.env['stock.picking'].create({ + 'location_id': self.pack_location.id, + 'location_dest_id': self.customer_location.id, + 'picking_type_id': self.env.ref('stock.picking_type_out').id, + }) + move_pack_cust = self.env['stock.move'].create({ + 'name': 'test_link_assign_7', + 'location_id': self.pack_location.id, + 'location_dest_id': self.customer_location.id, + 'product_id': self.product2.id, + 'product_uom': self.uom_dozen.id, + 'product_uom_qty': 1.0, + 'picking_id': picking_pack_cust.id, + }) + move_stock_pack.write({'move_dest_ids': [(4, move_pack_cust.id, 0)]}) + move_pack_cust.write({'move_orig_ids': [(4, move_stock_pack.id, 0)]}) + (move_stock_pack + move_pack_cust)._action_confirm() + + move_stock_pack._action_assign() + self.assertEqual(move_stock_pack.state, 'assigned') + move_pack_cust._action_assign() + self.assertEqual(move_pack_cust.state, 'waiting') + + for ml in move_stock_pack.move_line_ids: + ml.qty_done = 1 + picking_stock_pack.button_validate() + self.assertEqual(move_pack_cust.state, 'assigned') + for ml in move_pack_cust.move_line_ids: + self.assertEqual(ml.product_uom_qty, 1) + self.assertEqual(ml.product_uom_id.id, self.uom_unit.id) + self.assertTrue(bool(ml.lot_id.id)) + + def test_link_assign_9(self): + """ Create an uom "3 units" which is 3 times the units but without rounding. Create 3 + quants in stock and two chained moves. The first move will bring the 3 quants but the + second only validate 2 and create a backorder for the last one. Check that the reservation + is correctly cleared up for the last one. + """ + uom_3units = self.env['product.uom'].create({ + 'name': '3 units', + 'category_id': self.uom_unit.category_id.id, + 'factor_inv': 3, + 'rounding': 1, + }) + for i in range(1, 4): + lot_id = self.env['stock.production.lot'].create({ + 'name': 'lot%s' % str(i), + 'product_id': self.product2.id, + }) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1.0, lot_id=lot_id) + + picking_stock_pack = self.env['stock.picking'].create({ + 'location_id': self.stock_location.id, + 'location_dest_id': self.pack_location.id, + 'picking_type_id': self.env.ref('stock.picking_type_internal').id, + }) + move_stock_pack = self.env['stock.move'].create({ + 'name': 'test_link_assign_9', + 'location_id': self.stock_location.id, + 'location_dest_id': self.pack_location.id, + 'product_id': self.product2.id, + 'product_uom': uom_3units.id, + 'product_uom_qty': 1.0, + 'picking_id': picking_stock_pack.id, + }) + picking_pack_cust = self.env['stock.picking'].create({ + 'location_id': self.pack_location.id, + 'location_dest_id': self.customer_location.id, + 'picking_type_id': self.env.ref('stock.picking_type_out').id, + }) + move_pack_cust = self.env['stock.move'].create({ + 'name': 'test_link_assign_0', + 'location_id': self.pack_location.id, + 'location_dest_id': self.customer_location.id, + 'product_id': self.product2.id, + 'product_uom': uom_3units.id, + 'product_uom_qty': 1.0, + 'picking_id': picking_pack_cust.id, + }) + move_stock_pack.write({'move_dest_ids': [(4, move_pack_cust.id, 0)]}) + move_pack_cust.write({'move_orig_ids': [(4, move_stock_pack.id, 0)]}) + (move_stock_pack + move_pack_cust)._action_confirm() + + picking_stock_pack.action_assign() + for ml in picking_stock_pack.move_lines.move_line_ids: + ml.qty_done = 1 + picking_stock_pack.button_validate() + self.assertEqual(picking_pack_cust.state, 'assigned') + for ml in picking_pack_cust.move_lines.move_line_ids: + if ml.lot_id.name != 'lot3': + ml.qty_done = 1 + res_dict_for_back_order = picking_pack_cust.button_validate() + backorder_wizard = self.env[(res_dict_for_back_order.get('res_model'))].browse(res_dict_for_back_order.get('res_id')) + backorder_wizard.with_context(debug=True).process() + backorder = self.env['stock.picking'].search([('backorder_id', '=', picking_pack_cust.id)]) + backordered_ml = backorder.move_line_ids + quant_lot3 = self.env['stock.quant'].search([('lot_id', '=', backordered_ml.lot_id.id)]) + + # due to the rounding, the backordered quantity is 0.999 ; we shoudln't be able to reserve + # 0.999 on a tracked by serial number quant + self.assertEqual(backordered_ml.product_uom_qty, 0) + self.assertTrue(backordered_ml.lot_id) + + # force the serial number and validate + backordered_ml.qty_done = 1 + + overprocessed_wizard = backorder.button_validate() + overprocessed_wizard = self.env['stock.overprocessed.transfer'].browse(overprocessed_wizard['res_id']) + overprocessed_wizard.action_confirm() + + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.customer_location), 3) + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.pack_location), 0) def test_use_unreserved_move_line_1(self): """ Test that validating a stock move linked to an untracked product reserved by another one @@ -1943,7 +2133,7 @@ class StockMove(TransactionCase): self.assertEqual(move_line.product_qty, 5) move_line.qty_done = 5.0 self.assertEqual(move_line.product_qty, 5) # don't change reservation - move_line.with_context(debug=True).lot_id = lot1 + move_line.lot_id = lot1 self.assertEqual(move_line.product_qty, 5) # don't change reservation when assgning a lot now move1._action_done() @@ -3325,39 +3515,6 @@ class StockMove(TransactionCase): self.assertEqual(self.product1.qty_available, 5.0) self.assertEqual(self.product1.with_context(company_owned=True).qty_available, 10.0) - def test_split_1(self): - """ When we split a move line and having one without quantity done, we want to keep reservation - on the new one as it has not been unreserved during the copy. - """ - move1 = self.env['stock.move'].create({ - 'name': 'test_split_1', - 'location_id': self.stock_location.id, - 'location_dest_id': self.customer_location.id, - 'product_id': self.product1.id, - 'product_uom': self.uom_unit.id, - 'product_uom_qty': 10.0, - 'picking_type_id': self.env.ref('stock.picking_type_in').id, - }) - - self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 10) - - move1._action_confirm() - move1._action_assign() - move_line = move1.move_line_ids - - default = {'product_uom_qty': 3, - 'qty_done': 3} - move_line.copy(default=default) - move_line.with_context(bypass_reservation_update=True).write({'product_uom_qty': 7, 'qty_done': 0}) - move1._action_done() - - new_move = self.env['stock.move'].search([('name', '=', 'test_split_1'), ('state', '=', 'confirmed')]) - - self.assertEqual(move1.move_line_ids.product_uom_qty, 0.0) - self.assertEqual(move1.move_line_ids.qty_done, 3.0) - self.assertEqual(new_move.move_line_ids.product_uom_qty, 7.0) - self.assertEqual(new_move.move_line_ids.qty_done, 0.0) - def test_edit_initial_demand_1(self): """ Increase initial demand once everything is reserved and check if the existing move_line is updated. diff --git a/addons/stock/tests/test_move2.py b/addons/stock/tests/test_move2.py index 5d253b46f1d..4e22335cad2 100644 --- a/addons/stock/tests/test_move2.py +++ b/addons/stock/tests/test_move2.py @@ -1059,6 +1059,38 @@ class TestSinglePicking(TestStockCommon): for move in delivery.move_lines: self.assertEqual(move.quantity_done, move.product_uom_qty, 'Initial demand should be equals to quantity done') + def test_extra_move_5(self): + """ Create a picking a move that is problematic with + rounding (5.95 - 5.5 = 0.4500000000000002). Ensure that + initial demand is corrct afer action_done and backoder + are not created. + """ + delivery = self.env['stock.picking'].create({ + 'location_id': self.stock_location, + 'location_dest_id': self.customer_location, + 'partner_id': self.partner_delta_id, + 'picking_type_id': self.picking_type_out, + }) + self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 5.5, + 'quantity_done': 5.95, + 'product_uom': self.productA.uom_id.id, + 'picking_id': delivery.id, + 'location_id': self.stock_location, + 'location_dest_id': self.customer_location, + }) + stock_location = self.env['stock.location'].browse(self.stock_location) + self.env['stock.quant']._update_available_quantity(self.productA, stock_location, 5.5) + delivery.action_confirm() + delivery.action_assign() + delivery.action_done() + self.assertEqual(delivery.move_lines.product_uom_qty, 5.95, 'Move initial demand should be 5.95') + + back_order = self.env['stock.picking'].search([('backorder_id', '=', delivery.id)]) + self.assertFalse(back_order, 'There should be no back order') + def test_recheck_availability_1(self): """ Check the good behavior of check availability. I create a DO for 2 unit with only one in stock. After the first check availability, I should have 1 reserved diff --git a/addons/stock_account/models/stock.py b/addons/stock_account/models/stock.py index c29215f2b79..113ff99b87a 100644 --- a/addons/stock_account/models/stock.py +++ b/addons/stock_account/models/stock.py @@ -260,7 +260,7 @@ class StockMove(models.Model): # Update the standard price with the price of the last used candidate, if any. if new_standard_price and move.product_id.cost_method == 'fifo': - move.product_id.standard_price = new_standard_price + move.product_id.sudo().standard_price = new_standard_price # If there's still quantity to value but we're out of candidates, we fall in the # negative stock use case. We chose to value the out move at the price of the @@ -312,7 +312,9 @@ class StockMove(models.Model): self.write(vals) elif self._is_out(): valued_move_lines = self.move_line_ids.filtered(lambda ml: ml.location_id._should_be_valued() and not ml.location_dest_id._should_be_valued() and not ml.owner_id) - valued_quantity = sum(valued_move_lines.mapped('qty_done')) + valued_quantity = 0 + for valued_move_line in valued_move_lines: + valued_quantity += valued_move_line.product_uom_id._compute_quantity(valued_move_line.qty_done, self.product_id.uom_id) self.env['stock.move']._run_fifo(self, quantity=quantity) if self.product_id.cost_method in ['standard', 'average']: curr_rounding = self.company_id.currency_id.rounding @@ -528,17 +530,6 @@ class StockMove(models.Model): raise UserError(_("The cost of %s is currently equal to 0. Change the cost or the configuration of your product to avoid an incorrect valuation.") % (self.product_id.name,)) credit_value = debit_value - if self.product_id.cost_method == 'average' and self.company_id.anglo_saxon_accounting: - # in case of a supplier return in anglo saxon mode, for products in average costing method, the stock_input - # account books the real purchase price, while the stock account books the average price. The difference is - # booked in the dedicated price difference account. - if self.location_dest_id.usage == 'supplier' and self.origin_returned_move_id and self.origin_returned_move_id.purchase_line_id: - debit_value = self.origin_returned_move_id.price_unit * qty - # in case of a customer return in anglo saxon mode, for products in average costing method, the stock valuation - # is made using the original average price to negate the delivery effect. - if self.location_id.usage == 'customer' and self.origin_returned_move_id: - debit_value = self.origin_returned_move_id.price_unit * qty - credit_value = debit_value partner_id = (self.picking_id.partner_id and self.env['res.partner']._find_accounting_partner(self.picking_id.partner_id).id) or False debit_line_vals = { 'name': self.name, @@ -602,7 +593,7 @@ class StockMove(models.Model): move_lines = self.with_context(forced_ref=ref)._prepare_account_move_line(quantity, abs(self.value), credit_account_id, debit_account_id) if move_lines: date = self._context.get('force_period_date', fields.Date.context_today(self)) - new_account_move = AccountMove.create({ + new_account_move = AccountMove.sudo().create({ 'journal_id': journal_id, 'line_ids': move_lines, 'date': date, diff --git a/addons/web/static/src/js/core/ajax.js b/addons/web/static/src/js/core/ajax.js index 0ee6d2ad1ed..2912b319df2 100644 --- a/addons/web/static/src/js/core/ajax.js +++ b/addons/web/static/src/js/core/ajax.js @@ -260,8 +260,12 @@ function get_file(options) { if (options.error) { var body = this.contentDocument.body; var nodes = body.children.length === 0 ? body.childNodes : body.children; - var node = nodes[1] || nodes[0]; - options.error(JSON.parse(node.textContent)); + options.error({ + message: nodes.length > 1 ? nodes[1].textContent : '', + data: { + title: nodes.length > 0 ? nodes[0].textContent : '', + }, + }); } } finally { complete(); diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js index bb7f25d206b..da9621b085e 100644 --- a/addons/web/static/src/js/services/data_manager.js +++ b/addons/web/static/src/js/services/data_manager.js @@ -204,6 +204,25 @@ return core.Class.extend({ _invalidate: function (cache, key) { delete cache[key]; }, + // Attribute that contains for each viewType the fields for + // that viewType as defaults and + // All the fields of the other viewTypes + // useful to ensure that every field is present + // when swithcing from view to view + attrs.mergeViewsFields = {}; + _.each(attrs.views, function(firstObj, firstViewType) { + if (!attrs.mergeViewsFields[firstViewType]) { + attrs.mergeViewsFields[firstViewType] = {}; + } + _.defaults(attrs.mergeViewsFields[firstViewType], firstObj.fields); + + // We need to double-traverse the attrs.views to ensure + // every viewType contains all the other's fields + _.each(attrs.views, function(secondObj, secondViewType) { + _.defaults(attrs.mergeViewsFields[firstViewType], secondObj.fields); + }); + }); + }); }); diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index e02f51259ef..42eea2ccfd6 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -208,6 +208,8 @@ var BasicModel = AbstractModel.extend({ * assume main viewType from the record * @param {Array} [options.fieldNames] list of field names for which a * default value must be generated (used to complete the values dict) + * @param {record} [options.parentRecord] The parent record of the current one + * usefull to get all the fields from all the views the model can be displayed on. * @returns {Deferred} */ applyDefaultValues: function (recordID, values, options) { @@ -219,6 +221,20 @@ var BasicModel = AbstractModel.extend({ var fieldName; record._changes = record._changes || {}; + /* Get the field's definition in the parent record if it is + * not present in the current one. + * + * @param {string} fieldName The name of the field we try to get the definition for + * in the parent record + * @returns {Object} the field's definition + */ + function getFieldsFromOtherViews(fieldName) { + return options.parentRecord + && options.parentRecord.mergedViewsFields[viewType] + && options.parentRecord.mergedViewsFields[viewType][fieldName] + || {}; + } + // ignore values for non requested fields (for instance, fields that are // not in the view) values = _.pick(values, fieldNames); @@ -227,7 +243,7 @@ var BasicModel = AbstractModel.extend({ for (var i = 0; i < fieldNames.length; i++) { fieldName = fieldNames[i]; if (!(fieldName in values) && !(fieldName in record._changes)) { - field = record.fields[fieldName]; + field = record.fields[fieldName] || getFieldsFromOtherViews(fieldName); if (field.type === 'float' || field.type === 'integer' || field.type === 'monetary') { @@ -243,7 +259,7 @@ var BasicModel = AbstractModel.extend({ // parse each value and create dataPoints for relational fields var defs = []; for (fieldName in values) { - field = record.fields[fieldName]; + field = record.fields[fieldName] || getFieldsFromOtherViews(fieldName); record.data[fieldName] = null; var dp; if (field.type === 'many2one' && values[fieldName]) { @@ -2496,6 +2512,7 @@ var BasicModel = AbstractModel.extend({ var fieldNames = options && options.fieldNames || record.getFieldNames(); var viewType = options && options.viewType || record.viewType; _.each(fieldNames, function (fieldName) { + var mergedViewsFields = record.fieldsInfo[viewType] && record.fieldsInfo[viewType][fieldName].mergeViewsFields || {}; var field = record.fields[fieldName]; if (field.type === 'one2many' || field.type === 'many2many') { var fieldInfo = record.fieldsInfo[viewType][fieldName]; @@ -2518,6 +2535,7 @@ var BasicModel = AbstractModel.extend({ rawContext: rawContext, relationField: field.relation_field, viewType: view ? view.type : fieldInfo.viewType, + mergedViewsFields: mergedViewsFields, }); record.data[fieldName] = list.id; if (!fieldInfo.__no_fetch) { @@ -3222,6 +3240,8 @@ var BasicModel = AbstractModel.extend({ * @param {string} [params.type='record'|'list'] * @param {[type]} [params.value] * @param {string} [params.viewType] the type of the view, e.g. 'list' or 'form' + * @param {Object} [params.mergedViewsFields] Contains for each viewType + * all the other viewTypes' fields plus its own to allow switching views more smoothly * @returns {Object} the resource created */ _makeDataPoint: function (params) { @@ -3281,6 +3301,7 @@ var BasicModel = AbstractModel.extend({ type: type, // 'record' | 'list' value: value, viewType: params.viewType, + mergedViewsFields: params.mergedViewsFields || {}, }; // _editionViewType is a dict whose keys are field names and which is populated when a field @@ -3324,22 +3345,15 @@ var BasicModel = AbstractModel.extend({ */ _makeDefaultRecord: function (modelName, params) { var self = this; - + var parentRecord = self.localData[params.parentID]; var determineExtraFields = function() { // Fields that are present in the originating view, that need to be initialized // Hence preventing their value to crash when getting back to the originating view - var parentRecord = self.localData[params.parentID]; - var originView = parentRecord && parentRecord.fieldsInfo; if (!originView || !originView[parentRecord.viewType]) return []; - var fieldsFromOrigin = _.filter(Object.keys(originView[parentRecord.viewType]), - function(fieldname) { - return params.fields[fieldname] !== undefined; - }); - - return fieldsFromOrigin; + return Object.keys(originView[parentRecord.viewType]); } var fieldNames = Object.keys(params.fieldsInfo[params.viewType]); @@ -3364,7 +3378,7 @@ var BasicModel = AbstractModel.extend({ viewType: params.viewType, }); - return self.applyDefaultValues(record.id, result, {fieldNames: _.union(fieldNames, extraFields)}) + return self.applyDefaultValues(record.id, result, {fieldNames: _.union(fieldNames, extraFields), parentRecord: parentRecord}) .then(function () { var def = $.Deferred(); self._performOnChange(record, fields_key).always(function () { @@ -3847,6 +3861,10 @@ var BasicModel = AbstractModel.extend({ var emptyGroupsIDs = _.difference(_.pluck(previousGroups, 'id'), list.data); _.each(emptyGroupsIDs, function (groupID) { list.data.push(groupID); + var emptyGroup = self.localData[groupID]; + // this attribute hasn't been updated in the previous + // loop for empty groups + emptyGroup.aggregateValues = {}; }); } return $.when.apply($, defs).then(function () { diff --git a/addons/web/static/src/js/views/calendar/calendar_view.js b/addons/web/static/src/js/views/calendar/calendar_view.js index 217f6240711..009ad103a99 100644 --- a/addons/web/static/src/js/views/calendar/calendar_view.js +++ b/addons/web/static/src/js/views/calendar/calendar_view.js @@ -114,8 +114,20 @@ var CalendarView = AbstractView.extend({ //if quick_add = is NOT False and IS specified in view, we this one for widgets.QuickCreate' this.controllerParams.quickAddPop = (!('quick_add' in attrs) || utils.toBoolElse(attrs.quick_add+'', true)); this.controllerParams.disableQuickCreate = params.disable_quick_create || !this.controllerParams.quickAddPop; - // If this field is set ot true, we don't open the event in form view, but in a popup with the view_id passed by this parameter - this.controllerParams.formViewId = !attrs.form_view_id || !utils.toBoolElse(attrs.form_view_id, true) ? false : attrs.form_view_id; + + // If form_view_id is set, then the calendar view will open a form view + // with this id, when it needs to edit or create an event. + this.controllerParams.formViewId = + attrs.form_view_id ? parseInt(attrs.form_view_id, 10) : false; + if (!this.controllerParams.formViewId && params.action) { + var formViewDescr = _.find(params.action.views, function (v) { + return v[1] === 'form'; + }); + if (formViewDescr) { + this.controllerParams.formViewId = formViewDescr[0]; + } + } + this.controllerParams.readonlyFormViewId = !attrs.readonly_form_view_id || !utils.toBoolElse(attrs.readonly_form_view_id, true) ? false : attrs.readonly_form_view_id; this.controllerParams.eventOpenPopup = utils.toBoolElse(attrs.event_open_popup || '', false); this.controllerParams.mapping = mapping; diff --git a/addons/web/static/src/js/views/kanban/kanban_model.js b/addons/web/static/src/js/views/kanban/kanban_model.js index 411d4cc7b14..bf607d760d2 100644 --- a/addons/web/static/src/js/views/kanban/kanban_model.js +++ b/addons/web/static/src/js/views/kanban/kanban_model.js @@ -398,9 +398,8 @@ var KanbanModel = BasicModel.extend({ return $.when(); }, /** - * Reloads all progressbar data if the given id is a record's one. This is - * done after given deferred and insures that the given deferred's result is - * not lost. + * Reloads all progressbar data. This is done after given deferred and + * insures that the given deferred's result is not lost. * * @private * @param {string} recordID @@ -409,9 +408,6 @@ var KanbanModel = BasicModel.extend({ */ _reloadProgressBarGroupFromRecord: function (recordID, def) { var element = this.localData[recordID]; - if (element.type !== 'record') { - return def; - } // If we updated a record, then we must potentially update columns' // progressbars, so we need to load groups info again diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js index 9d7555cad19..53ef5bccd2d 100644 --- a/addons/web/static/src/js/views/list/list_editable_renderer.js +++ b/addons/web/static/src/js/views/list/list_editable_renderer.js @@ -537,8 +537,13 @@ ListRenderer.include({ * @returns {Deferred} this deferred is resolved immediately */ _renderView: function () { + var self = this; this.currentRow = null; - return this._super.apply(this, arguments); + return this._super.apply(this, arguments).then(function () { + if (self._isEditable()) { + self.$('table').addClass('o_editable_list'); + } + }); }, /** * Force the resequencing of the items in the list. diff --git a/addons/web/static/src/js/views/pivot/pivot_model.js b/addons/web/static/src/js/views/pivot/pivot_model.js index 6eddd44ffe7..76e22c8b4e5 100644 --- a/addons/web/static/src/js/views/pivot/pivot_model.js +++ b/addons/web/static/src/js/views/pivot/pivot_model.js @@ -17,6 +17,7 @@ odoo.define('web.PivotModel', function (require) { */ var AbstractModel = require('web.AbstractModel'); +var concurrency = require('web.concurrency'); var core = require('web.core'); var session = require('web.session'); var utils = require('web.utils'); @@ -32,6 +33,7 @@ var PivotModel = AbstractModel.extend({ this._super.apply(this, arguments); this.numbering = {}; this.data = null; + this._loadDataDropPrevious = new concurrency.DropPrevious(); }, //-------------------------------------------------------------------------- @@ -532,7 +534,7 @@ var PivotModel = AbstractModel.extend({ } } - return $.when.apply(null, groupBys.map(function (groupBy) { + return this._loadDataDropPrevious.add($.when.apply(null, groupBys.map(function (groupBy) { return self._rpc({ model: self.modelName, method: 'read_group', @@ -542,7 +544,7 @@ var PivotModel = AbstractModel.extend({ groupBy: groupBy, lazy: false, }); - })).then(function () { + }))).then(function () { var data = Array.prototype.slice.call(arguments); if (data[0][0].__count === 0) { self.data.has_data = false; diff --git a/addons/web/static/src/less/list_view.less b/addons/web/static/src/less/list_view.less index 73bd50e1966..1e57f9253bc 100644 --- a/addons/web/static/src/less/list_view.less +++ b/addons/web/static/src/less/list_view.less @@ -6,6 +6,14 @@ background-color: @odoo-view-background-color; margin-bottom: 0px; + // Checkbox in editable list + // should be clickable and activate the row + &.o_editable_list .o_data_row:not(.o_selected_row) .o_data_cell { + .o_checkbox:not(.o_readonly_modifier) { + pointer-events: none; + } + } + &.table { td, th { vertical-align: middle; diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index 29d3dad6056..1c050edf3f4 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -2331,6 +2331,50 @@ QUnit.module('relational_fields', { QUnit.module('FieldOne2Many'); + QUnit.test('one2many with two inline views', function (assert) { + assert.expect(1); + + // The inline list view has and uses a field that the inline form view doesn't have + // We need to test that returning from the form view to the list view unfolds smoothly + // Even if a field needed in the list is not set in the form + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<field name="turtles">' + + '<tree>' + + '<field name="turtle_foo"/>' + + '<field name="display_name" attrs="{\'readonly\': [(\'turtle_foo\', \'=\', \'lol\')]}"/>' + + '</tree>' + + '<form>' + + '<field name="display_name"/>' + + '</form>' + + '</field>' + + '</form>', + res_id: 1, + viewOptions: { + mode: 'edit', + }, + }); + + // Add a record with the form view + form.$('.o_field_x2many_list .o_field_x2many_list_row_add a').click(); + var modal = $('.modal-dialog'); + // Fill in the only field + modal.find('input[name=display_name]').val('lol').trigger('input'); + // Save the record + modal.find('.btn-primary').first().click(); + + // Now back to the list, verifying that the record is present + var $newRecord = form.$('.o_field_x2many_list tbody .o_data_row').eq(1); + assert.equal($newRecord.find('.o_data_cell').eq(1).text(), 'lol', + 'We should have created a record in the One2Many'); + + form.destroy(); + }); + QUnit.test('one2many list editable with cell readonly modifier', function (assert) { assert.expect(4); @@ -5699,7 +5743,7 @@ QUnit.module('relational_fields', { rpcCount++; if (args.method === 'write') { assert.deepEqual(args.args[1].p, [[0, args.args[1].p[0][1], { - int_field: 123, product_id: 41 + int_field: 123, product_id: 41, foo: false, }]]); } return this._super(route, args); diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js index 163961497d8..6c1d113951a 100644 --- a/addons/web/static/tests/helpers/mock_server.js +++ b/addons/web/static/tests/helpers/mock_server.js @@ -116,12 +116,12 @@ var MockServer = Class.extend({ console.log('%c[rpc] response' + route, 'color: blue; font-weight: bold;', JSON.parse(resultString)); } return JSON.parse(resultString); - }).fail(function (result) { + }, function (result, event) { var errorString = JSON.stringify(result || false); if (debug) { console.log('%c[rpc] response (error) ' + route, 'color: orange; font-weight: bold;', JSON.parse(errorString)); } - return JSON.parse(errorString); + return $.Deferred().reject(errorString, event || $.Event()); }); }, @@ -813,7 +813,7 @@ var MockServer = Class.extend({ */ _mockReadProgressBar: function (model, kwargs) { var domain = kwargs.domain; - var groupBy = kwargs.groupBy; + var groupBy = kwargs.group_by; var progress_bar = kwargs.progress_bar; var records = this._getRecords(model, domain || []); diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index 81eff3a30f8..a54ba356224 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -1875,6 +1875,101 @@ QUnit.module('Views', { calendar.destroy(); }); + + QUnit.test('form_view_id attribute works (for creating events)', function (assert) { + assert.expect(1); + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: '<calendar class="o_calendar_test" '+ + 'date_start="start" '+ + 'date_stop="stop" '+ + 'mode="month" '+ + 'form_view_id="42">'+ + '<field name="name"/>'+ + '</calendar>', + archs: archs, + viewOptions: { + initialDate: initialDate, + }, + mockRPC: function (route, args) { + if (args.method === "create") { + // we simulate here the case where a create call with just + // the field name fails. This is a normal flow, the server + // reject the create rpc (quick create), then the web client + // fall back to a form view. This happens typically when a + // model has required fields + return $.Deferred().reject('None shall pass!'); + } + return this._super(route, args); + }, + intercepts: { + do_action: function (event) { + assert.strictEqual(event.data.action.views[0][0], 42, + "should do a do_action with view id 42"); + }, + }, + }); + + var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); + testUtils.triggerMouseEvent($cell, "mousedown"); + testUtils.triggerMouseEvent($cell, "mouseup"); + var $input = $('.modal-body input:first'); + $input.val("It's just a fleshwound").trigger('input'); + $('.modal button.btn:contains(Create)').trigger('click'); + + calendar.destroy(); + }); + + QUnit.test('calendar fallback to form view id in action if necessary', function (assert) { + assert.expect(1); + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: '<calendar class="o_calendar_test" '+ + 'date_start="start" '+ + 'date_stop="stop" '+ + 'mode="month"> '+ + '<field name="name"/>'+ + '</calendar>', + archs: archs, + viewOptions: { + initialDate: initialDate, + action: {views: [[1, 'kanban'], [43, 'form']]} + }, + mockRPC: function (route, args) { + if (args.method === "create") { + // we simulate here the case where a create call with just + // the field name fails. This is a normal flow, the server + // reject the create rpc (quick create), then the web client + // fall back to a form view. This happens typically when a + // model has required fields + return $.Deferred().reject('None shall pass!'); + } + return this._super(route, args); + }, + intercepts: { + do_action: function (event) { + assert.strictEqual(event.data.action.views[0][0], 43, + "should do a do_action with view id 43"); + }, + }, + }); + + var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); + testUtils.triggerMouseEvent($cell, "mousedown"); + testUtils.triggerMouseEvent($cell, "mouseup"); + var $input = $('.modal-body input:first'); + $input.val("It's just a fleshwound").trigger('input'); + $('.modal button.btn:contains(Create)').trigger('click'); + + calendar.destroy(); + }); + }); }); diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js index 859a3b29ee9..902bb5c8cd8 100644 --- a/addons/web/static/tests/views/kanban_tests.js +++ b/addons/web/static/tests/views/kanban_tests.js @@ -3222,6 +3222,47 @@ QUnit.module('Views', { kanban.destroy(); }); + QUnit.test('column progressbars on archiving records update counter', function (assert) { + assert.expect(4); + + // add active field on partner model and make all records active + this.data.partner.fields.active = {string: 'Active', type: 'char', default: true}; + + var kanban = createView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: + '<kanban>' + + '<field name="active"/>' + + '<field name="bar"/>' + + '<field name="int_field"/>' + + '<progressbar field="foo" colors=\'{"yop": "success", "gnap": "warning", "blip": "danger"}\' sum_field="int_field"/>' + + '<templates><t t-name="kanban-box">' + + '<div>' + + '<field name="name"/>' + + '</div>' + + '</t></templates>' + + '</kanban>', + groupBy: ['bar'], + }); + + assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_counter_side').text(), "36", + "counter should contain the correct value"); + assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_counter_progress > .progress-bar:first').data('originalTitle'), "1 yop", + "the counter progressbars should be correctly displayed"); + + // archive all records of the second columns + kanban.$('.o_kanban_group:eq(1) .o_column_archive').click(); + + assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_counter_side').text(), "0", + "counter should contain the correct value"); + assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_counter_progress > .progress-bar:first').data('originalTitle'), "0 yop", + "the counter progressbars should have been correctly updated"); + + kanban.destroy(); + }); + QUnit.test('drag & drop records grouped by m2o with progressbar', function (assert) { assert.expect(4); diff --git a/addons/web/static/tests/views/pivot_tests.js b/addons/web/static/tests/views/pivot_tests.js index 9c27e2eeb35..fc20e3b6869 100644 --- a/addons/web/static/tests/views/pivot_tests.js +++ b/addons/web/static/tests/views/pivot_tests.js @@ -1006,4 +1006,37 @@ QUnit.module('Views', { pivot.destroy(); }); + + QUnit.test('parallel data loading should discard all but the last one', function (assert) { + assert.expect(2); + + var def; + + var pivot = createView({ + View: PivotView, + model: "partner", + data: this.data, + arch: '<pivot>' + + '<field name="foo" type="measure"/>' + + '</pivot>', + mockRPC: function (route, args) { + var result = this._super.apply(this, arguments); + if (args.method === 'read_group') { + return $.when(def).then(_.constant(result)); + } + return result; + }, + }); + + def = $.Deferred(); + pivot.update({groupBy: ['product_id']}); + pivot.update({groupBy: ['product_id', 'customer']}); + def.resolve(); + + assert.strictEqual(pivot.$('.o_pivot_cell_value').length, 6, + "should have 6 cells"); + assert.strictEqual(pivot.$('tbody tr').length, 6, + "should have 6 rows"); + pivot.destroy(); + }); });}); diff --git a/addons/web/tests/test_js.py b/addons/web/tests/test_js.py index f903fa704c5..04df8be91c1 100644 --- a/addons/web/tests/test_js.py +++ b/addons/web/tests/test_js.py @@ -32,6 +32,6 @@ class WebSuite(odoo.tests.HttpCase): filename = asset['filename'] if not filename or asset['atype'] != 'text/javascript': continue - with open(filename, 'r') as fp: - if RE_ONLY.search(fp.read()): + with open(filename, 'rb') as fp: + if RE_ONLY.search(fp.read().decode('utf-8')): self.fail("`QUnit.only()` used in file %r" % asset['url']) diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js b/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js index 955b49437a8..4cd9088da75 100644 --- a/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js +++ b/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js @@ -1,256 +1,41 @@ define([ - 'summernote/core/list', - 'summernote/core/dom', - 'summernote/core/key', - 'summernote/core/agent', - 'summernote/core/range' + 'summernote/core/list', + 'summernote/core/dom', + 'summernote/core/key', + 'summernote/core/agent', + 'summernote/core/range' ], function (list, dom, key, agent, range) { - var Clipboard = function (handler) { - var $paste; - - this.attach = function (layoutInfo) { - // [workaround] getting image from clipboard - // - IE11 and Firefox: CTRL+v hook - // - Webkit: event.clipboardData - if (agent.isMSIE && agent.browserVersion > 10) { - $paste = $('<div />').attr('contenteditable', true).css({ - position : 'absolute', - left : -100000, - opacity : 0 - }); - - layoutInfo.editable().on('keydown', function (e) { - if (e.ctrlKey && e.keyCode === key.code.V) { - handler.invoke('saveRange', layoutInfo.editable()); - $paste.focus(); - - setTimeout(function () { - pasteByHook(layoutInfo); - }, 0); - } - }); - - layoutInfo.editable().before($paste); - } else { - layoutInfo.editable().on('paste', pasteByEvent); - } - }; - - var pasteByHook = function (layoutInfo) { - var $editable = layoutInfo.editable(); - var node = $paste[0].firstChild; - - if (dom.isImg(node)) { - var dataURI = node.src; - var decodedData = atob(dataURI.split(',')[1]); - var array = new Uint8Array(decodedData.length); - for (var i = 0; i < decodedData.length; i++) { - array[i] = decodedData.charCodeAt(i); - } - - var blob = new Blob([array], { type : 'image/png' }); - blob.name = 'clipboard.png'; - - handler.invoke('restoreRange', $editable); - handler.invoke('focus', $editable); - handler.insertImages(layoutInfo, [blob]); - } else { - var pasteContent = $('<div />').html($paste.html()).html(); - handler.invoke('restoreRange', $editable); - handler.invoke('focus', $editable); - - if (pasteContent) { - handler.invoke('pasteHTML', $editable, pasteContent); - } - } - - $paste.empty(); - }; - - /** - * paste by clipboard event - * - * @param {Event} event - */ - var pasteByEvent = function (event) { - var clipboardData = event.originalEvent.clipboardData; - var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target); - var $editable = layoutInfo.editable(); - - if (["INPUT", "TEXTAREA"].indexOf(event.target.tagName) !== -1) { - return; - } - - if (clipboardData && clipboardData.items && clipboardData.items.length) { - var item = list.head(clipboardData.items); - if (item.kind === 'file' && item.type.indexOf('image/') !== -1) { - handler.insertImages(layoutInfo, [item.getAsFile()]); - } - handler.invoke('editor.afterCommand', $editable); - } - - event.preventDefault(); - - var html = clipboardData.getData("text/html"); - var $node = $('<div/>').html(html); - // if copying source did not provide html, default to plain text - if(!html) { - $node.text(clipboardData.getData("text/plain")).html(function(_, html){ - return html.replace(/\r?\n/g,'<br>'); - }); - } - pasteContent($node, layoutInfo, $editable); - }; - - /* - remove undesirable tag - filter classes and style attributes - remove undesirable attributes - */ - var filter_tag = function ($nodes, $editable) { - return $nodes.each(function() { - var $node = $(this); - - if ($node.attr('style')) { - var style = _.filter(_.compact($node.attr('style').split(/\s*;\s*/)), function (style) { - style = style.split(/\s*:\s*/); - return /width|height|color|background-color|font-weight|text-align|font-style|text-decoration/i.test(style[0]) && - !(style[1] === 'initial' || style[1] === 'inherit' || $node.css(style[0]) === $editable.css(style[0]) || - (style[0] === 'background-color' && style[1] === 'rgb(255, 255, 255)') || - (style[0] === 'color' && style[1] === 'rgb(0, 0, 0)')); - }).join(';'); - if (style.length) { - $node.attr('style', style); - } else { - $node.removeAttr('style'); - } - } - - if ($node.attr('class')) { - var classes = _.filter($node.attr('class').split(/\s+/), function (style) { - return /(^|\s)(fa|pull|text|bg)(\s|-|$)/.test(style); - }).join(' '); - if (classes.length) { - $node.attr('class', classes); - } else { - $node.removeAttr('class'); - } - } - }); - }; - - var pasteContent = function ($node, layoutInfo, $editable) { - $node.find('meta, script, style').remove(); - filter_tag($node.find('*'), $editable).removeAttr('title', 'alt', 'id', 'contenteditable'); - - /* - remove unless span and unwant font - */ - $node.find('span, font').filter(':not([class]):not([style])').each(function () { - $(this).replaceWith($(this).contents()); - }); - $node.find('span + span').each(function () { - - if (dom.isText(this.previousSibling)) { - if (dom.isVisibleText(this.previousSibling)) { - return; - } else { // keep space between 2 tags, but can merge the both tags - $(this).prev().append(this.previousSibling); - } - } - if ($(this).attr('class') === $(this).prev().attr('class') && $(this).attr('style') === $(this).prev().attr('style')) { - $(this).prev().append($(this).contents()); - $(this).remove(); - } - }); - - // remove empty table row and td - var $tdr; - while(($tdr = $node.find('tr:empty, td:empty, th:empty, tbody:empty, t-head:empty, table:empty')) && $tdr.length) { - $tdr.remove(); - } - - /* - reset architecture HTML node and add <p> tag - */ - var $arch = $('<div/>'); - var $last = $arch; - $node.contents().each(function () { - if (dom.isBR(this)) { - $(this).remove(); - $last = $('<p/>'); - $arch.append($last); - } else if (/h[0-9]+|li|table|p/i.test(this.tagName)) { - $last = $('<p/>'); - $arch.append(this).append($last); - } else if ($arch.is(':empty') && dom.isText(this)) { - $last = $('<p/>').append(this); - $arch.append($last); - } else if (this.nodeType !== Node.COMMENT_NODE) { - $last.append(this); - } - }); - $arch.find(':not([class]):not([style]):empty, p:empty').remove(); - - /* - history - */ - $editable.data('NoteHistory').recordUndo($editable, "paste"); - - /* - remove selected content - */ - var r = range.create(); - if (!r.isCollapsed()) { - r = r.deleteContents(); - r.select(); - } - - // If only pasting a <p/> element in an unique <p/> element, only paste - // the <p/> element text - var $p = $arch.children('p'); - var onlyAP = ($p.length === 1 && $arch.children().length === 1); - if (onlyAP) { - var $p1 = $(r.sc).closest('p'); - var $p2 = $(r.ec).closest('p'); - if ($p1.length && $p2.length && $p1[0] === $p2[0]) { - $arch.html($p.text()); - } - } - - /* - insert content - */ - var $nodes = $(); - $editable.on('DOMNodeInserted', function (event) { - $nodes = $nodes.add(event.originalEvent.target); - }); - window.document.execCommand('insertHTML', false, $arch.html()); - $editable.off('DOMNodeInserted'); - - /* - clean insterted content - */ - var $span = $nodes.filter('span'); - $span = $span.first().add($span.last()); - $span = $span.add($span.prev('span')); - $span = $span.add($span.next('span')); - filter_tag($span, $editable); - $span.not('[span], [style]').each(function () { - _.each(this.childNodes, function (node) { - $(node.parentNode).after(node); - }); - $(this).remove(); - }); - r = range.create(); - if (!dom.isText(r.ec)) { - r = range.create(r.sc.childNodes[r.so], dom.nodeLength(r.sc.childNodes[r.so])); - } - r.clean().select(); - - $editable.trigger('content_changed'); + // ODOO override: use 0.8.10 version of this, adapted for the old summernote + // version odoo is using + var Clipboard = function (handler) { + /** + * paste by clipboard event + * + * @param {Event} event + */ + var pasteByEvent = function (event) { + if (["INPUT", "TEXTAREA"].indexOf(event.target.tagName) !== -1) { + // ODOO override: from old summernote version + return; + } + + var clipboardData = event.originalEvent.clipboardData; + var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target); + var $editable = layoutInfo.editable(); + + if (clipboardData && clipboardData.items && clipboardData.items.length) { + var item = list.head(clipboardData.items); + if (item.kind === 'file' && item.type.indexOf('image/') !== -1) { + handler.insertImages(layoutInfo, [item.getAsFile()]); + } + handler.invoke('editor.afterCommand', $editable); + } + }; + + this.attach = function (layoutInfo) { + layoutInfo.editable().on('paste', pasteByEvent); + }; }; - }; - return Clipboard; + return Clipboard; }); diff --git a/addons/web_editor/static/src/js/editor/rte.summernote.js b/addons/web_editor/static/src/js/editor/rte.summernote.js index ddf588eb569..969b9c060b2 100644 --- a/addons/web_editor/static/src/js/editor/rte.summernote.js +++ b/addons/web_editor/static/src/js/editor/rte.summernote.js @@ -675,7 +675,7 @@ function summernote_mousedown(event) { return; } var editables = $(".o_editable[contenteditable], .note-editable[contenteditable]"); - var r_editable = editables.has((r||{}).sc); + var r_editable = editables.has((r||{}).sc).addBack(editables.filter((r||{}).sc)); if (!r_editable.closest('.note-editor').is($editable) && !r_editable.filter('.o_editable').is(editables)) { var saved_editable = editables.has((remember_selection||{}).sc); if ($editable.length && !saved_editable.closest('.o_editable, .note-editor').is($editable)) { diff --git a/addons/website_quote/controllers/main.py b/addons/website_quote/controllers/main.py index f795de5f4e6..434750c9250 100644 --- a/addons/website_quote/controllers/main.py +++ b/addons/website_quote/controllers/main.py @@ -8,6 +8,7 @@ from odoo.http import request from odoo.addons.portal.controllers.portal import get_records_pager from odoo.addons.sale.controllers.portal import CustomerPortal from odoo.addons.portal.controllers.mail import _message_post_helper +from odoo.osv import expression class CustomerPortal(CustomerPortal): @@ -49,7 +50,7 @@ class sale_quote(http.Controller): if Order and request.session.get('view_quote_%s' % Order.id) != now and request.env.user.share: request.session['view_quote_%s' % Order.id] = now body = _('Quotation viewed by customer') - _message_post_helper(res_model='sale.order', res_id=Order.id, message=body, token=token, message_type='notification', subtype="mail.mt_note", partner_ids=Order.user_id.sudo().partner_id.ids) + _message_post_helper(res_model='sale.order', res_id=Order.id, message=body, token=Order.access_token, message_type='notification', subtype="mail.mt_note", partner_ids=Order.user_id.sudo().partner_id.ids) if not Order: return request.render('website.404') @@ -89,7 +90,11 @@ class sale_quote(http.Controller): } if order_sudo.require_payment or values['need_payment']: - acquirers = request.env['payment.acquirer'].sudo().search([('website_published', '=', True), ('company_id', '=', order_sudo.company_id.id)]) + domain = expression.AND([ + ['&', ('website_published', '=', True), ('company_id', '=', order_sudo.company_id.id)], + ['|', ('specific_countries', '=', False), ('country_ids', 'in', [order_sudo.partner_id.country_id.id])] + ]) + acquirers = request.env['payment.acquirer'].sudo().search(domain) values['form_acquirers'] = [acq for acq in acquirers if acq.payment_flow == 'form' and acq.view_template_id] values['s2s_acquirers'] = [acq for acq in acquirers if acq.payment_flow == 's2s' and acq.registration_view_template_id] diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 448b2f1c77d..a0f136ce79c 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -12,6 +12,7 @@ from odoo.addons.website.controllers.main import QueryURL from odoo.exceptions import ValidationError from odoo.addons.website.controllers.main import Website from odoo.addons.website_form.controllers.main import WebsiteForm +from odoo.osv import expression _logger = logging.getLogger(__name__) @@ -756,9 +757,11 @@ class WebsiteSale(http.Controller): bootstrap_formatting= True ) - acquirers = request.env['payment.acquirer'].search( - [('website_published', '=', True), ('company_id', '=', order.company_id.id)] - ) + domain = expression.AND([ + ['&', ('website_published', '=', True), ('company_id', '=', order.company_id.id)], + ['|', ('specific_countries', '=', False), ('country_ids', 'in', [order.partner_id.country_id.id])] + ]) + acquirers = request.env['payment.acquirer'].search(domain) values['access_token'] = order.access_token values['form_acquirers'] = [acq for acq in acquirers if acq.payment_flow == 'form' and acq.view_template_id] diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index ba0b1305946..2ef722104b5 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -179,8 +179,9 @@ class WebsiteSlides(http.Controller): response.mimetype = 'application/pdf' return response - @http.route('''/slides/slide/<model("slide.slide"):slide>/download''', type='http', auth="public", website=True) - def slide_download(self, slide, sitemap=False): + @http.route('''/slides/slide/<model("slide.slide"):slide>/download''', type='http', auth="public", website=True, sitemap=False) + def slide_download(self, slide, **kw): + slide = slide.sudo() if slide.download_security == 'public' or (slide.download_security == 'user' and request.session.uid): filecontent = base64.b64decode(slide.datas) disposition = 'attachment; filename=%s.pdf' % werkzeug.urls.url_quote(slide.name) @@ -190,7 +191,7 @@ class WebsiteSlides(http.Controller): ('Content-Length', len(filecontent)), ('Content-Disposition', disposition)]) elif not request.session.uid and slide.download_security == 'user': - return werkzeug.utils.redirect('/web?redirect=/slides/slide/%s' % (slide.id)) + return request.redirect('/web/login?redirect=/slides/slide/%s' % (slide.id)) return request.render("website.403") @http.route('''/slides/slide/<model("slide.slide"):slide>/promote''', type='http', auth='user', website=True) diff --git a/addons/website_slides/models/slides.py b/addons/website_slides/models/slides.py index 764d8acfa6a..1689e8070c9 100644 --- a/addons/website_slides/models/slides.py +++ b/addons/website_slides/models/slides.py @@ -16,6 +16,8 @@ from odoo.addons.http_routing.models.ir_http import slug from odoo.tools import image from odoo.tools.translate import html_translate from odoo.exceptions import Warning +from odoo.http import request +from odoo.addons.http_routing.models.ir_http import url_for class Channel(models.Model): @@ -345,10 +347,11 @@ class Slide(models.Model): embed_code = fields.Text('Embed Code', readonly=True, compute='_get_embed_code') def _get_embed_code(self): - base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + base_url = request and request.httprequest.url_root or self.env['ir.config_parameter'].sudo().get_param('web.base.url') for record in self: if record.datas and (not record.document_id or record.slide_type in ['document', 'presentation']): - record.embed_code = '<iframe src="%s/slides/embed/%s?page=1" class="o_wslides_iframe_viewer" allowFullScreen="true" height="%s" width="%s" frameborder="0"></iframe>' % (base_url, record.id, 315, 420) + slide_url = base_url + url_for('/slides/embed/%s?page=1' % record.id) + record.embed_code = '<iframe src="%s" class="o_wslides_iframe_viewer" allowFullScreen="true" height="%s" width="%s" frameborder="0"></iframe>' % (slide_url, 315, 420) elif record.slide_type == 'video' and record.document_id: if not record.mime_type: # embed youtube video diff --git a/doc/cla/individual/nomadic-coding.md b/doc/cla/individual/nomadic-coding.md new file mode 100644 index 00000000000..4ac7e62b77c --- /dev/null +++ b/doc/cla/individual/nomadic-coding.md @@ -0,0 +1,11 @@ +Panama, 2018-05-01 + +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, + +Kumar Aberer hello@nomadic-coding.com https://github.com/nomadic-coding diff --git a/doc/reference/views.rst b/doc/reference/views.rst index 03dbdcd4816..8845e7806c3 100644 --- a/doc/reference/views.rst +++ b/doc/reference/views.rst @@ -954,7 +954,9 @@ calendar view are: ``readonly_form_view_id`` view to open in readonly mode ``form_view_id`` - view to open when the user create or edit an event + view to open when the user create or edit an event. Note that if this attribute + is not set, the calendar view will fall back to the id of the form view in the + current action, if any. ``event_open_popup`` If the option 'event_open_popup' is set to true, then the calendar view will open events (or records) in a FormViewDialog. Otherwise, it will open events diff --git a/odoo/addons/base/models/res_currency.py b/odoo/addons/base/models/res_currency.py index 509bb548ecc..96d6af00ae4 100644 --- a/odoo/addons/base/models/res_currency.py +++ b/odoo/addons/base/models/res_currency.py @@ -44,6 +44,7 @@ class Currency(models.Model): ] @api.multi + @api.depends('rate_ids.rate') def _compute_current_rate(self): date = self._context.get('date') or fields.Date.today() company_id = self._context.get('company_id') or self.env['res.users']._get_company().id |
