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)
|