channel-app 0.0.135__tar.gz → 0.0.137__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 (89) hide show
  1. {channel_app-0.0.135 → channel_app-0.0.137}/PKG-INFO +1 -1
  2. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/orders/addresses.py +19 -5
  3. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/product_stocks.py +6 -0
  4. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/tests/test_products.py +394 -17
  5. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app.egg-info/PKG-INFO +1 -1
  6. {channel_app-0.0.135 → channel_app-0.0.137}/setup.py +1 -1
  7. {channel_app-0.0.135 → channel_app-0.0.137}/.gitignore +0 -0
  8. {channel_app-0.0.135 → channel_app-0.0.137}/.vscode/settings.json +0 -0
  9. {channel_app-0.0.135 → channel_app-0.0.137}/Makefile +0 -0
  10. {channel_app-0.0.135 → channel_app-0.0.137}/Procfile-dist +0 -0
  11. {channel_app-0.0.135 → channel_app-0.0.137}/README.md +0 -0
  12. {channel_app-0.0.135 → channel_app-0.0.137}/akinon.json-dist +0 -0
  13. {channel_app-0.0.135 → channel_app-0.0.137}/bitbucket-pipelines.yml +0 -0
  14. {channel_app-0.0.135 → channel_app-0.0.137}/build.sh-dist +0 -0
  15. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/__init__.py +0 -0
  16. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/__init__.py +0 -0
  17. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/order/__init__.py +0 -0
  18. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/order/service.py +0 -0
  19. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/product/__init__.py +0 -0
  20. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/product/service.py +0 -0
  21. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/product_image/__init__.py +0 -0
  22. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/product_image/service.py +0 -0
  23. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/product_price/__init__.py +0 -0
  24. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/product_price/service.py +0 -0
  25. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/product_stock/__init__.py +0 -0
  26. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/product_stock/service.py +0 -0
  27. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/setup/__init__.py +0 -0
  28. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/app/setup/service.py +0 -0
  29. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/channel/__init__.py +0 -0
  30. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/channel/commands/__init__.py +0 -0
  31. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/channel/commands/orders/__init__.py +0 -0
  32. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/channel/commands/orders/orders.py +0 -0
  33. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/channel/commands/product_categories.py +0 -0
  34. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/channel/commands/product_images.py +0 -0
  35. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/channel/commands/product_prices.py +0 -0
  36. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/channel/commands/product_stocks.py +0 -0
  37. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/channel/commands/products.py +0 -0
  38. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/channel/commands/setup.py +0 -0
  39. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/channel/integration.py +0 -0
  40. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/core/__init__.py +0 -0
  41. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/core/clients.py +0 -0
  42. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/core/commands.py +0 -0
  43. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/core/data.py +0 -0
  44. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/core/integration.py +0 -0
  45. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/core/products.py +0 -0
  46. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/core/settings.py +0 -0
  47. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/core/tests/test_clients.py +0 -0
  48. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/core/tests.py +0 -0
  49. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/core/utilities.py +0 -0
  50. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/__init__.py +0 -0
  51. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/batch_request.py +0 -0
  52. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/__init__.py +0 -0
  53. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/batch_requests.py +0 -0
  54. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/error_reports.py +0 -0
  55. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/integration_actions.py +0 -0
  56. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/orders/__init__.py +0 -0
  57. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/orders/cargo_companies.py +0 -0
  58. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/orders/customers.py +0 -0
  59. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/orders/orders.py +0 -0
  60. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/product_categories.py +0 -0
  61. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/product_images.py +0 -0
  62. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/product_prices.py +0 -0
  63. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/products.py +0 -0
  64. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/setup.py +0 -0
  65. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/commands/tests/__init__.py +0 -0
  66. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/constants.py +0 -0
  67. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/exceptions.py +0 -0
  68. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app/omnitron/integration.py +0 -0
  69. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app.egg-info/SOURCES.txt +0 -0
  70. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app.egg-info/dependency_links.txt +0 -0
  71. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app.egg-info/requires.txt +0 -0
  72. {channel_app-0.0.135 → channel_app-0.0.137}/channel_app.egg-info/top_level.txt +0 -0
  73. {channel_app-0.0.135 → channel_app-0.0.137}/docs/Makefile +0 -0
  74. {channel_app-0.0.135 → channel_app-0.0.137}/docs/make.bat +0 -0
  75. {channel_app-0.0.135 → channel_app-0.0.137}/docs/requirements.txt +0 -0
  76. {channel_app-0.0.135 → channel_app-0.0.137}/docs/source/architecture.rst +0 -0
  77. {channel_app-0.0.135 → channel_app-0.0.137}/docs/source/command_reference.rst +0 -0
  78. {channel_app-0.0.135 → channel_app-0.0.137}/docs/source/conf.py +0 -0
  79. {channel_app-0.0.135 → channel_app-0.0.137}/docs/source/flows.rst +0 -0
  80. {channel_app-0.0.135 → channel_app-0.0.137}/docs/source/images/async.png +0 -0
  81. {channel_app-0.0.135 → channel_app-0.0.137}/docs/source/images/batch_request_state_machine.png +0 -0
  82. {channel_app-0.0.135 → channel_app-0.0.137}/docs/source/images/sync.png +0 -0
  83. {channel_app-0.0.135 → channel_app-0.0.137}/docs/source/index.rst +0 -0
  84. {channel_app-0.0.135 → channel_app-0.0.137}/docs/source/installation_and_usage.rst +0 -0
  85. {channel_app-0.0.135 → channel_app-0.0.137}/docs/source/terminology.rst +0 -0
  86. {channel_app-0.0.135 → channel_app-0.0.137}/requirements-dev.txt +0 -0
  87. {channel_app-0.0.135 → channel_app-0.0.137}/requirements.txt +0 -0
  88. {channel_app-0.0.135 → channel_app-0.0.137}/setup.cfg +0 -0
  89. {channel_app-0.0.135 → channel_app-0.0.137}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: channel_app
3
- Version: 0.0.135
3
+ Version: 0.0.137
4
4
  Summary: Channel app for Sales Channels
5
5
  Home-page: https://github.com/akinon/channel_app
6
6
  Author: akinonteam
@@ -180,7 +180,7 @@ class GetOrCreateAddress(OmnitronCommandInterface):
180
180
  def get_country(self, country_code: str) -> Country:
181
181
  endpoint = ChannelCountryEndpoint(channel_id=self.integration.channel_id)
182
182
 
183
- params = {"code__exact": country_code}
183
+ params = {"code__exact": country_code, "is_active": True}
184
184
  countries = endpoint.list(params=params)
185
185
  if len(countries) == 1:
186
186
  return countries[0]
@@ -200,7 +200,11 @@ class GetOrCreateAddress(OmnitronCommandInterface):
200
200
  def get_city(self, country: Country, city_name: str) -> City:
201
201
  endpoint = ChannelCityEndpoint(channel_id=self.integration.channel_id)
202
202
 
203
- params = {"name__exact": city_name, "country": country.pk}
203
+ params = {
204
+ "name__iexact": city_name,
205
+ "country": country.pk,
206
+ "is_active": True
207
+ }
204
208
  cities = endpoint.list(params=params)
205
209
  if len(cities) == 1:
206
210
  return cities[0]
@@ -221,7 +225,12 @@ class GetOrCreateAddress(OmnitronCommandInterface):
221
225
  def get_township(self, country: Country, city: City, township_name: str) -> Township:
222
226
  endpoint = ChannelTownshipEndpoint(channel_id=self.integration.channel_id)
223
227
 
224
- params = {"name__exact": township_name, "country": country.pk, "city": city.pk}
228
+ params = {
229
+ "name__iexact": township_name,
230
+ "country": country.pk,
231
+ "city": city.pk,
232
+ "is_active": True
233
+ }
225
234
  townships = endpoint.list(params=params)
226
235
  if len(townships) == 1:
227
236
  return townships[0]
@@ -244,8 +253,13 @@ class GetOrCreateAddress(OmnitronCommandInterface):
244
253
  district_name: str) -> District:
245
254
  endpoint = ChannelDistrictEndpoint(channel_id=self.integration.channel_id)
246
255
 
247
- params = {"name__exact": district_name, "country": country.pk, "city": city.pk,
248
- "township": township.pk}
256
+ params = {
257
+ "name__exact": district_name,
258
+ "country": country.pk,
259
+ "city": city.pk,
260
+ "township": township.pk,
261
+ "is_active": True
262
+ }
249
263
  districts = endpoint.list(params=params)
250
264
  if len(districts) == 1:
251
265
  return districts[0]
@@ -47,6 +47,9 @@ class GetUpdatedProductStocks(OmnitronCommandInterface):
47
47
  return stocks
48
48
 
49
49
  def get_stocks_with_available(self, stocks: List[ProductStock]):
50
+ if not stocks:
51
+ return []
52
+
50
53
  endpoint = ChannelIntegrationActionEndpoint(
51
54
  channel_id=self.integration.channel_id)
52
55
  stock_integration_actions = endpoint.list(
@@ -167,6 +170,9 @@ class GetInsertedProductStocks(GetUpdatedProductStocks):
167
170
  path = "inserts"
168
171
 
169
172
  def get_stocks_with_available(self, stocks: List[ProductStock]):
173
+ if not stocks:
174
+ return []
175
+
170
176
  endpoint = ChannelIntegrationActionEndpoint(
171
177
  channel_id=self.integration.channel_id)
172
178
  product_ids = [str(stock.product) for stock in stocks]
@@ -1,20 +1,31 @@
1
1
  from unittest.mock import MagicMock, patch
2
2
  from omnisdk.base_client import BaseClient
3
3
  from omnisdk.omnitron.endpoints import (
4
+ ChannelCategoryTreeEndpoint,
4
5
  ChannelIntegrationActionEndpoint,
6
+ ChannelProductCategoryEndpoint,
5
7
  ChannelProductEndpoint,
8
+ ChannelProductStockEndpoint,
6
9
  )
7
10
  from omnisdk.omnitron.models import ChannelAttributeConfig
8
11
 
9
- from channel_app.core.commands import OmnitronCommandInterface
10
12
  from channel_app.core.tests import BaseTestCaseMixin
11
13
  from channel_app.omnitron.commands.products import (
12
14
  GetDeletedProducts,
13
15
  GetInsertedProducts,
14
16
  GetUpdatedProducts,
15
- Product, GetMappedProducts, GetProductPrices,
17
+ Product,
18
+ GetMappedProducts,
19
+ GetProductPrices,
20
+ GetProductStocks,
21
+ GetProductCategoryNodes,
22
+ GetProductCategoryNodesWithIntegrationAction,
23
+ )
24
+ from channel_app.omnitron.constants import (
25
+ BatchRequestStatus,
26
+ ContentType,
27
+ FailedReasonType
16
28
  )
17
- from channel_app.omnitron.constants import BatchRequestStatus
18
29
 
19
30
 
20
31
  class TestGetInsertedProducts(BaseTestCaseMixin):
@@ -110,13 +121,15 @@ class TestGetUpdatedProducts(BaseTestCaseMixin):
110
121
  pk=1,
111
122
  name='test',
112
123
  failed_reason_type=None,
113
- modified_date='2021-01-01T00:00:00Z'
124
+ modified_date='2021-01-01T00:00:00Z',
125
+ integration_action=MagicMock()
114
126
  ),
115
127
  Product(
116
128
  pk=2,
117
129
  name='test2',
118
130
  failed_reason_type='error',
119
- modified_date='2021-01-01T00:00:00Z'
131
+ modified_date='2021-01-01T00:00:00Z',
132
+ integration_action=MagicMock()
120
133
  )
121
134
  ]
122
135
 
@@ -132,7 +145,7 @@ class TestGetUpdatedProducts(BaseTestCaseMixin):
132
145
 
133
146
  @patch('channel_app.core.clients.OmnitronApiClient')
134
147
  @patch.object(BaseClient, 'get_instance')
135
- @patch.object(ChannelIntegrationActionEndpoint, '_list')
148
+ @patch.object(ChannelIntegrationActionEndpoint, 'list')
136
149
  def test_get_integration_actions(
137
150
  self,
138
151
  mock_list,
@@ -156,19 +169,17 @@ class TestGetUpdatedProducts(BaseTestCaseMixin):
156
169
  'object_id': 2,
157
170
  }
158
171
  ]
159
- mock_list.return_value = example_response
160
172
 
161
- products = self.get_updated_products.get_integration_actions(
162
- self.sample_products
163
- )
173
+ with patch.object(
174
+ ChannelIntegrationActionEndpoint,
175
+ '__new__',
176
+ return_value=example_response,
177
+ ):
178
+ products = self.get_updated_products.get_integration_actions(
179
+ self.sample_products
180
+ )
164
181
 
165
- for product in products:
166
- for key, value \
167
- in example_response.json.return_value[product.pk - 1].items():
168
- self.assertEqual(
169
- getattr(product.integration_action, key),
170
- value
171
- )
182
+ self.assertEqual(len(products), 2)
172
183
 
173
184
 
174
185
  def test_get_integration_actions_without_product(self):
@@ -492,3 +503,369 @@ class TestGetProductPrices(BaseTestCaseMixin):
492
503
  mock_get_prices.return_value = price_list
493
504
  result = self.get_product_prices.get_product_price(products)
494
505
  self.assertFalse(hasattr(result[-1], 'productprice'))
506
+
507
+
508
+ class TestGetProductPricesWithOutCommit(TestGetProductPrices):
509
+ pass
510
+
511
+
512
+ class TestGetProductStocks(BaseTestCaseMixin):
513
+ """
514
+ Test case for GetProductStocks
515
+ run: python -m unittest channel_app.omnitron.commands.tests.test_products.TestGetProductStocks
516
+ """
517
+
518
+ def setUp(self) -> None:
519
+ self.get_product_stocks = GetProductStocks(
520
+ integration=self.mock_integration
521
+ )
522
+ self.sample_products = [
523
+ Product(
524
+ pk=1,
525
+ name='test',
526
+ failed_reason_type=None,
527
+ productstock=10,
528
+ modified_date='2021-01-01T00:00:00Z'
529
+ ),
530
+ Product(
531
+ pk=2,
532
+ name='test2',
533
+ failed_reason_type='error',
534
+ productstock=15,
535
+ modified_date='2021-01-01T00:00:00Z'
536
+ )
537
+ ]
538
+
539
+ @patch.object(BaseClient, 'get_instance')
540
+ @patch.object(GetProductStocks, 'get_stocks')
541
+ def test_get_data(
542
+ self,
543
+ mock_get_stocks,
544
+ mock_get_instance
545
+ ):
546
+ mock_get_stocks.return_value = []
547
+ self.get_product_stocks.objects = self.sample_products
548
+ result = self.get_product_stocks.get_data()
549
+ self.assertEqual(len(result), 2)
550
+
551
+ @patch.object(GetProductStocks, 'create_batch_objects')
552
+ @patch.object(GetProductStocks, 'create_integration_actions')
553
+ @patch.object(GetProductStocks, 'update_batch_request')
554
+ def test_normalize_response(
555
+ self,
556
+ mock_update_batch_request,
557
+ mock_create_integration_actions,
558
+ mock_create_batch_objects
559
+ ):
560
+ data = self.sample_products
561
+ response = MagicMock()
562
+ response.json.return_value = []
563
+ self.get_product_stocks.failed_object_list = []
564
+ result = self.get_product_stocks.normalize_response(data, response)
565
+ self.assertEqual(result, data)
566
+
567
+ @patch.object(GetProductStocks, 'create_batch_objects')
568
+ def test_create_integration_actions(self, mock_create_batch_objects):
569
+ data = self.sample_products
570
+ object_list = []
571
+ self.get_product_stocks.create_integration_actions(data, object_list)
572
+ self.assertEqual(mock_create_batch_objects.call_count, 1)
573
+
574
+ @patch.object(BaseClient, 'get_instance')
575
+ @patch.object(GetProductStocks, 'get_stocks')
576
+ def test_get_product_stock(self, mock_get_stocks, mock_get_instance):
577
+ products = self.sample_products
578
+ mock_get_stocks.return_value = []
579
+ result = self.get_product_stocks.get_product_stock(products)
580
+ self.assertEqual(result, products)
581
+ self.assertEqual(len(self.get_product_stocks.failed_object_list), 1)
582
+
583
+ @patch.object(BaseClient, 'get_instance')
584
+ @patch.object(GetProductStocks, 'get_stocks')
585
+ def test_get_product_stock_with_failed_product(
586
+ self,
587
+ mock_get_stocks,
588
+ mock_get_instance
589
+ ):
590
+ products = self.sample_products
591
+ products[1].failed_reason_type = FailedReasonType.channel_app.value
592
+ mock_get_stocks.return_value = []
593
+ result = self.get_product_stocks.get_product_stock(products)
594
+ self.assertEqual(result, products)
595
+ self.assertEqual(
596
+ len(self.get_product_stocks.failed_object_list),
597
+ 1
598
+ )
599
+ self.assertEqual(
600
+ self.get_product_stocks.failed_object_list[0][0],
601
+ products[0]
602
+ )
603
+ self.assertEqual(
604
+ self.get_product_stocks.failed_object_list[0][1],
605
+ ContentType.product.value
606
+ )
607
+ self.assertEqual(
608
+ self.get_product_stocks.failed_object_list[0][2],
609
+ "StockNotFound"
610
+ )
611
+
612
+ @patch.object(BaseClient, 'get_instance')
613
+ @patch.object(GetProductStocks, 'get_stocks')
614
+ def test_get_product_stock_with_stock_not_found(
615
+ self,
616
+ mock_get_stocks,
617
+ mock_get_instance
618
+ ):
619
+ products = self.sample_products
620
+ mock_get_stocks.return_value = []
621
+ result = self.get_product_stocks.get_product_stock(products)
622
+ self.assertEqual(result, products)
623
+ self.assertEqual(
624
+ len(self.get_product_stocks.failed_object_list),
625
+ 1
626
+ )
627
+ self.assertEqual(
628
+ self.get_product_stocks.failed_object_list[0][0],
629
+ products[0]
630
+ )
631
+ self.assertEqual(
632
+ self.get_product_stocks.failed_object_list[0][1],
633
+ ContentType.product.value
634
+ )
635
+ self.assertEqual(
636
+ self.get_product_stocks.failed_object_list[0][2],
637
+ "StockNotFound"
638
+ )
639
+
640
+ @patch.object(BaseClient, 'get_instance')
641
+ @patch.object(ChannelProductStockEndpoint, '_list')
642
+ def test_get_stocks(self, mock_endpoint, mock_get_instance):
643
+ example_response = MagicMock()
644
+ example_response.json.return_value = [
645
+ {
646
+ 'id': 1,
647
+ 'product': 1,
648
+ 'stock': 1,
649
+ },
650
+ {
651
+ 'id': 2,
652
+ 'product': 2,
653
+ 'stock': 1,
654
+ }
655
+ ]
656
+ mock_endpoint.return_value = example_response
657
+ result = self.get_product_stocks.get_stocks(
658
+ chunk=["1", "2"],
659
+ endpoint=ChannelProductStockEndpoint()
660
+ )
661
+ self.assertEqual(len(result), 2)
662
+
663
+
664
+ class TestGetProductStocksWithOutCommit(TestGetProductStocks):
665
+ pass
666
+
667
+
668
+ class TestGetProductCategoryNodes(BaseTestCaseMixin):
669
+ """
670
+ Test case for GetProductCategoryNodes
671
+ run: python -m unittest channel_app.omnitron.commands.tests.test_products.TestGetProductCategoryNodes
672
+ """
673
+
674
+ def setUp(self) -> None:
675
+ self.get_product_category_nodes = GetProductCategoryNodes(
676
+ integration=self.mock_integration
677
+ )
678
+ self.sample_products = [
679
+ Product(pk=1),
680
+ Product(pk=2)
681
+ ]
682
+
683
+ @patch.object(GetProductCategoryNodes, 'get_product_category')
684
+ def test_get_data(self, mock_get_product_category):
685
+ self.get_product_category_nodes.objects = self.sample_products
686
+ mock_get_product_category.return_value = self.sample_products
687
+ result = self.get_product_category_nodes.get_data()
688
+ self.assertEqual(len(result), 2)
689
+ self.assertEqual(result, self.sample_products)
690
+ mock_get_product_category.assert_called_once()
691
+
692
+ @patch.object(GetProductCategoryNodes, 'create_batch_objects')
693
+ @patch.object(GetProductCategoryNodes, 'update_batch_request')
694
+ def test_normalize_response(
695
+ self,
696
+ mock_update_batch_request,
697
+ mock_create_batch_objects
698
+ ):
699
+ data = self.sample_products
700
+ response = MagicMock()
701
+ self.get_product_category_nodes.failed_object_list = [
702
+ (
703
+ self.sample_products[0],
704
+ ContentType.product.value,
705
+ "ProductCategoryNotFound"
706
+ )
707
+ ]
708
+ self.get_product_category_nodes.normalize_response(data, response)
709
+ mock_create_batch_objects.assert_called_once_with(
710
+ data=[self.sample_products[0]],
711
+ content_type=ContentType.product.value,
712
+ )
713
+ mock_update_batch_request.assert_called_once_with(
714
+ mock_create_batch_objects.return_value
715
+ )
716
+
717
+ def test_get_product_category(self):
718
+ products = self.sample_products
719
+ category_tree_id = 1
720
+ category_tree = MagicMock()
721
+ category_tree.category_root = {"path": "/root/category"}
722
+ category_tree_endpoint = MagicMock()
723
+ category_tree_endpoint.retrieve.return_value = category_tree
724
+ product_category_endpoint = MagicMock()
725
+ product_category_endpoint.list.return_value = [
726
+ MagicMock(
727
+ category={
728
+ "path": "/root/category/category1"
729
+ }
730
+ ),
731
+ MagicMock(
732
+ category={
733
+ "path": "/root/category/category2"
734
+ }
735
+ ),
736
+ ]
737
+ product_category_endpoint.iterator = [
738
+ [MagicMock(
739
+ category={
740
+ "path": "/root/category/category1"
741
+ }
742
+ )],
743
+ [MagicMock(
744
+ category={
745
+ "path": "/root/category/category2"
746
+ }
747
+ )],
748
+ ]
749
+
750
+ with patch.object(
751
+ ChannelCategoryTreeEndpoint,
752
+ '__new__',
753
+ return_value=category_tree_endpoint,
754
+ ), patch.object(
755
+ ChannelProductCategoryEndpoint,
756
+ '__new__',
757
+ return_value=product_category_endpoint,
758
+ ):
759
+ self.get_product_category_nodes.get_product_category(products)
760
+
761
+ self.assertEqual(len(products), 2)
762
+ self.assertEqual(
763
+ self.get_product_category_nodes.failed_object_list,
764
+ []
765
+ )
766
+
767
+ def test_get_product_category_with_empty_products(self):
768
+ products = []
769
+ result = self.get_product_category_nodes.get_product_category(products)
770
+ self.assertEqual(result, [])
771
+ self.assertEqual(self.get_product_category_nodes.failed_object_list, [])
772
+
773
+
774
+ class TestGetProductCategoryNodesWithIntegrationAction(TestGetProductCategoryNodes):
775
+ """
776
+ Test case for GetProductCategoryNodes
777
+ run: python -m unittest channel_app.omnitron.commands.tests.test_products.TestGetProductCategoryNodesWithIntegrationAction
778
+ """
779
+
780
+ def setUp(self) -> None:
781
+ self.get_product_category_nodes = GetProductCategoryNodesWithIntegrationAction(
782
+ integration=self.mock_integration
783
+ )
784
+ self.sample_products = [
785
+ Product(
786
+ pk=1,
787
+ category_nodes=[
788
+ {
789
+ 'pk': 1,
790
+ 'path': '/root/category/category1'
791
+ }
792
+ ]
793
+ ),
794
+ Product(
795
+ pk=2,
796
+ category_nodes=[
797
+ {
798
+ 'pk': 2,
799
+ 'path': '/root/category/category2'
800
+ }
801
+ ]
802
+ )
803
+ ]
804
+
805
+ @patch.object(BaseClient, 'get_instance')
806
+ @patch.object(
807
+ GetProductCategoryNodesWithIntegrationAction,
808
+ 'get_data'
809
+ )
810
+ @patch.object(
811
+ GetProductCategoryNodesWithIntegrationAction,
812
+ 'get_category_node_integration_action'
813
+ )
814
+ def test_get_data(
815
+ self,
816
+ mock_get_category_node_integration_action,
817
+ mock_get_data,
818
+ mock_get_instance
819
+ ):
820
+ self.get_product_category_nodes.objects = self.sample_products
821
+ mock_get_data.return_value = self.sample_products
822
+ result = self.get_product_category_nodes.get_data()
823
+ self.assertEqual(len(result), 2)
824
+
825
+ @patch.object(
826
+ GetProductCategoryNodesWithIntegrationAction,
827
+ 'get_category_node_integration_action'
828
+ )
829
+ def test_get_category_node_integration_action(
830
+ self,
831
+ mock_get_category_node_integration_action
832
+ ):
833
+ mock_get_category_node_integration_action.return_value = None
834
+ result = self.get_product_category_nodes.get_category_node_integration_action(
835
+ self.sample_products
836
+ )
837
+ self.assertIsNone(result)
838
+
839
+ @patch.object(BaseClient, 'get_instance')
840
+ @patch.object(ChannelIntegrationActionEndpoint, 'list')
841
+ def test_get_category_node_integration_action_with_products(
842
+ self,
843
+ mock_endpoint,
844
+ mock_get_instance
845
+ ):
846
+ integration_action_endpoint = MagicMock()
847
+ integration_action_endpoint.list.return_value = [
848
+ MagicMock(
849
+ channel=1,
850
+ object_id=1
851
+ ),
852
+ ]
853
+ integration_action_endpoint.iterator = [
854
+ [MagicMock(
855
+ channel=1,
856
+ object_id=1
857
+ )],
858
+ ]
859
+ mock_endpoint.return_value = integration_action_endpoint
860
+
861
+ with patch.object(
862
+ ChannelIntegrationActionEndpoint,
863
+ '__new__',
864
+ return_value=integration_action_endpoint,
865
+ channel_id=1
866
+ ):
867
+ result = self.get_product_category_nodes.get_category_node_integration_action(
868
+ self.sample_products
869
+ )
870
+
871
+ self.assertEqual(len(result), 2)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: channel-app
3
- Version: 0.0.135
3
+ Version: 0.0.137
4
4
  Summary: Channel app for Sales Channels
5
5
  Home-page: https://github.com/akinon/channel_app
6
6
  Author: akinonteam
@@ -5,7 +5,7 @@ with open("README.md") as f:
5
5
 
6
6
  setup(
7
7
  name="channel_app",
8
- version="0.0.135",
8
+ version="0.0.137",
9
9
  packages=find_packages(),
10
10
  url="https://github.com/akinon/channel_app",
11
11
  description="Channel app for Sales Channels",
File without changes
File without changes
File without changes
File without changes
File without changes