From f0f3085cb942c647a48c7ce21916670151d04c04 Mon Sep 17 00:00:00 2001 From: Parthiv Patel Date: Sat, 16 Oct 2021 09:36:11 +0000 Subject: [PATCH] [PATCH] Upstream patch - 16102021 --- .../account/models/account_reconcile_model.py | 2 +- addons/account/views/report_invoice.xml | 2 +- addons/delivery/models/delivery_grid.py | 2 + addons/l10n_ar/tests/__init__.py | 3 + addons/l10n_ar/tests/common.py | 694 ++++++++++++++++++ addons/l10n_ar/tests/test_manual.py | 99 +++ addons/l10n_vn/data/account_data.xml | 6 +- addons/l10n_vn/data/account_tax_data.xml | 24 +- .../l10n_vn/data/account_tax_report_data.xml | 60 +- addons/l10n_vn/i18n_extra/l10n_vn.pot | 516 +++++++++---- addons/l10n_vn/i18n_extra/vi_VN.po | 555 +++++++++----- addons/mrp/models/stock_move.py | 2 +- .../models/mrp_production.py | 2 + .../tests/test_subcontracting.py | 72 ++ addons/point_of_sale/tests/common.py | 2 + addons/purchase/views/product_views.xml | 4 +- .../sale_mrp/tests/test_sale_mrp_kit_bom.py | 47 ++ addons/sale_stock/models/sale_order.py | 3 +- addons/sale_timesheet/models/project.py | 14 +- .../sale_timesheet/models/project_overview.py | 5 +- .../project_profitability_report_analysis.py | 199 ++--- addons/sale_timesheet/tests/__init__.py | 1 + .../sale_timesheet/tests/common_reporting.py | 132 ++++ .../tests/test_project_overview.py | 25 +- addons/sale_timesheet/tests/test_reporting.py | 676 +++++++++++++---- .../views/hr_timesheet_templates.xml | 8 + addons/stock/models/stock_move.py | 16 +- addons/stock/models/stock_production_lot.py | 2 +- addons/stock/models/stock_rule.py | 2 +- addons/stock/tests/test_stock_flow.py | 47 ++ addons/stock/views/stock_picking_views.xml | 2 +- .../static/src/js/editor/snippets.editor.js | 15 +- addons/website_slides/models/slide_slide.py | 2 +- 33 files changed, 2600 insertions(+), 641 deletions(-) create mode 100644 addons/l10n_ar/tests/__init__.py create mode 100644 addons/l10n_ar/tests/common.py create mode 100644 addons/l10n_ar/tests/test_manual.py create mode 100644 addons/sale_timesheet/tests/common_reporting.py diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py index 42e984679a..57b9b17b95 100644 --- a/addons/account/models/account_reconcile_model.py +++ b/addons/account/models/account_reconcile_model.py @@ -277,7 +277,7 @@ class AccountReconcileModel(models.Model): self.ensure_one() balance = base_line_dict['balance'] tax_type = tax.type_tax_use - is_refund = (tax_type == 'sale' and balance < 0) or (tax_type == 'purchase' and balance > 0) + is_refund = (tax_type == 'sale' and balance > 0) or (tax_type == 'purchase' and balance < 0) res = tax.compute_all(balance, is_refund=is_refund) diff --git a/addons/account/views/report_invoice.xml b/addons/account/views/report_invoice.xml index 322ecbdf37..52e3c4b826 100644 --- a/addons/account/views/report_invoice.xml +++ b/addons/account/views/report_invoice.xml @@ -199,7 +199,7 @@

Incoterm: -

-
+

Scan me with your banking app.

diff --git a/addons/delivery/models/delivery_grid.py b/addons/delivery/models/delivery_grid.py index e223d97e66..a1e0e068cb 100644 --- a/addons/delivery/models/delivery_grid.py +++ b/addons/delivery/models/delivery_grid.py @@ -82,6 +82,8 @@ class ProviderGrid(models.Model): total_delivery += line.price_total if not line.product_id or line.is_delivery: continue + if line.product_id.type == "service": + continue qty = line.product_uom._compute_quantity(line.product_uom_qty, line.product_id.uom_id) weight += (line.product_id.weight or 0.0) * qty volume += (line.product_id.volume or 0.0) * qty diff --git a/addons/l10n_ar/tests/__init__.py b/addons/l10n_ar/tests/__init__.py new file mode 100644 index 0000000000..ad35dc3d45 --- /dev/null +++ b/addons/l10n_ar/tests/__init__.py @@ -0,0 +1,3 @@ +# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. +from . import common +from . import test_manual diff --git a/addons/l10n_ar/tests/common.py b/addons/l10n_ar/tests/common.py new file mode 100644 index 0000000000..7ced2f05ce --- /dev/null +++ b/addons/l10n_ar/tests/common.py @@ -0,0 +1,694 @@ +# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. +from flectra import fields +from flectra.tests.common import Form +from flectra.addons.account.tests.common import AccountTestInvoicingCommon +import random +import logging +import time + +_logger = logging.getLogger(__name__) + + +class TestAr(AccountTestInvoicingCommon): + + @classmethod + def setUpClass(cls, chart_template_ref='l10n_ar.l10nar_ri_chart_template'): + super(TestAr, cls).setUpClass(chart_template_ref=chart_template_ref) + + # ==== Company ==== + cls.company_data['company'].write({ + 'parent_id': cls.env.ref('base.main_company').id, + 'currency_id': cls.env.ref('base.ARS').id, + 'name': '(AR) Responsable Inscripto (Unit Tests)', + "l10n_ar_afip_start_date": time.strftime('%Y-01-01'), + 'l10n_ar_gross_income_type': 'local', + 'l10n_ar_gross_income_number': '901-21885123', + }) + cls.company_ri = cls.company_data['company'] + + cls.company_ri.partner_id.write({ + 'name': '(AR) Responsable Inscripto (Unit Tests)', + 'l10n_ar_afip_responsibility_type_id': cls.env.ref("l10n_ar.res_IVARI").id, + 'l10n_latam_identification_type_id': cls.env.ref("l10n_ar.it_cuit").id, + 'vat': '30111111118', + "street": 'Calle Falsa 123', + "city": 'Rosario', + "country_id": cls.env.ref("base.ar").id, + "state_id": cls.env.ref("base.state_ar_s").id, + "zip": '2000', + "phone": '+1 555 123 7073', + "email": 'info@example.com', + "website": 'www.example.com', + }) + cls.partner_ri = cls.company_ri.partner_id + + # ==== Company MONO ==== + cls.company_mono = cls.setup_company_data('(AR) Monotributista (Unit Tests)', chart_template=cls.env.ref('l10n_ar.l10nar_base_chart_template'))['company'] + cls.company_mono.write({ + 'parent_id': cls.env.ref('base.main_company').id, + 'currency_id': cls.env.ref('base.ARS').id, + 'name': '(AR) Monotributista (Unit Tests)', + "l10n_ar_afip_start_date": time.strftime('%Y-01-01'), + 'l10n_ar_gross_income_type': 'exempt', + }) + cls.company_mono.partner_id.write({ + 'name': '(AR) Monotributista (Unit Tests)', + 'l10n_ar_afip_responsibility_type_id': cls.env.ref("l10n_ar.res_RM").id, + 'l10n_latam_identification_type_id': cls.env.ref("l10n_ar.it_cuit").id, + 'vat': '20222222223', + "street": 'Calle Falsa 123', + "city": 'Rosario', + "country_id": cls.env.ref("base.ar").id, + "state_id": cls.env.ref("base.state_ar_s").id, + "zip": '2000', + "phone": '+1 555 123 7073', + "email": 'info@example.com', + "website": 'www.example.com', + }) + cls.partner_mono = cls.company_mono.partner_id + + # ==== Bank Account ==== + cls.bank_account_ri = cls.env['res.partner.bank'].create({ + 'acc_number': '7982898111100056688080', + 'partner_id': cls.company_ri.partner_id.id, + 'company_id': cls.company_ri.id, + }) + + # ==== Partners / Customers ==== + cls.res_partner_adhoc = cls.env['res.partner'].create({ + "name": "ADHOC SA", + "is_company": 1, + "city": "Rosario", + "zip": "2000", + "state_id": cls.env.ref("base.state_ar_s").id, + "country_id": cls.env.ref("base.ar").id, + "street": "Ovidio Lagos 41 bis", + "email": "info@adhoc.com.ar", + "phone": "(+54) (341) 208 0203", + "website": "http://www.adhoc.com.ar", + 'l10n_latam_identification_type_id': cls.env.ref("l10n_ar.it_cuit").id, + 'vat': "30714295698", + 'l10n_ar_afip_responsibility_type_id': cls.env.ref("l10n_ar.res_IVARI").id, + }) + cls.partner_cf = cls.env['res.partner'].create({ + "name": "Consumidor Final Anónimo", + "l10n_latam_identification_type_id": cls.env.ref('l10n_ar.it_Sigd').id, + "l10n_ar_afip_responsibility_type_id": cls.env.ref("l10n_ar.res_CF").id, + }) + cls.res_partner_gritti_mono = cls.env['res.partner'].create({ + "name": "Gritti Agrimensura (Monotributo)", + "is_company": 1, + "city": "Rosario", + "zip": "2000", + "state_id": cls.env.ref("base.state_ar_s").id, + "country_id": cls.env.ref("base.ar").id, + "street": "Calle Falsa 123", + "email": "info@example.com.ar", + "phone": "(+54) (341) 111 2222", + "website": "http://www.grittiagrimensura.com", + 'l10n_latam_identification_type_id': cls.env.ref("l10n_ar.it_cuit").id, + 'vat': "27320732811", + 'l10n_ar_afip_responsibility_type_id': cls.env.ref("l10n_ar.res_RM").id, + }) + cls.res_partner_cerrocastor = cls.env['res.partner'].create({ + "name": "Cerro Castor (Tierra del Fuego)", + "is_company": 1, + "city": "Ushuaia", + "state_id": cls.env.ref("base.state_ar_v").id, + "country_id": cls.env.ref("base.ar").id, + "street": "Ruta 3 km 26", + "email": "info@cerrocastor.com", + "phone": "(+00) (11) 4444 5556", + "website": "http://www.cerrocastor.com", + 'l10n_latam_identification_type_id': cls.env.ref("l10n_ar.it_cuit").id, + 'vat': "27333333339", + 'l10n_ar_afip_responsibility_type_id': cls.env.ref("l10n_ar.res_IVA_LIB").id, + }) + cls.res_partner_cmr = cls.env['res.partner'].create({ + "name": "Concejo Municipal de Rosario (IVA Sujeto Exento)", + "is_company": 1, + "city": "Rosario", + "zip": "2000", + "state_id": cls.env.ref("base.state_ar_s").id, + "country_id": cls.env.ref("base.ar").id, + "street": "Cordoba 501", + "email": "info@example.com.ar", + "phone": "(+54) (341) 222 3333", + "website": "http://www.concejorosario.gov.ar/", + 'l10n_latam_identification_type_id': cls.env.ref("l10n_ar.it_cuit").id, + 'vat': "30684679372", + 'l10n_ar_afip_responsibility_type_id': cls.env.ref("l10n_ar.res_IVAE").id, + }) + cls.res_partner_expresso = cls.env['res.partner'].create({ + "name": "Expresso", + "is_company": 1, + "city": "Barcelona", + "zip": "11002", + "country_id": cls.env.ref("base.es").id, + "street": "La gran avenida 123", + "email": "info@expresso.com", + "phone": "(+00) (11) 222 3333", + "website": "http://www.expresso.com/", + 'l10n_latam_identification_type_id': cls.env.ref("l10n_latam_base.it_fid").id, + 'vat': "2222333344445555", + 'l10n_ar_afip_responsibility_type_id': cls.env.ref("l10n_ar.res_EXT").id, + }) + cls.partner_mipyme = cls.env['res.partner'].create({ + "name": "Belgrano Cargas Y Logistica S (Mipyme)", + "is_company": 1, + "city": "Buenos Aires", + "zip": "1425", + "state_id": cls.env.ref("base.state_ar_c").id, + "country_id": cls.env.ref("base.ar").id, + "street": "Av. Santa Fe 4636", + "email": "mipyme@example.com", + "phone": "(123)-456-7890", + "website": "http://www.mypime-inc.com", + 'l10n_latam_identification_type_id': cls.env.ref("l10n_ar.it_cuit").id, + 'vat': "30714101443", + 'l10n_ar_afip_responsibility_type_id': cls.env.ref("l10n_ar.res_IVARI").id, + }) + cls.partner_mipyme_ex = cls.partner_mipyme.copy({'name': 'MiPyme Exento', 'l10n_ar_afip_responsibility_type_id': cls.env.ref('l10n_ar.res_IVAE').id}) + + # ==== Taxes ==== + cls.tax_21 = cls._search_tax(cls, 'iva_21') + cls.tax_27 = cls._search_tax(cls, 'iva_27') + cls.tax_0 = cls._search_tax(cls, 'iva_0') + cls.tax_10_5 = cls._search_tax(cls, 'iva_105') + cls.tax_no_gravado = cls._search_tax(cls, 'iva_no_gravado') + cls.tax_perc_iibb = cls._search_tax(cls, 'percepcion_iibb_ba') + cls.tax_iva_exento = cls._search_tax(cls, 'iva_exento') + + # ==== Products ==== + uom_unit = cls.env.ref('uom.product_uom_unit') + uom_hour = cls.env.ref('uom.product_uom_hour') + + cls.product_iva_21 = cls.env['product.product'].create({ + 'name': 'Large Cabinet (VAT 21)', + 'uom_id': uom_unit.id, + 'uom_po_id': uom_unit.id, + 'lst_price': 320.0, + 'type': "consu", + 'default_code': 'E-COM07', + }) + cls.service_iva_27 = cls.env['product.product'].create({ + # demo 'product_product_telefonia' + 'name': 'Telephone service (VAT 27)', + 'uom_id': uom_unit.id, + 'uom_po_id': uom_unit.id, + 'lst_price': 130.0, + 'type': 'service', + 'default_code': 'TELEFONIA', + 'taxes_id': [(6, 0, cls.tax_27.ids)], + }) + cls.product_iva_cero = cls.env['product.product'].create({ + # demo 'product_product_cero' + 'name': 'Non-industrialized animals and vegetables (VAT Zero)', + 'uom_id': uom_unit.id, + 'uom_po_id': uom_unit.id, + 'list_price': 160.0, + 'type': 'consu', + 'default_code': 'CERO', + 'taxes_id': [(6, 0, cls.tax_0.ids)], + }) + cls.product_iva_105 = cls.env['product.product'].create({ + # demo 'product.product_product_27' + 'name': 'Laptop Customized (VAT 10,5)', + 'uom_id': uom_unit.id, + 'uom_po_id': uom_unit.id, + 'type': 'consu', + 'default_code': '10,5', + 'taxes_id': [(6, 0, cls.tax_10_5.ids)], + }) + cls.service_iva_21 = cls.env['product.product'].create({ + # demo data product.product_product_2 + 'name': 'Virtual Home Staging (VAT 21)', + 'uom_id': uom_hour.id, + 'uom_po_id': uom_hour.id, + 'list_price': 38.25, + 'type': 'service', + 'default_code': 'VAT 21', + 'taxes_id': [(6, 0, cls.tax_21.ids)], + }) + cls.product_no_gravado = cls.env['product.product'].create({ + # demo data product_product_no_gravado + 'name': 'Untaxed concepts (VAT NT)', + 'uom_id': uom_unit.id, + 'uom_po_id': uom_unit.id, + 'list_price': 40.00, + 'type': 'consu', + 'default_code': 'NOGRAVADO', + 'taxes_id': [(6, 0, cls.tax_no_gravado.ids)], + }) + cls.product_iva_105_perc = cls.product_iva_105.copy({ + # product.product_product_25 + "name": "Laptop E5023 (VAT 10,5)", + # agregamos percecipn aplicada y sufrida tambien + 'taxes_id': [(6, 0, [cls.tax_10_5.id, cls.tax_perc_iibb.id])], + }) + cls.product_iva_exento = cls.env['product.product'].create({ + # demo product_product_exento + 'name': 'Book: Development in Flectra (VAT Exempt)', + 'uom_id': uom_unit.id, + 'uom_po_id': uom_unit.id, + "list_price": 80.0, + 'type': 'consu', + 'default_code': 'EXENTO', + 'taxes_id': [(6, 0, cls.tax_iva_exento.ids)], + }) + + # ==== Document Types ==== + cls.document_type = { + 'invoice_a': cls.env.ref('l10n_ar.dc_a_f'), + 'credit_note_a': cls.env.ref('l10n_ar.dc_a_nc'), + 'invoice_b': cls.env.ref('l10n_ar.dc_b_f'), + 'credit_note_b': cls.env.ref('l10n_ar.dc_b_nc'), + 'invoice_e': cls.env.ref('l10n_ar.dc_e_f'), + 'invoice_mipyme_a': cls.env.ref('l10n_ar.dc_fce_a_f'), + 'invoice_mipyme_b': cls.env.ref('l10n_ar.dc_fce_b_f'), + } + + # ==== Journals ==== + cls.sale_expo_journal_ri = cls.env["account.journal"].create({ + 'name': "Expo Sales Journal", + 'company_id': cls.company_ri.id, + 'type': "sale", + 'code': "S0002", + 'l10n_latam_use_documents': "True", + 'l10n_ar_afip_pos_number': 2, + 'l10n_ar_afip_pos_partner_id': cls.partner_ri.id, + 'l10n_ar_afip_pos_system': "FEERCEL", + 'refund_sequence': False, + }) + + # ==== Invoices ==== + cls.demo_invoices = {} + + def _create_test_invoices_like_demo(self, use_current_date=True): + """ Create in the unit tests the same invoices created in demo data """ + payment_term_id = self.env.ref("account.account_payment_term_end_following_month") + invoice_user_id = self.env.user + incoterm = self.env.ref("account.incoterm_EXW") + + invoices_to_create = { + 'test_invoice_1': { + "ref": "test_invoice_1: Invoice to gritti support service, vat 21", + "partner_id": self.res_partner_gritti_mono, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": "out_invoice", + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.service_iva_21} + ], + }, + 'test_invoice_2': { + "ref": "test_invoice_2: Invoice to CMR with vat 21, 27 and 10,5", + "partner_id": self.res_partner_cmr, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": "out_invoice", + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.product_iva_105, 'price_unit': 642.0, 'quantity': 5}, + {'product_id': self.service_iva_27, 'price_unit': 250.0, 'quantity': 1}, + {'product_id': self.product_iva_105_perc, 'price_unit': 3245.0, 'quantity': 2} + ], + }, + 'test_invoice_3': { + "ref": "test_invoice_3: Invoice to ADHOC with vat cero and 21", + "partner_id": self.res_partner_adhoc, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.product_iva_105, 'price_unit': 642.0, 'quantity': 5}, + {'product_id': self.product_iva_cero, 'price_unit': 200.0, 'quantity': 1} + ], + }, + 'test_invoice_4': { + 'ref': 'test_invoice_4: Invoice to ADHOC with vat exempt and 21', + "partner_id": self.res_partner_adhoc, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.product_iva_105, 'price_unit': 642.0, 'quantity': 5}, + {'product_id': self.product_iva_exento, 'price_unit': 100.0, 'quantity': 1}, + ], + }, + 'test_invoice_5': { + 'ref': 'test_invoice_5: Invoice to ADHOC with all type of taxes', + "partner_id": self.res_partner_adhoc, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.product_iva_105, 'price_unit': 642.0, 'quantity': 5}, + {'product_id': self.service_iva_27, 'price_unit': 250.0, 'quantity': 1}, + {'product_id': self.product_iva_105_perc, 'price_unit': 3245.0, 'quantity': 2}, + {'product_id': self.product_no_gravado, 'price_unit': 50.0, 'quantity': 10}, + {'product_id': self.product_iva_cero, 'price_unit': 200.0, 'quantity': 1}, + {'product_id': self.product_iva_exento, 'price_unit': 100.0, 'quantity': 1} + ], + }, + 'test_invoice_6': { + 'ref': 'test_invoice_6: Invoice to cerro castor, fiscal position changes taxes to exempt', + "partner_id": self.res_partner_cerrocastor, + "journal_id": self.sale_expo_journal_ri, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_incoterm_id": incoterm, + "invoice_line_ids": [ + {'product_id': self.product_iva_105, 'price_unit': 642.0, 'quantity': 5}, + {'product_id': self.service_iva_27, 'price_unit': 250.0, 'quantity': 1}, + {'product_id': self.product_iva_105_perc, 'price_unit': 3245.0, 'quantity': 2}, + {'product_id': self.product_no_gravado, 'price_unit': 50.0, 'quantity': 10}, + {'product_id': self.product_iva_cero, 'price_unit': 200.0, 'quantity': 1}, + {'product_id': self.product_iva_exento, 'price_unit': 100.0, 'quantity': 1}, + ], + }, + 'test_invoice_7': { + 'ref': 'test_invoice_7: Export invoice to expresso, fiscal position changes tax to exempt (type 4 because it have services)', + "partner_id": self.res_partner_expresso, + "journal_id": self.sale_expo_journal_ri, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_incoterm_id": incoterm, + "invoice_line_ids": [ + {'product_id': self.product_iva_105, 'price_unit': 642.0, 'quantity': 5}, + {'product_id': self.service_iva_27, 'price_unit': 250.0, 'quantity': 1}, + {'product_id': self.product_iva_105_perc, 'price_unit': 3245.0, 'quantity': 2}, + {'product_id': self.product_no_gravado, 'price_unit': 50.0, 'quantity': 10}, + {'product_id': self.product_iva_cero, 'price_unit': 200.0, 'quantity': 1}, + {'product_id': self.product_iva_exento, 'price_unit': 100.0, 'quantity': 1}, + ], + }, + 'test_invoice_8': { + 'ref': 'test_invoice_8: Invoice to consumidor final', + "partner_id": self.partner_cf, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.service_iva_21, 'price_unit': 642.0, 'quantity': 1}, + ], + }, + 'test_invoice_10': { + 'ref': 'test_invoice_10; Invoice to ADHOC in USD and vat 21', + "partner_id": self.res_partner_adhoc, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.product_iva_105, 'price_unit': 1000.0, 'quantity': 5}, + ], + "currency_id": self.env.ref("base.USD"), + }, + 'test_invoice_11': { + 'ref': 'test_invoice_11: Invoice to ADHOC with many lines in order to prove rounding error, with 4 decimals of precision for the currency and 2 decimals for the product the error apperar', + "partner_id": self.res_partner_adhoc, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.service_iva_21, 'price_unit': 1.12, 'quantity': 1, 'name': 'Support Services 1'}, + {'product_id': self.service_iva_21, 'price_unit': 1.12, 'quantity': 1, 'name': 'Support Services 2'}, + {'product_id': self.service_iva_21, 'price_unit': 1.12, 'quantity': 1, 'name': 'Support Services 3'}, + {'product_id': self.service_iva_21, 'price_unit': 1.12, 'quantity': 1, 'name': 'Support Services 4'}, + ], + }, + 'test_invoice_12': { + 'ref': 'test_invoice_12: Invoice to ADHOC with many lines in order to test rounding error, it is required to use a 4 decimal precision in prodct in order to the error occur', + "partner_id": self.res_partner_adhoc, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.service_iva_21, 'price_unit': 15.7076, 'quantity': 1, 'name': 'Support Services 1'}, + {'product_id': self.service_iva_21, 'price_unit': 5.3076, 'quantity': 2, 'name': 'Support Services 2'}, + {'product_id': self.service_iva_21, 'price_unit': 3.5384, 'quantity': 2, 'name': 'Support Services 3'}, + {'product_id': self.service_iva_21, 'price_unit': 1.6376, 'quantity': 2, 'name': 'Support Services 4'}, + ], + }, + 'test_invoice_13': { + 'ref': 'test_invoice_13: Invoice to ADHOC with many lines in order to test zero amount invoices y rounding error. it is required to set the product decimal precision to 4 and change 260.59 for 260.60 in order to reproduce the error', + "partner_id": self.res_partner_adhoc, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.service_iva_21, 'price_unit': 24.3, 'quantity': 3, 'name': 'Support Services 1'}, + {'product_id': self.service_iva_21, 'price_unit': 260.59, 'quantity': 1, 'name': 'Support Services 2'}, + {'product_id': self.service_iva_21, 'price_unit': 48.72, 'quantity': 1, 'name': 'Support Services 3'}, + {'product_id': self.service_iva_21, 'price_unit': 13.666, 'quantity': 1, 'name': 'Support Services 4'}, + {'product_id': self.service_iva_21, 'price_unit': 11.329, 'quantity': 2, 'name': 'Support Services 5'}, + {'product_id': self.service_iva_21, 'price_unit': 68.9408, 'quantity': 1, 'name': 'Support Services 6'}, + {'product_id': self.service_iva_21, 'price_unit': 4.7881, 'quantity': 2, 'name': 'Support Services 7'}, + {'product_id': self.service_iva_21, 'price_unit': 12.0625, 'quantity': 2, 'name': 'Support Services 8'}, + ], + }, + 'test_invoice_14': { + 'ref': 'test_invoice_14: Export invoice to expresso, fiscal position changes tax to exempt (type 1 because only products)', + "partner_id": self.res_partner_expresso, + "journal_id": self.sale_expo_journal_ri, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_incoterm_id": incoterm, + "invoice_line_ids": [ + {'product_id': self.product_iva_105, 'price_unit': 642.0, 'quantity': 5}, + ], + }, + 'test_invoice_15': { + 'ref': 'test_invoice_15: Export invoice to expresso, fiscal position changes tax to exempt (type 2 because only service)', + "partner_id": self.res_partner_expresso, + "journal_id": self.sale_expo_journal_ri, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_incoterm_id": incoterm, + "invoice_line_ids": [ + {'product_id': self.service_iva_27, 'price_unit': 250.0, 'quantity': 1}, + ], + }, + 'test_invoice_16': { + 'ref': 'test_invoice_16: Export invoice to expresso, fiscal position changes tax to exempt (type 1 because it have products only, used to test refund of expo)', + "partner_id": self.res_partner_expresso, + "journal_id": self.sale_expo_journal_ri, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_incoterm_id": incoterm, + "invoice_line_ids": [ + {'product_id': self.product_iva_105, 'price_unit': 642.0, 'quantity': 5}, + ], + }, + 'test_invoice_17': { + 'ref': 'test_invoice_17: Invoice to ADHOC with 100%% of discount', + "partner_id": self.res_partner_adhoc, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.service_iva_21, 'price_unit': 24.3, 'quantity': 3, 'name': 'Support Services 8', 'discount': 100}, + ], + }, + 'test_invoice_18': { + 'ref': 'test_invoice_18: Invoice to ADHOC with 100%% of discount and with different VAT aliquots', + "partner_id": self.res_partner_adhoc, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.service_iva_21, 'price_unit': 24.3, 'quantity': 3, 'name': 'Support Services 8', 'discount': 100}, + {'product_id': self.service_iva_27, 'price_unit': 250.0, 'quantity': 1, 'discount': 100}, + {'product_id': self.product_iva_105_perc, 'price_unit': 3245.0, 'quantity': 1}, + ], + }, + 'test_invoice_19': { + 'ref': 'test_invoice_19: Invoice to ADHOC with multiple taxes and perceptions', + "partner_id": self.res_partner_adhoc, + "invoice_user_id": invoice_user_id, + "invoice_payment_term_id": payment_term_id, + "move_type": 'out_invoice', + "company_id": self.company_ri, + "invoice_line_ids": [ + {'product_id': self.service_iva_21, 'price_unit': 24.3, 'quantity': 3, 'name': 'Support Services 8'}, + {'product_id': self.service_iva_27, 'price_unit': 250.0, 'quantity': 1}, + {'product_id': self.product_iva_105_perc, 'price_unit': 3245.0, 'quantity': 1}, + ], + } + } + + for key, values in invoices_to_create.items(): + with Form(self.env['account.move'].with_context(default_move_type=values['move_type'])) as invoice_form: + invoice_form.ref = values['ref'] + invoice_form.partner_id = values['partner_id'] + invoice_form.invoice_user_id = values['invoice_user_id'] + invoice_form.invoice_payment_term_id = values['invoice_payment_term_id'] + if not use_current_date: + invoice_form.invoice_date = values['invoice_date'] + if values.get('invoice_incoterm_id'): + invoice_form.invoice_incoterm_id = values['invoice_incoterm_id'] + for line in values['invoice_line_ids']: + with invoice_form.invoice_line_ids.new() as line_form: + line_form.product_id = line.get('product_id') + line_form.price_unit = line.get('price_unit') + line_form.quantity = line.get('quantity') + line_form.name = 'xxxx' + line_form.account_id = self.company_data['default_account_revenue'] + invoice = invoice_form.save() + self.demo_invoices[key] = invoice + + # Helpers + + @classmethod + def _get_afip_pos_system_real_name(cls): + return {'PREPRINTED': 'II_IM'} + + def _create_journal(self, afip_ws, data=None): + """ Create a journal of a given AFIP ws type. + If there is a problem because we are using a AFIP certificate that is already been in use then change the certificate and try again """ + data = data or {} + afip_ws = afip_ws.upper() + pos_number = str(random.randint(0, 99999)) + if 'l10n_ar_afip_pos_number' in data: + pos_number = data.get('l10n_ar_afip_pos_number') + values = {'name': '%s %s' % (afip_ws.replace('WS', ''), pos_number), + 'type': 'sale', + 'code': afip_ws, + 'l10n_ar_afip_pos_system': self._get_afip_pos_system_real_name().get(afip_ws), + 'l10n_ar_afip_pos_number': pos_number, + 'l10n_latam_use_documents': True, + 'company_id': self.env.company.id, + 'l10n_ar_afip_pos_partner_id': self.partner_ri.id, + 'sequence': 1} + values.update(data) + + journal = self.env['account.journal'].create(values) + _logger.info('Created journal %s for company %s' % (journal.name, self.env.company.name)) + return journal + + def _create_invoice(self, data=None, invoice_type='out_invoice'): + data = data or {} + with Form(self.env['account.move'].with_context(default_move_type=invoice_type)) as invoice_form: + invoice_form.partner_id = data.get('partner', self.partner) + if 'in_' not in invoice_type: + invoice_form.journal_id = data.get('journal', self.journal) + + if data.get('document_type'): + invoice_form.l10n_latam_document_type_id = data.get('document_type') + if data.get('document_number'): + invoice_form.l10n_latam_document_number = data.get('document_number') + if data.get('incoterm'): + invoice_form.invoice_incoterm_id = data.get('incoterm') + if data.get('currency'): + invoice_form.currency_id = data.get('currency') + for line in data.get('lines', [{}]): + with invoice_form.invoice_line_ids.new() as invoice_line_form: + if line.get('display_type'): + invoice_line_form.display_type = line.get('display_type') + invoice_line_form.name = line.get('name', 'not invoice line') + else: + invoice_line_form.product_id = line.get('product', self.product_iva_21) + invoice_line_form.quantity = line.get('quantity', 1) + invoice_line_form.price_unit = line.get('price_unit', 100) + invoice_form.invoice_date = invoice_form.date + invoice = invoice_form.save() + return invoice + + def _create_invoice_product(self, data=None): + data = data or {} + return self._create_invoice(data) + + def _create_invoice_service(self, data=None): + data = data or {} + newlines = [] + for line in data.get('lines', [{}]): + line.update({'product': self.service_iva_27}) + newlines.append(line) + data.update({'lines': newlines}) + return self._create_invoice(data) + + def _create_invoice_product_service(self, data=None): + data = data or {} + newlines = [] + for line in data.get('lines', [{}]): + line.update({'product': self.product_iva_21}) + newlines.append(line) + data.update({'lines': newlines + [{'product': self.service_iva_27}]}) + return self._create_invoice(data) + + def _create_credit_note(self, invoice, data=None): + data = data or {} + refund_wizard = self.env['account.move.reversal'].with_context({'active_ids': [invoice.id], 'active_model': 'account.move'}).create({ + 'reason': data.get('reason', 'Mercadería defectuosa'), + 'refund_method': data.get('refund_method', 'refund')}) + + forced_document_type = data.get('document_type') + if forced_document_type: + refund_wizard.l10n_latam_document_type_id = forced_document_type.id + + res = refund_wizard.reverse_moves() + refund = self.env['account.move'].browse(res['res_id']) + return refund + + def _create_debit_note(self, invoice, data=None): + data = data or {} + debit_note_wizard = self.env['account.debit.note'].with_context( + {'active_ids': [invoice.id], 'active_model': 'account.move', 'default_copy_lines': True}).create({ + 'reason': data.get('reason', 'Mercadería defectuosa')}) + res = debit_note_wizard.create_debit() + debit_note = self.env['account.move'].browse(res['res_id']) + return debit_note + + def _search_tax(self, tax_type): + res = self.env['account.tax'].with_context(active_test=False).search([ + ('type_tax_use', '=', 'sale'), + ('company_id', '=', self.env.company.id), + ('tax_group_id', '=', self.env.ref('l10n_ar.tax_group_' + tax_type).id)], limit=1) + self.assertTrue(res, '%s Tax was not found' % (tax_type)) + return res + + def _search_fp(self, name): + return self.env['account.fiscal.position'].search([('company_id', '=', self.env.company.id), ('name', '=', name)]) + + def _post(self, invoice): + invoice.action_post() + self.assertEqual(invoice.state, 'posted') + + def _prepare_multicurrency_values(self): + # Enable multi currency + self.env.user.write({'groups_id': [(4, self.env.ref('base.group_multi_currency').id)]}) + # Set ARS as main currency + self._set_today_rate(self.env.ref('base.ARS'), 1.0) + # Set Rates for USD currency + self._set_today_rate(self.env.ref('base.USD'), 1.0 / 162.013) + + def _set_today_rate(self, currency, value): + rate_obj = self.env['res.currency.rate'] + rate = rate_obj.search([('currency_id', '=', currency.id), ('name', '=', fields.Date.to_string(fields.Date.today())), + ('company_id', '=', self.env.company.id)]) + if rate: + rate.rate = value + else: + rate_obj.create({'company_id': self.env.company.id, 'currency_id': currency.id, 'rate': value}) + _logger.log(25, 'Using %s rate %s' % (currency.name, currency.rate)) diff --git a/addons/l10n_ar/tests/test_manual.py b/addons/l10n_ar/tests/test_manual.py new file mode 100644 index 0000000000..e5fe6e1851 --- /dev/null +++ b/addons/l10n_ar/tests/test_manual.py @@ -0,0 +1,99 @@ +# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. +from . import common +from flectra.tests import tagged + + +@tagged('-at_install', 'post_install') +class TestManual(common.TestAr): + + @classmethod + def setUpClass(cls): + super(TestManual, cls).setUpClass() + cls.journal = cls._create_journal(cls, 'preprinted') + cls.partner = cls.res_partner_adhoc + cls._create_test_invoices_like_demo(cls) + + def test_01_create_invoice(self): + """ Create and validate an invoice for a Responsable Inscripto + + * Proper set the current user company + * Properly set the tax amount of the product / partner + * Proper fiscal position (this case not fiscal position is selected) + """ + invoice = self._create_invoice() + self.assertEqual(invoice.company_id, self.company_ri, 'created with wrong company') + self.assertEqual(invoice.amount_tax, 21, 'invoice taxes are not properly set') + self.assertEqual(invoice.amount_total, 121.0, 'invoice taxes has not been applied to the total') + self.assertEqual(invoice.l10n_latam_document_type_id, self.document_type['invoice_a'], 'selected document type should be Factura A') + self._post(invoice) + self.assertEqual(invoice.state, 'posted', 'invoice has not been validate in Flectra') + self.assertEqual(invoice.name, 'FA-A %05d-00000002' % self.journal.l10n_ar_afip_pos_number, 'Invoice number is wrong') + + def test_02_fiscal_position(self): + # ADHOC SA > IVA Responsable Inscripto > Without Fiscal Positon + invoice = self._create_invoice({'partner': self.partner}) + self.assertFalse(invoice.fiscal_position_id, 'Fiscal position should be set to empty') + + # Consumidor Final > IVA Responsable Inscripto > Without Fiscal Positon + invoice = self._create_invoice({'partner': self.partner_cf}) + self.assertFalse(invoice.fiscal_position_id, 'Fiscal position should be set to empty') + + # Cerro Castor > IVA Liberado – Ley Nº 19.640 > Compras / Ventas Zona Franca > IVA Exento + invoice = self._create_invoice({'partner': self.res_partner_cerrocastor}) + self.assertEqual(invoice.fiscal_position_id, self._search_fp('Compras / Ventas Zona Franca')) + + # Expresso > Cliente / Proveedor del Exterior > > IVA Exento + invoice = self._create_invoice({'partner': self.res_partner_expresso}) + self.assertEqual(invoice.fiscal_position_id, self._search_fp('Compras / Ventas al exterior')) + + def test_03_corner_cases(self): + """ Mono partner of type Service and VAT 21 """ + self._post(self.demo_invoices['test_invoice_1']) + + def test_04_corner_cases(self): + """ Exento partner with multiple VAT types 21, 27 and 10,5' """ + self._post(self.demo_invoices['test_invoice_2']) + + def test_05_corner_cases(self): + """ RI partner with VAT 0 and 21 """ + self._post(self.demo_invoices['test_invoice_3']) + + def test_06_corner_cases(self): + """ RI partner with VAT exempt and 21 """ + self._post(self.demo_invoices['test_invoice_4']) + + def test_07_corner_cases(self): + """ RI partner with all type of taxes """ + self._post(self.demo_invoices['test_invoice_5']) + + def test_08_corner_cases(self): + """ Consumidor Final """ + self._post(self.demo_invoices['test_invoice_8']) + + def test_09_corner_cases(self): + """ RI partner with many lines in order to prove rounding error, with 4 decimals of precision for the + currency and 2 decimals for the product the error appear """ + self._post(self.demo_invoices['test_invoice_11']) + + def test_10_corner_cases(self): + """ RI partner with many lines in order to test rounding error, it is required to use a 4 decimal precision + in product in order to the error occur """ + self._post(self.demo_invoices['test_invoice_12']) + + def test_11_corner_cases(self): + """ RI partner with many lines in order to test zero amount invoices y rounding error. it is required to + set the product decimal precision to 4 and change 260,59 for 260.60 in order to reproduce the error """ + self._post(self.demo_invoices['test_invoice_13']) + + def test_12_corner_cases(self): + """ RI partner with 100%% of discount """ + self._post(self.demo_invoices['test_invoice_17']) + + def test_13_corner_cases(self): + """ RI partner with 100%% of discount and with different VAT aliquots """ + self._post(self.demo_invoices['test_invoice_18']) + + def test_14_corner_cases(self): + """ Responsable Inscripto" in USD and VAT 21 """ + self._prepare_multicurrency_values() + self._post(self.demo_invoices['test_invoice_10']) diff --git a/addons/l10n_vn/data/account_data.xml b/addons/l10n_vn/data/account_data.xml index c125c2e639..5c20979879 100644 --- a/addons/l10n_vn/data/account_data.xml +++ b/addons/l10n_vn/data/account_data.xml @@ -4,13 +4,13 @@ - Thuế GTGT 0% + VAT 0% - Thuế GTGT 5% + VAT 5% - Thuế GTGT 10% + VAT 10% diff --git a/addons/l10n_vn/data/account_tax_data.xml b/addons/l10n_vn/data/account_tax_data.xml index 0c42c62c2a..b5c0259f15 100644 --- a/addons/l10n_vn/data/account_tax_data.xml +++ b/addons/l10n_vn/data/account_tax_data.xml @@ -4,8 +4,8 @@ - Thuế GTGT được khấu trừ 10% - Thuế GTGT được khấu trừ 10% + Deductible VAT 10% + Deductible VAT 10% percent purchase @@ -39,8 +39,8 @@ - Thuế GTGT được khấu trừ 5% - Thuế GTGT được khấu trừ 5% + Deductible VAT 5% + Deductible VAT 5% percent purchase @@ -74,8 +74,8 @@ - Thuế GTGT được khấu trừ 0% - Thuế GTGT được khấu trừ 0% + Deductible VAT 0% + Deductible VAT 0% percent purchase @@ -107,8 +107,8 @@ - Thuế GTGT phải nộp 10% - Thuế GTGT phải nộp 10% + Value Added Tax (VAT) 10% + Value Added Tax (VAT) 10% percent sale @@ -142,8 +142,8 @@ - Thuế GTGT phải nộp 5% - Thuế GTGT phải nộp 5% + Value Added Tax (VAT) 5% + Value Added Tax (VAT) 5% percent sale @@ -177,8 +177,8 @@ - Thuế GTGT phải nộp 0% - Thuế GTGT phải nộp 0% + Value Added Tax (VAT) 0% + Value Added Tax (VAT) 0% percent sale diff --git a/addons/l10n_vn/data/account_tax_report_data.xml b/addons/l10n_vn/data/account_tax_report_data.xml index 96e218b61a..ee49f009f9 100644 --- a/addons/l10n_vn/data/account_tax_report_data.xml +++ b/addons/l10n_vn/data/account_tax_report_data.xml @@ -7,136 +7,136 @@ - HHDV mua vào + Purchase of Goods and Services - Thuế GTGT HHDV mua vào + VAT on purchase of goods and services - Thuế GTGT HHDV mua vào chịu thuế 0% - Thuế GTGT HHDV mua vào chịu thuế 0% + VAT on purchase of goods and services 0% + VAT on purchase of goods and services 0% - Thuế GTGT HHDV mua vào chịu thuế 5% - Thuế GTGT HHDV mua vào chịu thuế 5% + VAT on purchase of goods and services 5% + VAT on purchase of goods and services 5% - Thuế GTGT HHDV mua vào chịu thuế 10% - Thuế GTGT HHDV mua vào chịu thuế 10% + VAT on purchase of goods and services 10% + VAT on purchase of goods and services 10% - Giá trị HHDV mua vào + Untaxed Purchase of Goods and Services - Giá trị HHDV mua vào chịu thuế 0% - Giá trị HHDV mua vào chịu thuế 0% + Untaxed Purchase of Goods and Services taxed 0% + Untaxed Purchase of Goods and Services taxed 0% - Giá trị HHDV mua vào chịu thuế 5% - Giá trị HHDV mua vào chịu thuế 5% + Untaxed Purchase of Goods and Services taxed 5% + Untaxed Purchase of Goods and Services taxed 5% - Giá trị HHDV mua vào chịu thuế 10% - Giá trị HHDV mua vào chịu thuế 10% + Untaxed Purchase of Goods and Services taxed 10% + Untaxed Purchase of Goods and Services taxed 10% - HHDV bán ra + Sales of Goods and Services - Thuế GTGT HHDV bán ra + VAT on sales of goods and services - Thuế GTGT HHDV bán ra chịu thuế 0% - Thuế GTGT HHDV bán ra chịu thuế 0% + VAT on sales of goods and services 0% + VAT on sales of goods and services 0% - Thuế GTGT HHDV bán ra chịu thuế 5% - Thuế GTGT HHDV bán ra chịu thuế 5% + VAT on sales of goods and services 5% + VAT on sales of goods and services 5% - Thuế GTGT HHDV bán ra chịu thuế 10% - Thuế GTGT HHDV bán ra chịu thuế 10% + VAT on sales of goods and services 10% + VAT on sales of goods and services 10% - Giá trị HHDV bán ra + Untaxed Sales of Goods and Services - Giá trị HHDV bán ra chịu thuế 0% - Giá trị HHDV bán ra chịu thuế 0% + Untaxed sales of goods and services taxed 0% + Untaxed sales of goods and services taxed 0% - Giá trị HHDV bán ra chịu thuế 5% - Giá trị HHDV bán ra chịu thuế 5% + Untaxed sales of goods and services taxed 5% + Untaxed sales of goods and services taxed 5% - Giá trị HHDV bán ra chịu thuế 10% - Giá trị HHDV bán ra chịu thuế 10% + Untaxed sales of goods and services taxed 10% + Untaxed sales of goods and services taxed 10% diff --git a/addons/l10n_vn/i18n_extra/l10n_vn.pot b/addons/l10n_vn/i18n_extra/l10n_vn.pot index 10de7c801c..f068fd353e 100644 --- a/addons/l10n_vn/i18n_extra/l10n_vn.pot +++ b/addons/l10n_vn/i18n_extra/l10n_vn.pot @@ -4,10 +4,10 @@ # msgid "" msgstr "" -"Project-Id-Version: Flectra Server 2.0alpha1+e\n" +"Project-Id-Version: Flectra Server 2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-02-21 11:21+0000\n" -"PO-Revision-Date: 2020-02-21 11:21+0000\n" +"POT-Creation-Date: 2021-09-30 03:34+0000\n" +"PO-Revision-Date: 2021-09-30 03:34+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -16,217 +16,285 @@ msgstr "" "Plural-Forms: \n" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart335 #: model:account.account.template,name:l10n_vn.chart335 msgid "Accrued expenses" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart141 #: model:account.account.template,name:l10n_vn.chart141 msgid "Advances" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2291 #: model:account.account.template,name:l10n_vn.chart2291 msgid "Allowances for decline in value of trading securities" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2293 #: model:account.account.template,name:l10n_vn.chart2293 msgid "Allowances for doubtful debts" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2292 #: model:account.account.template,name:l10n_vn.chart2292 msgid "Allowances for impairment of investments in other entities" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2294 #: model:account.account.template,name:l10n_vn.chart2294 msgid "Allowances for inventories" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2143 #: model:account.account.template,name:l10n_vn.chart2143 msgid "Amortization of intangible assets" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart34312 #: model:account.account.template,name:l10n_vn.chart34312 msgid "Bond discounts" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart34313 #: model:account.account.template,name:l10n_vn.chart34313 msgid "Bond premiums" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1212 +#: model:account.account,name:l10n_vn.1_chart1282 #: model:account.account.template,name:l10n_vn.chart1212 #: model:account.account.template,name:l10n_vn.chart1282 msgid "Bonds" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3531 #: model:account.account.template,name:l10n_vn.chart3531 msgid "Bonus fund" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3411 #: model:account.account.template,name:l10n_vn.chart3411 msgid "Borrowing loans liabilities" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2111 #: model:account.account.template,name:l10n_vn.chart2111 msgid "Buildings and structures" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart441 #: model:account.account.template,name:l10n_vn.chart441 msgid "Capital expenditure funds" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4112 #: model:account.account.template,name:l10n_vn.chart4112 msgid "Capital surplus" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2135 #: model:account.account.template,name:l10n_vn.chart2135 msgid "Computer software" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1541 #: model:account.account.template,name:l10n_vn.chart1541 msgid "Construction contracts" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3522 #: model:account.account.template,name:l10n_vn.chart3522 msgid "Construction warranty provisions" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2412 #: model:account.account.template,name:l10n_vn.chart2412 msgid "Construction works" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4113 #: model:account.account.template,name:l10n_vn.chart4113 msgid "Conversion options on convertible bonds" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3432 #: model:account.account.template,name:l10n_vn.chart3432 msgid "Convertible bonds" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2132 #: model:account.account.template,name:l10n_vn.chart2132 msgid "Copyrights" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3334 #: model:account.account.template,name:l10n_vn.chart3334 msgid "Corporate income tax" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart632 #: model:account.account.template,name:l10n_vn.chart632 msgid "Costs of goods sold" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart8211 #: model:account.account.template,name:l10n_vn.chart8211 msgid "Current tax expense" msgstr "" #. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_purchase_vat0 +#: model:account.tax,name:l10n_vn.1_tax_purchase_vat0 +#: model:account.tax.template,description:l10n_vn.tax_purchase_vat0 +#: model:account.tax.template,name:l10n_vn.tax_purchase_vat0 +msgid "Deductible VAT 0%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_purchase_vat10 +#: model:account.tax,name:l10n_vn.1_tax_purchase_vat10 +#: model:account.tax.template,description:l10n_vn.tax_purchase_vat10 +#: model:account.tax.template,name:l10n_vn.tax_purchase_vat10 +msgid "Deductible VAT 10%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_purchase_vat5 +#: model:account.tax,name:l10n_vn.1_tax_purchase_vat5 +#: model:account.tax.template,description:l10n_vn.tax_purchase_vat5 +#: model:account.tax.template,name:l10n_vn.tax_purchase_vat5 +msgid "Deductible VAT 5%" +msgstr "" + +#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart243 #: model:account.account.template,name:l10n_vn.chart243 msgid "Deferred tax assets" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart8212 #: model:account.account.template,name:l10n_vn.chart8212 msgid "Deferred tax expense" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart347 #: model:account.account.template,name:l10n_vn.chart347 msgid "Deferred tax liabilities" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart344 #: model:account.account.template,name:l10n_vn.chart344 msgid "Deposits received" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6234 #: model:account.account.template,name:l10n_vn.chart6234 msgid "Depreciation expense" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2142 #: model:account.account.template,name:l10n_vn.chart2142 msgid "Depreciation of finance lease assets" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2147 #: model:account.account.template,name:l10n_vn.chart2147 msgid "Depreciation of investment properties" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2141 #: model:account.account.template,name:l10n_vn.chart2141 msgid "Depreciation of tangible fixed assets" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart412 #: model:account.account.template,name:l10n_vn.chart412 msgid "Differences upon asset revaluation" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart622 #: model:account.account.template,name:l10n_vn.chart622 msgid "Direct labour costs" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart621 #: model:account.account.template,name:l10n_vn.chart621 msgid "Direct raw material costs" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart417 #: model:account.account.template,name:l10n_vn.chart417 msgid "Enterprise reorganization assistance fund" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3523 #: model:account.account.template,name:l10n_vn.chart3523 msgid "Enterprise restructuring provisions" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart33381 #: model:account.account.template,name:l10n_vn.chart33381 msgid "Environment protection tax" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1534 #: model:account.account.template,name:l10n_vn.chart1534 msgid "Equipment and spare parts for replacement" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2281 #: model:account.account.template,name:l10n_vn.chart2281 msgid "Equity investments in other entities Other investment" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4132 #: model:account.account.template,name:l10n_vn.chart4132 msgid "Exchange rate differences in pre-operating period" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4131 #: model:account.account.template,name:l10n_vn.chart4131 msgid "" "Exchange rate differences on revaluation of monetary items denominated in " @@ -234,355 +302,363 @@ msgid "" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1611 #: model:account.account.template,name:l10n_vn.chart1611 msgid "Expenditure brought forward" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1612 #: model:account.account.template,name:l10n_vn.chart1612 msgid "Expenditure of current year" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6271 #: model:account.account.template,name:l10n_vn.chart6271 msgid "Factory staff costs" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3339 #: model:account.account.template,name:l10n_vn.chart3339 msgid "Fees, charges and other payables" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2122 #: model:account.account.template,name:l10n_vn.chart2122 msgid "Finance lease intangible fixed assets" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3412 #: model:account.account.template,name:l10n_vn.chart3412 msgid "Finance lease liabilities" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2121 #: model:account.account.template,name:l10n_vn.chart2121 msgid "Finance lease tangible fixed assets" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart635 #: model:account.account.template,name:l10n_vn.chart635 msgid "Financial expenses" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart515 #: model:account.account.template,name:l10n_vn.chart515 msgid "Financial income" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1551 #: model:account.account.template,name:l10n_vn.chart1551 msgid "Finished products - inventory" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1557 #: model:account.account.template,name:l10n_vn.chart1557 msgid "Finished products - real estates" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6414 #: model:account.account.template,name:l10n_vn.chart6414 msgid "Fixed asset deprecation" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6274 +#: model:account.account,name:l10n_vn.1_chart6424 #: model:account.account.template,name:l10n_vn.chart6274 #: model:account.account.template,name:l10n_vn.chart6424 msgid "Fixed asset depreciation" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2411 #: model:account.account.template,name:l10n_vn.chart2411 msgid "Fixed assets prior to commissioning" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1122 #: model:account.account.template,name:l10n_vn.chart1122 msgid "Foreign currencies" msgstr "" #. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_vn -msgid "Giá trị HHDV bán ra" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_02_02_vn -msgid "Giá trị HHDV bán ra chịu thuế 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_02_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_02_02_vn -msgid "Giá trị HHDV bán ra chịu thuế 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_02_02_vn -msgid "Giá trị HHDV bán ra chịu thuế 5%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_vn -msgid "Giá trị HHDV mua vào" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_02_01_vn -msgid "Giá trị HHDV mua vào chịu thuế 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_02_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_02_01_vn -msgid "Giá trị HHDV mua vào chịu thuế 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_02_01_vn -msgid "Giá trị HHDV mua vào chịu thuế 5%" -msgstr "" - -#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart158 #: model:account.account.template,name:l10n_vn.chart158 msgid "Goods in bonded warehouse" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart151 #: model:account.account.template,name:l10n_vn.chart151 msgid "Goods in transit" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart171 #: model:account.account.template,name:l10n_vn.chart171 msgid "Government bonds purchased for resale" msgstr "" #. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_vn -msgid "HHDV bán ra" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_vn -msgid "HHDV mua vào" -msgstr "" - -#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3384 #: model:account.account.template,name:l10n_vn.chart3384 msgid "Health insurance" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3333 #: model:account.account.template,name:l10n_vn.chart3333 msgid "Import and export tax" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1562 #: model:account.account.template,name:l10n_vn.chart1562 msgid "Incidental purchase costs" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart911 #: model:account.account.template,name:l10n_vn.chart911 msgid "Income Summary" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1533 #: model:account.account.template,name:l10n_vn.chart1533 msgid "Instruments for renting" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3363 #: model:account.account.template,name:l10n_vn.chart3363 msgid "Intra-company payables for borrowing costs eligible to be capitalized" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3362 #: model:account.account.template,name:l10n_vn.chart3362 msgid "Intra-company payables for foreign exchange differences" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3361 #: model:account.account.template,name:l10n_vn.chart3361 msgid "Intra-company payables for operating capital received" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1363 #: model:account.account.template,name:l10n_vn.chart1363 msgid "" "Intra-company receivables on borrowing costs eligible to be capitalized" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1362 #: model:account.account.template,name:l10n_vn.chart1362 msgid "Intra-company receivables on foreign exchange" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart414 #: model:account.account.template,name:l10n_vn.chart414 msgid "Investment and development fund" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart222 #: model:account.account.template,name:l10n_vn.chart222 msgid "Investment in joint ventures and associates" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart221 #: model:account.account.template,name:l10n_vn.chart221 msgid "Investment in subsidiaries" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart217 #: model:account.account.template,name:l10n_vn.chart217 msgid "Investment properties" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6231 #: model:account.account.template,name:l10n_vn.chart6231 msgid "Labour costs" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3337 #: model:account.account.template,name:l10n_vn.chart3337 msgid "Land and housing tax, and rental charges" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2131 #: model:account.account.template,name:l10n_vn.chart2131 msgid "Land use rights" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1283 #: model:account.account.template,name:l10n_vn.chart1283 msgid "Lending loans" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2136 #: model:account.account.template,name:l10n_vn.chart2136 msgid "Licenses and franchises" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_vn_template_liquidity_transfer #: model:account.account.template,name:l10n_vn.vn_template_liquidity_transfer msgid "Liquidity Transfer" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2112 #: model:account.account.template,name:l10n_vn.chart2112 msgid "Machinery and equipment" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2413 #: model:account.account.template,name:l10n_vn.chart2413 msgid "Major repairs of fixed assets" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3534 #: model:account.account.template,name:l10n_vn.chart3534 msgid "Management bonus fund" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6232 +#: model:account.account,name:l10n_vn.1_chart6272 #: model:account.account.template,name:l10n_vn.chart6232 #: model:account.account.template,name:l10n_vn.chart6272 msgid "Material costs" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6412 #: model:account.account.template,name:l10n_vn.chart6412 msgid "Materials and packing materials" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2113 #: model:account.account.template,name:l10n_vn.chart2113 msgid "Means of transportation and transmission" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1123 #: model:account.account.template,name:l10n_vn.chart1123 msgid "Monetary Gold" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart244 #: model:account.account.template,name:l10n_vn.chart244 msgid "Mortgage, collaterals and deposits" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4611 #: model:account.account.template,name:l10n_vn.chart4611 msgid "Non-business funds bought forward" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4612 #: model:account.account.template,name:l10n_vn.chart4612 msgid "Non-business funds for current year" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart466 #: model:account.account.template,name:l10n_vn.chart466 msgid "Non-business funds used for fixed asset acquisitions" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2114 #: model:account.account.template,name:l10n_vn.chart2114 msgid "Office equipment and furniture" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6423 #: model:account.account.template,name:l10n_vn.chart6423 msgid "Office equipment expenses" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6422 #: model:account.account.template,name:l10n_vn.chart6422 msgid "Office supply expenses" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3431 #: model:account.account.template,name:l10n_vn.chart3431 msgid "Ordinary bonds" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart41111 #: model:account.account.template,name:l10n_vn.chart41111 msgid "Ordinary shares with voting rights" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart8111 #: model:account.account.template,name:l10n_vn.chart8111 msgid "Other Expenses" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart711 #: model:account.account.template,name:l10n_vn.chart711 msgid "Other Income" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4118 #: model:account.account.template,name:l10n_vn.chart4118 msgid "Other capital" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart418 #: model:account.account.template,name:l10n_vn.chart418 msgid "Other equity funds" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6238 +#: model:account.account,name:l10n_vn.1_chart6278 +#: model:account.account,name:l10n_vn.1_chart6418 +#: model:account.account,name:l10n_vn.1_chart6428 #: model:account.account.template,name:l10n_vn.chart6238 #: model:account.account.template,name:l10n_vn.chart6278 #: model:account.account.template,name:l10n_vn.chart6418 @@ -591,71 +667,87 @@ msgid "Other expenses" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2118 #: model:account.account.template,name:l10n_vn.chart2118 msgid "Other fixed assets" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1288 #: model:account.account.template,name:l10n_vn.chart1288 msgid "Other held to maturity investments" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2138 #: model:account.account.template,name:l10n_vn.chart2138 msgid "Other intangible fixed assets" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3368 #: model:account.account.template,name:l10n_vn.chart3368 msgid "Other inter-company payables" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1368 #: model:account.account.template,name:l10n_vn.chart1368 msgid "Other intra-company receivables" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1542 #: model:account.account.template,name:l10n_vn.chart1542 msgid "Other products" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3524 #: model:account.account.template,name:l10n_vn.chart3524 msgid "Other provisions" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5118 #: model:account.account.template,name:l10n_vn.chart5118 msgid "Other revenue" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1218 #: model:account.account.template,name:l10n_vn.chart1218 msgid "Other securities and financial instruments" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart33382 #: model:account.account.template,name:l10n_vn.chart33382 msgid "Other taxes" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3388 #: model:account.account.template,name:l10n_vn.chart3388 msgid "Others" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1388 #: model:account.account.template,name:l10n_vn.chart1388 msgid "Others receivables" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart33311 #: model:account.account.template,name:l10n_vn.chart33311 msgid "Output VAT" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6277 +#: model:account.account,name:l10n_vn.1_chart6417 +#: model:account.account,name:l10n_vn.1_chart6427 #: model:account.account.template,name:l10n_vn.chart6277 #: model:account.account.template,name:l10n_vn.chart6417 #: model:account.account.template,name:l10n_vn.chart6427 @@ -663,315 +755,274 @@ msgid "Outside services" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6237 #: model:account.account.template,name:l10n_vn.chart6237 msgid "Outside services " msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart157 #: model:account.account.template,name:l10n_vn.chart157 msgid "Outward goods on consignment" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart34311 #: model:account.account.template,name:l10n_vn.chart34311 msgid "Par value of bonds" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2133 #: model:account.account.template,name:l10n_vn.chart2133 msgid "Patents and inventions" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3385 #: model:account.account.template,name:l10n_vn.chart3385 msgid "Payables on equitization" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3348 #: model:account.account.template,name:l10n_vn.chart3348 msgid "Payables to others" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3341 #: model:account.account.template,name:l10n_vn.chart3341 msgid "Payables to staff" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2115 #: model:account.account.template,name:l10n_vn.chart2115 msgid "Perennial plants, working animals and farm livestocks" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3335 #: model:account.account.template,name:l10n_vn.chart3335 msgid "Personal income tax" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart41112 #: model:account.account.template,name:l10n_vn.chart41112 msgid "Preference shares" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart242 #: model:account.account.template,name:l10n_vn.chart242 msgid "Prepaid expenses" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart357 #: model:account.account.template,name:l10n_vn.chart357 msgid "Price stabilization fund" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2134 #: model:account.account.template,name:l10n_vn.chart2134 msgid "Product labels and trademarks" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3521 #: model:account.account.template,name:l10n_vn.chart3521 msgid "Product warranty provisions" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart631 #: model:account.account.template,name:l10n_vn.chart631 msgid "Production costs" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart337 #: model:account.account.template,name:l10n_vn.chart337 msgid "Progress billings for construction contracts" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1567 #: model:account.account.template,name:l10n_vn.chart1567 msgid "Properties held for sale" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6426 #: model:account.account.template,name:l10n_vn.chart6426 msgid "Provision expenses" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1561 #: model:account.account.template,name:l10n_vn.chart1561 msgid "Purchase costs" msgstr "" #. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_vn +msgid "Purchase of Goods and Services" +msgstr "" + +#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6111 #: model:account.account.template,name:l10n_vn.chart6111 msgid "Purchases of raw materials" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart152 #: model:account.account.template,name:l10n_vn.chart152 msgid "Raw materials" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1385 #: model:account.account.template,name:l10n_vn.chart1385 msgid "Receivables from privatization" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1532 #: model:account.account.template,name:l10n_vn.chart1532 msgid "Reusable packaging materials" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5114 #: model:account.account.template,name:l10n_vn.chart5114 msgid "Revenue from government grants" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5117 #: model:account.account.template,name:l10n_vn.chart5117 msgid "Revenue from investment properties" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5112 #: model:account.account.template,name:l10n_vn.chart5112 msgid "Revenue from sales of finished goods" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5111 #: model:account.account.template,name:l10n_vn.chart5111 msgid "Revenue from sales of merchandises" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5113 #: model:account.account.template,name:l10n_vn.chart5113 msgid "Revenue from services rendered" msgstr "" #. module: l10n_vn -#: model:account.account.template,name:l10n_vn.chart5223 +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_vn +msgid "Sales of Goods and Services" +msgstr "" + +#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5213 +#: model:account.account.template,name:l10n_vn.chart5213 msgid "Sales rebates" msgstr "" #. module: l10n_vn -#: model:account.account.template,name:l10n_vn.chart5222 +#: model:account.account,name:l10n_vn.1_chart5212 +#: model:account.account.template,name:l10n_vn.chart5212 msgid "Sales returns" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3561 #: model:account.account.template,name:l10n_vn.chart3561 msgid "Science and technology development fund" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3562 #: model:account.account.template,name:l10n_vn.chart3562 msgid "" "Science and technology development fund used for fixed asset acquisition" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1543 #: model:account.account.template,name:l10n_vn.chart1543 msgid "Services" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1211 #: model:account.account.template,name:l10n_vn.chart1211 msgid "Shares" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1381 #: model:account.account.template,name:l10n_vn.chart1381 msgid "Shortage of assets awaiting resolution" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3383 #: model:account.account.template,name:l10n_vn.chart3383 msgid "Social insurance" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3332 #: model:account.account.template,name:l10n_vn.chart3332 msgid "Special consumption tax" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6411 +#: model:account.account,name:l10n_vn.1_chart6421 #: model:account.account.template,name:l10n_vn.chart6411 #: model:account.account.template,name:l10n_vn.chart6421 msgid "Staff expenses" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3381 #: model:account.account.template,name:l10n_vn.chart3381 msgid "Surplus of assets awaiting resolution" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3336 #: model:account.account.template,name:l10n_vn.chart3336 msgid "Tax on use of natural resources " msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6425 #: model:account.account.template,name:l10n_vn.chart6425 msgid "Taxes, fees and charges" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1281 #: model:account.account.template,name:l10n_vn.chart1281 msgid "Term deposits" msgstr "" #. module: l10n_vn -#: model:account.tax.group,name:l10n_vn.tax_group_0 -msgid "Thuế GTGT 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.group,name:l10n_vn.tax_group_10 -msgid "Thuế GTGT 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.group,name:l10n_vn.tax_group_5 -msgid "Thuế GTGT 5%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_vn -msgid "Thuế GTGT HHDV bán ra" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_01_02_vn -msgid "Thuế GTGT HHDV bán ra chịu thuế 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_01_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_01_02_vn -msgid "Thuế GTGT HHDV bán ra chịu thuế 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_01_02_vn -msgid "Thuế GTGT HHDV bán ra chịu thuế 5%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_vn -msgid "Thuế GTGT HHDV mua vào" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_01_01_vn -msgid "Thuế GTGT HHDV mua vào chịu thuế 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_01_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_01_01_vn -msgid "Thuế GTGT HHDV mua vào chịu thuế 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_01_01_vn -msgid "Thuế GTGT HHDV mua vào chịu thuế 5%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_sale_vat0 -#: model:account.tax.template,name:l10n_vn.tax_sale_vat0 -msgid "Thuế GTGT phải nộp 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_sale_vat10 -#: model:account.tax.template,name:l10n_vn.tax_sale_vat10 -msgid "Thuế GTGT phải nộp 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_sale_vat5 -#: model:account.tax.template,name:l10n_vn.tax_sale_vat5 -msgid "Thuế GTGT phải nộp 5%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_purchase_vat0 -#: model:account.tax.template,name:l10n_vn.tax_purchase_vat0 -msgid "Thuế GTGT được khấu trừ 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_purchase_vat10 -#: model:account.tax.template,name:l10n_vn.tax_purchase_vat10 -msgid "Thuế GTGT được khấu trừ 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_purchase_vat5 -#: model:account.tax.template,name:l10n_vn.tax_purchase_vat5 -msgid "Thuế GTGT được khấu trừ 5%" -msgstr "" - -#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6233 +#: model:account.account,name:l10n_vn.1_chart6273 +#: model:account.account,name:l10n_vn.1_chart6413 #: model:account.account.template,name:l10n_vn.chart6233 #: model:account.account.template,name:l10n_vn.chart6273 #: model:account.account.template,name:l10n_vn.chart6413 @@ -979,111 +1030,258 @@ msgid "Tools and instruments" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1531 #: model:account.account.template,name:l10n_vn.chart1531 msgid "Tools and supplies" msgstr "" #. module: l10n_vn -#: model:account.account.template,name:l10n_vn.chart5221 +#: model:account.account,name:l10n_vn.1_chart5211 +#: model:account.account.template,name:l10n_vn.chart5211 msgid "Trade discounts" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart331 #: model:account.account.template,name:l10n_vn.chart331 msgid "Trade payables" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart131 #: model:account.account.template,name:l10n_vn.chart131 msgid "Trade receivables" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart132 #: model:account.account.template,name:l10n_vn.chart132 msgid "Trade receivables(pos)" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3382 #: model:account.account.template,name:l10n_vn.chart3382 msgid "Trade union fees" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart419 #: model:account.account.template,name:l10n_vn.chart419 msgid "Treasury shares" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4211 #: model:account.account.template,name:l10n_vn.chart4211 msgid "Undistributed profit after tax brought forward" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4212 #: model:account.account.template,name:l10n_vn.chart4212 msgid "Undistributed profit(loss) after tax for the current year" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3387 #: model:account.account.template,name:l10n_vn.chart3387 msgid "Unearned revenue" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3386 #: model:account.account.template,name:l10n_vn.chart3386 msgid "Unemployment insurance" msgstr "" #. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_vn +msgid "Untaxed Purchase of Goods and Services" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_02_01_vn +msgid "Untaxed Purchase of Goods and Services taxed 0%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_02_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_02_01_vn +msgid "Untaxed Purchase of Goods and Services taxed 10%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_02_01_vn +msgid "Untaxed Purchase of Goods and Services taxed 5%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_vn +msgid "Untaxed Sales of Goods and Services" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_02_02_vn +msgid "Untaxed sales of goods and services taxed 0%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_02_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_02_02_vn +msgid "Untaxed sales of goods and services taxed 10%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_02_02_vn +msgid "Untaxed sales of goods and services taxed 5%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.group,name:l10n_vn.tax_group_0 +msgid "VAT 0%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.group,name:l10n_vn.tax_group_10 +msgid "VAT 10%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.group,name:l10n_vn.tax_group_5 +msgid "VAT 5%" +msgstr "" + +#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart33312 #: model:account.account.template,name:l10n_vn.chart33312 msgid "VAT on imported goods" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1332 #: model:account.account.template,name:l10n_vn.chart1332 msgid "VAT on purchase of fixed assets" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1331 #: model:account.account.template,name:l10n_vn.chart1331 +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_vn msgid "VAT on purchase of goods and services" msgstr "" +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_01_01_vn +msgid "VAT on purchase of goods and services 0%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_01_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_01_01_vn +msgid "VAT on purchase of goods and services 10%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_01_01_vn +msgid "VAT on purchase of goods and services 5%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_vn +msgid "VAT on sales of goods and services" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_01_02_vn +msgid "VAT on sales of goods and services 0%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_01_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_01_02_vn +msgid "VAT on sales of goods and services 10%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_01_02_vn +msgid "VAT on sales of goods and services 5%" +msgstr "" + #. module: l10n_vn #: model:account.chart.template,name:l10n_vn.vn_template msgid "VN - Chart of Accounts" msgstr "" +#. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_sale_vat0 +#: model:account.tax,name:l10n_vn.1_tax_sale_vat0 +#: model:account.tax.template,description:l10n_vn.tax_sale_vat0 +#: model:account.tax.template,name:l10n_vn.tax_sale_vat0 +msgid "Value Added Tax (VAT) 0%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_sale_vat10 +#: model:account.tax,name:l10n_vn.1_tax_sale_vat10 +#: model:account.tax.template,description:l10n_vn.tax_sale_vat10 +#: model:account.tax.template,name:l10n_vn.tax_sale_vat10 +msgid "Value Added Tax (VAT) 10%" +msgstr "" + +#. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_sale_vat5 +#: model:account.tax,name:l10n_vn.1_tax_sale_vat5 +#: model:account.tax.template,description:l10n_vn.tax_sale_vat5 +#: model:account.tax.template,name:l10n_vn.tax_sale_vat5 +msgid "Value Added Tax (VAT) 5%" +msgstr "" + #. module: l10n_vn #: model:ir.ui.menu,name:l10n_vn.account_reports_vn_statements_menu msgid "Vietnam" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1121 #: model:account.account.template,name:l10n_vn.chart1121 msgid "Vietnamese Dong" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1544 #: model:account.account.template,name:l10n_vn.chart1544 msgid "Warranty costs" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6415 #: model:account.account.template,name:l10n_vn.chart6415 msgid "Warranty expenses" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3532 #: model:account.account.template,name:l10n_vn.chart3532 msgid "Welfare fund" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3533 #: model:account.account.template,name:l10n_vn.chart3533 msgid "Welfare fund used for fixed asset acquisitions" msgstr "" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1361 #: model:account.account.template,name:l10n_vn.chart1361 msgid "Working capital provided to sub-units" msgstr "" diff --git a/addons/l10n_vn/i18n_extra/vi_VN.po b/addons/l10n_vn/i18n_extra/vi_VN.po index 1e0728c5fc..3da72a4730 100644 --- a/addons/l10n_vn/i18n_extra/vi_VN.po +++ b/addons/l10n_vn/i18n_extra/vi_VN.po @@ -4,587 +4,662 @@ # msgid "" msgstr "" -"Project-Id-Version: Flectra Server 2.0alpha1+e\n" +"Project-Id-Version: Flectra Server 2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-02-21 11:22+0000\n" -"PO-Revision-Date: 2020-02-21 11:22+0000\n" +"POT-Creation-Date: 2021-09-30 03:34+0000\n" +"PO-Revision-Date: 2021-09-30 03:34+0000\n" "Last-Translator: \n" "Language-Team: \n" -"Language: vi_VN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart335 #: model:account.account.template,name:l10n_vn.chart335 msgid "Accrued expenses" msgstr "Chi phí phải trả" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart141 #: model:account.account.template,name:l10n_vn.chart141 msgid "Advances" msgstr "Tạm ứng" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2291 #: model:account.account.template,name:l10n_vn.chart2291 msgid "Allowances for decline in value of trading securities" msgstr "Dự phòng giảm giá chứng khoán kinh doanh" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2293 #: model:account.account.template,name:l10n_vn.chart2293 msgid "Allowances for doubtful debts" msgstr "Dự phòng phải thu khó đòi" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2292 #: model:account.account.template,name:l10n_vn.chart2292 msgid "Allowances for impairment of investments in other entities" msgstr "Dự phòng tổn thất đầu tư vào đơn vị khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2294 #: model:account.account.template,name:l10n_vn.chart2294 msgid "Allowances for inventories" msgstr "Dự phòng giảm giá hàng tồn kho" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2143 #: model:account.account.template,name:l10n_vn.chart2143 msgid "Amortization of intangible assets" msgstr "Hao mòn TSCĐ vô hình" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart34312 #: model:account.account.template,name:l10n_vn.chart34312 msgid "Bond discounts" msgstr "Chiết khấu trái phiếu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart34313 #: model:account.account.template,name:l10n_vn.chart34313 msgid "Bond premiums" msgstr "Phụ trội trái phiếu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1212 +#: model:account.account,name:l10n_vn.1_chart1282 #: model:account.account.template,name:l10n_vn.chart1212 #: model:account.account.template,name:l10n_vn.chart1282 msgid "Bonds" -msgstr "Trái phiế" +msgstr "Trái phiếu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3531 #: model:account.account.template,name:l10n_vn.chart3531 msgid "Bonus fund" msgstr "Quỹ khen thưởng" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3411 #: model:account.account.template,name:l10n_vn.chart3411 msgid "Borrowing loans liabilities" msgstr "Các khoản đi vay" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2111 #: model:account.account.template,name:l10n_vn.chart2111 msgid "Buildings and structures" msgstr "Nhà cửa, vật kiến trúc" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart441 #: model:account.account.template,name:l10n_vn.chart441 msgid "Capital expenditure funds" -msgstr "Nguồn vốn đầu tư xây dựng cơbản" +msgstr "Nguồn vốn đầu tư xây dựng cơ bản" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4112 #: model:account.account.template,name:l10n_vn.chart4112 msgid "Capital surplus" msgstr "Thặng dư vốn cổ phần" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2135 #: model:account.account.template,name:l10n_vn.chart2135 msgid "Computer software" msgstr "Chương trình phần mềm" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1541 #: model:account.account.template,name:l10n_vn.chart1541 msgid "Construction contracts" msgstr "Xây lắp" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3522 #: model:account.account.template,name:l10n_vn.chart3522 msgid "Construction warranty provisions" msgstr "Dự phòng bảo hành công trình xây dựng" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2412 #: model:account.account.template,name:l10n_vn.chart2412 msgid "Construction works" msgstr "Xây dựng cơ bản" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4113 #: model:account.account.template,name:l10n_vn.chart4113 msgid "Conversion options on convertible bonds" msgstr "Quyền chọn chuyển đổi trái phiếu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3432 #: model:account.account.template,name:l10n_vn.chart3432 msgid "Convertible bonds" -msgstr "TráI phiếu chuyển đổi" +msgstr "Trái phiếu chuyển đổi" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2132 #: model:account.account.template,name:l10n_vn.chart2132 msgid "Copyrights" msgstr "Quyền phát hành" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3334 #: model:account.account.template,name:l10n_vn.chart3334 msgid "Corporate income tax" -msgstr "Thuế thu nhập doan nghiệp" +msgstr "Thuế thu nhập doanh nghiệp" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart632 #: model:account.account.template,name:l10n_vn.chart632 msgid "Costs of goods sold" msgstr "Giá vốn hàng bán" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart8211 #: model:account.account.template,name:l10n_vn.chart8211 msgid "Current tax expense" msgstr "Chi phí thuế thu nhập doanh nghiệp hiện hành" #. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_purchase_vat0 +#: model:account.tax,name:l10n_vn.1_tax_purchase_vat0 +#: model:account.tax.template,description:l10n_vn.tax_purchase_vat0 +#: model:account.tax.template,name:l10n_vn.tax_purchase_vat0 +msgid "Deductible VAT 0%" +msgstr "Thuế GTGT được khấu trừ 0%" + +#. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_purchase_vat10 +#: model:account.tax,name:l10n_vn.1_tax_purchase_vat10 +#: model:account.tax.template,description:l10n_vn.tax_purchase_vat10 +#: model:account.tax.template,name:l10n_vn.tax_purchase_vat10 +msgid "Deductible VAT 10%" +msgstr "Thuế GTGT được khấu trừ 10%" + +#. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_purchase_vat5 +#: model:account.tax,name:l10n_vn.1_tax_purchase_vat5 +#: model:account.tax.template,description:l10n_vn.tax_purchase_vat5 +#: model:account.tax.template,name:l10n_vn.tax_purchase_vat5 +msgid "Deductible VAT 5%" +msgstr "Thuế GTGT được khấu trừ 5%" + +#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart243 #: model:account.account.template,name:l10n_vn.chart243 msgid "Deferred tax assets" msgstr "Tài sản thuế thu nhập hoãn lại" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart8212 #: model:account.account.template,name:l10n_vn.chart8212 msgid "Deferred tax expense" msgstr "Chi phí thuế thu nhập doanh nghiệp hoãn lại" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart347 #: model:account.account.template,name:l10n_vn.chart347 msgid "Deferred tax liabilities" msgstr "Thuế thu nhập hoãn lại phải trả" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart344 #: model:account.account.template,name:l10n_vn.chart344 msgid "Deposits received" msgstr "Nhận ký quỹ, ký cược" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6234 #: model:account.account.template,name:l10n_vn.chart6234 msgid "Depreciation expense" msgstr "Chi phí khấu hao máy thi công" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2142 #: model:account.account.template,name:l10n_vn.chart2142 msgid "Depreciation of finance lease assets" msgstr "Hao mòn TSCĐ thuê tài chính" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2147 #: model:account.account.template,name:l10n_vn.chart2147 msgid "Depreciation of investment properties" msgstr "Hao mòn bất động sản đầu tư" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2141 #: model:account.account.template,name:l10n_vn.chart2141 msgid "Depreciation of tangible fixed assets" msgstr "Hao mòn TSCĐ hữu hình" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart412 #: model:account.account.template,name:l10n_vn.chart412 msgid "Differences upon asset revaluation" msgstr "Chênh lệch đánh giá lại tài sản" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart622 #: model:account.account.template,name:l10n_vn.chart622 msgid "Direct labour costs" msgstr "Chi phí nhân công trực tiếp" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart621 #: model:account.account.template,name:l10n_vn.chart621 msgid "Direct raw material costs" msgstr "Chi phí nguyên liệu, vật liệu trực tiếp" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart417 #: model:account.account.template,name:l10n_vn.chart417 msgid "Enterprise reorganization assistance fund" msgstr "Quỹ hỗ trợ sắp xếp doanh nghiệp" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3523 #: model:account.account.template,name:l10n_vn.chart3523 msgid "Enterprise restructuring provisions" msgstr "Dự phòng tái cơ cấu doanh nghiệp" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart33381 #: model:account.account.template,name:l10n_vn.chart33381 msgid "Environment protection tax" msgstr "Thuế bảo vệ môi trường" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1534 #: model:account.account.template,name:l10n_vn.chart1534 msgid "Equipment and spare parts for replacement" msgstr "Thiết bị, phụ tùng thay thế" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2281 #: model:account.account.template,name:l10n_vn.chart2281 msgid "Equity investments in other entities Other investment" msgstr "Đầu tư góp vốn vào đơn vị khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4132 #: model:account.account.template,name:l10n_vn.chart4132 msgid "Exchange rate differences in pre-operating period" msgstr "Chênh lệch tỷ giá hối đoái trong giai đoạn trước hoạt động" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4131 #: model:account.account.template,name:l10n_vn.chart4131 msgid "" "Exchange rate differences on revaluation of monetary items denominated in " "foreign currency " msgstr "" -"Chênh lệch tỷ giá do đánh giá lại các khoản mục tiềntệ có gốc ngoại tệ" +"Chênh lệch tỷ giá do đánh giá lại các khoản mục tiền tệ có gốc ngoại tệ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1611 #: model:account.account.template,name:l10n_vn.chart1611 msgid "Expenditure brought forward" msgstr "Chi sự nghiệp năm trước" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1612 #: model:account.account.template,name:l10n_vn.chart1612 msgid "Expenditure of current year" msgstr "Chi sự nghiệp năm nay" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6271 #: model:account.account.template,name:l10n_vn.chart6271 msgid "Factory staff costs" msgstr "Chi phí nhân viên phân xưởng" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3339 #: model:account.account.template,name:l10n_vn.chart3339 msgid "Fees, charges and other payables" msgstr "Phí, lệ phí và các khoản phải nộp khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2122 #: model:account.account.template,name:l10n_vn.chart2122 msgid "Finance lease intangible fixed assets" msgstr "TSCĐ vô hình thuê tài chính" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3412 #: model:account.account.template,name:l10n_vn.chart3412 msgid "Finance lease liabilities" msgstr "Nợ thuê tài chính" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2121 #: model:account.account.template,name:l10n_vn.chart2121 msgid "Finance lease tangible fixed assets" msgstr "TSCĐ hữu hình thuê tài chính" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart635 #: model:account.account.template,name:l10n_vn.chart635 msgid "Financial expenses" msgstr "Chi phí tài chính" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart515 #: model:account.account.template,name:l10n_vn.chart515 msgid "Financial income" msgstr "Doanh thu hoạt động tài chính" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1551 #: model:account.account.template,name:l10n_vn.chart1551 msgid "Finished products - inventory" msgstr "Thành phẩm nhập kho" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1557 #: model:account.account.template,name:l10n_vn.chart1557 msgid "Finished products - real estates" msgstr "Thành phẩm bất động sản" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6414 #: model:account.account.template,name:l10n_vn.chart6414 msgid "Fixed asset deprecation" msgstr "Chi phí khấu hao TSCĐ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6274 +#: model:account.account,name:l10n_vn.1_chart6424 #: model:account.account.template,name:l10n_vn.chart6274 #: model:account.account.template,name:l10n_vn.chart6424 msgid "Fixed asset depreciation" msgstr "Chi phí khấu hao TSCĐ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2411 #: model:account.account.template,name:l10n_vn.chart2411 msgid "Fixed assets prior to commissioning" msgstr "Mua sắm TSCĐ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1122 #: model:account.account.template,name:l10n_vn.chart1122 msgid "Foreign currencies" msgstr "Ngoại tệ" #. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_vn -msgid "Giá trị HHDV bán ra" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_02_02_vn -msgid "Giá trị HHDV bán ra chịu thuế 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_02_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_02_02_vn -msgid "Giá trị HHDV bán ra chịu thuế 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_02_02_vn -msgid "Giá trị HHDV bán ra chịu thuế 5%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_vn -msgid "Giá trị HHDV mua vào" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_02_01_vn -msgid "Giá trị HHDV mua vào chịu thuế 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_02_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_02_01_vn -msgid "Giá trị HHDV mua vào chịu thuế 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_02_01_vn -msgid "Giá trị HHDV mua vào chịu thuế 5%" -msgstr "" - -#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart158 #: model:account.account.template,name:l10n_vn.chart158 msgid "Goods in bonded warehouse" msgstr "Hàng hóa kho bảo thuế" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart151 #: model:account.account.template,name:l10n_vn.chart151 msgid "Goods in transit" msgstr "Hàng mua đang đi đường" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart171 #: model:account.account.template,name:l10n_vn.chart171 msgid "Government bonds purchased for resale" msgstr "Giao dịch mua bán lại trái phiếu chính phủ" #. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_vn -msgid "HHDV bán ra" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_vn -msgid "HHDV mua vào" -msgstr "" - -#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3384 #: model:account.account.template,name:l10n_vn.chart3384 msgid "Health insurance" msgstr "Bảo hiểm y tế" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3333 #: model:account.account.template,name:l10n_vn.chart3333 msgid "Import and export tax" msgstr "Thuế xuất, nhập khẩu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1562 #: model:account.account.template,name:l10n_vn.chart1562 msgid "Incidental purchase costs" msgstr "Chi phí thu mua hàng hoá" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart911 #: model:account.account.template,name:l10n_vn.chart911 msgid "Income Summary" msgstr "Xác định kết quả kinh doanh" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1533 #: model:account.account.template,name:l10n_vn.chart1533 msgid "Instruments for renting" msgstr "Đồ dùng cho thuê" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3363 #: model:account.account.template,name:l10n_vn.chart3363 msgid "Intra-company payables for borrowing costs eligible to be capitalized" msgstr "Phải trả nội bộ về chi phí đi vay đủ điều kiện được vốn hoá" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3362 #: model:account.account.template,name:l10n_vn.chart3362 msgid "Intra-company payables for foreign exchange differences" msgstr "Phải trả nội bộ về chênh lệch tỷ giá" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3361 #: model:account.account.template,name:l10n_vn.chart3361 msgid "Intra-company payables for operating capital received" msgstr "Phải trả nội bộ về vốn kinh doanh" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1363 #: model:account.account.template,name:l10n_vn.chart1363 msgid "" "Intra-company receivables on borrowing costs eligible to be capitalized" msgstr "Phải thu nội bộ về chi phí đi vay đủ điều kiện được vốn hóa" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1362 #: model:account.account.template,name:l10n_vn.chart1362 msgid "Intra-company receivables on foreign exchange" msgstr "Phải thu nội bộ về chênh lệch tỷ giá" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart414 #: model:account.account.template,name:l10n_vn.chart414 msgid "Investment and development fund" msgstr "Quỹ đầu tư phát triển" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart222 #: model:account.account.template,name:l10n_vn.chart222 msgid "Investment in joint ventures and associates" -msgstr "Đầu tư vào công ty liên doanh,liên kết" +msgstr "Đầu tư vào công ty liên doanh, liên kết" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart221 #: model:account.account.template,name:l10n_vn.chart221 msgid "Investment in subsidiaries" msgstr "Đầu tư vào công ty con" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart217 #: model:account.account.template,name:l10n_vn.chart217 msgid "Investment properties" msgstr "Bất động sản đầu tư" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6231 #: model:account.account.template,name:l10n_vn.chart6231 msgid "Labour costs" msgstr "Chi phí nhân công" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3337 #: model:account.account.template,name:l10n_vn.chart3337 msgid "Land and housing tax, and rental charges" msgstr "Thuế nhà đất, tiền thuê đất" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2131 #: model:account.account.template,name:l10n_vn.chart2131 msgid "Land use rights" msgstr "Quyền sử dụng đất" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1283 #: model:account.account.template,name:l10n_vn.chart1283 msgid "Lending loans" msgstr "Cho vay" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2136 #: model:account.account.template,name:l10n_vn.chart2136 msgid "Licenses and franchises" msgstr "Giấy phép và giấy phép nhượng quyền" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_vn_template_liquidity_transfer #: model:account.account.template,name:l10n_vn.vn_template_liquidity_transfer msgid "Liquidity Transfer" msgstr "Tiền đang chuyển" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2112 #: model:account.account.template,name:l10n_vn.chart2112 msgid "Machinery and equipment" msgstr "Máy móc, thiết bị" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2413 #: model:account.account.template,name:l10n_vn.chart2413 msgid "Major repairs of fixed assets" msgstr "Sửa chữa lớn TSCĐ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3534 #: model:account.account.template,name:l10n_vn.chart3534 msgid "Management bonus fund" -msgstr "Quỹ thưởng ban điều hành" +msgstr "Quỹ thưởng ban quản lý điều hành công ty" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6232 +#: model:account.account,name:l10n_vn.1_chart6272 #: model:account.account.template,name:l10n_vn.chart6232 #: model:account.account.template,name:l10n_vn.chart6272 msgid "Material costs" msgstr "Chi phí nguyên, vật liệu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6412 #: model:account.account.template,name:l10n_vn.chart6412 msgid "Materials and packing materials" -msgstr "Chi phí nguyên vật liệu,bao bì" +msgstr "Chi phí nguyên vật liệu, bao bì" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2113 #: model:account.account.template,name:l10n_vn.chart2113 msgid "Means of transportation and transmission" -msgstr "Phương tiện vận tải,truyền dẫn" +msgstr "Phương tiện vận tải, truyền dẫn" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1123 #: model:account.account.template,name:l10n_vn.chart1123 msgid "Monetary Gold" msgstr "Vàng tiền tệ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart244 #: model:account.account.template,name:l10n_vn.chart244 msgid "Mortgage, collaterals and deposits" msgstr "Cầm cố, thế chấp, ký quỹ, kýcược" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4611 #: model:account.account.template,name:l10n_vn.chart4611 msgid "Non-business funds bought forward" msgstr "Nguồn kinh phí sự nghiệp năm trước" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4612 #: model:account.account.template,name:l10n_vn.chart4612 msgid "Non-business funds for current year" msgstr "Nguồn kinh phí sự nghiệp năm nay" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart466 #: model:account.account.template,name:l10n_vn.chart466 msgid "Non-business funds used for fixed asset acquisitions" msgstr "Nguồn kinh phí sự nghiệp đã hình thành TSCĐ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2114 #: model:account.account.template,name:l10n_vn.chart2114 msgid "Office equipment and furniture" msgstr "Thiết bị, dụng cụ quản lý" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6423 #: model:account.account.template,name:l10n_vn.chart6423 msgid "Office equipment expenses" msgstr "Chi phí đồ dùng văn phòng" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6422 #: model:account.account.template,name:l10n_vn.chart6422 msgid "Office supply expenses" msgstr "Chi phí vật liệu quản lý" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3431 #: model:account.account.template,name:l10n_vn.chart3431 msgid "Ordinary bonds" msgstr "Trái phiếu thường" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart41111 #: model:account.account.template,name:l10n_vn.chart41111 msgid "Ordinary shares with voting rights" -msgstr "Cổ phiếu phổ thôngcó quyền biểu quyết" +msgstr "Cổ phiếu phổ thông có quyền biểu quyết" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart8111 #: model:account.account.template,name:l10n_vn.chart8111 msgid "Other Expenses" msgstr "Chi phí bằng tiền khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart711 #: model:account.account.template,name:l10n_vn.chart711 msgid "Other Income" msgstr "Thu nhập khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4118 #: model:account.account.template,name:l10n_vn.chart4118 msgid "Other capital" msgstr "Vốn khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart418 #: model:account.account.template,name:l10n_vn.chart418 msgid "Other equity funds" msgstr "Các quỹ khác thuộc vốn chủ sở hữu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6238 +#: model:account.account,name:l10n_vn.1_chart6278 +#: model:account.account,name:l10n_vn.1_chart6418 +#: model:account.account,name:l10n_vn.1_chart6428 #: model:account.account.template,name:l10n_vn.chart6238 #: model:account.account.template,name:l10n_vn.chart6278 #: model:account.account.template,name:l10n_vn.chart6418 @@ -593,71 +668,87 @@ msgid "Other expenses" msgstr "Chi phí bằng tiền khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2118 #: model:account.account.template,name:l10n_vn.chart2118 msgid "Other fixed assets" msgstr "Tài sản cố định khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1288 #: model:account.account.template,name:l10n_vn.chart1288 msgid "Other held to maturity investments" msgstr "Các khoản đầu tư khác nắm giữ đến ngày đáo hạn" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2138 #: model:account.account.template,name:l10n_vn.chart2138 msgid "Other intangible fixed assets" msgstr "TSCĐ vô hình khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3368 #: model:account.account.template,name:l10n_vn.chart3368 msgid "Other inter-company payables" msgstr "Phải trả nội bộ khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1368 #: model:account.account.template,name:l10n_vn.chart1368 msgid "Other intra-company receivables" msgstr "Phải thu nội bộ khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1542 #: model:account.account.template,name:l10n_vn.chart1542 msgid "Other products" msgstr "Sản phẩm khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3524 #: model:account.account.template,name:l10n_vn.chart3524 msgid "Other provisions" -msgstr "Qũy thưởng ban quản lý điều hành công ty" +msgstr "Dự phòng phải trả khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5118 #: model:account.account.template,name:l10n_vn.chart5118 msgid "Other revenue" msgstr "Doanh thu khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1218 #: model:account.account.template,name:l10n_vn.chart1218 msgid "Other securities and financial instruments" -msgstr "Chứng khoán và công cụtài chính khác" +msgstr "Chứng khoán và công cụ tài chính khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart33382 #: model:account.account.template,name:l10n_vn.chart33382 msgid "Other taxes" msgstr "Các loại thuế khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3388 #: model:account.account.template,name:l10n_vn.chart3388 msgid "Others" -msgstr "Phải trả, phải nộp khác" +msgstr "Phải thu khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1388 #: model:account.account.template,name:l10n_vn.chart1388 msgid "Others receivables" msgstr "Phải thu khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart33311 #: model:account.account.template,name:l10n_vn.chart33311 msgid "Output VAT" msgstr "Thuế GTGT đầu ra" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6277 +#: model:account.account,name:l10n_vn.1_chart6417 +#: model:account.account,name:l10n_vn.1_chart6427 #: model:account.account.template,name:l10n_vn.chart6277 #: model:account.account.template,name:l10n_vn.chart6417 #: model:account.account.template,name:l10n_vn.chart6427 @@ -665,315 +756,274 @@ msgid "Outside services" msgstr "Chi phí dịch vụ mua ngoài" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6237 #: model:account.account.template,name:l10n_vn.chart6237 msgid "Outside services " msgstr "Chi phí dịch vụ mua ngoài" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart157 #: model:account.account.template,name:l10n_vn.chart157 msgid "Outward goods on consignment" msgstr "Hàng gửi đi bán" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart34311 #: model:account.account.template,name:l10n_vn.chart34311 msgid "Par value of bonds" msgstr "Mệnh giá trái phiếu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2133 #: model:account.account.template,name:l10n_vn.chart2133 msgid "Patents and inventions" msgstr "Bản quyền, bằng sáng chế" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3385 #: model:account.account.template,name:l10n_vn.chart3385 msgid "Payables on equitization" msgstr "Phải trả về cổ phần hóa" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3348 #: model:account.account.template,name:l10n_vn.chart3348 msgid "Payables to others" msgstr "Phải trả người lao động khác" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3341 #: model:account.account.template,name:l10n_vn.chart3341 msgid "Payables to staff" msgstr "Phải trả công nhân viên" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2115 #: model:account.account.template,name:l10n_vn.chart2115 msgid "Perennial plants, working animals and farm livestocks" msgstr "Cây lâu năm, súc vật làm việc và cho sản phẩm" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3335 #: model:account.account.template,name:l10n_vn.chart3335 msgid "Personal income tax" msgstr "Thuế thu nhập cá nhân" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart41112 #: model:account.account.template,name:l10n_vn.chart41112 msgid "Preference shares" msgstr "Cổ phiếu ưu đãi" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart242 #: model:account.account.template,name:l10n_vn.chart242 msgid "Prepaid expenses" msgstr "Chi phí trả trước" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart357 #: model:account.account.template,name:l10n_vn.chart357 msgid "Price stabilization fund" msgstr "Quỹ bình ổn giá" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart2134 #: model:account.account.template,name:l10n_vn.chart2134 msgid "Product labels and trademarks" msgstr "Nhãn hiệu, tên thương mại" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3521 #: model:account.account.template,name:l10n_vn.chart3521 msgid "Product warranty provisions" msgstr "Dự phòng bảo hành sản phẩm hàng hóa" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart631 #: model:account.account.template,name:l10n_vn.chart631 msgid "Production costs" msgstr "Giá thành sản xuất" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart337 #: model:account.account.template,name:l10n_vn.chart337 msgid "Progress billings for construction contracts" msgstr "Thanh toán theo tiến độ kế hoạch hợp đồng xây dựng" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1567 #: model:account.account.template,name:l10n_vn.chart1567 msgid "Properties held for sale" msgstr "Hàng hóa bất động sản" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6426 #: model:account.account.template,name:l10n_vn.chart6426 msgid "Provision expenses" msgstr "Chi phí dự phòng" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1561 #: model:account.account.template,name:l10n_vn.chart1561 msgid "Purchase costs" msgstr "Chi phí dự phòng" #. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_vn +msgid "Purchase of Goods and Services" +msgstr "HHDV Mua vào" + +#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6111 #: model:account.account.template,name:l10n_vn.chart6111 msgid "Purchases of raw materials" msgstr "Mua nguyên liệu, vật liệu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart152 #: model:account.account.template,name:l10n_vn.chart152 msgid "Raw materials" msgstr "Nguyên liệu, vật liệu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1385 #: model:account.account.template,name:l10n_vn.chart1385 msgid "Receivables from privatization" msgstr "Phải thu về cổ phần hóa" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1532 #: model:account.account.template,name:l10n_vn.chart1532 msgid "Reusable packaging materials" msgstr "Bao bì luân chuyển" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5114 #: model:account.account.template,name:l10n_vn.chart5114 msgid "Revenue from government grants" msgstr "Doanh thu trợ cấp, trợ giá" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5117 #: model:account.account.template,name:l10n_vn.chart5117 msgid "Revenue from investment properties" msgstr "Doanh thu kinh doanh bất động sản đầu tư" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5112 #: model:account.account.template,name:l10n_vn.chart5112 msgid "Revenue from sales of finished goods" msgstr "Doanh thu bán các thành phẩm" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5111 #: model:account.account.template,name:l10n_vn.chart5111 msgid "Revenue from sales of merchandises" msgstr "Doanh thu bán hàng hoá" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5113 #: model:account.account.template,name:l10n_vn.chart5113 msgid "Revenue from services rendered" msgstr "Doanh thu cung cấp dịch vụ" #. module: l10n_vn -#: model:account.account.template,name:l10n_vn.chart5223 +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_vn +msgid "Sales of Goods and Services" +msgstr "HHDV Bán ra" + +#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart5213 +#: model:account.account.template,name:l10n_vn.chart5213 msgid "Sales rebates" -msgstr "Giảm giá bán hàng" +msgstr "Giảm giá hàng bán" #. module: l10n_vn -#: model:account.account.template,name:l10n_vn.chart5222 +#: model:account.account,name:l10n_vn.1_chart5212 +#: model:account.account.template,name:l10n_vn.chart5212 msgid "Sales returns" -msgstr "Lợi nhuận bán hàng" +msgstr "Hàng bán bị trả lại" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3561 #: model:account.account.template,name:l10n_vn.chart3561 msgid "Science and technology development fund" msgstr "Quỹ phát triển khoa học và công nghệ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3562 #: model:account.account.template,name:l10n_vn.chart3562 msgid "" "Science and technology development fund used for fixed asset acquisition" msgstr "Quỹ phát triển khoa học và công nghệ đã hình thành TSCĐ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1543 #: model:account.account.template,name:l10n_vn.chart1543 msgid "Services" msgstr "Dịch vụ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1211 #: model:account.account.template,name:l10n_vn.chart1211 msgid "Shares" msgstr "Cổ phiếu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1381 #: model:account.account.template,name:l10n_vn.chart1381 msgid "Shortage of assets awaiting resolution" msgstr "Tài sản thiếu chờ xử lý" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3383 #: model:account.account.template,name:l10n_vn.chart3383 msgid "Social insurance" msgstr "Bảo hiểm xã hội" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3332 #: model:account.account.template,name:l10n_vn.chart3332 msgid "Special consumption tax" msgstr "Thuế tiêu thụ đặc biệt" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6411 +#: model:account.account,name:l10n_vn.1_chart6421 #: model:account.account.template,name:l10n_vn.chart6411 #: model:account.account.template,name:l10n_vn.chart6421 msgid "Staff expenses" msgstr "Chi phí nhân viên" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3381 #: model:account.account.template,name:l10n_vn.chart3381 msgid "Surplus of assets awaiting resolution" msgstr "Thặng dư tài sản đang chờ giải quyết" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3336 #: model:account.account.template,name:l10n_vn.chart3336 msgid "Tax on use of natural resources " msgstr "Thuế tài nguyên" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6425 #: model:account.account.template,name:l10n_vn.chart6425 msgid "Taxes, fees and charges" msgstr "Thuế, phí và lệ phí" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1281 #: model:account.account.template,name:l10n_vn.chart1281 msgid "Term deposits" msgstr "Tiền gửi có kỳ hạn" #. module: l10n_vn -#: model:account.tax.group,name:l10n_vn.tax_group_0 -msgid "Thuế GTGT 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.group,name:l10n_vn.tax_group_10 -msgid "Thuế GTGT 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.group,name:l10n_vn.tax_group_5 -msgid "Thuế GTGT 5%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_vn -msgid "Thuế GTGT HHDV bán ra" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_01_02_vn -msgid "Thuế GTGT HHDV bán ra chịu thuế 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_01_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_01_02_vn -msgid "Thuế GTGT HHDV bán ra chịu thuế 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_02_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_01_02_vn -msgid "Thuế GTGT HHDV bán ra chịu thuế 5%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_vn -msgid "Thuế GTGT HHDV mua vào" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_01_01_vn -msgid "Thuế GTGT HHDV mua vào chịu thuế 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_01_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_01_01_vn -msgid "Thuế GTGT HHDV mua vào chịu thuế 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_01_vn -#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_01_01_vn -msgid "Thuế GTGT HHDV mua vào chịu thuế 5%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_sale_vat0 -#: model:account.tax.template,name:l10n_vn.tax_sale_vat0 -msgid "Thuế GTGT phải nộp 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_sale_vat10 -#: model:account.tax.template,name:l10n_vn.tax_sale_vat10 -msgid "Thuế GTGT phải nộp 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_sale_vat5 -#: model:account.tax.template,name:l10n_vn.tax_sale_vat5 -msgid "Thuế GTGT phải nộp 5%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_purchase_vat0 -#: model:account.tax.template,name:l10n_vn.tax_purchase_vat0 -msgid "Thuế GTGT được khấu trừ 0%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_purchase_vat10 -#: model:account.tax.template,name:l10n_vn.tax_purchase_vat10 -msgid "Thuế GTGT được khấu trừ 10%" -msgstr "" - -#. module: l10n_vn -#: model:account.tax.template,description:l10n_vn.tax_purchase_vat5 -#: model:account.tax.template,name:l10n_vn.tax_purchase_vat5 -msgid "Thuế GTGT được khấu trừ 5%" -msgstr "" - -#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6233 +#: model:account.account,name:l10n_vn.1_chart6273 +#: model:account.account,name:l10n_vn.1_chart6413 #: model:account.account.template,name:l10n_vn.chart6233 #: model:account.account.template,name:l10n_vn.chart6273 #: model:account.account.template,name:l10n_vn.chart6413 @@ -981,111 +1031,258 @@ msgid "Tools and instruments" msgstr "Chi phí dụng cụ, đồ dùng" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1531 #: model:account.account.template,name:l10n_vn.chart1531 msgid "Tools and supplies" msgstr "Công cụ, dụng cụ" #. module: l10n_vn -#: model:account.account.template,name:l10n_vn.chart5221 +#: model:account.account,name:l10n_vn.1_chart5211 +#: model:account.account.template,name:l10n_vn.chart5211 msgid "Trade discounts" msgstr "Chiết khấu thương mại" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart331 #: model:account.account.template,name:l10n_vn.chart331 msgid "Trade payables" msgstr "Các khoản phải trả thương mại" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart131 #: model:account.account.template,name:l10n_vn.chart131 msgid "Trade receivables" msgstr "Phải thu của khách hàng" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart132 #: model:account.account.template,name:l10n_vn.chart132 msgid "Trade receivables(pos)" msgstr "Phải thu của khách hàng(pos)" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3382 #: model:account.account.template,name:l10n_vn.chart3382 msgid "Trade union fees" msgstr "Kinh phí công đoàn" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart419 #: model:account.account.template,name:l10n_vn.chart419 msgid "Treasury shares" msgstr "Cổ phiếu quỹ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4211 #: model:account.account.template,name:l10n_vn.chart4211 msgid "Undistributed profit after tax brought forward" msgstr "Lợi nhuận sau thuế chưa phân phối năm trước" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart4212 #: model:account.account.template,name:l10n_vn.chart4212 msgid "Undistributed profit(loss) after tax for the current year" msgstr "Lợi nhuận sau thuế chưa phân phối năm nay" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3387 #: model:account.account.template,name:l10n_vn.chart3387 msgid "Unearned revenue" msgstr "Doanh thu chưa thực hiện" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3386 #: model:account.account.template,name:l10n_vn.chart3386 msgid "Unemployment insurance" msgstr "Bảo hiểm thất nghiệp" #. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_vn +msgid "Untaxed Purchase of Goods and Services" +msgstr "Giá trị HHDV Mua vào" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_02_01_vn +msgid "Untaxed Purchase of Goods and Services taxed 0%" +msgstr "Giá trị HHDV Mua vào chịu thuế 0%" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_02_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_02_01_vn +msgid "Untaxed Purchase of Goods and Services taxed 10%" +msgstr "Giá trị HHDV Mua vào chịu thuế 10%" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_02_01_vn +msgid "Untaxed Purchase of Goods and Services taxed 5%" +msgstr "Giá trị HHDV Mua vào chịu thuế 5%" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_vn +msgid "Untaxed Sales of Goods and Services" +msgstr "Giá trị HHDV Bán ra" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_02_02_vn +msgid "Untaxed sales of goods and services taxed 0%" +msgstr "Giá trị HHDV Bán ra chịu thuế 0%" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_02_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_02_02_vn +msgid "Untaxed sales of goods and services taxed 10%" +msgstr "Giá trị HHDV Bán ra chịu thuế 10%" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_02_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_02_02_vn +msgid "Untaxed sales of goods and services taxed 5%" +msgstr "Giá trị HHDV Bán ra chịu thuế 5%" + +#. module: l10n_vn +#: model:account.tax.group,name:l10n_vn.tax_group_0 +msgid "VAT 0%" +msgstr "Thuế GTGT 0%" + +#. module: l10n_vn +#: model:account.tax.group,name:l10n_vn.tax_group_10 +msgid "VAT 10%" +msgstr "Thuế GTGT 10%" + +#. module: l10n_vn +#: model:account.tax.group,name:l10n_vn.tax_group_5 +msgid "VAT 5%" +msgstr "Thuế GTGT 5%" + +#. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart33312 #: model:account.account.template,name:l10n_vn.chart33312 msgid "VAT on imported goods" msgstr "Thuế GTGT hàng nhập khẩu" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1332 #: model:account.account.template,name:l10n_vn.chart1332 msgid "VAT on purchase of fixed assets" msgstr "Thuế GTGT được khấu trừ của tài sản cố định" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1331 #: model:account.account.template,name:l10n_vn.chart1331 +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_vn msgid "VAT on purchase of goods and services" -msgstr "Thuế GTGT được khấu trừ của hàng hoá, dịch vụ" +msgstr "Thuế GTGT HHDV mua vào" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_01_01_vn +msgid "VAT on purchase of goods and services 0%" +msgstr "Thuế GTGT HHDV mua vào chịu thuế 0%" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_01_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_01_01_vn +msgid "VAT on purchase of goods and services 10%" +msgstr "Thuế GTGT HHDV mua vào chịu thuế 10%" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_01_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_01_01_vn +msgid "VAT on purchase of goods and services 5%" +msgstr "Thuế GTGT HHDV mua vào chịu thuế 5%" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_02_vn +msgid "VAT on sales of goods and services" +msgstr "Thuế GTGT HHDV bán ra" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_01_01_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_01_01_02_vn +msgid "VAT on sales of goods and services 0%" +msgstr "Thuế GTGT HHDV bán ra chịu thuế 0%" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_03_01_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_03_01_02_vn +msgid "VAT on sales of goods and services 10%" +msgstr "Thuế GTGT HHDV bán ra chịu thuế 10%" + +#. module: l10n_vn +#: model:account.tax.report.line,name:l10n_vn.account_tax_report_line_02_01_02_vn +#: model:account.tax.report.line,tag_name:l10n_vn.account_tax_report_line_02_01_02_vn +msgid "VAT on sales of goods and services 5%" +msgstr "Thuế GTGT HHDV bán ra chịu thuế 5%" #. module: l10n_vn #: model:account.chart.template,name:l10n_vn.vn_template msgid "VN - Chart of Accounts" -msgstr "" +msgstr "VN - Hệ thống tài khoản" + +#. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_sale_vat0 +#: model:account.tax,name:l10n_vn.1_tax_sale_vat0 +#: model:account.tax.template,description:l10n_vn.tax_sale_vat0 +#: model:account.tax.template,name:l10n_vn.tax_sale_vat0 +msgid "Value Added Tax (VAT) 0%" +msgstr "Thuế GTGT phải nộp 0%" + +#. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_sale_vat10 +#: model:account.tax,name:l10n_vn.1_tax_sale_vat10 +#: model:account.tax.template,description:l10n_vn.tax_sale_vat10 +#: model:account.tax.template,name:l10n_vn.tax_sale_vat10 +msgid "Value Added Tax (VAT) 10%" +msgstr "Thuế GTGT phải nộp 10%" + +#. module: l10n_vn +#: model:account.tax,description:l10n_vn.1_tax_sale_vat5 +#: model:account.tax,name:l10n_vn.1_tax_sale_vat5 +#: model:account.tax.template,description:l10n_vn.tax_sale_vat5 +#: model:account.tax.template,name:l10n_vn.tax_sale_vat5 +msgid "Value Added Tax (VAT) 5%" +msgstr "Thuế GTGT phải nộp 5%" #. module: l10n_vn #: model:ir.ui.menu,name:l10n_vn.account_reports_vn_statements_menu msgid "Vietnam" -msgstr "" +msgstr "Việt Nam" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1121 #: model:account.account.template,name:l10n_vn.chart1121 msgid "Vietnamese Dong" msgstr "Tiền Việt Nam" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1544 #: model:account.account.template,name:l10n_vn.chart1544 msgid "Warranty costs" msgstr "Chi phí bảo hành xây lắp" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart6415 #: model:account.account.template,name:l10n_vn.chart6415 msgid "Warranty expenses" msgstr "Chi phí bảo hành" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3532 #: model:account.account.template,name:l10n_vn.chart3532 msgid "Welfare fund" -msgstr "Chi phí bảo hành" +msgstr "Quỹ phúc lợi" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart3533 #: model:account.account.template,name:l10n_vn.chart3533 msgid "Welfare fund used for fixed asset acquisitions" msgstr "Quỹ phúc lợi đã hình thành TSCĐ" #. module: l10n_vn +#: model:account.account,name:l10n_vn.1_chart1361 #: model:account.account.template,name:l10n_vn.chart1361 msgid "Working capital provided to sub-units" msgstr "Vốn kinh doanh ở các đơn vị trực thuộc" diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py index 71ad7bfcf3..319edf8d68 100644 --- a/addons/mrp/models/stock_move.py +++ b/addons/mrp/models/stock_move.py @@ -395,7 +395,7 @@ class StockMove(models.Model): # Then, we collect every relevant moves related to a specific component # to know how many are considered delivered. uom_qty_per_kit = bom_line_data['qty'] / bom_line_data['original_qty'] - qty_per_kit = bom_line.product_uom_id._compute_quantity(uom_qty_per_kit, bom_line.product_id.uom_id) + qty_per_kit = bom_line.product_uom_id._compute_quantity(uom_qty_per_kit, bom_line.product_id.uom_id, round=False) if not qty_per_kit: continue incoming_moves = bom_line_moves.filtered(filters['incoming_moves']) diff --git a/addons/mrp_subcontracting/models/mrp_production.py b/addons/mrp_subcontracting/models/mrp_production.py index 53b2338968..1692c3f04c 100644 --- a/addons/mrp_subcontracting/models/mrp_production.py +++ b/addons/mrp_subcontracting/models/mrp_production.py @@ -135,6 +135,8 @@ class MrpProduction(models.Model): return False if not all(line.lot_id for line in mo.move_raw_ids.filtered(lambda sm: sm.has_tracking != 'none').move_line_ids): return False + if mo.product_id.tracking != 'none' and not mo.lot_producing_id: + return False return True return self.filtered(filter_in) diff --git a/addons/mrp_subcontracting/tests/test_subcontracting.py b/addons/mrp_subcontracting/tests/test_subcontracting.py index 3eb758369d..cdfcec6515 100644 --- a/addons/mrp_subcontracting/tests/test_subcontracting.py +++ b/addons/mrp_subcontracting/tests/test_subcontracting.py @@ -735,3 +735,75 @@ class TestSubcontractingTracking(TransactionCase): self.assertEqual(avail_qty_comp1, -todo_nb) self.assertEqual(avail_qty_comp2, -todo_nb) self.assertEqual(avail_qty_finished, todo_nb) + + def test_flow_tracked_backorder02(self): + """ Both component and finished product are tracked by lot. """ + todo_nb = 4 + resupply_sub_on_order_route = self.env['stock.location.route'].search([('name', '=', 'Resupply Subcontractor on Order')]) + finished_product, component = self.env['product.product'].create([{ + 'name': 'SuperProduct', + 'type': 'product', + 'tracking': 'lot', + }, { + 'name': 'Component', + 'type': 'product', + 'tracking': 'lot', + 'route_ids': [(4, resupply_sub_on_order_route.id)], + }]) + + bom_form = Form(self.env['mrp.bom']) + bom_form.type = 'subcontract' + bom_form.subcontractor_ids.add(self.subcontractor_partner1) + bom_form.product_tmpl_id = finished_product.product_tmpl_id + with bom_form.bom_line_ids.new() as bom_line: + bom_line.product_id = component + bom_line.product_qty = 1 + bom = bom_form.save() + + finished_lot, component_lot = self.env['stock.production.lot'].create([{ + 'name': 'lot_%s' % product.name, + 'product_id': product.id, + 'company_id': self.env.company.id, + } for product in [finished_product, component]]) + + self.env['stock.quant']._update_available_quantity(component, self.env.ref('stock.stock_location_stock'), todo_nb, lot_id=component_lot) + + # Create a receipt picking from the subcontractor + picking_form = Form(self.env['stock.picking']) + picking_form.picking_type_id = self.env.ref('stock.picking_type_in') + picking_form.partner_id = self.subcontractor_partner1 + with picking_form.move_ids_without_package.new() as move: + move.product_id = finished_product + move.product_uom_qty = todo_nb + picking_receipt = picking_form.save() + picking_receipt.action_confirm() + + mo = self.env['mrp.production'].search([('bom_id', '=', bom.id)]) + + # Process the delivery of the components + compo_picking = mo.picking_ids + compo_picking.action_assign() + wizard_data = compo_picking.button_validate() + wizard = Form(self.env[wizard_data['res_model']].with_context(wizard_data['context'])).save() + wizard.process() + + for qty in [3, 1]: + # Record the receiption of finished products + picking_receipt = self.env['stock.picking'].search([('partner_id', '=', self.subcontractor_partner1.id), ('state', '!=', 'done')]) + action = picking_receipt.action_record_components() + mo = self.env['mrp.production'].browse(action['res_id']) + mo_form = Form(mo.with_context(**action['context']), view=action['view_id']) + mo_form.qty_producing = qty + mo_form.lot_producing_id = finished_lot + with mo_form.move_line_raw_ids.edit(0) as ml: + ml.lot_id = component_lot + mo = mo_form.save() + mo.subcontracting_record_component() + + # Validate the picking and create a backorder + wizard_data = picking_receipt.button_validate() + if qty == 3: + wizard = Form(self.env[wizard_data['res_model']].with_context(wizard_data['context'])).save() + wizard.process() + + self.assertEqual(picking_receipt.state, 'done') diff --git a/addons/point_of_sale/tests/common.py b/addons/point_of_sale/tests/common.py index bb312adeeb..e7c681759e 100644 --- a/addons/point_of_sale/tests/common.py +++ b/addons/point_of_sale/tests/common.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from random import randint +from datetime import datetime from flectra import fields, tools from flectra.addons.stock_account.tests.test_anglo_saxon_valuation_reconciliation_common import ValuationReconciliationTestCommon @@ -272,6 +273,7 @@ class TestPoSCommon(ValuationReconciliationTestCommon): cls.env['res.currency.rate'].create({ 'rate': 0.5, 'currency_id': cls.other_currency.id, + 'name': datetime.today().date(), }) other_cash_journal = cls.env['account.journal'].create({ 'name': 'Cash Other', diff --git a/addons/purchase/views/product_views.xml b/addons/purchase/views/product_views.xml index eb6b9f5ec0..a25fe5f4cb 100644 --- a/addons/purchase/views/product_views.xml +++ b/addons/purchase/views/product_views.xml @@ -40,8 +40,8 @@ 0 - - + + purchase.group_purchase_manager diff --git a/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py b/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py index cbdee75d8a..beba3909e3 100644 --- a/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py +++ b/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py @@ -296,3 +296,50 @@ class TestSaleMrpKitBom(TransactionCase): purchase_price = line.product_id.with_company(line.company_id)._compute_average_price(0, line.product_uom_qty, line.move_ids) self.assertEqual(purchase_price, 92, "The purchase price must be the total cost of the components multiplied by their unit of measure") + def test_qty_delivered_with_bom(self): + """Check the quantity delivered, when a bom line has a non integer quantity""" + + self.env['ir.model.data'].xmlid_to_object('product.decimal_product_uom').digits = 5 + + self.kit = self._create_product('Kit', 'product', 0.00) + self.comp = self._create_product('Component', 'product', 0.00) + + # Create BoM for Kit + bom_product_form = Form(self.env['mrp.bom']) + bom_product_form.product_id = self.kit + bom_product_form.product_tmpl_id = self.kit.product_tmpl_id + bom_product_form.product_qty = 1.0 + bom_product_form.type = 'phantom' + with bom_product_form.bom_line_ids.new() as bom_line: + bom_line.product_id = self.comp + bom_line.product_qty = 0.08600 + self.bom = bom_product_form.save() + + + self.customer = self.env['res.partner'].create({ + 'name': 'customer', + }) + + so = self.env['sale.order'].create({ + 'partner_id': self.customer.id, + 'order_line': [ + (0, 0, { + 'name': self.kit.name, + 'product_id': self.kit.id, + 'product_uom_qty': 10.0, + 'product_uom': self.kit.uom_id.id, + 'price_unit': 1, + 'tax_id': False, + })], + }) + so.action_confirm() + + self.assertTrue(so.picking_ids) + self.assertEqual(so.order_line.qty_delivered, 0) + + picking = so.picking_ids + picking.move_lines.quantity_done = 0.86000 + picking.button_validate() + + # Checks the delivery amount (must be 10). + self.assertEqual(so.order_line.qty_delivered, 10) diff --git a/addons/sale_stock/models/sale_order.py b/addons/sale_stock/models/sale_order.py index 21b4384269..f80efb5037 100644 --- a/addons/sale_stock/models/sale_order.py +++ b/addons/sale_stock/models/sale_order.py @@ -162,7 +162,8 @@ class SaleOrder(models.Model): @api.onchange('user_id') def onchange_user_id(self): super().onchange_user_id() - self.warehouse_id = self.user_id.with_company(self.company_id.id)._get_default_warehouse_id().id + if self.state in ['draft','sent']: + self.warehouse_id = self.user_id.with_company(self.company_id.id)._get_default_warehouse_id().id @api.onchange('partner_shipping_id') def _onchange_partner_shipping_id(self): diff --git a/addons/sale_timesheet/models/project.py b/addons/sale_timesheet/models/project.py index bb56d4734c..1278085fd1 100644 --- a/addons/sale_timesheet/models/project.py +++ b/addons/sale_timesheet/models/project.py @@ -202,10 +202,11 @@ class ProjectTask(models.Model): # override sale_order_id and make it computed stored field instead of regular field. sale_order_id = fields.Many2one(compute='_compute_sale_order_id', store=True, readonly=False, domain="['|', '|', ('partner_id', '=', partner_id), ('partner_id', 'child_of', commercial_partner_id), ('partner_id', 'parent_of', partner_id)]") + # content in related parameter of the field definition is removed to manually define the compute and the search method. + project_sale_order_id = fields.Many2one(compute='_compute_project_sale_order_id', search='_search_project_sale_order_id', related=None) analytic_account_id = fields.Many2one('account.analytic.account', related='sale_order_id.analytic_account_id') bill_type = fields.Selection(related="project_id.bill_type") pricing_type = fields.Selection(related="project_id.pricing_type") - sale_line_id = fields.Many2one(domain="[('company_id', '=', company_id), ('is_service', '=', True), ('order_partner_id', 'child_of', commercial_partner_id), ('is_expense', '=', False), ('state', 'in', ['sale', 'done']), '|', ('project_id.bill_type', '=', 'customer_task'), ('order_id', '=?', project_sale_order_id)]") is_project_map_empty = fields.Boolean("Is Project map empty", compute='_compute_is_project_map_empty') has_multi_sol = fields.Boolean(compute='_compute_has_multi_sol', compute_sudo=True) allow_billable = fields.Boolean(related="project_id.allow_billable") @@ -271,6 +272,14 @@ class ProjectTask(models.Model): for task in self: task.analytic_account_active = task.analytic_account_active or task.analytic_account_id.active + @api.depends('project_id.bill_type', 'project_id.sale_order_id') + def _compute_project_sale_order_id(self): + for task in self: + if task.bill_type != 'customer_task': + task.project_sale_order_id = task.project_id.sale_order_id + else: + task.project_sale_order_id = False + @api.depends('sale_line_id', 'project_id', 'allow_billable', 'non_allow_billable') def _compute_sale_order_id(self): for task in self: @@ -309,6 +318,9 @@ class ProjectTask(models.Model): if not self.sale_line_id: self.sale_line_id = self.project_id.sale_line_id + def _search_project_sale_order_id(self, operator, value): + return [('bill_type', '!=', 'customer_task'), ('project_id.sale_order_id', operator, value)] + def write(self, values): res = super(ProjectTask, self).write(values) # Done after super to avoid constraints on field recomputation diff --git a/addons/sale_timesheet/models/project_overview.py b/addons/sale_timesheet/models/project_overview.py index 1c518ff426..e2a635140c 100644 --- a/addons/sale_timesheet/models/project_overview.py +++ b/addons/sale_timesheet/models/project_overview.py @@ -101,9 +101,10 @@ class Project(models.Model): 'amount_untaxed_to_invoice': 'to_invoice', 'timesheet_cost': 'cost', 'expense_cost': 'expense_cost', - 'expense_amount_untaxed_invoiced': 'expense_amount_untaxed_invoiced', + 'expense_amount_untaxed_invoiced': 'expense_amount_untaxed_invoiced', + 'expense_amount_untaxed_to_invoice': 'expense_amount_untaxed_to_invoice', 'other_revenues': 'other_revenues' - } + } profit = dict.fromkeys(list(field_map.values()) + ['other_revenues', 'total'], 0.0) profitability_raw_data = self.env['project.profitability.report'].read_group([('project_id', 'in', self.ids)], ['project_id'] + list(field_map), ['project_id']) for data in profitability_raw_data: diff --git a/addons/sale_timesheet/report/project_profitability_report_analysis.py b/addons/sale_timesheet/report/project_profitability_report_analysis.py index 3669b28c0e..265061617c 100644 --- a/addons/sale_timesheet/report/project_profitability_report_analysis.py +++ b/addons/sale_timesheet/report/project_profitability_report_analysis.py @@ -132,7 +132,6 @@ class ProfitabilityAnalysis(models.Model): SUM(timesheet_cost) AS timesheet_cost, SUM(expense_cost) AS expense_cost, SUM(other_revenues) AS other_revenues, - SUM(downpayment_invoiced) AS downpayment_invoiced, SUM(expense_amount_untaxed_to_invoice) AS expense_amount_untaxed_to_invoice, SUM(expense_amount_untaxed_invoiced) AS expense_amount_untaxed_invoiced, SUM(amount_untaxed_to_invoice) AS amount_untaxed_to_invoice, @@ -148,7 +147,6 @@ class ProfitabilityAnalysis(models.Model): TS.amount AS timesheet_cost, 0.0 AS other_revenues, 0.0 AS expense_cost, - 0.0 AS downpayment_invoiced, 0.0 AS expense_amount_untaxed_to_invoice, 0.0 AS expense_amount_untaxed_invoiced, 0.0 AS amount_untaxed_to_invoice, @@ -159,7 +157,7 @@ class ProfitabilityAnalysis(models.Model): UNION ALL - -- Get the other revenues + -- Get the other revenues (products that are not services) SELECT P.id AS project_id, P.analytic_account_id AS analytic_account_id, @@ -168,7 +166,6 @@ class ProfitabilityAnalysis(models.Model): 0.0 AS timesheet_cost, AAL.amount AS other_revenues, 0.0 AS expense_cost, - 0.0 AS downpayment_invoiced, 0.0 AS expense_amount_untaxed_to_invoice, 0.0 AS expense_amount_untaxed_invoiced, 0.0 AS amount_untaxed_to_invoice, @@ -177,16 +174,12 @@ class ProfitabilityAnalysis(models.Model): FROM project_project P JOIN account_analytic_account AA ON P.analytic_account_id = AA.id JOIN account_analytic_line AAL ON AAL.account_id = AA.id - JOIN product_product PP ON PP.id = AAL.product_id - JOIN product_template PT ON PT.id = PP.product_tmpl_id LEFT JOIN sale_order_line_invoice_rel SOINV ON SOINV.invoice_line_id = AAL.move_id LEFT JOIN sale_order_line SOL ON SOINV.order_line_id = SOL.id WHERE AAL.amount > 0.0 AND AAL.project_id IS NULL AND P.active = 't' AND P.allow_timesheets = 't' - AND PT.service_type = 'manual' -- default value or Milestone service for services products - AND PT.service_tracking = 'no' -- default value or not a tracking service for services products AND (SOL.id IS NULL - OR (SOL.is_expense IS NOT TRUE AND SOL.is_downpayment IS NOT TRUE)) + OR (SOL.is_expense IS NOT TRUE AND SOL.is_downpayment IS NOT TRUE AND SOL.is_service IS NOT TRUE)) UNION ALL @@ -199,64 +192,32 @@ class ProfitabilityAnalysis(models.Model): 0.0 AS timesheet_cost, 0.0 AS other_revenues, AAL.amount AS expense_cost, - 0.0 AS downpayment_invoiced, 0.0 AS expense_amount_untaxed_to_invoice, 0.0 AS expense_amount_untaxed_invoiced, 0.0 AS amount_untaxed_to_invoice, 0.0 AS amount_untaxed_invoiced, AAL.date AS line_date FROM project_project P - LEFT JOIN account_analytic_account AA ON P.analytic_account_id = AA.id - LEFT JOIN account_analytic_line AAL ON AAL.account_id = AA.id - WHERE AAL.amount < 0.0 AND AAL.project_id IS NULL AND P.active = 't' AND P.allow_timesheets = 't' - - UNION ALL - - -- Get the invoiced downpayments - SELECT - P.id AS project_id, - P.analytic_account_id AS analytic_account_id, - MY_SOLS.id AS sale_line_id, - 0.0 AS timesheet_unit_amount, - 0.0 AS timesheet_cost, - 0.0 AS other_revenues, - 0.0 AS expense_cost, - CASE WHEN MY_SOLS.invoice_status = 'invoiced' THEN MY_SOLS.price_reduce ELSE 0.0 END AS downpayment_invoiced, - 0.0 AS expense_amount_untaxed_to_invoice, - 0.0 AS expense_amount_untaxed_invoiced, - 0.0 AS amount_untaxed_to_invoice, - 0.0 AS amount_untaxed_invoiced, - MY_S.date_order AS line_date - FROM project_project P - LEFT JOIN sale_order_line MY_SOL ON P.sale_line_id = MY_SOL.id - LEFT JOIN sale_order MY_S ON MY_SOL.order_id = MY_S.id - LEFT JOIN sale_order_line MY_SOLS ON MY_SOLS.order_id = MY_S.id - WHERE MY_SOLS.is_downpayment = 't' - - UNION ALL - - -- Get the expense costs from sale order line - SELECT - P.id AS project_id, - P.analytic_account_id AS analytic_account_id, - OLIS.id AS sale_line_id, - 0.0 AS timesheet_unit_amount, - 0.0 AS timesheet_cost, - 0.0 AS other_revenues, - OLIS.price_reduce AS expense_cost, - 0.0 AS downpayment_invoiced, - 0.0 AS expense_amount_untaxed_to_invoice, - 0.0 AS expense_amount_untaxed_invoiced, - 0.0 AS amount_untaxed_to_invoice, - 0.0 AS amount_untaxed_invoiced, - ANLI.date AS line_date - FROM project_project P - LEFT JOIN account_analytic_account ANAC ON P.analytic_account_id = ANAC.id - LEFT JOIN account_analytic_line ANLI ON ANAC.id = ANLI.account_id - LEFT JOIN sale_order_line OLI ON P.sale_line_id = OLI.id - LEFT JOIN sale_order ORD ON OLI.order_id = ORD.id - LEFT JOIN sale_order_line OLIS ON ORD.id = OLIS.order_id - WHERE OLIS.product_id = ANLI.product_id AND OLIS.is_downpayment = 't' AND ANLI.amount < 0.0 AND ANLI.project_id IS NULL AND P.active = 't' AND P.allow_timesheets = 't' + JOIN account_analytic_account AA ON P.analytic_account_id = AA.id + JOIN account_analytic_line AAL ON AAL.account_id = AA.id + LEFT JOIN account_move_line RINVL ON AAL.move_id = RINVL.id + AND RINVL.parent_state = 'posted' + AND RINVL.exclude_from_invoice_tab = 'f' + -- Check if the AAL is not related to a reversed credit note + LEFT JOIN account_move RINV ON RINV.id = RINVL.move_id + LEFT JOIN account_move_line INVL ON INVL.move_id = RINV.reversed_entry_id + AND INVL.parent_state = 'posted' + AND INVL.exclude_from_invoice_tab = 'f' + AND INVL.product_id = RINVL.product_id + LEFT JOIN sale_order_line_invoice_rel SOINV ON SOINV.invoice_line_id = INVL.id + LEFT JOIN sale_order_line SOL ON SOINV.order_line_id = SOL.id + AND SOL.product_id = AAL.product_id + -- Check if the AAL is not related to a consumed downpayment (when the SOL is fully invoiced - with downpayment discounted.) + LEFT JOIN sale_order_line_invoice_rel SOINVDOWN ON SOINVDOWN.invoice_line_id = RINVL.id + LEFT JOIN sale_order_line SOLDOWN on SOINVDOWN.order_line_id = SOLDOWN.id AND SOLDOWN.is_downpayment = 't' + WHERE AAL.amount < 0.0 AND AAL.project_id IS NULL + AND SOL.id IS NULL AND SOLDOWN.id IS NULL -- Not linked to a credit note and not a downpayment + AND P.active = 't' AND P.allow_timesheets = 't' UNION ALL @@ -270,17 +231,16 @@ class ProfitabilityAnalysis(models.Model): 0.0 AS timesheet_cost, 0.0 AS other_revenues, 0.0 AS expense_cost, - 0.0 AS downpayment_invoiced, CASE WHEN SOL.qty_delivered_method = 'analytic' THEN (SOL.untaxed_amount_to_invoice / CASE COALESCE(S.currency_rate, 0) WHEN 0 THEN 1.0 ELSE S.currency_rate END) ELSE 0.0 END AS expense_amount_untaxed_to_invoice, CASE - WHEN SOL.qty_delivered_method = 'analytic' AND SOL.invoice_status != 'no' + WHEN SOL.qty_delivered_method = 'analytic' AND SOL.invoice_status = 'invoiced' THEN CASE WHEN T.expense_policy = 'sales_price' - THEN (SOL.price_reduce / CASE COALESCE(S.currency_rate, 0) WHEN 0 THEN 1.0 ELSE S.currency_rate END) * SOL.qty_invoiced + THEN (SOL.untaxed_amount_invoiced / CASE COALESCE(S.currency_rate, 0) WHEN 0 THEN 1.0 ELSE S.currency_rate END) ELSE -AMOUNT_UNTAXED.expense_cost END ELSE 0.0 @@ -290,31 +250,80 @@ class ProfitabilityAnalysis(models.Model): ELSE 0.0 END AS amount_untaxed_to_invoice, CASE - WHEN SOL.qty_delivered_method IN ('timesheet', 'manual') THEN (COALESCE(SOL.untaxed_amount_invoiced, AMOUNT_UNTAXED.downpayment_invoiced) / CASE COALESCE(S.currency_rate, 0) WHEN 0 THEN 1.0 ELSE S.currency_rate END) + WHEN SOL.qty_delivered_method IN ('timesheet', 'manual') THEN (SOL.untaxed_amount_invoiced / CASE COALESCE(S.currency_rate, 0) WHEN 0 THEN 1.0 ELSE S.currency_rate END) ELSE 0.0 END AS amount_untaxed_invoiced, S.date_order AS line_date FROM project_project P JOIN res_company C ON C.id = P.company_id LEFT JOIN ( + -- Gets SOL linked to timesheets SELECT P.id AS project_id, P.analytic_account_id AS analytic_account_id, AAL.so_line AS sale_line_id, - 0.0 AS expense_cost, - 0.0 AS downpayment_invoiced + 0.0 AS expense_cost FROM account_analytic_line AAL, project_project P WHERE AAL.project_id IS NOT NULL AND P.id = AAL.project_id AND P.active = 't' GROUP BY P.id, AAL.so_line - + UNION + -- Service SOL linked to a project task AND not yet timesheeted + SELECT + P.id AS project_id, + P.analytic_account_id AS analytic_account_id, + SOL.id AS sale_line_id, + 0.0 AS expense_cost + FROM sale_order_line SOL + JOIN project_task T ON T.sale_line_id = SOL.id + JOIN project_project P ON T.project_id = P.id + LEFT JOIN account_analytic_line AAL ON AAL.task_id = T.id + WHERE SOL.is_service = 't' + AND AAL.id IS NULL -- not timesheeted + AND P.active = 't' AND P.allow_timesheets = 't' + GROUP BY P.id, SOL.id + UNION + -- Service SOL linked to project AND not yet timesheeted + SELECT + P.id AS project_id, + P.analytic_account_id AS analytic_account_id, + SOL.id AS sale_line_id, + 0.0 AS expense_cost + FROM sale_order_line SOL + JOIN project_project P ON P.sale_line_id = SOL.id + LEFT JOIN account_analytic_line AAL ON AAL.project_id = P.id + LEFT JOIN project_task T ON T.sale_line_id = SOL.id + WHERE SOL.is_service = 't' + AND AAL.id IS NULL -- not timesheeted + AND (T.id IS NULL OR T.project_id != P.id) -- not linked to a task in this project + AND P.active = 't' AND P.allow_timesheets = 't' + GROUP BY P.id, SOL.id + UNION + -- Service SOL linked to analytic account AND not yet timesheeted + SELECT + P.id AS project_id, + P.analytic_account_id AS analytic_account_id, + SOL.id AS sale_line_id, + 0.0 AS expense_cost + FROM sale_order_line SOL + JOIN sale_order SO ON SO.id = SOL.order_id + JOIN account_analytic_account AA ON AA.id = SO.analytic_account_id + JOIN project_project P ON P.analytic_account_id = AA.id + LEFT JOIN project_project PSOL ON PSOL.sale_line_id = SOL.id + LEFT JOIN project_task TSOL ON TSOL.sale_line_id = SOL.id + LEFT JOIN account_analytic_line AAL ON AAL.so_line = SOL.id + WHERE SOL.is_service = 't' + AND AAL.id IS NULL -- not timesheeted + AND TSOL.id IS NULL -- not linked to a task + AND PSOL.id IS NULL -- not linked to a project + AND P.active = 't' AND P.allow_timesheets = 't' + GROUP BY P.id, SOL.id UNION SELECT P.id AS project_id, P.analytic_account_id AS analytic_account_id, AAL.so_line AS sale_line_id, - 0.0 AS expense_cost, - 0.0 AS downpayment_invoiced + 0.0 AS expense_cost FROM project_project P LEFT JOIN account_analytic_account AA ON P.analytic_account_id = AA.id LEFT JOIN account_analytic_line AAL ON AAL.account_id = AA.id @@ -325,8 +334,7 @@ class ProfitabilityAnalysis(models.Model): P.id AS project_id, P.analytic_account_id AS analytic_account_id, AAL.so_line AS sale_line_id, - SUM(AAL.amount) AS expense_cost, - 0.0 AS downpayment_invoiced + SUM(AAL.amount) AS expense_cost FROM project_project P LEFT JOIN account_analytic_account AA ON P.analytic_account_id = AA.id LEFT JOIN account_analytic_line AAL ON AAL.account_id = AA.id @@ -336,37 +344,31 @@ class ProfitabilityAnalysis(models.Model): SELECT P.id AS project_id, P.analytic_account_id AS analytic_account_id, - MY_SOLS.id AS sale_line_id, - 0.0 AS expense_cost, - CASE WHEN MY_SOLS.invoice_status = 'invoiced' THEN MY_SOLS.price_reduce ELSE 0.0 END AS downpayment_invoiced + SOLDOWN.id AS sale_line_id, + 0.0 AS expense_cost FROM project_project P - LEFT JOIN sale_order_line MY_SOL ON P.sale_line_id = MY_SOL.id - LEFT JOIN sale_order MY_S ON MY_SOL.order_id = MY_S.id - LEFT JOIN sale_order_line MY_SOLS ON MY_SOLS.order_id = MY_S.id - WHERE MY_SOLS.is_downpayment = 't' - GROUP BY P.id, MY_SOLS.id - UNION - SELECT - P.id AS project_id, - P.analytic_account_id AS analytic_account_id, - OLIS.id AS sale_line_id, - OLIS.price_reduce AS expense_cost, - 0.0 AS downpayment_invoiced - FROM project_project P - LEFT JOIN account_analytic_account ANAC ON P.analytic_account_id = ANAC.id - LEFT JOIN account_analytic_line ANLI ON ANAC.id = ANLI.account_id - LEFT JOIN sale_order_line OLI ON P.sale_line_id = OLI.id - LEFT JOIN sale_order ORD ON OLI.order_id = ORD.id - LEFT JOIN sale_order_line OLIS ON ORD.id = OLIS.order_id - WHERE OLIS.product_id = ANLI.product_id AND OLIS.is_downpayment = 't' AND ANLI.amount < 0.0 AND ANLI.project_id IS NULL AND P.active = 't' AND P.allow_timesheets = 't' - GROUP BY P.id, OLIS.id + LEFT JOIN sale_order_line SOL ON P.sale_line_id = SOL.id + LEFT JOIN sale_order SO ON SO.id = SOL.order_id OR SO.analytic_account_id = P.analytic_account_id + LEFT JOIN sale_order_line SOLDOWN ON SOLDOWN.order_id = SO.id AND SOLDOWN.is_downpayment = 't' + LEFT JOIN sale_order_line_invoice_rel SOINV ON SOINV.order_line_id = SOLDOWN.id + LEFT JOIN account_move_line INVL ON SOINV.invoice_line_id = INVL.id + AND INVL.parent_state = 'posted' + AND INVL.exclude_from_invoice_tab = 'f' + LEFT JOIN account_move RINV ON INVL.move_id = RINV.reversed_entry_id + LEFT JOIN account_move_line RINVL ON RINV.id = RINVL.move_id + AND RINVL.parent_state = 'posted' + AND RINVL.exclude_from_invoice_tab = 'f' + AND RINVL.product_id = SOLDOWN.product_id + LEFT JOIN account_analytic_line ANLI ON ANLI.move_id = RINVL.id AND ANLI.amount < 0.0 + WHERE ANLI.id IS NULL -- there are no credit note for this downpayment + AND P.active = 't' AND P.allow_timesheets = 't' + GROUP BY P.id, SOLDOWN.id UNION SELECT P.id AS project_id, P.analytic_account_id AS analytic_account_id, SOL.id AS sale_line_id, - 0.0 AS expense_cost, - 0.0 AS downpayment_invoiced + 0.0 AS expense_cost FROM sale_order_line SOL INNER JOIN project_project P ON SOL.project_id = P.id WHERE P.active = 't' AND P.allow_timesheets = 't' @@ -375,8 +377,7 @@ class ProfitabilityAnalysis(models.Model): P.id AS project_id, P.analytic_account_id AS analytic_account_id, SOL.id AS sale_line_id, - 0.0 AS expense_cost, - 0.0 AS downpayment_invoiced + 0.0 AS expense_cost FROM sale_order_line SOL INNER JOIN project_task T ON SOL.task_id = T.id INNER JOIN project_project P ON P.id = T.project_id diff --git a/addons/sale_timesheet/tests/__init__.py b/addons/sale_timesheet/tests/__init__.py index d9f4f3f399..bd6e321fca 100644 --- a/addons/sale_timesheet/tests/__init__.py +++ b/addons/sale_timesheet/tests/__init__.py @@ -2,6 +2,7 @@ # # Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. from . import common +from . import common_reporting from . import test_sale_timesheet from . import test_sale_service from . import test_project_billing diff --git a/addons/sale_timesheet/tests/common_reporting.py b/addons/sale_timesheet/tests/common_reporting.py new file mode 100644 index 0000000000..e960ab17b2 --- /dev/null +++ b/addons/sale_timesheet/tests/common_reporting.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- +# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. +from flectra.tools import float_is_zero, float_compare +from flectra.addons.sale_timesheet.tests.common import TestCommonSaleTimesheet + + +class TestCommonReporting(TestCommonSaleTimesheet): + + @classmethod + def setUpClass(cls, chart_template_ref=None): + super().setUpClass(chart_template_ref=chart_template_ref) + + # expense product + cls.product_expense = cls.env['product.product'].with_context(mail_notrack=True, mail_create_nolog=True).create({ + 'name': "Expense service", + 'standard_price': 10, + 'list_price': 20, + 'type': 'service', + 'invoice_policy': 'delivery', + 'expense_policy': 'sales_price', + 'default_code': 'EXP', + 'service_type': 'manual', + 'taxes_id': False, + 'property_account_income_id': cls.company_data['default_account_revenue'].id, + }) + + # create Analytic Accounts + cls.analytic_account_1 = cls.env['account.analytic.account'].create({ + 'name': 'Test AA 1', + 'code': 'AA1', + 'company_id': cls.company_data['company'].id, + 'partner_id': cls.partner_a.id + }) + cls.analytic_account_2 = cls.env['account.analytic.account'].create({ + 'name': 'Test AA 2', + 'code': 'AA2', + 'company_id': cls.company_data['company'].id, + 'partner_id': cls.partner_a.id + }) + cls.analytic_account_3 = cls.env['account.analytic.account'].create({ + 'name': 'Test AA 3', + 'code': 'AA3', + 'company_id': cls.company_data['company'].id, + 'partner_id': cls.partner_a.id + }) + + # Sale orders each will create project and a task in a global project (one SO is 'delivered', the other is 'ordered') + # and a third one using fixed_price (which is 'delivered') + cls.sale_order_1 = cls.env['sale.order'].with_context(mail_notrack=True, mail_create_nolog=True).create({ + 'partner_id': cls.partner_a.id, + 'partner_invoice_id': cls.partner_a.id, + 'partner_shipping_id': cls.partner_a.id, + 'analytic_account_id': cls.analytic_account_1.id, + }) + cls.so_line_deliver_project = cls.env['sale.order.line'].create({ + 'name': cls.product_delivery_timesheet3.name, + 'product_id': cls.product_delivery_timesheet3.id, + 'product_uom_qty': 5, + 'product_uom': cls.product_delivery_timesheet3.uom_id.id, + 'price_unit': cls.product_delivery_timesheet3.list_price, + 'order_id': cls.sale_order_1.id, + }) + cls.so_line_deliver_task = cls.env['sale.order.line'].create({ + 'name': cls.product_delivery_timesheet2.name, + 'product_id': cls.product_delivery_timesheet2.id, + 'product_uom_qty': 7, + 'product_uom': cls.product_delivery_timesheet2.uom_id.id, + 'price_unit': cls.product_delivery_timesheet2.list_price, + 'order_id': cls.sale_order_1.id, + }) + + cls.sale_order_2 = cls.env['sale.order'].with_context(mail_notrack=True, mail_create_nolog=True).create({ + 'partner_id': cls.partner_a.id, + 'partner_invoice_id': cls.partner_a.id, + 'partner_shipping_id': cls.partner_a.id, + 'analytic_account_id': cls.analytic_account_2.id, + }) + cls.so_line_order_project = cls.env['sale.order.line'].create({ + 'name': cls.product_order_timesheet3.name, + 'product_id': cls.product_order_timesheet3.id, + 'product_uom_qty': 5, + 'product_uom': cls.product_order_timesheet3.uom_id.id, + 'price_unit': cls.product_order_timesheet3.list_price, + 'order_id': cls.sale_order_2.id, + }) + cls.so_line_order_task = cls.env['sale.order.line'].create({ + 'name': cls.product_order_timesheet2.name, + 'product_id': cls.product_order_timesheet2.id, + 'product_uom_qty': 7, + 'product_uom': cls.product_order_timesheet2.uom_id.id, + 'price_unit': cls.product_order_timesheet2.list_price, + 'order_id': cls.sale_order_2.id, + }) + + cls.sale_order_3 = cls.env['sale.order'].with_context(mail_notrack=True, mail_create_nolog=True).create({ + 'partner_id': cls.partner_a.id, + 'partner_invoice_id': cls.partner_a.id, + 'partner_shipping_id': cls.partner_a.id, + 'analytic_account_id': cls.analytic_account_3.id, + }) + cls.so_line_deliver_manual_project = cls.env['sale.order.line'].create({ + 'name': cls.product_delivery_manual3.name, + 'product_id': cls.product_delivery_manual3.id, + 'product_uom_qty': 11, + 'product_uom': cls.product_delivery_manual3.uom_id.id, + 'price_unit': cls.product_delivery_manual3.list_price, + 'order_id': cls.sale_order_3.id, + }) + + def _log_timesheet_user(self, project, unit_amount, task=False): + """ Utility method to log timesheet """ + Timesheet = self.env['account.analytic.line'] + return Timesheet.create({ + 'name': 'timesheet employee on project_so_1 only', + 'account_id': project.analytic_account_id.id, + 'project_id': project.id, + 'employee_id': self.employee_user.id, + 'unit_amount': unit_amount, + 'task_id': task.id if task else False, + }) + + def _log_timesheet_manager(self, project, unit_amount, task=False): + """ Utility method to log timesheet """ + Timesheet = self.env['account.analytic.line'] + return Timesheet.create({ + 'name': 'timesheet employee on project_so_1 only', + 'account_id': project.analytic_account_id.id, + 'project_id': project.id, + 'employee_id': self.employee_manager.id, + 'unit_amount': unit_amount, + 'task_id': task.id if task else False, + }) diff --git a/addons/sale_timesheet/tests/test_project_overview.py b/addons/sale_timesheet/tests/test_project_overview.py index 71f4e04e90..a7612f23ea 100644 --- a/addons/sale_timesheet/tests/test_project_overview.py +++ b/addons/sale_timesheet/tests/test_project_overview.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- # Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. -from flectra.addons.sale_timesheet.tests.test_reporting import TestReporting -from flectra.tools import float_compare +from flectra.addons.sale_timesheet.tests.common_reporting import TestCommonReporting +from flectra.tools import float_compare, float_is_zero from flectra.tests import tagged @tagged('-at_install', 'post_install') -class TestSaleProject(TestReporting): +class TestSaleProject(TestCommonReporting): def test_project_overview_by_project(self): rounding = self.env.company.currency_id.rounding @@ -34,7 +34,6 @@ class TestSaleProject(TestReporting): project_so = self.so_line_order_project.project_id # log timesheet for billable time timesheet1 = self._log_timesheet_manager(project_so, 10, so_line_deliver_global_project.task_id) - task_so = self.so_line_order_project.task_id # logged some timesheets: on project only, then on tasks with different employees timesheet2 = self._log_timesheet_user(project_so, 2) @@ -89,7 +88,7 @@ class TestSaleProject(TestReporting): }) other_revenues = self.env['account.analytic.line'].create({ - 'name': 'pther revenues on project_so', + 'name': 'other revenues on project_so', 'account_id': project_so.analytic_account_id.id, 'employee_id': self.employee_user.id, 'unit_amount': 1, @@ -103,10 +102,10 @@ class TestSaleProject(TestReporting): dashboard_value = timesheet2.unit_amount + timesheet3.unit_amount + timesheet4.unit_amount + timesheet5.unit_amount + timesheet1.unit_amount project_so_timesheet_sold_unit = timesheet3.unit_amount + timesheet4.unit_amount - project_rate_non_billable = timesheet5.unit_amount / dashboard_value * 100 - project_rate_non_billable_project = timesheet2.unit_amount / dashboard_value * 100 - project_rate_billable_time = timesheet1.unit_amount / dashboard_value * 100 - project_rate_billable_fixed = project_so_timesheet_sold_unit / dashboard_value * 100 + project_rate_non_billable = round(timesheet5.unit_amount / dashboard_value * 100, 2) + project_rate_non_billable_project = round(timesheet2.unit_amount / dashboard_value * 100, 2) + project_rate_billable_time = round(timesheet1.unit_amount / dashboard_value * 100, 2) + project_rate_billable_fixed = round(project_so_timesheet_sold_unit / dashboard_value * 100, 2) project_rate_total = project_rate_non_billable + project_rate_non_billable_project + project_rate_billable_time + project_rate_billable_fixed project_invoiced = self.so_line_order_project.price_unit * self.so_line_order_project.product_uom_qty * timesheet1.unit_amount project_timesheet_cost = timesheet2.amount + timesheet3.amount + timesheet4.amount + timesheet5.amount + timesheet1.amount @@ -122,9 +121,11 @@ class TestSaleProject(TestReporting): self.assertEqual(float_compare(vals['dashboard']['rates']['billable_time'], project_rate_billable_time, precision_rounding=rounding), 0, "The rate billable-time should be the one from the SO2 line, as we are in ordered quantity") self.assertEqual(float_compare(vals['dashboard']['rates']['billable_fixed'], project_rate_billable_fixed, precision_rounding=rounding), 0, "The rate billable-fixed should be the one from the SO2 line, as we are in ordered quantity") self.assertEqual(float_compare(vals['dashboard']['rates']['total'], project_rate_total, precision_rounding=rounding), 0, "The total rates should be the one from the SO2 line, as we are in ordered quantity") - self.assertEqual(float_compare(vals['dashboard']['profit']['invoiced'], project_invoiced, precision_rounding=rounding), 0, "The amount invoiced should be the one from the SO2 line, as we are in ordered quantity") + self.assertEqual(float_compare(vals['dashboard']['profit']['invoiced'], project_invoiced + project_other_revenues.price_total, precision_rounding=rounding), 0, "The amount invoiced should be the one from the SO2 line, as we are in ordered quantity") self.assertEqual(float_compare(vals['dashboard']['profit']['cost'], project_timesheet_cost, precision_rounding=rounding), 0, "The amount cost should be the one from the SO2 line, as we are in ordered quantity") self.assertEqual(float_compare(vals['dashboard']['profit']['expense_cost'], expense.amount, precision_rounding=rounding), 0, "The amount expense-cost should be the one from the SO2 line, as we are in ordered quantity") - self.assertEqual(float_compare(vals['dashboard']['profit']['other_revenues'], other_revenues.amount + project_other_revenues.price_total, precision_rounding=rounding), 0, "The amount of the other revenues should be equal to the corresponding account move line and the one from the SO line") - self.assertEqual(float_compare(vals['dashboard']['profit']['total'], project_invoiced + project_timesheet_cost + expense.amount + other_revenues.amount + project_other_revenues.price_total, precision_rounding=rounding), 0, "The total amount should be the sum of the SO2 line and the created other_revenues account analytic line") + self.assertEqual(float_compare(vals['dashboard']['profit']['other_revenues'], other_revenues.amount, precision_rounding=rounding), 0, "The amount of the other revenues should be equal to the corresponding account move line and the one from the SO line") + self.assertEqual(float_compare(vals['dashboard']['profit']['expense_amount_untaxed_to_invoice'], -expense.amount, precision_rounding=rounding), 0, "The amount of expense to re-invoice shoul be equal to the opposite of expense amount") + self.assertTrue(float_is_zero(vals['dashboard']['profit']['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The amount of expense re-invoiced should be equal to 0") + self.assertEqual(float_compare(vals['dashboard']['profit']['total'], project_invoiced + project_timesheet_cost + other_revenues.amount + project_other_revenues.price_total, precision_rounding=rounding), 0, "The total amount should be the sum of the SO2 line and the created other_revenues account analytic line") self.assertEqual(float_compare(vals['repartition_employee_max'], 11.0, precision_rounding=rounding), 0, "The amount of repartition-employee-max should be the one from SO2 line") diff --git a/addons/sale_timesheet/tests/test_reporting.py b/addons/sale_timesheet/tests/test_reporting.py index 577b138b9b..77ab7ebe94 100644 --- a/addons/sale_timesheet/tests/test_reporting.py +++ b/addons/sale_timesheet/tests/test_reporting.py @@ -1,115 +1,13 @@ # -*- coding: utf-8 -*- # Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. +from flectra.osv import expression from flectra.tools import float_is_zero, float_compare -from flectra.addons.sale_timesheet.tests.common import TestCommonSaleTimesheet +from flectra.addons.sale_timesheet.tests.common_reporting import TestCommonReporting from flectra.tests import tagged @tagged('-at_install', 'post_install') -class TestReporting(TestCommonSaleTimesheet): - - @classmethod - def setUpClass(cls, chart_template_ref=None): - super().setUpClass(chart_template_ref=chart_template_ref) - - # expense product - cls.product_expense = cls.env['product.product'].with_context(mail_notrack=True, mail_create_nolog=True).create({ - 'name': "Expense service", - 'standard_price': 10, - 'list_price': 20, - 'type': 'service', - 'invoice_policy': 'delivery', - 'expense_policy': 'sales_price', - 'default_code': 'EXP', - 'service_type': 'manual', - 'taxes_id': False, - 'property_account_income_id': cls.company_data['default_account_revenue'].id, - }) - - # create Analytic Accounts - cls.analytic_account_1 = cls.env['account.analytic.account'].create({ - 'name': 'Test AA 1', - 'code': 'AA1', - 'company_id': cls.company_data['company'].id, - 'partner_id': cls.partner_a.id - }) - cls.analytic_account_2 = cls.env['account.analytic.account'].create({ - 'name': 'Test AA 2', - 'code': 'AA2', - 'company_id': cls.company_data['company'].id, - 'partner_id': cls.partner_a.id - }) - - # Sale orders each will create project and a task in a global project (one SO is 'delivered', the other is 'ordered') - cls.sale_order_1 = cls.env['sale.order'].with_context(mail_notrack=True, mail_create_nolog=True).create({ - 'partner_id': cls.partner_a.id, - 'partner_invoice_id': cls.partner_a.id, - 'partner_shipping_id': cls.partner_a.id, - 'analytic_account_id': cls.analytic_account_1.id, - }) - cls.so_line_deliver_project = cls.env['sale.order.line'].create({ - 'name': cls.product_delivery_timesheet3.name, - 'product_id': cls.product_delivery_timesheet3.id, - 'product_uom_qty': 5, - 'product_uom': cls.product_delivery_timesheet3.uom_id.id, - 'price_unit': cls.product_delivery_timesheet3.list_price, - 'order_id': cls.sale_order_1.id, - }) - cls.so_line_deliver_task = cls.env['sale.order.line'].create({ - 'name': cls.product_delivery_timesheet2.name, - 'product_id': cls.product_delivery_timesheet2.id, - 'product_uom_qty': 7, - 'product_uom': cls.product_delivery_timesheet2.uom_id.id, - 'price_unit': cls.product_delivery_timesheet2.list_price, - 'order_id': cls.sale_order_1.id, - }) - - cls.sale_order_2 = cls.env['sale.order'].with_context(mail_notrack=True, mail_create_nolog=True).create({ - 'partner_id': cls.partner_a.id, - 'partner_invoice_id': cls.partner_a.id, - 'partner_shipping_id': cls.partner_a.id, - 'analytic_account_id': cls.analytic_account_2.id, - }) - cls.so_line_order_project = cls.env['sale.order.line'].create({ - 'name': cls.product_order_timesheet3.name, - 'product_id': cls.product_order_timesheet3.id, - 'product_uom_qty': 5, - 'product_uom': cls.product_order_timesheet3.uom_id.id, - 'price_unit': cls.product_order_timesheet3.list_price, - 'order_id': cls.sale_order_2.id, - }) - cls.so_line_order_task = cls.env['sale.order.line'].create({ - 'name': cls.product_order_timesheet2.name, - 'product_id': cls.product_order_timesheet2.id, - 'product_uom_qty': 7, - 'product_uom': cls.product_order_timesheet2.uom_id.id, - 'price_unit': cls.product_order_timesheet2.list_price, - 'order_id': cls.sale_order_2.id, - }) - - def _log_timesheet_user(self, project, unit_amount, task=False): - """ Utility method to log timesheet """ - Timesheet = self.env['account.analytic.line'] - return Timesheet.create({ - 'name': 'timesheet employee on project_so_1 only', - 'account_id': project.analytic_account_id.id, - 'project_id': project.id, - 'employee_id': self.employee_user.id, - 'unit_amount': unit_amount, - 'task_id': task.id if task else False, - }) - - def _log_timesheet_manager(self, project, unit_amount, task=False): - """ Utility method to log timesheet """ - Timesheet = self.env['account.analytic.line'] - return Timesheet.create({ - 'name': 'timesheet employee on project_so_1 only', - 'account_id': project.analytic_account_id.id, - 'project_id': project.id, - 'employee_id': self.employee_manager.id, - 'unit_amount': unit_amount, - 'task_id': task.id if task else False, - }) +class TestReporting(TestCommonReporting): def test_profitability_report(self): @@ -125,31 +23,38 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the global project should be 0.0") self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the global project should be 0.0") self.assertTrue(float_is_zero(project_global_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the global project should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the global project should be 0.0") # confirm sales orders self.sale_order_1.action_confirm() self.sale_order_2.action_confirm() + self.sale_order_3.action_confirm() self.env['project.profitability.report'].flush() project_so_1 = self.so_line_deliver_project.project_id project_so_2 = self.so_line_order_project.project_id + project_so_3 = self.so_line_deliver_manual_project.project_id + task_so_1 = self.so_line_deliver_project.task_id task_so_2 = self.so_line_order_project.task_id + task_so_3 = self.so_line_deliver_manual_project.task_id + task_in_global_1 = self.so_line_deliver_task.task_id task_in_global_2 = self.so_line_order_task.task_id # deliver project should not be impacted, as no timesheet are logged yet - project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] self.assertTrue(float_is_zero(project_so_1_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_1_stat['amount_untaxed_to_invoice'], precision_rounding=rounding), "The amount to invoice of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_1_stat['timesheet_unit_amount'], precision_rounding=rounding), "The timesheet unit amount of the project from SO1 should be 0.0") - self.assertTrue(float_is_zero(project_so_1_stat['timesheet_cost'], precision_rounding=rounding), "The timesheet cost of the global project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['timesheet_cost'], precision_rounding=rounding), "The timesheet cost of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO1 should be 0.0") - self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the global project should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_1_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO1 should be 0.0") # order project should be to invoice, but nothing has been delivered yet - project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] self.assertTrue(float_is_zero(project_so_2_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO2 should be 0.0") self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_to_invoice'], self.so_line_order_project.price_unit * self.so_line_order_project.qty_to_invoice, precision_rounding=rounding), 0, "The amount to invoice should be the one from the SO line, as we are in ordered quantity") self.assertTrue(float_is_zero(project_so_2_stat['timesheet_unit_amount'], precision_rounding=rounding), "The timesheet unit amount of the project from SO2 should be 0.0") @@ -157,9 +62,21 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO2 should be 0.0") self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the global project should be 0.0") self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO2 should be 0.0") - # global project now contain 2 tasks: 'deliver' one which has no effect (no timesheet yet), and the 'order' one which should update the 'to invoice' amount - project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + # fixed price project should not be impacted, as no delivered quantity are logged yet + project_so_3_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_3.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + self.assertTrue(float_is_zero(project_so_3_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['amount_untaxed_to_invoice'], precision_rounding=rounding), "The amount to invoice of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['timesheet_unit_amount'], precision_rounding=rounding), "The timesheet unit amount of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['timesheet_cost'], precision_rounding=rounding), "The timesheet cost of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO3 should be 0.0") + + # global project now contain 3 tasks: 'deliver' ones which have no effect (no timesheet or delivered yet), and the 'order' one which should update the 'to invoice' amount + project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] self.assertTrue(float_is_zero(project_global_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the global project should be 0.0") self.assertEqual(float_compare(project_global_stat['amount_untaxed_to_invoice'], self.so_line_order_task.price_unit * self.so_line_order_task.qty_to_invoice, precision_rounding=rounding), 0, "The amount to invoice of global project should take the task in 'oredered qty' into account") self.assertTrue(float_is_zero(project_global_stat['timesheet_unit_amount'], precision_rounding=rounding), "The timesheet unit amount of the global project should be 0.0") @@ -167,21 +84,22 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the global project should be 0.0") self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the global project should be 0.0") self.assertTrue(float_is_zero(project_global_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the global project should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the global project should be 0.0") # logged some timesheets: on project only, then on tasks with different employees timesheet1 = self._log_timesheet_user(project_so_1, 2) timesheet2 = self._log_timesheet_user(project_so_2, 2) timesheet3 = self._log_timesheet_user(project_so_1, 3, task_so_1) timesheet4 = self._log_timesheet_user(project_so_2, 3, task_so_2) - timesheet5 = self._log_timesheet_manager(project_so_1, 1, task_so_1) timesheet6 = self._log_timesheet_manager(project_so_2, 1, task_so_2) timesheet7 = self._log_timesheet_manager(self.project_global, 3, task_in_global_1) timesheet8 = self._log_timesheet_manager(self.project_global, 3, task_in_global_2) + timesheet9 = self._log_timesheet_user(project_so_3, 4, task_so_3) self.env['project.profitability.report'].flush() # deliver project should now have cost and something to invoice - project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_so_1_timesheet_cost = timesheet1.amount + timesheet3.amount + timesheet5.amount project_so_1_timesheet_sold_unit = timesheet1.unit_amount + timesheet3.unit_amount + timesheet5.unit_amount self.assertTrue(float_is_zero(project_so_1_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO1 should be 0.0") @@ -191,9 +109,10 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_1_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the deliver project should be 0.0") # order project still have something to invoice but has costs now - project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_so_2_timesheet_cost = timesheet2.amount + timesheet4.amount + timesheet6.amount project_so_2_timesheet_sold_unit = timesheet2.unit_amount + timesheet4.unit_amount + timesheet6.unit_amount self.assertTrue(float_is_zero(project_so_2_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO2 should be 0.0") @@ -203,9 +122,23 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO2 should be 0.0") self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO2 should be 0.0") + + # fixed price project should ow have cost and nothing to invoice as no delivered quantity are logged yet + project_so_3_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_3.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + project_so_3_timesheet_cost = timesheet9.amount + project_so_3_timesheet_sold_unit = timesheet9.unit_amount + self.assertTrue(float_is_zero(project_so_3_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['amount_untaxed_to_invoice'], precision_rounding=rounding), "The amount to invoice of the project from SO3 should be 0.0") + self.assertEqual(float_compare(project_so_3_stat['timesheet_unit_amount'], project_so_3_timesheet_sold_unit, precision_rounding=rounding), 0, "The timesheet unit amount of the project from SO3") + self.assertEqual(float_compare(project_so_3_stat['timesheet_cost'], project_so_3_timesheet_cost, precision_rounding=rounding), 0, "The timesheet cost of the project from SO3") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO3 should be 0.0") # global project should have more to invoice, and should now have costs - project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_global_timesheet_cost = timesheet7.amount + timesheet8.amount project_global_timesheet_unit = timesheet7.unit_amount + timesheet8.unit_amount project_global_to_invoice = (self.so_line_order_task.price_unit * self.so_line_order_task.product_uom_qty) + (self.so_line_deliver_task.price_unit * timesheet7.unit_amount) @@ -216,6 +149,63 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the global project should be 0.0") self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_global_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the global project should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the global project should be 0.0") + + self.so_line_deliver_manual_project.write({'qty_delivered': 7.0}) + self.env['project.profitability.report'].flush() + + # deliver project should now have cost and something to invoice + project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + project_so_1_timesheet_cost = timesheet1.amount + timesheet3.amount + timesheet5.amount + project_so_1_timesheet_sold_unit = timesheet1.unit_amount + timesheet3.unit_amount + timesheet5.unit_amount + self.assertTrue(float_is_zero(project_so_1_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO1 should be 0.0") + self.assertEqual(float_compare(project_so_1_stat['amount_untaxed_to_invoice'], self.so_line_deliver_project.price_unit * project_so_1_timesheet_sold_unit, precision_rounding=rounding), 0, "The amount to invoice of the project from SO1 should only include timesheet linked to task") + self.assertEqual(float_compare(project_so_1_stat['timesheet_unit_amount'], project_so_1_timesheet_sold_unit, precision_rounding=rounding), 0, "The timesheet unit amount of the project from SO1 should include all timesheet in project") + self.assertEqual(float_compare(project_so_1_stat['timesheet_cost'], project_so_1_timesheet_cost, precision_rounding=rounding), 0, "The timesheet cost of the project from SO1 should include all timesheet") + self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the deliver project should be 0.0") + + # order project still have something to invoice but has costs now + project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + project_so_2_timesheet_cost = timesheet2.amount + timesheet4.amount + timesheet6.amount + project_so_2_timesheet_sold_unit = timesheet2.unit_amount + timesheet4.unit_amount + timesheet6.unit_amount + self.assertTrue(float_is_zero(project_so_2_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO2 should be 0.0") + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_to_invoice'], self.so_line_order_project.price_unit * self.so_line_order_project.qty_to_invoice, precision_rounding=rounding), 0, "The amount to invoice should be the one from the SO line, as we are in ordered quantity") + self.assertEqual(float_compare(project_so_2_stat['timesheet_unit_amount'], project_so_2_timesheet_sold_unit, precision_rounding=rounding), 0, "The timesheet unit amount of the project from SO2 should include all timesheet") + self.assertEqual(float_compare(project_so_2_stat['timesheet_cost'], project_so_2_timesheet_cost, precision_rounding=rounding), 0, "The timesheet cost of the project from SO2 should include all timesheet") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO2 should be 0.0") + + # fixed price project should ow have cost and something to invoice as some delivered quantity are logged in + project_so_3_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_3.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + project_so_3_timesheet_cost = timesheet9.amount + project_so_3_timesheet_sold_unit = timesheet9.unit_amount + self.assertTrue(float_is_zero(project_so_3_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO3 should be 0.0") + self.assertEqual(float_compare(project_so_3_stat['amount_untaxed_to_invoice'], self.so_line_deliver_manual_project.price_unit * self.so_line_deliver_manual_project.qty_to_invoice, precision_rounding=rounding), 0, "The amount to invoice of the project from SO3 should be 0.0") + self.assertEqual(float_compare(project_so_3_stat['timesheet_unit_amount'], project_so_3_timesheet_sold_unit, precision_rounding=rounding), 0, "The timesheet unit amount of the project from SO3") + self.assertEqual(float_compare(project_so_3_stat['timesheet_cost'], project_so_3_timesheet_cost, precision_rounding=rounding), 0, "The timesheet cost of the project from SO3") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO3 should be 0.0") + + # global project should have more to invoice, and should now have costs + project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + project_global_timesheet_cost = timesheet7.amount + timesheet8.amount + project_global_timesheet_unit = timesheet7.unit_amount + timesheet8.unit_amount + project_global_to_invoice = (self.so_line_order_task.price_unit * self.so_line_order_task.product_uom_qty) + (self.so_line_deliver_task.price_unit * timesheet7.unit_amount) + self.assertTrue(float_is_zero(project_global_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the global project should be 0.0") + self.assertEqual(float_compare(project_global_stat['amount_untaxed_to_invoice'], project_global_to_invoice, precision_rounding=rounding), 0, "The amount to invoice of global project should take the task in 'oredered qty' and the delivered timesheets into account") + self.assertEqual(float_compare(project_global_stat['timesheet_unit_amount'], project_global_timesheet_unit, precision_rounding=rounding), 0, "The timesheet unit amount of the global project should include all timesheet") + self.assertEqual(float_compare(project_global_stat['timesheet_cost'], project_global_timesheet_cost, precision_rounding=rounding), 0, "The timesheet cost of the global project should include all timesheet") + self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the global project should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the global project should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the global project should be 0.0") InvoiceWizard = self.env['sale.advance.payment.inv'].with_context(mail_notrack=True) @@ -236,7 +226,7 @@ class TestReporting(TestCommonSaleTimesheet): self.env['project.profitability.report'].flush() # deliver project should now have cost and something invoiced - project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_so_1_timesheet_cost = timesheet1.amount + timesheet3.amount + timesheet5.amount project_so_1_timesheet_sold_unit = timesheet1.unit_amount + timesheet3.unit_amount + timesheet5.unit_amount @@ -247,9 +237,10 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_1_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the deliver project should be 0.0") # order project has still nothing invoiced - project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_so_2_timesheet_cost = timesheet2.amount + timesheet4.amount + timesheet6.amount project_so_2_timesheet_sold_unit = timesheet2.unit_amount + timesheet4.unit_amount + timesheet6.unit_amount self.assertTrue(float_is_zero(project_so_2_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO2 should be 0.0") @@ -259,9 +250,23 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO2 should be 0.0") self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO2 should be 0.0") + + # fixed price project has still nothing invoice + project_so_3_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_3.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + project_so_3_timesheet_cost = timesheet9.amount + project_so_3_timesheet_sold_unit = timesheet9.unit_amount + self.assertTrue(float_is_zero(project_so_3_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO3 should be 0.0") + self.assertEqual(float_compare(project_so_3_stat['amount_untaxed_to_invoice'], self.so_line_deliver_manual_project.price_unit * self.so_line_deliver_manual_project.qty_to_invoice, precision_rounding=rounding), 0, "The amount to invoice of the project from SO3 should be 0.0") + self.assertEqual(float_compare(project_so_3_stat['timesheet_unit_amount'], project_so_3_timesheet_sold_unit, precision_rounding=rounding), 0, "The timesheet unit amount of the project from SO3") + self.assertEqual(float_compare(project_so_3_stat['timesheet_cost'], project_so_3_timesheet_cost, precision_rounding=rounding), 0, "The timesheet cost of the project from SO3") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO3 should be 0.0") # global project should have more to invoice, and should now have costs - project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_global_timesheet_cost = timesheet7.amount + timesheet8.amount project_global_timesheet_unit = timesheet7.unit_amount + timesheet8.unit_amount project_global_to_invoice = self.so_line_order_task.price_unit * self.so_line_order_task.product_uom_qty @@ -273,6 +278,7 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the global project should be 0.0") self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_global_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the global project should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the global project should be 0.0") # invoice the Sales Order SO2 context = { @@ -291,7 +297,7 @@ class TestReporting(TestCommonSaleTimesheet): self.env['project.profitability.report'].flush() # deliver project should not be impacted by the invoice of the other SO - project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_so_1_timesheet_cost = timesheet1.amount + timesheet3.amount + timesheet5.amount project_so_1_timesheet_sold_unit = timesheet1.unit_amount + timesheet3.unit_amount + timesheet5.unit_amount self.assertEqual(float_compare(project_so_1_stat['amount_untaxed_invoiced'], self.so_line_deliver_project.price_unit * project_so_1_timesheet_sold_unit, precision_rounding=rounding), 0, "The invoiced amount of the project from SO1 should only include timesheet linked to task") @@ -301,9 +307,10 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_1_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the deliver project should be 0.0") # order project is now totally invoiced, as we are in ordered qty - project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_so_2_timesheet_cost = timesheet2.amount + timesheet4.amount + timesheet6.amount project_so_2_timesheet_sold_unit = timesheet2.unit_amount + timesheet4.unit_amount + timesheet6.unit_amount self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_invoiced'], self.so_line_order_project.price_unit * self.so_line_order_project.product_uom_qty, precision_rounding=rounding), 0, "The invoiced amount should be the one from the SO line, as we are in ordered quantity") @@ -313,9 +320,23 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO2 should be 0.0") self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO2 should be 0.0") + + # fixed price project has still nothing invoice + project_so_3_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_3.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + project_so_3_timesheet_cost = timesheet9.amount + project_so_3_timesheet_sold_unit = timesheet9.unit_amount + self.assertTrue(float_is_zero(project_so_3_stat['amount_untaxed_invoiced'], precision_rounding=rounding), "The invoiced amount of the project from SO3 should be 0.0") + self.assertEqual(float_compare(project_so_3_stat['amount_untaxed_to_invoice'], self.so_line_deliver_manual_project.price_unit * self.so_line_deliver_manual_project.qty_to_invoice, precision_rounding=rounding), 0, "The amount to invoice of the project from SO3 should be 0.0") + self.assertEqual(float_compare(project_so_3_stat['timesheet_unit_amount'], project_so_3_timesheet_sold_unit, precision_rounding=rounding), 0, "The timesheet unit amount of the project from SO3") + self.assertEqual(float_compare(project_so_3_stat['timesheet_cost'], project_so_3_timesheet_cost, precision_rounding=rounding), 0, "The timesheet cost of the project from SO3") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO3 should be 0.0") # global project should be totally invoiced - project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_global_timesheet_cost = timesheet7.amount + timesheet8.amount project_global_timesheet_unit = timesheet7.unit_amount + timesheet8.unit_amount project_global_invoiced = self.so_line_order_task.price_unit * self.so_line_order_task.product_uom_qty + self.so_line_deliver_task.price_unit * timesheet7.unit_amount @@ -326,6 +347,76 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the global project should be 0.0") self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_global_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the global project should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the global project should be 0.0") + + # invoice the Sales Order SO3 + context = { + "active_model": 'sale.order', + "active_ids": [self.sale_order_3.id], + "active_id": self.sale_order_3.id, + 'open_invoices': True, + } + payment = InvoiceWizard.create({ + 'advance_payment_method': 'delivered', + }) + action_invoice = payment.with_context(context).create_invoices() + invoice_id = action_invoice['res_id'] + invoice_3 = self.env['account.move'].browse(invoice_id) + invoice_3.action_post() + self.env['project.profitability.report'].flush() + + # deliver project should not be impacted by the invoice of the other SO + project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + project_so_1_timesheet_cost = timesheet1.amount + timesheet3.amount + timesheet5.amount + project_so_1_timesheet_sold_unit = timesheet1.unit_amount + timesheet3.unit_amount + timesheet5.unit_amount + self.assertEqual(float_compare(project_so_1_stat['amount_untaxed_invoiced'], self.so_line_deliver_project.price_unit * project_so_1_timesheet_sold_unit, precision_rounding=rounding), 0, "The invoiced amount of the project from SO1 should only include timesheet linked to task") + self.assertTrue(float_is_zero(project_so_1_stat['amount_untaxed_to_invoice'], precision_rounding=rounding), "The amount to invoice of the project from SO1 should be 0.0") + self.assertEqual(float_compare(project_so_1_stat['timesheet_unit_amount'], project_so_1_timesheet_sold_unit, precision_rounding=rounding), 0, "The timesheet unit amount of the project from SO1 should include all timesheet in project") + self.assertEqual(float_compare(project_so_1_stat['timesheet_cost'], project_so_1_timesheet_cost, precision_rounding=rounding), 0, "The timesheet cost of the project from SO1 should include all timesheet") + self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the deliver project should be 0.0") + + # order project should not be impacted by the invoice of the other SO + project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + project_so_2_timesheet_cost = timesheet2.amount + timesheet4.amount + timesheet6.amount + project_so_2_timesheet_sold_unit = timesheet2.unit_amount + timesheet4.unit_amount + timesheet6.unit_amount + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_invoiced'], self.so_line_order_project.price_unit * self.so_line_order_project.product_uom_qty, precision_rounding=rounding), 0, "The invoiced amount should be the one from the SO line, as we are in ordered quantity") + self.assertTrue(float_is_zero(project_so_2_stat['amount_untaxed_to_invoice'], precision_rounding=rounding), "The amount to invoice should be the one 0.0, as all ordered quantity is invoiced") + self.assertEqual(float_compare(project_so_2_stat['timesheet_unit_amount'], project_so_2_timesheet_sold_unit, precision_rounding=rounding), 0, "The timesheet unit amount of the project from SO2 should include all timesheet") + self.assertEqual(float_compare(project_so_2_stat['timesheet_cost'], project_so_2_timesheet_cost, precision_rounding=rounding), 0, "The timesheet cost of the project from SO2 should include all timesheet") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO2 should be 0.0") + + # fixed price project is now partially invoiced, as we are in delivered qty + project_so_3_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_3.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + project_so_3_timesheet_cost = timesheet9.amount + project_so_3_timesheet_sold_unit = timesheet9.unit_amount + self.assertEqual(float_compare(project_so_3_stat['amount_untaxed_invoiced'], self.so_line_deliver_manual_project.price_unit * self.so_line_deliver_manual_project.qty_delivered, precision_rounding=rounding), 0, "The invoiced amount of the project from SO3 should be the delivered quantity * the unit price") + self.assertTrue(float_is_zero(project_so_3_stat['amount_untaxed_to_invoice'], precision_rounding=rounding), "The amount to invoice of the project from SO3 should be 0.0") + self.assertEqual(float_compare(project_so_3_stat['timesheet_unit_amount'], project_so_3_timesheet_sold_unit, precision_rounding=rounding), 0, "The timesheet unit amount of the project from SO3") + self.assertEqual(float_compare(project_so_3_stat['timesheet_cost'], project_so_3_timesheet_cost, precision_rounding=rounding), 0, "The timesheet cost of the project from SO3") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO3 should be 0.0") + self.assertTrue(float_is_zero(project_so_3_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO3 should be 0.0") + + # global project should be totally invoiced + project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] + project_global_timesheet_cost = timesheet7.amount + timesheet8.amount + project_global_timesheet_unit = timesheet7.unit_amount + timesheet8.unit_amount + project_global_invoiced = self.so_line_order_task.price_unit * self.so_line_order_task.product_uom_qty + self.so_line_deliver_task.price_unit * timesheet7.unit_amount + self.assertEqual(float_compare(project_global_stat['amount_untaxed_invoiced'], project_global_invoiced, precision_rounding=rounding), 0, "The invoiced amount of the global project should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['amount_untaxed_to_invoice'], precision_rounding=rounding), "The amount to invoice of global project should take the task in 'oredered qty' and the delivered timesheets into account") + self.assertEqual(float_compare(project_global_stat['timesheet_unit_amount'], project_global_timesheet_unit, precision_rounding=rounding), 0, "The timesheet unit amount of the global project should include all timesheet") + self.assertEqual(float_compare(project_global_stat['timesheet_cost'], project_global_timesheet_cost, precision_rounding=rounding), 0, "The timesheet cost of the global project should include all timesheet") + self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the global project should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the global project should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the global project should be 0.0") # simulate the auto creation of the SO line for expense, like we confirm a vendor bill. so_line_expense = self.env['sale.order.line'].create({ @@ -362,7 +453,7 @@ class TestReporting(TestCommonSaleTimesheet): self.env['project.profitability.report'].flush() # deliver project should now have expense cost, and expense to reinvoice as there is a still open sales order linked to the AA1 - project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_so_1_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_1.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_so_1_timesheet_cost = timesheet1.amount + timesheet3.amount + timesheet5.amount project_so_1_timesheet_sold_unit = timesheet1.unit_amount + timesheet3.unit_amount + timesheet5.unit_amount self.assertEqual(float_compare(project_so_1_stat['amount_untaxed_invoiced'], self.so_line_deliver_project.price_unit * project_so_1_timesheet_sold_unit, precision_rounding=rounding), 0, "The invoiced amount of the project from SO1 should only include timesheet linked to task") @@ -372,9 +463,10 @@ class TestReporting(TestCommonSaleTimesheet): self.assertEqual(float_compare(project_so_1_stat['expense_amount_untaxed_to_invoice'], -1 * expense1.amount, precision_rounding=rounding), 0, "The expense cost to reinvoice of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_1_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertEqual(float_compare(project_so_1_stat['expense_cost'], expense1.amount, precision_rounding=rounding), 0, "The expense cost of the project from SO1 should be 0.0") + self.assertTrue(float_is_zero(project_so_1_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the deliver project should be 0.0") # order project is not impacted by the expenses - project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_so_2_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', project_so_2.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_so_2_timesheet_cost = timesheet2.amount + timesheet4.amount + timesheet6.amount project_so_2_timesheet_sold_unit = timesheet2.unit_amount + timesheet4.unit_amount + timesheet6.unit_amount self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_invoiced'], self.so_line_order_project.price_unit * self.so_line_order_project.product_uom_qty, precision_rounding=rounding), 0, "The invoiced amount should be the one from the SO line, as we are in ordered quantity") @@ -384,9 +476,10 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the project from SO2 should be 0.0") self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the project from SO2 should be 0.0") # global project should have an expense, but not reinvoiceable - project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced'], ['project_id'])[0] + project_global_stat = self.env['project.profitability.report'].read_group([('project_id', 'in', self.project_global.ids)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], ['project_id'])[0] project_global_timesheet_cost = timesheet7.amount + timesheet8.amount project_global_timesheet_unit = timesheet7.unit_amount + timesheet8.unit_amount project_global_invoiced = self.so_line_order_task.price_unit * self.so_line_order_task.product_uom_qty + self.so_line_deliver_task.price_unit * timesheet7.unit_amount @@ -397,3 +490,338 @@ class TestReporting(TestCommonSaleTimesheet): self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), "The expense cost to reinvoice of the global project should be 0.0") self.assertTrue(float_is_zero(project_global_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), "The expense invoiced amount of the project from SO1 should be 0.0") self.assertEqual(float_compare(project_global_stat['expense_cost'], expense2.amount, precision_rounding=rounding), 0, "The expense cost of the global project should be 0.0") + self.assertTrue(float_is_zero(project_global_stat['other_revenues'], precision_rounding=rounding), "The other revenues of the global project should be 0.0") + + def test_reversed_downpayment(self): + # this test suppose everything is in the same currency as the current one + currency = self.env.company.currency_id + rounding = currency.rounding + + self.sale_order_2.action_confirm() + context = { + 'active_model': 'sale.order', + 'active_ids': self.sale_order_2.ids, + 'active_id': self.sale_order_2.id, + 'default_journal_id': self.company_data['default_journal_sale'].id, + 'open_invoices': True, + } + # Let's do an invoice for a deposit of 100 + downpayment = self.env['sale.advance.payment.inv'].with_context(context).create({ + 'advance_payment_method': 'percentage', + 'amount': 10, + }) + action_invoice = downpayment.create_invoices() + invoice_id = action_invoice['res_id'] + invoice_downpayment = self.env['account.move'].browse(invoice_id) + invoice_downpayment.action_post() + posted_invoice_res_ids = [invoice_id] + downpayment2 = self.env['sale.advance.payment.inv'].with_context(context).create({ + 'advance_payment_method': 'percentage', + 'amount': 25, + }) + action_invoice = downpayment2.create_invoices() + invoice_downpayment2 = self.env['account.move'].search(expression.AND([action_invoice['domain'], [('id', 'not in', posted_invoice_res_ids)]])) + invoice_downpayment2.action_post() + posted_invoice_res_ids += invoice_downpayment2.ids + milestone_to_invoice = self.so_line_order_project.price_unit * self.so_line_order_project.qty_to_invoice + timesheets_to_invoice = self.so_line_order_task.price_unit * self.so_line_order_task.qty_to_invoice + total_product_price = milestone_to_invoice + timesheets_to_invoice + credit_note_wizard = self.env['account.move.reversal'].with_context({ + 'active_ids': invoice_downpayment2.ids, + 'active_id': invoice_downpayment2.id, + 'active_model': 'account.move' + }).create({ + 'refund_method': 'refund', + 'reason': 'reason test create', + }) + action_moves = credit_note_wizard.reverse_moves() + credit_id = action_moves['res_id'] + invoice_credit = self.env['account.move'].browse(credit_id) + invoice_credit.action_post() + posted_invoice_res_ids += invoice_credit.ids + project_so_2 = self.so_line_order_project.project_id + task_so_2 = self.so_line_order_project.task_id + task_in_global_2 = self.so_line_order_task.task_id + + self.env['project.profitability.report'].flush() + project_so_2_stat = self.env['project.profitability.report'].read_group( + [('project_id', 'in', project_so_2.ids)], + ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], + ['project_id'] + )[0] + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_invoiced'], 0.1 * total_product_price, precision_rounding=rounding), 0, + "The invoiced amount is the amount of downpayments not reversed") + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_to_invoice'], milestone_to_invoice - 0.1 * total_product_price, precision_rounding=rounding), 0, + "The amount to invoice is the milestone product minus the downpayment not reversed") + self.assertTrue(float_is_zero(project_so_2_stat['timesheet_unit_amount'], precision_rounding=rounding), + "The timesheet unit amount of the project from SO2 is 0") + self.assertTrue(float_is_zero(project_so_2_stat['timesheet_cost'], precision_rounding=rounding), + "The timesheet cost of the project from SO2 is 0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), + "The expense cost to reinvoice of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), + "The expense invoiced amount of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), + "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), + "The other revenues of the project from SO2 should be 0.0") + + # logged some timesheets: on project only, then on tasks with different employees + timesheet2 = self._log_timesheet_user(project_so_2, 2) + timesheet4 = self._log_timesheet_user(project_so_2, 3, task_so_2) + timesheet6 = self._log_timesheet_manager(project_so_2, 2, task_so_2) + timesheet8 = self._log_timesheet_manager(self.project_global, 3, task_in_global_2) + + # simulate the auto creation of the SO line for expense, like we confirm a vendor bill. + so_line_expense = self.env['sale.order.line'].create({ + 'name': self.product_expense.name, + 'product_id': self.product_expense.id, + 'product_uom_qty': 0.0, + 'product_uom': self.product_expense.uom_id.id, + 'price_unit': self.product_expense.list_price, # reinvoice at sales price + 'order_id': self.sale_order_2.id, + 'is_expense': True, + }) + + expense1 = self.env['account.analytic.line'].create({ + 'name': 'expense on project_so_2', + 'account_id': project_so_2.analytic_account_id.id, + 'so_line': so_line_expense.id, + 'employee_id': self.employee_user.id, + 'unit_amount': 4, + 'amount': 4 * self.product_expense.list_price * -1, + 'product_id': self.product_expense.id, + 'product_uom_id': self.product_expense.uom_id.id, + }) + + self.env['project.profitability.report'].flush() + + project_so_2_stat = self.env['project.profitability.report'].read_group( + [('project_id', 'in', project_so_2.ids)], + ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], + ['project_id'] + )[0] + project_so_2_timesheet_cost = timesheet2.amount + timesheet4.amount + timesheet6.amount + project_so_2_timesheet_sold_unit = timesheet2.unit_amount + timesheet4.unit_amount + timesheet6.unit_amount + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_invoiced'], 0.1 * total_product_price, precision_rounding=rounding), 0, + "The invoiced amount of the project from SO2 should only include downpayment not reversed") + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_to_invoice'], milestone_to_invoice - 0.1 * total_product_price, precision_rounding=rounding), 0, + "The amount to invoice of the project from SO2 should include the milestone to invoice minus the downpayment") + self.assertEqual(float_compare(project_so_2_stat['timesheet_unit_amount'], project_so_2_timesheet_sold_unit, precision_rounding=rounding), 0, + "The timesheet unit amount of the project from SO2 should include all timesheet in project") + self.assertEqual(float_compare(project_so_2_stat['timesheet_cost'], project_so_2_timesheet_cost, precision_rounding=rounding), 0, + "The timesheet cost of the project from SO2 should include all timesheet") + self.assertEqual(float_compare(project_so_2_stat['expense_amount_untaxed_to_invoice'], -expense1.amount, precision_rounding=rounding), 0, + "The expense cost to reinvoice of the project from SO2 should be the expense amount") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), + "The expense invoiced amount of the project from SO2 should be 0.0") + self.assertEqual(float_compare(project_so_2_stat['expense_cost'], expense1.amount, precision_rounding=rounding), 0, + "The expense cost of the project from SO1 should be expense amount") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), + "The other revenues of the project from SO2 should be 0.0") + + # invoice the Sales Order SO2 + context = { + "active_model": 'sale.order', + "active_ids": self.sale_order_2.ids, + "active_id": self.sale_order_2.id, + 'open_invoices': True, + 'mail_notrack': True, + } + payment = self.env['sale.advance.payment.inv'].with_context(mail_notrack=True).create({ + 'advance_payment_method': 'delivered', + }) + action_invoice = payment.with_context(context).create_invoices() + invoice_payment = self.env['account.move'].search(expression.AND([action_invoice['domain'], [('id', 'not in', posted_invoice_res_ids)]])) + invoice_payment.action_post() + self.env['project.profitability.report'].flush() + + project_so_2_stat = self.env['project.profitability.report'].read_group( + [('project_id', 'in', project_so_2.ids)], + ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], + ['project_id'] + )[0] + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_invoiced'], milestone_to_invoice, precision_rounding=rounding), 0, + "The invoiced amount of the project from SO2 should only include timesheet linked to task") + self.assertTrue(float_is_zero(project_so_2_stat['amount_untaxed_to_invoice'], precision_rounding=rounding), + "The amount to invoice of the project from SO2 should be 0.0") + self.assertEqual(float_compare(project_so_2_stat['timesheet_unit_amount'], project_so_2_timesheet_sold_unit, precision_rounding=rounding), 0, + "The timesheet unit amount of the project from SO2 should include all timesheet in project") + self.assertEqual(float_compare(project_so_2_stat['timesheet_cost'], project_so_2_timesheet_cost, precision_rounding=rounding), 0, + "The timesheet cost of the project from SO2 should include all timesheet") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), + "The expense to invoice amount of the project from SO2 should be 0.0") + self.assertEqual(float_compare(project_so_2_stat['expense_amount_untaxed_invoiced'], -1 * expense1.amount, precision_rounding=rounding), 0, + "The expense cost reinvoiced of the project from SO2 should be the expense amount") + self.assertEqual(float_compare(project_so_2_stat['expense_cost'], expense1.amount, precision_rounding=rounding), 0, + "The expense cost of the project from SO2 should be the expense amount") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), + "The other revenues of the project from SO2 should be 0.0") + + credit_note_wizard = self.env['account.move.reversal'].with_context({ + 'active_ids': invoice_payment.ids, + 'active_id': invoice_payment.id, + 'active_model': 'account.move' + }).create({ + 'refund_method': 'refund', + 'reason': 'reason test create', + }) + action_moves = credit_note_wizard.reverse_moves() + credit_id = action_moves['res_id'] + invoice_credit = self.env['account.move'].browse(credit_id) + invoice_credit.action_post() + self.env['project.profitability.report'].flush() + + project_so_2_stat = self.env['project.profitability.report'].read_group( + [('project_id', 'in', project_so_2.ids)], + ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], + ['project_id'] + )[0] + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_invoiced'], 0.1 * total_product_price, precision_rounding=rounding), 0, + "The invoiced amount of the project from SO2 should only include downpayment not reversed") + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_to_invoice'], milestone_to_invoice - 0.1 * total_product_price, precision_rounding=rounding), 0, + "The amount to invoice of the project from SO2 should include the milestone to invoice minus the downpayment") + self.assertEqual(float_compare(project_so_2_stat['timesheet_unit_amount'], project_so_2_timesheet_sold_unit, precision_rounding=rounding), 0, + "The timesheet unit amount of the project from SO2 should include all timesheet in project") + self.assertEqual(float_compare(project_so_2_stat['timesheet_cost'], project_so_2_timesheet_cost, precision_rounding=rounding), 0, + "The timesheet cost of the project from SO2 should include all timesheet") + self.assertEqual(float_compare(project_so_2_stat['expense_amount_untaxed_to_invoice'], -expense1.amount, precision_rounding=rounding), 0, + "The expense cost to reinvoice of the project from SO2 should be the expense amount") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), + "The expense invoiced amount of the project from SO2 should be 0.0") + self.assertEqual(float_compare(project_so_2_stat['expense_cost'], expense1.amount, precision_rounding=rounding), 0, + "The expense cost of the project from SO1 should be expense amount") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), + "The other revenues of the project from SO2 should be 0.0") + + def test_milestone_no_tracking(self): + # this test suppose everything is in the same currency as the current one + currency = self.env.company.currency_id + rounding = currency.rounding + so_line_deliver_no_task = self.env['sale.order.line'].create({ + 'name': self.product_delivery_manual1.name, + 'product_id': self.product_delivery_manual1.id, + 'product_uom_qty': 50, + 'product_uom': self.product_delivery_manual1.uom_id.id, + 'price_unit': self.product_delivery_manual1.list_price, + 'order_id': self.sale_order_2.id, + }) + so_line_deliver_no_task.write({'qty_delivered': 1.0}) + self.sale_order_2.action_confirm() + milestone_to_invoice = self.so_line_order_project.price_unit * self.so_line_order_project.qty_to_invoice + milestone_no_task = so_line_deliver_no_task.price_unit * so_line_deliver_no_task.qty_to_invoice + self.env['project.profitability.report'].flush() + + project_so_2 = self.so_line_order_project.project_id + project_so_2_stat = self.env['project.profitability.report'].read_group( + [('project_id', 'in', project_so_2.ids)], + ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], + ['project_id'] + )[0] + self.assertTrue(float_is_zero(project_so_2_stat['amount_untaxed_invoiced'], precision_rounding=rounding), + "The invoiced amount of the project from SO2 should be 0.0") + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_to_invoice'], milestone_to_invoice + milestone_no_task, precision_rounding=rounding), 0, + "The amount to invoice of the project from SO2 should include the milestone to invoice") + self.assertTrue(float_is_zero(project_so_2_stat['timesheet_unit_amount'], precision_rounding=rounding), + "The timesheet unit amount of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['timesheet_cost'], precision_rounding=rounding), + "The timesheet cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), + "The expense cost to reinvoice of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), + "The expense invoiced amount of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), + "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), + "The other revenues of the project from SO2 should be 0.0") + + task_using_milestone_not_tracked = self.env['project.task'].create({ + 'name': 'Task with milestone not tracked', + 'project_id': project_so_2.id, + 'partner_id': project_so_2.partner_id.id, + 'sale_line_id': so_line_deliver_no_task.id, + }) + self.env['project.profitability.report'].flush() + project_so_2_stat = self.env['project.profitability.report'].read_group( + [('project_id', 'in', project_so_2.ids)], + ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], + ['project_id'] + )[0] + self.assertTrue(float_is_zero(project_so_2_stat['amount_untaxed_invoiced'], precision_rounding=rounding), + "The invoiced amount of the project from SO2 should be 0.0") + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_to_invoice'], milestone_to_invoice + milestone_no_task, precision_rounding=rounding), 0, + "The amount to invoice of the project from SO2 should include the milestone to invoice linked to the project or project's task") + self.assertTrue(float_is_zero(project_so_2_stat['timesheet_unit_amount'], precision_rounding=rounding), + "The timesheet unit amount of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['timesheet_cost'], precision_rounding=rounding), + "The timesheet cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), + "The expense cost to reinvoice of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), + "The expense invoiced amount of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), + "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), + "The other revenues of the project from SO2 should be 0.0") + + timesheet = self._log_timesheet_user(project_so_2, 3, task_using_milestone_not_tracked) + self.env['project.profitability.report'].flush() + project_so_2_stat = self.env['project.profitability.report'].read_group( + [('project_id', 'in', project_so_2.ids)], + ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], + ['project_id'] + )[0] + project_so_2_timesheet_cost = timesheet.amount + project_so_2_timesheet_sold_unit = timesheet.unit_amount + self.assertTrue(float_is_zero(project_so_2_stat['amount_untaxed_invoiced'], precision_rounding=rounding), + "The invoiced amount of the project from SO2 should only include downpayment not reversed") + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_to_invoice'], milestone_to_invoice + milestone_no_task, precision_rounding=rounding), 0, + "The amount to invoice of the project from SO2 should include the milestone to invoice minus the downpayment") + self.assertEqual(float_compare(project_so_2_stat['timesheet_unit_amount'], project_so_2_timesheet_sold_unit, precision_rounding=rounding), 0, + "The timesheet unit amount of the project from SO2 should include all timesheet in project") + self.assertEqual(float_compare(project_so_2_stat['timesheet_cost'], project_so_2_timesheet_cost, precision_rounding=rounding), 0, + "The timesheet cost of the project from SO2 should include all timesheet") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), + "The expense cost to reinvoice of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), + "The expense invoiced amount of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), + "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), + "The other revenues of the project from SO2 should be 0.0") + # invoice the Sales Order SO2 + context = { + "active_model": 'sale.order', + "active_ids": self.sale_order_2.ids, + "active_id": self.sale_order_2.id, + 'open_invoices': True, + 'mail_notrack': True, + } + payment = self.env['sale.advance.payment.inv'].with_context(mail_notrack=True).create({ + 'advance_payment_method': 'delivered', + }) + action_invoice = payment.with_context(context).create_invoices() + invoice_payment = self.env['account.move'].browse(action_invoice['res_id']) + invoice_payment.action_post() + self.env['project.profitability.report'].flush() + project_so_2_stat = self.env['project.profitability.report'].read_group( + [('project_id', 'in', project_so_2.ids)], + ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_unit_amount', 'timesheet_cost', 'expense_cost', 'expense_amount_untaxed_to_invoice', 'expense_amount_untaxed_invoiced', 'other_revenues'], + ['project_id'] + )[0] + self.assertEqual(float_compare(project_so_2_stat['amount_untaxed_invoiced'], milestone_to_invoice + milestone_no_task, precision_rounding=rounding), 0, + "The invoiced amount of the project from SO2 should include the milestone invoiced") + self.assertTrue(float_is_zero(project_so_2_stat['amount_untaxed_to_invoice'], precision_rounding=rounding), + "The amount to invoice of the project from SO2 should include the milestone to invoice") + self.assertEqual(float_compare(project_so_2_stat['timesheet_unit_amount'], project_so_2_timesheet_sold_unit, precision_rounding=rounding), 0, + "The timesheet unit amount of the project from SO2 should include all timesheet in project") + self.assertEqual(float_compare(project_so_2_stat['timesheet_cost'], project_so_2_timesheet_cost, precision_rounding=rounding), 0, + "The timesheet cost of the project from SO2 should include all timesheet") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_to_invoice'], precision_rounding=rounding), + "The expense cost to reinvoice of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_amount_untaxed_invoiced'], precision_rounding=rounding), + "The expense invoiced amount of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['expense_cost'], precision_rounding=rounding), + "The expense cost of the project from SO2 should be 0.0") + self.assertTrue(float_is_zero(project_so_2_stat['other_revenues'], precision_rounding=rounding), + "The other revenues of the project from SO2 should be 0.0") diff --git a/addons/sale_timesheet/views/hr_timesheet_templates.xml b/addons/sale_timesheet/views/hr_timesheet_templates.xml index acd2fc875b..4cea40e0ff 100644 --- a/addons/sale_timesheet/views/hr_timesheet_templates.xml +++ b/addons/sale_timesheet/views/hr_timesheet_templates.xml @@ -241,6 +241,14 @@ Re-invoiced costs + + + + + + To re-invoice costs + + diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 259823edbe..184ec84c30 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -1270,17 +1270,16 @@ class StockMove(models.Model): # Find a candidate move line to update or create a new one. for reserved_quant, quantity in quants: - to_update = self.move_line_ids.filtered(lambda ml: ml._reservation_is_updatable(quantity, reserved_quant)) + to_update = next((line for line in self.move_line_ids if line._reservation_is_updatable(quantity, reserved_quant)), False) if to_update: - uom_quantity = self.product_id.uom_id._compute_quantity(quantity, to_update[0].product_uom_id, rounding_method='HALF-UP') + uom_quantity = self.product_id.uom_id._compute_quantity(quantity, to_update.product_uom_id, rounding_method='HALF-UP') uom_quantity = float_round(uom_quantity, precision_digits=rounding) - uom_quantity_back_to_product_uom = to_update[0].product_uom_id._compute_quantity(uom_quantity, self.product_id.uom_id, rounding_method='HALF-UP') + uom_quantity_back_to_product_uom = to_update.product_uom_id._compute_quantity(uom_quantity, self.product_id.uom_id, rounding_method='HALF-UP') if to_update and float_compare(quantity, uom_quantity_back_to_product_uom, precision_digits=rounding) == 0: - to_update[0].with_context(bypass_reservation_update=True).product_uom_qty += uom_quantity + to_update.with_context(bypass_reservation_update=True).product_uom_qty += uom_quantity else: if self.product_id.tracking == 'serial': - for i in range(0, int(quantity)): - self.env['stock.move.line'].create(self._prepare_move_line_vals(quantity=1, reserved_quant=reserved_quant)) + self.env['stock.move.line'].create([self._prepare_move_line_vals(quantity=1, reserved_quant=reserved_quant) for i in range(int(quantity))]) else: self.env['stock.move.line'].create(self._prepare_move_line_vals(quantity=quantity, reserved_quant=reserved_quant)) return taken_quantity @@ -1652,7 +1651,7 @@ class StockMove(models.Model): else: moves_state_to_write['confirmed'].add(move.id) for state, moves_ids in moves_state_to_write.items(): - self.browse(moves_ids).write({'state': state}) + self.browse(moves_ids).filtered(lambda m: m.state != state).state = state @api.model def _consuming_picking_types(self): @@ -1818,5 +1817,6 @@ class StockMove(models.Model): for move in self: domains.append([('product_id', '=', move.product_id.id), ('location_id', '=', move.location_dest_id.id)]) static_domain = [('state', 'in', ['confirmed', 'partially_available']), ('procure_method', '=', 'make_to_stock')] - moves_to_reserve = self.env['stock.move'].search(expression.AND([static_domain, expression.OR(domains)])) + moves_to_reserve = self.env['stock.move'].search(expression.AND([static_domain, expression.OR(domains)]), + order='priority desc, date asc, id asc') moves_to_reserve._action_assign() diff --git a/addons/stock/models/stock_production_lot.py b/addons/stock/models/stock_production_lot.py index b556a79037..2adb0a0c80 100644 --- a/addons/stock/models/stock_production_lot.py +++ b/addons/stock/models/stock_production_lot.py @@ -77,7 +77,7 @@ class ProductionLot(models.Model): @api.model_create_multi def create(self, vals_list): self._check_create() - return super(ProductionLot, self).create(vals_list) + return super(ProductionLot, self.with_context(mail_create_nosubscribe=True)).create(vals_list) def write(self, vals): if 'company_id' in vals: diff --git a/addons/stock/models/stock_rule.py b/addons/stock/models/stock_rule.py index 305832a14c..4790be576c 100644 --- a/addons/stock/models/stock_rule.py +++ b/addons/stock/models/stock_rule.py @@ -521,7 +521,7 @@ class ProcurementGroup(models.Model): # Search all confirmed stock_moves and try to assign them domain = self._get_moves_to_assign_domain(company_id) moves_to_assign = self.env['stock.move'].search(domain, limit=None, - order='priority desc, date asc') + order='priority desc, date asc, id asc') for moves_chunk in split_every(100, moves_to_assign.ids): self.env['stock.move'].browse(moves_chunk).sudo()._action_assign() if use_new_cursor: diff --git a/addons/stock/tests/test_stock_flow.py b/addons/stock/tests/test_stock_flow.py index 2d2f4026de..da38d5b179 100644 --- a/addons/stock/tests/test_stock_flow.py +++ b/addons/stock/tests/test_stock_flow.py @@ -2092,3 +2092,50 @@ class TestStockFlow(TestStockCommon): # Validates the two receipts => It should raise an error as there is duplicate SN. with self.assertRaises(ValidationError): (receipt_1 | receipt_2).button_validate() + + def test_assign_qty_to_first_move(self): + """ Suppose two out picking waiting for an available quantity. When receiving such + a quantity, the latter should be assign to the picking with the highest priority + and the earliest scheduled date. """ + def create_picking(type, from_loc, to_loc, sequence=10, delay=0): + picking = self.PickingObj.create({ + 'picking_type_id': type, + 'location_id': from_loc, + 'location_dest_id': to_loc, + }) + self.MoveObj.create({ + 'name': self.productA.name, + 'sequence': sequence, + 'date': fields.Datetime.add(fields.Datetime.now(), second=delay), + 'product_id': self.productA.id, + 'product_uom_qty': 1, + 'product_uom': self.productA.uom_id.id, + 'picking_id': picking.id, + 'location_id': from_loc, + 'location_dest_id': to_loc, + }) + picking.action_confirm() + return picking + + def validate_picking(picking): + res_dict = picking.button_validate() + wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save() + wizard.process() + + out01 = create_picking(self.picking_type_out, self.stock_location, self.customer_location) + out02 = create_picking(self.picking_type_out, self.stock_location, self.customer_location, sequence=2, delay=1) + in01 = create_picking(self.picking_type_in, self.supplier_location, self.stock_location, delay=2) + + validate_picking(in01) + self.assertEqual(out01.state, 'assigned') + self.assertEqual(out02.state, 'confirmed') + + validate_picking(out01) + + out03 = create_picking(self.picking_type_out, self.stock_location, self.customer_location, delay=3) + out03.priority = "1" + in02 = create_picking(self.picking_type_in, self.supplier_location, self.stock_location, delay=4) + + validate_picking(in02) + self.assertEqual(out02.state, 'confirmed') + self.assertEqual(out03.state, 'assigned') diff --git a/addons/stock/views/stock_picking_views.xml b/addons/stock/views/stock_picking_views.xml index 5a659b8503..82abb9a6a7 100644 --- a/addons/stock/views/stock_picking_views.xml +++ b/addons/stock/views/stock_picking_views.xml @@ -460,7 +460,7 @@ - + diff --git a/addons/web_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js index 91f26c03df..b14869c15f 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -1660,8 +1660,11 @@ var SnippetsMenu = Widget.extend({ * when the DOM elements must be in an editable environment to be * considered (@see noCheck), this is true if the DOM elements' * parent must also be in an editable environment to be considered. + * @param {string} excludeParent + * jQuery selector that the parents of DOM elements must *not* match + * to be considered as potential snippet. */ - _computeSelectorFunctions: function (selector, exclude, target, noCheck, isChildren) { + _computeSelectorFunctions: function (selector, exclude, target, noCheck, isChildren, excludeParent) { var self = this; exclude += `${exclude && ', '}.o_snippet_not_selectable`; @@ -1675,6 +1678,12 @@ var SnippetsMenu = Widget.extend({ return oldFilter.apply(this) && $(this).find(target).length !== 0; }; } + if (excludeParent) { + const oldFilter = filterFunc; + filterFunc = function () { + return oldFilter.apply(this) && !$(this).parent().is(excludeParent); + }; + } // Prepare the functions var functions = { @@ -1735,10 +1744,12 @@ var SnippetsMenu = Widget.extend({ this.templateOptions = []; var selectors = []; var $styles = $html.find('[data-selector]'); + const snippetAdditionDropIn = $styles.filter('#so_snippet_addition').data('drop-in'); $styles.each(function () { var $style = $(this); var selector = $style.data('selector'); var exclude = $style.data('exclude') || ''; + const excludeParent = $style.attr('id') === "so_content_addition" ? snippetAdditionDropIn : ''; var target = $style.data('target'); var noCheck = $style.data('no-check'); var optionID = $style.data('js') || $style.data('option-name'); // used in tour js as selector @@ -1749,7 +1760,7 @@ var SnippetsMenu = Widget.extend({ 'base_target': target, 'selector': self._computeSelectorFunctions(selector, exclude, target, noCheck), '$el': $style, - 'drop-near': $style.data('drop-near') && self._computeSelectorFunctions($style.data('drop-near'), '', false, noCheck, true), + 'drop-near': $style.data('drop-near') && self._computeSelectorFunctions($style.data('drop-near'), '', false, noCheck, true, excludeParent), 'drop-in': $style.data('drop-in') && self._computeSelectorFunctions($style.data('drop-in'), '', false, noCheck), 'data': _.extend({string: $style.attr('string')}, $style.data()), }; diff --git a/addons/website_slides/models/slide_slide.py b/addons/website_slides/models/slide_slide.py index e47de303a1..354587d934 100644 --- a/addons/website_slides/models/slide_slide.py +++ b/addons/website_slides/models/slide_slide.py @@ -173,7 +173,7 @@ class Slide(models.Model): slide_resource_ids = fields.One2many('slide.slide.resource', 'slide_id', string="Additional Resource for this slide") slide_resource_downloadable = fields.Boolean('Allow Download', default=True, help="Allow the user to download the content of the slide.") mime_type = fields.Char('Mime-type') - html_content = fields.Html("HTML Content", help="Custom HTML content for slides of type 'Web Page'.", translate=True, sanitize_form=False) + html_content = fields.Html("HTML Content", help="Custom HTML content for slides of type 'Web Page'.", translate=True, sanitize_attributes=False, sanitize_form=False) # website website_id = fields.Many2one(related='channel_id.website_id', readonly=True) date_published = fields.Datetime('Publish Date', readonly=True, tracking=1)