[ADD] report_carbone, jsonifier, export_json : carbone is an alternative to Py3o
This commit is contained in:
821
export_json/tests/test_export_json.py
Normal file
821
export_json/tests/test_export_json.py
Normal file
@@ -0,0 +1,821 @@
|
||||
import json
|
||||
import re
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from odoo.tests import common, tagged
|
||||
|
||||
from odoo.addons.export_json.controller import main as controller_module
|
||||
from odoo.addons.export_json.controller.main import JsonExportFormat
|
||||
|
||||
|
||||
@tagged("export_json")
|
||||
class TestExportJson(common.HttpCase):
|
||||
def setUp(self):
|
||||
self.partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "TEST",
|
||||
"email": "test@test.fr",
|
||||
"type": "contact",
|
||||
"child_ids": [
|
||||
(
|
||||
0,
|
||||
None,
|
||||
{
|
||||
"name": "test child 1",
|
||||
"email": "test_child_1@test.fr",
|
||||
"type": "delivery",
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
None,
|
||||
{
|
||||
"name": "test child 2",
|
||||
"email": "test_child_2@test.fr",
|
||||
"type": "invoice",
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
self.data_dict = {
|
||||
"model": "res.partner",
|
||||
"fields": [
|
||||
{"name": "id", "label": "External ID"},
|
||||
{"name": "name", "label": "Name"},
|
||||
{"name": "email", "label": "Email"},
|
||||
{"name": "type", "label": "Type"},
|
||||
{"name": "child_ids/name", "label": "Name"},
|
||||
{"name": "child_ids/email", "label": "Email"},
|
||||
{"name": "child_ids/type", "label": "Type"},
|
||||
],
|
||||
"ids": [self.partner.id],
|
||||
"domain": [["type", "in", ("contact", "delivery")]],
|
||||
"groupby": [],
|
||||
"context": {
|
||||
"lang": "en_US",
|
||||
"tz": "Europe/Paris",
|
||||
"uid": 2,
|
||||
"allowed_company_ids": [1],
|
||||
},
|
||||
"import_compat": True,
|
||||
}
|
||||
self.basic_expect_dict = {
|
||||
"id": self.partner.id,
|
||||
"name": "TEST",
|
||||
"email": "test@test.fr",
|
||||
"type": "contact",
|
||||
"child_ids": [
|
||||
{
|
||||
"name": "test child 1",
|
||||
"email": "test_child_1@test.fr",
|
||||
"type": "delivery",
|
||||
},
|
||||
{
|
||||
"name": "test child 2",
|
||||
"email": "test_child_2@test.fr",
|
||||
"type": "invoice",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
self.expected_list_dict_merge = [
|
||||
{
|
||||
"amount_total": 300.0,
|
||||
"amount_untaxed": 250.0,
|
||||
"company_id": "My Company",
|
||||
"currency_id": "EUR",
|
||||
"invoice_status": "invoice_status",
|
||||
"invoice_status_FR": "Rien à facturer",
|
||||
"invoice_status_US": "Nothing to Bill",
|
||||
"order_line": [
|
||||
{
|
||||
"company_id": "My Company",
|
||||
"currency_id": "EUR",
|
||||
"display_type": "Section",
|
||||
"name": "Exmple de section",
|
||||
"state": "order_line/state",
|
||||
"state_FR": "Bon de commande fournisseur",
|
||||
"state_US": "Purchase Order",
|
||||
"tax_calculation_rounding_method": "order_line/tax_calculation_rounding_method",
|
||||
"tax_calculation_rounding_method_FR": "Arrondir à la ligne",
|
||||
"tax_calculation_rounding_method_US": "Round per Line",
|
||||
"taxes_id": [],
|
||||
},
|
||||
{
|
||||
"company_id": "My Company",
|
||||
"currency_id": "EUR",
|
||||
"name": "Produit test 2",
|
||||
"price_subtotal": 75.0,
|
||||
"price_unit": 75.0,
|
||||
"product_id": "order_line/product_id",
|
||||
"product_id_FR": "Produit test 2",
|
||||
"product_id_US": "ENGLISH Produit test 2",
|
||||
"product_type": "order_line/product_type",
|
||||
"product_type_FR": "Biens",
|
||||
"product_type_US": "Goods",
|
||||
"product_uom": "order_line/product_uom",
|
||||
"product_uom_FR": "Unité(s)",
|
||||
"product_uom_US": "Units",
|
||||
"product_uom_category_id": "order_line/product_uom_category_id",
|
||||
"product_uom_category_id_FR": "Unité",
|
||||
"product_uom_category_id_US": "Unit",
|
||||
"state": "order_line/state",
|
||||
"state_FR": "Bon de commande fournisseur",
|
||||
"state_US": "Purchase Order",
|
||||
"tax_calculation_rounding_method": "order_line/tax_calculation_rounding_method",
|
||||
"tax_calculation_rounding_method_FR": "Arrondir à la ligne",
|
||||
"tax_calculation_rounding_method_US": "Round per Line",
|
||||
"taxes_id": ["20%"],
|
||||
},
|
||||
],
|
||||
"payment_term_id": "payment_term_id",
|
||||
"payment_term_id_FR": "21 jours ",
|
||||
"payment_term_id_US": "21 Days",
|
||||
"tax_country_id": "tax_country_id",
|
||||
"tax_country_id_FR": "États-Unis",
|
||||
"tax_country_id_US": "United States",
|
||||
}
|
||||
]
|
||||
|
||||
self.data_str = str(self.data_dict)
|
||||
self.data = json.dumps(self.data_dict)
|
||||
|
||||
self.json_export_format = JsonExportFormat()
|
||||
self.mock_request = MagicMock()
|
||||
self.mock_request.env = self.env
|
||||
super().setUp()
|
||||
|
||||
def helper_get_csrf_token(self):
|
||||
resp = self.url_open("/web/login")
|
||||
html = resp.content.decode()
|
||||
match = re.search(r'csrf_token:\s*"([^"]+)"', html)
|
||||
return match and match.group(1) or False
|
||||
|
||||
def test_generate_export_json(self):
|
||||
# Perform the json export
|
||||
fields = [field["name"] for field in self.data_dict["fields"]]
|
||||
model = self.env[self.data_dict["model"]]
|
||||
|
||||
with patch.object(controller_module, "request", self.mock_request):
|
||||
result_json = self.json_export_format.perform_json_export(
|
||||
self.data_dict["domain"], fields, self.data_dict["ids"], model
|
||||
)
|
||||
|
||||
dict_result_json = json.loads(result_json)
|
||||
self.assertDictEqual(
|
||||
self.basic_expect_dict,
|
||||
dict_result_json[0],
|
||||
"Check if json export is equal to expected data",
|
||||
)
|
||||
|
||||
def test_perform_json_export_with_lang(self):
|
||||
self.env["res.lang"]._activate_lang("fr_FR")
|
||||
|
||||
self.data_dict["fields"].append({"name": "title/name", "label": "Title"})
|
||||
self.data_dict["fields"].append({"name": "country_id/name", "label": "Country"})
|
||||
fields = [field["name"] for field in self.data_dict["fields"]]
|
||||
model = self.env[self.data_dict["model"]]
|
||||
|
||||
# Ajouts de traductions
|
||||
title = (
|
||||
self.env["res.partner.title"]
|
||||
.with_context(lang="en_US")
|
||||
.create(
|
||||
{
|
||||
"name": "Doctor",
|
||||
}
|
||||
)
|
||||
)
|
||||
title.with_context(lang="fr_FR").name = "Docteur"
|
||||
self.partner.title = title
|
||||
|
||||
self.env.ref("base.es").with_context(lang="fr_FR").name = "Espagne"
|
||||
self.partner.country_id = self.env.ref("base.es")
|
||||
|
||||
with patch.object(controller_module, "request", self.mock_request):
|
||||
result_json = self.json_export_format.perform_json_export(
|
||||
self.data_dict["domain"],
|
||||
fields,
|
||||
self.data_dict["ids"],
|
||||
model,
|
||||
langs_code=["fr_FR", "en_US"],
|
||||
)
|
||||
|
||||
dict_result_json = json.loads(result_json)
|
||||
expected_dict = {
|
||||
"id": self.partner.id,
|
||||
"name": "TEST",
|
||||
"email": "test@test.fr",
|
||||
"type": "contact",
|
||||
"title": {
|
||||
"name": "title/name",
|
||||
"name_FR": "Docteur",
|
||||
"name_US": "Doctor",
|
||||
},
|
||||
"country_id": {
|
||||
"name": "country_id/name",
|
||||
"name_FR": "Espagne",
|
||||
"name_US": "Spain",
|
||||
},
|
||||
"child_ids": [
|
||||
{
|
||||
"name": "test child 1",
|
||||
"email": "test_child_1@test.fr",
|
||||
"type": "delivery",
|
||||
},
|
||||
{
|
||||
"name": "test child 2",
|
||||
"email": "test_child_2@test.fr",
|
||||
"type": "invoice",
|
||||
},
|
||||
],
|
||||
}
|
||||
self.assertDictEqual(expected_dict, dict_result_json[0], "Le json doit contenir les traductions")
|
||||
|
||||
def test_convert_simple_list(self):
|
||||
"""La fonction _convert_simple_list prend en entrée une liste de clée, correspondant
|
||||
à des noms de champs, et retourne une liste de dict{"name": nom_de_champ}"""
|
||||
res_partner_fields_names = list(self.partner._fields.keys())
|
||||
|
||||
res = self.json_export_format._convert_simple_list(res_partner_fields_names)
|
||||
|
||||
self.assertEqual(
|
||||
len(res_partner_fields_names),
|
||||
len(res),
|
||||
"Tous les noms de champs du modèle res.partner doivent être retourné sous la forme {'name': nom_de_champ}",
|
||||
)
|
||||
|
||||
# Si on ajoute un dict dans les noms de champ du res_partner, le dict doit être retourné tel quel, lors
|
||||
# du passage de la fonction _convert_simple_list
|
||||
|
||||
mock_dict = {
|
||||
"random_key": "random_value",
|
||||
"random_key1": "random_value1",
|
||||
"random_key2": "random_value2",
|
||||
}
|
||||
res_partner_fields_names.append(mock_dict)
|
||||
|
||||
res = self.json_export_format._convert_simple_list(res_partner_fields_names)
|
||||
|
||||
self.assertEqual(len(res_partner_fields_names), len(res))
|
||||
self.assertIn(
|
||||
mock_dict,
|
||||
res,
|
||||
"Le dict ajouté dans les champs de res.partner est bien retourner telquel dans la list",
|
||||
)
|
||||
|
||||
def test_get_country_code(self):
|
||||
"""La fonction prend un paramètre un string de lang, elle doit retourner la deuxième partie du code
|
||||
(séparé par le premier '_' du string)"""
|
||||
|
||||
for test_val, expected in [
|
||||
("fr_FR", "FR"),
|
||||
("_fr_FR", "fr"),
|
||||
("FR_", ""),
|
||||
("", ""),
|
||||
]:
|
||||
self.assertEqual(self.json_export_format.get_country_code(test_val), expected)
|
||||
|
||||
def test_add_unique_vals(self):
|
||||
"""La fonction prend en paramètre un dict, et retourne un set de valeur unique.
|
||||
La fonction stringify les list et les dicts, si dans le dict d'entrée, des valeurs sont
|
||||
des dicts ou des lists."""
|
||||
|
||||
mock_dict_same_value = {
|
||||
"random_key": "random_value",
|
||||
"random_key1": "random_value",
|
||||
"random_key2": "random_value",
|
||||
}
|
||||
res = self.json_export_format.add_unique_vals(mock_dict_same_value)
|
||||
|
||||
self.assertEqual(
|
||||
len(res),
|
||||
1,
|
||||
"Le dict d'entrée contenait 3 clés valeurs, mais les valeurs liées aux clés étaient identiques.",
|
||||
)
|
||||
self.assertIn("random_value", res)
|
||||
|
||||
mock_dict_different_value = {
|
||||
"random_key": "random_value",
|
||||
"random_key1": "random_value1",
|
||||
"random_key2": "random_value",
|
||||
}
|
||||
res = self.json_export_format.add_unique_vals(mock_dict_different_value)
|
||||
self.assertEqual(len(res), 2)
|
||||
for expected in ["random_value", "random_value1"]:
|
||||
self.assertIn(expected, res)
|
||||
|
||||
mock_dict_with_dict_list = {
|
||||
"random_key": {"an_other": "one"},
|
||||
"random_key1": [10, 20, 40],
|
||||
"random_key2": [10, 20, 40],
|
||||
}
|
||||
res = self.json_export_format.add_unique_vals(mock_dict_with_dict_list)
|
||||
|
||||
self.assertEqual(len(res), 2)
|
||||
for expected in ["{'an_other': 'one'}", "[10, 20, 40]"]:
|
||||
self.assertIn(expected, res)
|
||||
|
||||
self.assertEqual(0, len(self.json_export_format.add_unique_vals({})))
|
||||
|
||||
def test_retrieve_all_keys(self):
|
||||
test_dict = {
|
||||
"fr_FR": {
|
||||
"champ_1": "valeur",
|
||||
"champ_2": "valeur",
|
||||
"champ_3": "valeur",
|
||||
"champ_4": "valeur",
|
||||
},
|
||||
"zn_CN": {
|
||||
"champ_5": "valeur",
|
||||
"champ_6": "valeur",
|
||||
"champ_3": "valeur",
|
||||
"champ_4": "valeur",
|
||||
},
|
||||
}
|
||||
|
||||
res = self.json_export_format.retrieve_all_keys(test_dict)
|
||||
for expected in [
|
||||
"champ_1",
|
||||
"champ_2",
|
||||
"champ_3",
|
||||
"champ_4",
|
||||
"champ_5",
|
||||
"champ_6",
|
||||
]:
|
||||
self.assertIn(expected, res)
|
||||
|
||||
other_dict = {
|
||||
"champ_1": "valeur",
|
||||
"champ_2": "valeur",
|
||||
"champ_3": "valeur",
|
||||
}
|
||||
with self.assertRaises(AssertionError):
|
||||
self.json_export_format.retrieve_all_keys(other_dict)
|
||||
|
||||
def test_process_keys_without_parent_key(self):
|
||||
test_dict = {
|
||||
"fr_FR": {
|
||||
"champ_1": "valeur",
|
||||
"champ_2": "valeur",
|
||||
"champ_3": "valeur",
|
||||
"champ_4": "valeur",
|
||||
},
|
||||
"zn_CN": {
|
||||
"champ_5": "valeur",
|
||||
"champ_6": "valeur",
|
||||
"champ_3": "valeur",
|
||||
"champ_4": "valeur",
|
||||
},
|
||||
}
|
||||
|
||||
merged_dict = {}
|
||||
all_keys = self.json_export_format.retrieve_all_keys(test_dict)
|
||||
|
||||
self.json_export_format.process_keys(all_keys, test_dict, merged_dict)
|
||||
|
||||
for expected in [
|
||||
"champ_1",
|
||||
"champ_2",
|
||||
"champ_3",
|
||||
"champ_4",
|
||||
"champ_5",
|
||||
"champ_6",
|
||||
]:
|
||||
self.assertIn(
|
||||
expected,
|
||||
merged_dict,
|
||||
"Chaque champ doit être inclus dans le dictionnaire final, qui fusionne"
|
||||
"l'ensemble des champs des dictionnaires d'entrées, par langue.",
|
||||
)
|
||||
|
||||
self.json_export_format.process_keys(all_keys, test_dict, merged_dict)
|
||||
|
||||
# Si pour un même nom de champ donné, la valeur est différente entre des langues, les deux clés concaténées
|
||||
# du suffixe du code la langue,
|
||||
# doivent être présent dans le dict final.
|
||||
test_dict_2 = {
|
||||
"fr_FR": {
|
||||
"champ_1": "valeur",
|
||||
"champ_2": "valeur",
|
||||
"champ_3": "VALEUR EN FRANÇAIS",
|
||||
"champ_4": "valeur",
|
||||
},
|
||||
"zn_CN": {
|
||||
"champ_5": "valeur",
|
||||
"champ_6": "valeur",
|
||||
"champ_3": "VALEUR PAS EN FRANÇAIS",
|
||||
"champ_4": "valeur",
|
||||
},
|
||||
}
|
||||
self.json_export_format.process_keys(all_keys, test_dict_2, merged_dict)
|
||||
for expected in [
|
||||
"champ_1",
|
||||
"champ_2",
|
||||
"champ_3",
|
||||
"champ_4",
|
||||
"champ_5",
|
||||
"champ_6",
|
||||
"champ_3_FR",
|
||||
"champ_3_CN",
|
||||
]:
|
||||
self.assertIn(
|
||||
expected,
|
||||
merged_dict,
|
||||
"Chaque champ doit être inclus dans le dictionnaire final, qui fusionne"
|
||||
"l'ensemble des champs des dictionnaires d'entrées, par langue.",
|
||||
)
|
||||
self.assertEqual(merged_dict.get("champ_3_FR"), "VALEUR EN FRANÇAIS")
|
||||
self.assertEqual(merged_dict.get("champ_3_CN"), "VALEUR PAS EN FRANÇAIS")
|
||||
|
||||
def test_process_keys_with_parent_key(self):
|
||||
test_dict = {
|
||||
"fr_FR": {
|
||||
"champ_1": "valeur",
|
||||
"champ_2": "valeur",
|
||||
"champ_3": {
|
||||
"cle_dict_imbrique_1": "valeur1",
|
||||
"cle_dict_imbrique_2": "valeur2",
|
||||
"cle_dict_imbrique_3": [
|
||||
"element_liste_imbriqueFR",
|
||||
"element_autre_listeFR",
|
||||
],
|
||||
},
|
||||
},
|
||||
"zn_CN": {
|
||||
"champ_1": "valeur",
|
||||
"champ_2": "valeur",
|
||||
"champ_3": {
|
||||
"cle_dict_imbrique_1": "valeur1489",
|
||||
"cle_dict_imbrique_2": "valeur24996",
|
||||
"cle_dict_imbrique_3": [
|
||||
"element_liste_imbrique",
|
||||
"element_autre_liste",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
merged_dict = {}
|
||||
all_keys = self.json_export_format.retrieve_all_keys(test_dict)
|
||||
|
||||
self.json_export_format.process_keys(all_keys, test_dict, merged_dict, "champ_3")
|
||||
|
||||
# Le dict attendu doit contenir toutes les valeurs de chaque langues, même si les valeurs sont eux mêmes dans
|
||||
# des dict ou dans des listes. Un regroupement doit être effectué autour du champ_3 :
|
||||
# le dict du champ_3 doit contenir la clé original de chaque dict (cle_dict_imbrique_1, cle_dict_imbrique_2,
|
||||
# cle_dict_imbrique_3)
|
||||
# avec pour valeurs le chemin absolu de la valeur (champ_3/cle_dict_imbrique_1, champ_3/cle_dict_imbrique_2,
|
||||
# champ_3/cle_dict_imbrique_3)
|
||||
|
||||
expected_dict = {
|
||||
"champ_1": "valeur",
|
||||
"champ_2": "valeur",
|
||||
"champ_3": {
|
||||
"cle_dict_imbrique_1": "champ_3/cle_dict_imbrique_1",
|
||||
"cle_dict_imbrique_1_CN": "valeur1489",
|
||||
"cle_dict_imbrique_1_FR": "valeur1",
|
||||
"cle_dict_imbrique_2": "champ_3/cle_dict_imbrique_2",
|
||||
"cle_dict_imbrique_2_CN": "valeur24996",
|
||||
"cle_dict_imbrique_2_FR": "valeur2",
|
||||
"cle_dict_imbrique_3": "champ_3/cle_dict_imbrique_3",
|
||||
"cle_dict_imbrique_3_CN": [
|
||||
"element_liste_imbrique",
|
||||
"element_autre_liste",
|
||||
],
|
||||
"cle_dict_imbrique_3_FR": [
|
||||
"element_liste_imbriqueFR",
|
||||
"element_autre_listeFR",
|
||||
],
|
||||
},
|
||||
}
|
||||
self.assertDictEqual(expected_dict, merged_dict)
|
||||
|
||||
def test_process_keys_nested_dict(self):
|
||||
test_dict = {
|
||||
"fr_FR": {
|
||||
"champ_1": [
|
||||
{
|
||||
"cle_dict_imbrique_1": "valeur1",
|
||||
"cle_dict_imbrique_2": "valeur2",
|
||||
"cle_dict_imbrique_3": [
|
||||
"element_liste_imbriqueFR",
|
||||
"element_autre_listeFR",
|
||||
],
|
||||
},
|
||||
{
|
||||
"cle_dict_imbrique_1": "valeur44",
|
||||
"cle_dict_imbrique_2": "valeur4858",
|
||||
"cle_dict_imbrique_3": [
|
||||
"element_liste_imbriqueFR",
|
||||
"element_autre_liste",
|
||||
],
|
||||
},
|
||||
],
|
||||
"champ_2": "valeur",
|
||||
},
|
||||
"zn_CN": {
|
||||
"champ_1": [
|
||||
{
|
||||
"cle_dict_imbrique_1": "valeur1",
|
||||
"cle_dict_imbrique_2": "valeur2",
|
||||
"cle_dict_imbrique_3": [
|
||||
"element_liste_imbriqueFR",
|
||||
"element_autre_listeFR",
|
||||
],
|
||||
},
|
||||
{
|
||||
"cle_dict_imbrique_1": "valeur44",
|
||||
"cle_dict_imbrique_2": "valeur4858",
|
||||
"cle_dict_imbrique_3": [
|
||||
"element_liste_imbrique",
|
||||
"element_autre_liste",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
merged_dict = {}
|
||||
all_keys = self.json_export_format.retrieve_all_keys(test_dict)
|
||||
self.json_export_format.process_keys(all_keys, test_dict, merged_dict)
|
||||
|
||||
expected_dict = {
|
||||
"champ_1": [
|
||||
{
|
||||
"cle_dict_imbrique_1": "valeur1",
|
||||
"cle_dict_imbrique_2": "valeur2",
|
||||
"cle_dict_imbrique_3": [
|
||||
"element_liste_imbriqueFR",
|
||||
"element_autre_listeFR",
|
||||
],
|
||||
},
|
||||
{
|
||||
"cle_dict_imbrique_1": "valeur44",
|
||||
"cle_dict_imbrique_2": "valeur4858",
|
||||
"cle_dict_imbrique_3": "champ_1/cle_dict_imbrique_3",
|
||||
"cle_dict_imbrique_3_CN": [
|
||||
"element_liste_imbrique",
|
||||
"element_autre_liste",
|
||||
],
|
||||
"cle_dict_imbrique_3_FR": [
|
||||
"element_liste_imbriqueFR",
|
||||
"element_autre_liste",
|
||||
],
|
||||
},
|
||||
],
|
||||
"champ_2": "valeur",
|
||||
}
|
||||
self.assertDictEqual(expected_dict, merged_dict)
|
||||
|
||||
def test_merge_list_of_dicts_without_lang(self):
|
||||
self.assertEqual(
|
||||
[],
|
||||
self.json_export_format._merge_list_of_dicts({}),
|
||||
"Sans langue, cette fonction ne doit rien faire et retourner une liste vide",
|
||||
)
|
||||
self.assertEqual(
|
||||
[],
|
||||
self.json_export_format.merge_multilingual_dicts({}),
|
||||
"Même chose, sans langue, pas de dict",
|
||||
)
|
||||
|
||||
def test_merge_multilingual_dicts(self):
|
||||
test_dict = {
|
||||
"en_US": [
|
||||
{
|
||||
"amount_total": 300.0,
|
||||
"amount_untaxed": 250.0,
|
||||
"company_id": "My Company",
|
||||
"currency_id": "EUR",
|
||||
"invoice_status": "Nothing to Bill",
|
||||
"order_line": [
|
||||
{
|
||||
"company_id": "My Company",
|
||||
"currency_id": "EUR",
|
||||
"display_type": "Section",
|
||||
"name": "Exmple de section",
|
||||
"state": "Purchase Order",
|
||||
"tax_calculation_rounding_method": "Round per Line",
|
||||
"taxes_id": [],
|
||||
},
|
||||
{
|
||||
"company_id": "My Company",
|
||||
"currency_id": "EUR",
|
||||
"name": "Produit test 2",
|
||||
"price_subtotal": 75.0,
|
||||
"price_unit": 75.0,
|
||||
"product_type": "Goods",
|
||||
"product_id": "ENGLISH Produit test 2",
|
||||
"product_uom": "Units",
|
||||
"product_uom_category_id": "Unit",
|
||||
"state": "Purchase Order",
|
||||
"tax_calculation_rounding_method": "Round per Line",
|
||||
"taxes_id": ["20%"],
|
||||
},
|
||||
],
|
||||
"payment_term_id": "21 Days",
|
||||
"tax_country_id": "United States",
|
||||
}
|
||||
],
|
||||
"fr_FR": [
|
||||
{
|
||||
"amount_total": 300.0,
|
||||
"amount_untaxed": 250.0,
|
||||
"company_id": "My Company",
|
||||
"currency_id": "EUR",
|
||||
"invoice_status": "Rien à facturer",
|
||||
"order_line": [
|
||||
{
|
||||
"company_id": "My Company",
|
||||
"currency_id": "EUR",
|
||||
"display_type": "Section",
|
||||
"name": "Exmple de section",
|
||||
"state": "Bon de commande fournisseur",
|
||||
"tax_calculation_rounding_method": "Arrondir à la ligne",
|
||||
"taxes_id": [],
|
||||
},
|
||||
{
|
||||
"company_id": "My Company",
|
||||
"currency_id": "EUR",
|
||||
"name": "Produit test 2",
|
||||
"price_subtotal": 75.0,
|
||||
"price_unit": 75.0,
|
||||
"product_id": "Produit test 2",
|
||||
"product_type": "Biens",
|
||||
"product_uom": "Unité(s)",
|
||||
"product_uom_category_id": "Unité",
|
||||
"state": "Bon de commande fournisseur",
|
||||
"tax_calculation_rounding_method": "Arrondir à la ligne",
|
||||
"taxes_id": ["20%"],
|
||||
},
|
||||
],
|
||||
"payment_term_id": "21 jours ",
|
||||
"tax_country_id": "États-Unis",
|
||||
}
|
||||
],
|
||||
}
|
||||
self.assertDictEqual(
|
||||
self.expected_list_dict_merge[0],
|
||||
self.json_export_format.merge_multilingual_dicts(test_dict)[0],
|
||||
)
|
||||
|
||||
def test_format_data(self):
|
||||
fields = self.expected_list_dict_merge
|
||||
res_json = self.json_export_format.format_data(fields)
|
||||
self.assertTrue(json.loads(res_json), "Le résultat de la fonction doit être au format .json")
|
||||
|
||||
fields[0].update({"mock_bytes_key": b"mock_bytes_value"})
|
||||
res_json = self.json_export_format.format_data(fields)
|
||||
|
||||
list_dict_from_json = json.loads(res_json)
|
||||
bytes_key = list_dict_from_json[0].get("mock_bytes_key")
|
||||
self.assertEqual(
|
||||
"data:image/png;base64,mock_bytes_value",
|
||||
bytes_key,
|
||||
"La présence d'une clé contenant une valeur en bytes, dans les champs d'entrée, doit obligatoirement"
|
||||
"être modifié en sorti dans le json, pour y inclure un préfixe.",
|
||||
)
|
||||
|
||||
def test_define_parser(self):
|
||||
res_partner_fields_names = list(self.partner._fields.keys())
|
||||
set_fields_names = set(res_partner_fields_names)
|
||||
|
||||
# Ajouts de faux nom de champs qui sont concaténés.
|
||||
res_partner_fields_names.append("company_id/name")
|
||||
res_partner_fields_names.append("company_id/street1")
|
||||
res_partner_fields_names.append("company_id/siret")
|
||||
|
||||
res_partner_fields_names.append("country_id/currency_id/name")
|
||||
res_partner_fields_names.append("country_id/currency_id/iso_numeric")
|
||||
converted_fields_name = self.json_export_format._convert_simple_list(res_partner_fields_names)
|
||||
|
||||
parser = self.json_export_format.define_parser(converted_fields_name)
|
||||
|
||||
self.assertTrue(
|
||||
set_fields_names.issubset(parser),
|
||||
"Tous les champs du modèle res.partner doivent être présent dans le parser.",
|
||||
)
|
||||
expected_tuple_1 = ("company_id", ["name", "street1", "siret"])
|
||||
expected_tuple_2 = ("country_id", [("currency_id", ["name", "iso_numeric"])])
|
||||
for expected_tuple in [expected_tuple_1, expected_tuple_2]:
|
||||
self.assertIn(
|
||||
expected_tuple,
|
||||
parser,
|
||||
"Un tuple nom_de_champ et liste de nom de champ (qui peut lui même contenir un tuple avec "
|
||||
"la même combinaison), doit être présent, pour les champs de type M2O, avec un accès à un "
|
||||
"des champs du M2O",
|
||||
)
|
||||
|
||||
def test_add_list_or_dict_on_merge_item(self):
|
||||
# Faire la version avec un parent_key qui est un dict
|
||||
test_dict = {
|
||||
"fr_FR": {
|
||||
"champ_2": "valeur",
|
||||
"champ_3": {
|
||||
"cle_dict_imbrique_1": "valeur1",
|
||||
"cle_dict_imbrique_2": "valeur2",
|
||||
"cle_dict_imbrique_3": [
|
||||
"element_liste_imbriqueFR",
|
||||
"element_autre_listeFR",
|
||||
],
|
||||
},
|
||||
},
|
||||
"zn_CN": {
|
||||
"champ_2": "valeur",
|
||||
"champ_3": {
|
||||
"cle_dict_imbrique_1": "valeur1489",
|
||||
"cle_dict_imbrique_2": "valeur24996",
|
||||
"cle_dict_imbrique_3": [
|
||||
"element_liste_imbrique",
|
||||
"element_autre_liste",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
merged_dict = {}
|
||||
all_keys = self.json_export_format.retrieve_all_keys(test_dict)
|
||||
|
||||
# On simule le fait que le champ_2 soit le parent key de tout le dict d'entrée "test_dict".
|
||||
# La clé doit apparaître dans l'arborescence de chaque champ imbriquée.
|
||||
self.json_export_format.process_keys(all_keys, test_dict, merged_dict, "champ_2")
|
||||
|
||||
expected_dict = {
|
||||
"champ_2": "valeur",
|
||||
"champ_3": {
|
||||
"cle_dict_imbrique_2": "champ_2/champ_3/cle_dict_imbrique_2",
|
||||
"cle_dict_imbrique_2_FR": "valeur2",
|
||||
"cle_dict_imbrique_2_CN": "valeur24996",
|
||||
"cle_dict_imbrique_3": "champ_2/champ_3/cle_dict_imbrique_3",
|
||||
"cle_dict_imbrique_3_FR": [
|
||||
"element_liste_imbriqueFR",
|
||||
"element_autre_listeFR",
|
||||
],
|
||||
"cle_dict_imbrique_3_CN": [
|
||||
"element_liste_imbrique",
|
||||
"element_autre_liste",
|
||||
],
|
||||
"cle_dict_imbrique_1": "champ_2/champ_3/cle_dict_imbrique_1",
|
||||
"cle_dict_imbrique_1_FR": "valeur1",
|
||||
"cle_dict_imbrique_1_CN": "valeur1489",
|
||||
},
|
||||
}
|
||||
self.assertDictEqual(expected_dict, merged_dict)
|
||||
|
||||
def test_index_json_export_route(self):
|
||||
# Fonction appelé par le controller qui gère l'export au format json (bouton "Action" > "Exporter")
|
||||
self.authenticate("admin", "admin")
|
||||
csrf = self.helper_get_csrf_token()
|
||||
|
||||
url = "/web/export/json"
|
||||
payload = {
|
||||
"csrf_token": csrf,
|
||||
"data": json.dumps(self.data_dict),
|
||||
}
|
||||
|
||||
response = self.url_open(url, payload)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertDictEqual(self.basic_expect_dict, response.json()[0])
|
||||
|
||||
def test_formats_export_formats(self):
|
||||
# On vérifie que la pop-up d'export ajoute bien la coche json dans les options de format de sortie.
|
||||
self.authenticate("admin", "admin")
|
||||
url = "/web/export/formats"
|
||||
payload = {"jsonrpc": "2.0", "method": "call", "params": {}, "id": 1}
|
||||
|
||||
response = self.url_open(
|
||||
url,
|
||||
data=json.dumps(payload),
|
||||
headers={"Content-Type": "application/json"},
|
||||
)
|
||||
result_format = response.json().get("result")
|
||||
self.assertIn(
|
||||
{"label": "JSON", "tag": "json"},
|
||||
result_format,
|
||||
"Le nouveau format json doit être disponible enexport",
|
||||
)
|
||||
|
||||
def test_json_export_on_none_ordinary_table(self):
|
||||
fields = [field["name"] for field in self.data_dict["fields"]]
|
||||
model = self.env[self.data_dict["model"]]
|
||||
with patch("odoo.models.BaseModel._is_an_ordinary_table", return_value=False):
|
||||
with patch.object(controller_module, "request", self.mock_request):
|
||||
result_json = self.json_export_format.perform_json_export(
|
||||
self.data_dict["domain"], fields, self.data_dict["ids"], model
|
||||
)
|
||||
|
||||
res_dict = json.loads(result_json)
|
||||
self.basic_expect_dict.pop("id")
|
||||
self.assertDictEqual(
|
||||
res_dict[0],
|
||||
self.basic_expect_dict,
|
||||
"Seul l'id ne doit pas être récupérer, "
|
||||
"si la table associé au modèle ne correspond pas à une table classique."
|
||||
"Toutes les autres informations doivent être récupérés normalement.",
|
||||
)
|
||||
|
||||
def test_property_extension(self):
|
||||
self.assertEqual(self.json_export_format.extension, ".json")
|
||||
|
||||
def test_property_content_type(self):
|
||||
self.assertEqual(self.json_export_format.content_type, "text/json;charset=utf8")
|
||||
Reference in New Issue
Block a user