odoo-somconnexio-python-client 0.1.43__tar.gz → 0.1.45__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/PKG-INFO +1 -1
  2. odoo-somconnexio-python-client-0.1.45/odoo_somconnexio_python_client/__init__.py +1 -0
  3. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/client.py +7 -6
  4. odoo-somconnexio-python-client-0.1.45/odoo_somconnexio_python_client/resources/knowledge.py +116 -0
  5. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/product_catalog.py +23 -2
  6. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client.egg-info/PKG-INFO +1 -1
  7. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client.egg-info/SOURCES.txt +2 -0
  8. odoo-somconnexio-python-client-0.1.45/tests/resources/test_knowledge.py +91 -0
  9. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_product_catalog.py +24 -15
  10. odoo-somconnexio-python-client-0.1.43/odoo_somconnexio_python_client/__init__.py +0 -1
  11. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/LICENSE +0 -0
  12. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/README.md +0 -0
  13. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/exceptions.py +0 -0
  14. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/helpers.py +0 -0
  15. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/__init__.py +0 -0
  16. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/address.py +0 -0
  17. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/broadband_isp_info.py +0 -0
  18. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/contract.py +0 -0
  19. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/coop_agreement.py +0 -0
  20. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/crm_lead.py +0 -0
  21. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/crm_lead_line.py +0 -0
  22. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/discovery_channel.py +0 -0
  23. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/fiber_contracts.py +0 -0
  24. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/invoice.py +0 -0
  25. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/mobile_isp_info.py +0 -0
  26. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/odoo_paging.py +0 -0
  27. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/one_shot_catalog.py +0 -0
  28. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/partner.py +0 -0
  29. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/provider.py +0 -0
  30. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/sponsees.py +0 -0
  31. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client/resources/subscription_request.py +0 -0
  32. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client.egg-info/dependency_links.txt +0 -0
  33. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client.egg-info/not-zip-safe +0 -0
  34. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client.egg-info/requires.txt +0 -0
  35. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/odoo_somconnexio_python_client.egg-info/top_level.txt +0 -0
  36. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/setup.cfg +0 -0
  37. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/setup.py +0 -0
  38. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/__init__.py +0 -0
  39. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_address.py +0 -0
  40. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_contract.py +0 -0
  41. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_coop_agreement.py +0 -0
  42. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_crm_lead.py +0 -0
  43. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_discovery_channel.py +0 -0
  44. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_fiber_contracts.py +0 -0
  45. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_invoice.py +0 -0
  46. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_one_shot_catalog.py +0 -0
  47. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_partner.py +0 -0
  48. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_providers.py +0 -0
  49. {odoo-somconnexio-python-client-0.1.43 → odoo-somconnexio-python-client-0.1.45}/tests/resources/test_subscription_request.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: odoo-somconnexio-python-client
3
- Version: 0.1.43
3
+ Version: 0.1.45
4
4
  Summary: Python wrapper for SomConnexio's Odoo (using REST API)
5
5
  Home-page: https://gitlab.com/coopdevs/odoo-somconnexio-python-client
6
6
  Author: Coopdevs
@@ -23,7 +23,7 @@ class Client(object):
23
23
  self.baseurl = helpers.getenv_or_fail("ODOO_BASEURL")
24
24
  self.api_key = helpers.getenv_or_fail("ODOO_APIKEY")
25
25
 
26
- def get(self, route, params={}, extra_headers={}):
26
+ def get(self, route, params={}, extra_headers={}, secondary_domain=False):
27
27
  """Send a GET HTTP requests
28
28
 
29
29
  Args:
@@ -34,12 +34,12 @@ class Client(object):
34
34
  """
35
35
  return self._send_request(
36
36
  verb="GET",
37
- url=self._format_url(route),
37
+ url=self._format_url(route, secondary_domain),
38
38
  params=params,
39
39
  extra_headers=extra_headers,
40
40
  )
41
41
 
42
- def post(self, route, body):
42
+ def post(self, route, body, secondary_domain=False):
43
43
  """Send a POST HTTP requests
44
44
 
45
45
  Args:
@@ -54,13 +54,14 @@ class Client(object):
54
54
  }
55
55
  return self._send_request(
56
56
  verb="POST",
57
- url=self._format_url(route),
57
+ url=self._format_url(route, secondary_domain),
58
58
  payload=body,
59
59
  extra_headers=headers,
60
60
  )
61
61
 
62
- def _format_url(self, path):
63
- path = "/api" + path
62
+ def _format_url(self, path, secondary_domain):
63
+ domain = "/api2" if secondary_domain else "/api"
64
+ path = domain + path
64
65
  return urllib.parse.urljoin(self.baseurl, path)
65
66
 
66
67
  def _send_request(self, verb, url, payload=None, params={}, extra_headers={}):
@@ -0,0 +1,116 @@
1
+ from odoo_somconnexio_python_client.client import Client
2
+
3
+
4
+ class Category:
5
+ def __init__(self, reference, name, childs, breadcrumb=[], **kwargs):
6
+ self.ref = reference
7
+ self.name = name
8
+ self.type = "category"
9
+ self.children = [
10
+ Category(**child, breadcrumb=[reference])
11
+ for child in childs
12
+ if child["type"] == "category"
13
+ ]
14
+ self.pages = [
15
+ {
16
+ "ref": child["reference"],
17
+ "name": child["name"],
18
+ "breadcrumb": [child["reference"], reference] + breadcrumb,
19
+ }
20
+ for child in childs
21
+ if child["type"] == "content"
22
+ ]
23
+
24
+
25
+ class Page:
26
+ def __init__(self, reference, name, content, parent_reference, tags, **kwargs):
27
+ self.ref = reference
28
+ self.name = name
29
+ self.type = "page"
30
+ self.content = content
31
+ self.category = parent_reference
32
+ self.tags = tags
33
+
34
+
35
+ class SearchResult:
36
+ def __init__(self, reference, name, tags, breadcrumb, **kwargs):
37
+ self.ref = reference
38
+ self.name = name
39
+ self.type = "page"
40
+ self.tags = tags
41
+ self.breadcrumb = breadcrumb["references"]
42
+
43
+
44
+ class Knowledge:
45
+ _url_base_path = "/knowledge"
46
+ _url_categories_path = "categories"
47
+ _url_page_path = "page"
48
+ _url_highlighted_path = "highlighted"
49
+ _url_search_path = "search"
50
+
51
+ def __init__(self, url_resource_path, lang):
52
+ self.response_data = Client().get(
53
+ "{base}/{resource}".format(
54
+ base=self._url_base_path, resource=url_resource_path
55
+ ),
56
+ # Review _ES in lang. Now we are managing it in other way. Product-catalog example
57
+ {"lang": "{}_ES".format(lang)},
58
+ secondary_domain=True,
59
+ )
60
+
61
+ @classmethod
62
+ def get_categories(cls, lang="ca"):
63
+ response_data = cls(cls._url_categories_path, lang).response_data
64
+ if not response_data:
65
+ return []
66
+
67
+ return [Category(**data) for data in response_data]
68
+
69
+ @classmethod
70
+ def get_category(cls, category_ref, lang="ca"):
71
+ url_resource_path = "{resource}/{ref}".format(
72
+ resource=cls._url_categories_path, ref=category_ref
73
+ )
74
+
75
+ response_data = cls(url_resource_path, lang).response_data
76
+ if not response_data:
77
+ raise Exception("Category not found")
78
+
79
+ return Category(**response_data[0])
80
+
81
+ @classmethod
82
+ def get_pages_by_highlight(cls, highlight_code, lang="ca"):
83
+ url_resource_path = "{resource}/{code}".format(
84
+ resource=cls._url_highlighted_path, code=highlight_code
85
+ )
86
+
87
+ response_data = cls(url_resource_path, lang).response_data
88
+ if not response_data:
89
+ return []
90
+
91
+ return [Page(**datum) for datum in response_data]
92
+
93
+ @classmethod
94
+ def search_pages(cls, pattern, lang="ca"):
95
+ url_resource_path = "{resource}/{pattern}".format(
96
+ resource=cls._url_search_path,
97
+ pattern=pattern,
98
+ )
99
+
100
+ response_data = cls(url_resource_path, lang).response_data
101
+ if not response_data:
102
+ return []
103
+
104
+ return [SearchResult(**datum) for datum in response_data]
105
+
106
+ @classmethod
107
+ def get_page(cls, page_ref, lang="ca"):
108
+ url_resource_path = "{resource}/{ref}".format(
109
+ resource=cls._url_page_path, ref=page_ref
110
+ )
111
+
112
+ response_data = cls(url_resource_path, lang).response_data
113
+ if not response_data:
114
+ raise Exception("Page not found")
115
+
116
+ return Page(**response_data)
@@ -72,11 +72,32 @@ class ProductCatalog:
72
72
  self.packs = [Pack(**pack) for pack in packs]
73
73
 
74
74
  @classmethod
75
- def search(cls, code="", category="", lang="ca", product_code=""):
75
+ def search(cls, code="", category="", lang="ca", is_company="false"):
76
+ return cls._get_product_catalog(
77
+ {
78
+ "code": code,
79
+ "categ": category,
80
+ "is_company": is_company,
81
+ },
82
+ lang,
83
+ )
84
+
85
+ @classmethod
86
+ def get_by_product_code(cls, code="", lang="ca", product_code=""):
87
+ return cls._get_product_catalog(
88
+ {
89
+ "code": code,
90
+ "product_code": product_code,
91
+ },
92
+ lang,
93
+ )
94
+
95
+ @classmethod
96
+ def _get_product_catalog(cls, params, lang):
76
97
  headers = {"Accept-Language": lang}
77
98
  response_data = Client().get(
78
99
  cls._url_path,
79
- params={"code": code, "categ": category, "product_code": product_code},
100
+ params={**params},
80
101
  extra_headers=headers,
81
102
  )
82
103
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: odoo-somconnexio-python-client
3
- Version: 0.1.43
3
+ Version: 0.1.45
4
4
  Summary: Python wrapper for SomConnexio's Odoo (using REST API)
5
5
  Home-page: https://gitlab.com/coopdevs/odoo-somconnexio-python-client
6
6
  Author: Coopdevs
@@ -21,6 +21,7 @@ odoo_somconnexio_python_client/resources/crm_lead_line.py
21
21
  odoo_somconnexio_python_client/resources/discovery_channel.py
22
22
  odoo_somconnexio_python_client/resources/fiber_contracts.py
23
23
  odoo_somconnexio_python_client/resources/invoice.py
24
+ odoo_somconnexio_python_client/resources/knowledge.py
24
25
  odoo_somconnexio_python_client/resources/mobile_isp_info.py
25
26
  odoo_somconnexio_python_client/resources/odoo_paging.py
26
27
  odoo_somconnexio_python_client/resources/one_shot_catalog.py
@@ -37,6 +38,7 @@ tests/resources/test_crm_lead.py
37
38
  tests/resources/test_discovery_channel.py
38
39
  tests/resources/test_fiber_contracts.py
39
40
  tests/resources/test_invoice.py
41
+ tests/resources/test_knowledge.py
40
42
  tests/resources/test_one_shot_catalog.py
41
43
  tests/resources/test_partner.py
42
44
  tests/resources/test_product_catalog.py
@@ -0,0 +1,91 @@
1
+ import pytest
2
+ import unittest2 as unittest
3
+
4
+ from odoo_somconnexio_python_client.resources.knowledge import Knowledge
5
+
6
+
7
+ class KnowledgeTests(unittest.TestCase):
8
+ @pytest.mark.vcr()
9
+ def test_get_categories(self):
10
+ categories = Knowledge.get_categories()
11
+ self._assert_category(categories[1])
12
+
13
+ @pytest.mark.vcr()
14
+ def test_get_categories_not_found(self):
15
+ assert Knowledge.get_categories() == []
16
+
17
+ @pytest.mark.vcr()
18
+ def test_get_category(self):
19
+ category = Knowledge.get_category("test")
20
+ self._assert_category(category)
21
+
22
+ @pytest.mark.vcr()
23
+ def test_get_category_not_found(self):
24
+ self.assertRaises(
25
+ Exception,
26
+ Knowledge.get_category,
27
+ category_ref="dummy",
28
+ )
29
+
30
+ @pytest.mark.vcr()
31
+ def test_get_pages_by_highlight(self):
32
+ pages = Knowledge.get_pages_by_highlight("test")
33
+ self._assert_page(pages[0])
34
+
35
+ @pytest.mark.vcr()
36
+ def test_get_pages_by_highlight_not_found(self):
37
+ assert Knowledge.get_pages_by_highlight("dummy") == []
38
+
39
+ @pytest.mark.vcr()
40
+ def test_search_pages(self):
41
+ pages = Knowledge.search_pages("search")
42
+ self._assert_search_page(pages[0])
43
+
44
+ @pytest.mark.vcr()
45
+ def test_lang_search_pages(self):
46
+ pages = Knowledge.search_pages("busqueda", "es")
47
+ self._assert_search_page(pages[0])
48
+
49
+ @pytest.mark.vcr()
50
+ def test_search_pages_not_found(self):
51
+ assert Knowledge.search_pages("dummy") == []
52
+
53
+ @pytest.mark.vcr()
54
+ def test_get_page(self):
55
+ page = Knowledge.get_page("test_test")
56
+ self._assert_page(page)
57
+
58
+ @pytest.mark.vcr()
59
+ def test_get_page_not_found(self):
60
+ self.assertRaises(
61
+ Exception,
62
+ Knowledge.get_page,
63
+ page_ref="dummy",
64
+ )
65
+
66
+ def _assert_category(self, cat):
67
+ assert cat.ref == "test"
68
+ assert cat.name == "Test"
69
+ assert cat.type == "category"
70
+ assert cat.children[0].ref == "test_child_cat"
71
+ assert cat.children[0].name == "Test child cat"
72
+ assert cat.children[0].type == "category"
73
+ assert cat.children[0].pages == []
74
+ assert cat.pages[0]["ref"] == "test_test"
75
+ assert cat.pages[0]["name"] == "Test"
76
+ assert cat.pages[0]["breadcrumb"] == ["test_test", "test"]
77
+
78
+ def _assert_page(self, page):
79
+ assert page.ref == "test_test"
80
+ assert page.name == "Test"
81
+ assert page.type == "page"
82
+ assert page.content == "<p>Content</p><p>search_test<br></p>"
83
+ assert page.category == "test"
84
+ assert page.tags == []
85
+
86
+ def _assert_search_page(self, page):
87
+ assert page.ref == "test_test"
88
+ assert page.name == "Test"
89
+ assert page.type == "page"
90
+ assert page.tags == []
91
+ assert page.breadcrumb == ["test_test", "test"]
@@ -28,7 +28,7 @@ class TariffTests(unittest.TestCase):
28
28
  tariff_names.append(product.name)
29
29
  tariff_codes.append(product.code)
30
30
  tariff_available_for.append(product.available_for)
31
- if product.code == "SE_SC_REC_MOBILE_T_UNL_2048":
31
+ if product.code == "SE_SC_REC_MOBILE_T_UNL_30720":
32
32
  tariff_offer = product.offer
33
33
 
34
34
  self.assertIn("ADSL sense fix", tariff_names)
@@ -36,9 +36,9 @@ class TariffTests(unittest.TestCase):
36
36
  self.assertIn(["member"], tariff_available_for)
37
37
 
38
38
  self.assertIsInstance(tariff_offer, Offer)
39
- self.assertIn("SE_SC_REC_MOBILE_PACK_UNL_2048", tariff_offer.code)
40
- self.assertIn("Il·limitades 2 GB associat a fibra", tariff_offer.name)
41
- self.assertEqual(8, tariff_offer.price)
39
+ self.assertIn("SE_SC_REC_MOBILE_PACK_UNL_30720", tariff_offer.code)
40
+ self.assertIn("Il·limitades 30 GB (Pack)", tariff_offer.name)
41
+ self.assertEqual(1.0, tariff_offer.price)
42
42
 
43
43
  adsl_wo_fix_product = list(
44
44
  filter(lambda p: p.code == "SE_SC_REC_BA_ADSL_SF", pricelist_21IVA.products)
@@ -73,11 +73,11 @@ class TariffTests(unittest.TestCase):
73
73
  pack_tariff_codes.append(product.code)
74
74
 
75
75
  self.assertIn("SE_SC_REC_PACK_FIBER_100_UNL_20480", pack_codes)
76
- self.assertIn("Fibra 100 amb fix+ 2 M\u00f2bils", pack_names)
77
- self.assertIn("Fibra 100Mb amb fix", pack_tariff_names)
76
+ self.assertIn("Fibra 1Gb + Fix + 50 GB compartides 2 mòbils", pack_names)
77
+ self.assertIn("Fibra 300Mb Sense Fix", pack_tariff_names)
78
78
  self.assertIn("SE_SC_REC_MOBILE_PACK_UNL_20480", pack_tariff_codes)
79
- self.assertIn("2", pack_mobiles_in_pack)
80
- self.assertIn("100", pack_fiber_bandwidth)
79
+ self.assertIn(2, pack_mobiles_in_pack)
80
+ self.assertIn(100, pack_fiber_bandwidth)
81
81
 
82
82
  @pytest.mark.vcr()
83
83
  def test_search_non_existant_code(self):
@@ -104,15 +104,24 @@ class TariffTests(unittest.TestCase):
104
104
  ca_product_names = [p.name for p in ca_pricelists[0].products]
105
105
  es_product_names = [p.name for p in es_pricelists[0].products]
106
106
 
107
- self.assertIn("Il·limitades 10 GB", ca_product_names)
108
- self.assertIn("Ilimitadas 10 GB", es_product_names)
107
+ self.assertIn("Il·limitades 30 GB", ca_product_names)
108
+ self.assertIn("Ilimitadas 30 GB", es_product_names)
109
109
 
110
110
  @pytest.mark.vcr()
111
- def test_search_available_products_for_product_code(self):
111
+ def test_get_by_product_code(self):
112
112
  """For product fibra 100Mb only are available other Fiber products."""
113
- pricelists = ProductCatalog.search(product_code="SE_SC_REC_BA_F_100")
113
+ pricelists = ProductCatalog.get_by_product_code(
114
+ product_code="SE_SC_REC_BA_F_100"
115
+ )
116
+ product_codes = [p.code for p in pricelists[0].products]
117
+
118
+ self.assertIn("SE_SC_REC_BA_F_100_SF", product_codes)
119
+
120
+ @pytest.mark.vcr()
121
+ def test_search_company_catalog(self):
122
+ pricelists = ProductCatalog.search(is_company="true")
114
123
  product_codes = [p.code for p in pricelists[0].products]
124
+ pack_codes = [p.code for p in pricelists[0].packs]
115
125
 
116
- self.assertIn("SE_SC_REC_BA_F_1024", product_codes)
117
- self.assertIn("SE_SC_REC_BA_F_600", product_codes)
118
- self.assertNotIn("SE_SC_REC_BA_ADSL_SF", product_codes)
126
+ self.assertIn("SE_SC_REC_MOBILE_T_UNL_30720", product_codes)
127
+ self.assertIn("SE_SC_REC_PACK_FIBER_1000_2_MOBILES_50", pack_codes)