channel-app 0.0.148__tar.gz → 0.0.149__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 (95) hide show
  1. {channel_app-0.0.148 → channel_app-0.0.149}/.gitignore +2 -1
  2. {channel_app-0.0.148/channel_app.egg-info → channel_app-0.0.149}/PKG-INFO +1 -1
  3. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/order/service.py +205 -28
  4. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/channel/commands/orders/orders.py +129 -18
  5. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/channel/commands/setup.py +5 -0
  6. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/channel/integration.py +5 -3
  7. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/core/commands.py +25 -16
  8. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/core/data.py +19 -1
  9. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/core/settings.py +4 -2
  10. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/orders/addresses.py +5 -1
  11. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/orders/cargo_companies.py +2 -1
  12. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/orders/orders.py +133 -8
  13. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/tests/test_orders.py +112 -4
  14. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/constants.py +5 -0
  15. channel_app-0.0.149/channel_app/omnitron/exceptions.py +39 -0
  16. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/integration.py +4 -0
  17. {channel_app-0.0.148 → channel_app-0.0.149/channel_app.egg-info}/PKG-INFO +1 -1
  18. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app.egg-info/SOURCES.txt +0 -1
  19. channel_app-0.0.149/requirements-dev.txt +2 -0
  20. {channel_app-0.0.148 → channel_app-0.0.149}/requirements.txt +1 -0
  21. {channel_app-0.0.148 → channel_app-0.0.149}/setup.py +1 -1
  22. channel_app-0.0.148/channel_app/core/tests/test_clients.py +0 -164
  23. channel_app-0.0.148/channel_app/omnitron/exceptions.py +0 -42
  24. channel_app-0.0.148/requirements-dev.txt +0 -2
  25. {channel_app-0.0.148 → channel_app-0.0.149}/.vscode/settings.json +0 -0
  26. {channel_app-0.0.148 → channel_app-0.0.149}/Makefile +0 -0
  27. {channel_app-0.0.148 → channel_app-0.0.149}/Procfile-dist +0 -0
  28. {channel_app-0.0.148 → channel_app-0.0.149}/README.md +0 -0
  29. {channel_app-0.0.148 → channel_app-0.0.149}/akinon.json-dist +0 -0
  30. {channel_app-0.0.148 → channel_app-0.0.149}/bitbucket-pipelines.yml +0 -0
  31. {channel_app-0.0.148 → channel_app-0.0.149}/build.sh-dist +0 -0
  32. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/__init__.py +0 -0
  33. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/__init__.py +0 -0
  34. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/order/__init__.py +0 -0
  35. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/product/__init__.py +0 -0
  36. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/product/service.py +0 -0
  37. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/product_image/__init__.py +0 -0
  38. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/product_image/service.py +0 -0
  39. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/product_price/__init__.py +0 -0
  40. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/product_price/service.py +0 -0
  41. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/product_stock/__init__.py +0 -0
  42. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/product_stock/service.py +0 -0
  43. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/setup/__init__.py +0 -0
  44. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/app/setup/service.py +0 -0
  45. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/channel/__init__.py +0 -0
  46. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/channel/commands/__init__.py +0 -0
  47. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/channel/commands/orders/__init__.py +0 -0
  48. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/channel/commands/product_categories.py +0 -0
  49. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/channel/commands/product_images.py +0 -0
  50. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/channel/commands/product_prices.py +0 -0
  51. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/channel/commands/product_stocks.py +0 -0
  52. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/channel/commands/products.py +0 -0
  53. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/core/__init__.py +0 -0
  54. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/core/clients.py +0 -0
  55. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/core/integration.py +0 -0
  56. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/core/products.py +0 -0
  57. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/core/tests.py +0 -0
  58. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/core/utilities.py +0 -0
  59. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/__init__.py +0 -0
  60. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/batch_request.py +0 -0
  61. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/__init__.py +0 -0
  62. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/batch_requests.py +0 -0
  63. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/error_reports.py +0 -0
  64. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/integration_actions.py +0 -0
  65. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/orders/__init__.py +0 -0
  66. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/orders/customers.py +0 -0
  67. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/product_categories.py +0 -0
  68. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/product_images.py +0 -0
  69. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/product_prices.py +0 -0
  70. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/product_stocks.py +0 -0
  71. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/products.py +0 -0
  72. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/setup.py +0 -0
  73. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/tests/__init__.py +0 -0
  74. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/tests/test_product_images.py +0 -0
  75. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/tests/test_product_prices.py +0 -0
  76. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/tests/test_product_stocks.py +0 -0
  77. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app/omnitron/commands/tests/test_products.py +0 -0
  78. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app.egg-info/dependency_links.txt +0 -0
  79. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app.egg-info/requires.txt +0 -0
  80. {channel_app-0.0.148 → channel_app-0.0.149}/channel_app.egg-info/top_level.txt +0 -0
  81. {channel_app-0.0.148 → channel_app-0.0.149}/docs/Makefile +0 -0
  82. {channel_app-0.0.148 → channel_app-0.0.149}/docs/make.bat +0 -0
  83. {channel_app-0.0.148 → channel_app-0.0.149}/docs/requirements.txt +0 -0
  84. {channel_app-0.0.148 → channel_app-0.0.149}/docs/source/architecture.rst +0 -0
  85. {channel_app-0.0.148 → channel_app-0.0.149}/docs/source/command_reference.rst +0 -0
  86. {channel_app-0.0.148 → channel_app-0.0.149}/docs/source/conf.py +0 -0
  87. {channel_app-0.0.148 → channel_app-0.0.149}/docs/source/flows.rst +0 -0
  88. {channel_app-0.0.148 → channel_app-0.0.149}/docs/source/images/async.png +0 -0
  89. {channel_app-0.0.148 → channel_app-0.0.149}/docs/source/images/batch_request_state_machine.png +0 -0
  90. {channel_app-0.0.148 → channel_app-0.0.149}/docs/source/images/sync.png +0 -0
  91. {channel_app-0.0.148 → channel_app-0.0.149}/docs/source/index.rst +0 -0
  92. {channel_app-0.0.148 → channel_app-0.0.149}/docs/source/installation_and_usage.rst +0 -0
  93. {channel_app-0.0.148 → channel_app-0.0.149}/docs/source/terminology.rst +0 -0
  94. {channel_app-0.0.148 → channel_app-0.0.149}/setup.cfg +0 -0
  95. {channel_app-0.0.148 → channel_app-0.0.149}/tox.ini +0 -0
@@ -83,4 +83,5 @@ coverage.xml
83
83
  *.py,cover
84
84
  .hypothesis/
85
85
  .pytest_cache/
86
- cover/
86
+ cover/
87
+ venv/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: channel_app
3
- Version: 0.0.148
3
+ Version: 0.0.149
4
4
  Summary: Channel app for Sales Channels
5
5
  Home-page: https://github.com/akinon/channel_app
6
6
  Author: akinonteam
@@ -1,18 +1,27 @@
1
1
  from dataclasses import asdict
2
2
  from typing import List, Generator, Union
3
3
 
4
+ from requests import exceptions as requests_exceptions
5
+
4
6
  from omnisdk.omnitron.models import (Customer, Address, CargoCompany, Order,
5
- BatchRequest)
7
+ BatchRequest, CancellationRequest)
8
+ from omnisdk.omnitron.endpoints import ChannelIntegrationActionEndpoint
6
9
 
7
10
  from channel_app.core import settings
8
- from channel_app.core.data import (OmnitronCreateOrderDto, OmnitronOrderDto,
11
+ from channel_app.core.data import (BatchRequestResponseDto,
12
+ CancellationRequestDto,
13
+ ChannelCancellationRequestDto,
14
+ OmnitronCreateOrderDto,
15
+ OmnitronOrderDto,
9
16
  ChannelCreateOrderDto,
10
17
  ErrorReportDto,
11
- OrderBatchRequestResponseDto, CancelOrderDto,
18
+ OrderBatchRequestResponseDto,
19
+ CancelOrderDto,
12
20
  ChannelUpdateOrderItemDto)
13
21
  from channel_app.core.settings import OmnitronIntegration, ChannelIntegration
14
22
  from channel_app.omnitron.batch_request import ClientBatchRequest
15
- from channel_app.omnitron.constants import ContentType
23
+ from channel_app.omnitron.constants import (BatchRequestStatus, ContentType,
24
+ FailedReasonType)
16
25
  from channel_app.omnitron.exceptions import (CityException,
17
26
  TownshipException,
18
27
  DistrictException,
@@ -35,21 +44,21 @@ class OrderService(object):
35
44
  order_batch_objects = []
36
45
  while True:
37
46
  try:
38
- channel_create_order, report, _ = next(get_orders)
47
+ channel_create_order, report_list, _ = next(get_orders)
39
48
  except StopIteration:
40
49
  break
41
50
 
42
51
  # tips
43
52
  channel_create_order: ChannelCreateOrderDto
44
- report: ErrorReportDto
45
-
46
- if report and (is_success_log or not report.is_ok):
47
- report.error_code = \
48
- f"{omnitron_integration.batch_request.local_batch_id}" \
49
- f"_GetOrders_{channel_create_order.order.number}"
50
- omnitron_integration.do_action(
51
- key='create_error_report',
52
- objects=report)
53
+ report_list: List[ErrorReportDto]
54
+ for report in report_list:
55
+ if is_success_log or not report.is_ok:
56
+ report.error_code = \
57
+ f"{omnitron_integration.batch_request.local_batch_id}" \
58
+ f"-Channel-GetOrders_{channel_create_order.order.number}"
59
+ omnitron_integration.do_action(
60
+ key='create_error_report',
61
+ objects=report)
53
62
 
54
63
  order = self.create_order(omnitron_integration=omnitron_integration,
55
64
  channel_order=channel_create_order)
@@ -57,10 +66,15 @@ class OrderService(object):
57
66
  order_batch_objects.extend(omnitron_integration.batch_request.objects)
58
67
 
59
68
  omnitron_integration.batch_request.objects = order_batch_objects
60
-
61
- self.batch_service(settings.OMNITRON_CHANNEL_ID).to_done(
62
- batch_request=omnitron_integration.batch_request
63
- )
69
+ try:
70
+ self.batch_service(settings.OMNITRON_CHANNEL_ID).to_done(
71
+ batch_request=omnitron_integration.batch_request
72
+ )
73
+ except requests_exceptions.HTTPError as exc:
74
+ if exc.response.status_code == 406 and "batch_request_status_100_1" in exc.response.text:
75
+ pass
76
+ else:
77
+ raise exc
64
78
 
65
79
  def create_order(self, omnitron_integration: OmnitronIntegration,
66
80
  channel_order: ChannelCreateOrderDto
@@ -144,21 +158,21 @@ class OrderService(object):
144
158
  order_batch_objects = []
145
159
  while True:
146
160
  try:
147
- channel_update_order, report, _ = next(get_updated_orders)
161
+ channel_update_order, report_list, _ = next(get_updated_orders)
148
162
  except StopIteration:
149
163
  break
150
164
 
151
165
  # tips
152
166
  channel_update_order: ChannelUpdateOrderItemDto
153
- report: ErrorReportDto
154
-
155
- if report and (is_success_log or not report.is_ok):
156
- report.error_code = \
157
- f"{omnitron_integration.batch_request.local_batch_id}" \
158
- f"_GetUpdatedOrders_{channel_update_order.remote_id}"
159
- omnitron_integration.do_action(
160
- key='create_error_report',
161
- objects=report)
167
+ report_list: List[ErrorReportDto]
168
+ for report in report_list:
169
+ if report and (is_success_log or not report.is_ok):
170
+ report.error_code = \
171
+ f"{omnitron_integration.batch_request.local_batch_id}" \
172
+ f"_GetUpdatedOrders_{channel_update_order.remote_id}"
173
+ omnitron_integration.do_action(
174
+ key='create_error_report',
175
+ objects=report)
162
176
 
163
177
  omnitron_integration.do_action(
164
178
  key='update_order_items', objects=channel_update_order)
@@ -288,3 +302,166 @@ class OrderService(object):
288
302
  return success_data
289
303
  except IndexError:
290
304
  return
305
+
306
+ def fetch_and_create_cancellation_requests(self, is_success_log=True):
307
+ with OmnitronIntegration(
308
+ content_type=ContentType.cancellation_request.value) as omnitron_integration:
309
+ get_cancellation_requests = ChannelIntegration().do_action(
310
+ key='get_cancellation_requests',
311
+ batch_request=omnitron_integration.batch_request)
312
+ get_cancellation_requests: Generator
313
+ while True:
314
+ try:
315
+ cancellation_request, report_list, _ = next(get_cancellation_requests)
316
+ except StopIteration:
317
+ break
318
+
319
+ # tips
320
+ cancellation_request: CancellationRequestDto
321
+ report_list: List[ErrorReportDto]
322
+ for report in report_list:
323
+ if report and (is_success_log or not report.is_ok):
324
+ report.error_code = \
325
+ f"{omnitron_integration.batch_request.local_batch_id}" \
326
+ f"-Channel-GetCancellationRequests_{cancellation_request.order_item}"
327
+ omnitron_integration.do_action(
328
+ key='create_error_report',
329
+ objects=report)
330
+
331
+ # omnitron integration do action create_cancellation_request
332
+ cancellation_request_response = omnitron_integration.do_action(
333
+ key='create_cancellation_requests',
334
+ objects=cancellation_request)
335
+ try:
336
+ self.batch_service(settings.OMNITRON_CHANNEL_ID).to_done(
337
+ batch_request=omnitron_integration.batch_request
338
+ )
339
+ except requests_exceptions.HTTPError as exc:
340
+ if exc.response.status_code == 406 and "batch_request_status_100_1" in exc.response.text:
341
+ pass
342
+ else:
343
+ raise exc
344
+
345
+
346
+
347
+
348
+ def update_cancellation_requests(self, is_success_log=True):
349
+ with OmnitronIntegration(
350
+ content_type=ContentType.cancellation_request.value) as omnitron_integration:
351
+ cancellation_requests = omnitron_integration.do_action(
352
+ key='get_cancellation_requests_update', objects={})
353
+ cancellation_requests: List[CancellationRequest]
354
+
355
+ if not cancellation_requests:
356
+ omnitron_integration.batch_request.objects = None
357
+ self.batch_service(omnitron_integration.channel_id).to_fail(
358
+ omnitron_integration.batch_request)
359
+ return
360
+
361
+ batch_request_object_list = []
362
+
363
+ for cancellation_request in cancellation_requests:
364
+ remote_order_item = self.get_channel_order_item(
365
+ omnitron_integration, cancellation_request.order_item)
366
+ remote_reason = self.get_channel_reason(
367
+ omnitron_integration, cancellation_request.reason)
368
+ remote_cancellation_request = self.get_channel_cancellation_request(
369
+ omnitron_integration, cancellation_request.id)
370
+
371
+ channel_cancellation_request = ChannelCancellationRequestDto(
372
+ cancellation_type=cancellation_request.cancellation_type,
373
+ status=cancellation_request.status,
374
+ order_item=remote_order_item,
375
+ reason=remote_reason,
376
+ description=cancellation_request.description,
377
+ remote_id=remote_cancellation_request,
378
+ )
379
+ response_data, reports, data = ChannelIntegration().do_action(
380
+ key='update_cancellation_request',
381
+ objects=channel_cancellation_request,
382
+ batch_request=omnitron_integration.batch_request,
383
+ is_sync=True)
384
+
385
+ # tips
386
+ response_data: List[BatchRequestResponseDto]
387
+ reports: List[ErrorReportDto]
388
+ data: List[ChannelCancellationRequestDto]
389
+
390
+ if reports and (is_success_log or not reports[0].is_ok):
391
+ for report in reports:
392
+ omnitron_integration.do_action(
393
+ key='create_error_report',
394
+ objects=report)
395
+
396
+ if response_data:
397
+ failed_reason_type = None
398
+ else:
399
+ failed_reason_type = FailedReasonType.remote.value
400
+
401
+ batch_request_object_dto = dict(
402
+ pk=cancellation_request.id,
403
+ version_date=cancellation_request.modified_date,
404
+ content_type=ContentType.cancellation_request.value,
405
+ failed_reason_type=failed_reason_type,
406
+ remote_id=remote_cancellation_request)
407
+
408
+ batch_request_object_list.append(batch_request_object_dto)
409
+
410
+ status = BatchRequestStatus.fail.value
411
+ if any([br["failed_reason_type"] is None for br in batch_request_object_list]):
412
+ status = BatchRequestStatus.done.value
413
+
414
+ omnitron_integration.batch_request.objects = batch_request_object_list
415
+ service = self.batch_service(omnitron_integration.channel_id)
416
+
417
+ if status == BatchRequestStatus.done.value:
418
+ service.to_done(batch_request=omnitron_integration.batch_request)
419
+ else:
420
+ service.to_fail(batch_request=omnitron_integration.batch_request)
421
+
422
+ def get_channel_order_item(self, omnitron_integration, order_item):
423
+ channel_id = omnitron_integration.channel_id
424
+ end_point = ChannelIntegrationActionEndpoint(
425
+ channel_id=channel_id)
426
+ params = {
427
+ "channel": channel_id,
428
+ "content_type_name": ContentType.order_item.value,
429
+ "object_id": order_item
430
+ }
431
+ integration_action = end_point.list(params=params)
432
+ if not integration_action:
433
+ return Exception("Order item remote id not found: {}".format(order_item))
434
+ if len(integration_action) > 1:
435
+ return Exception("Multiple order item remote id found: {}".format(order_item))
436
+ return integration_action[0].remote_id
437
+
438
+ def get_channel_reason(self, omnitron_integration, omnitron_reason):
439
+ configuration = omnitron_integration.channel.conf
440
+ # configuration icinde yer alan reason_mapping anahtari bir json objesi,
441
+ # key channel_reason value omnitron_reason olan bir dict objesinden
442
+ # channel_reason'u döndürür
443
+ for channel_reason, omnitron_reason in configuration.get("reason_mapping", {}):
444
+ if omnitron_reason == omnitron_reason:
445
+ return channel_reason
446
+
447
+ return "10"
448
+
449
+ def get_channel_cancellation_request(self, omnitron_integration,
450
+ omnitron_cancel_request_pk):
451
+ channel_id = omnitron_integration.channel_id
452
+ end_point = ChannelIntegrationActionEndpoint(
453
+ channel_id=channel_id)
454
+ params = {
455
+ "channel": channel_id,
456
+ "content_type_name": ContentType.cancellation_request.value,
457
+ "object_id": omnitron_cancel_request_pk
458
+ }
459
+ integration_action = end_point.list(params=params)
460
+ if not integration_action:
461
+ return Exception("Cancellation request remote id not found: {}".format(
462
+ omnitron_cancel_request_pk))
463
+ if len(integration_action) > 1:
464
+ return Exception("Multiple cancellation request remote id found: {}".format(
465
+ omnitron_cancel_request_pk))
466
+ return integration_action[0].remote_id
467
+
@@ -5,9 +5,13 @@ from typing import Tuple, Any, List
5
5
  from omnisdk.omnitron.models import Order, BatchRequest
6
6
 
7
7
  from channel_app.core.commands import ChannelCommandInterface
8
- from channel_app.core.data import (ErrorReportDto, ChannelCreateOrderDto,
9
- AddressDto, CustomerDto, ChannelOrderDto,
10
- OrderItemDto, OrderBatchRequestResponseDto,
8
+ from channel_app.core.data import (BatchRequestResponseDto,
9
+ CancellationRequestDto,
10
+ ChannelCancellationRequestDto,
11
+ ErrorReportDto,
12
+ ChannelCreateOrderDto, AddressDto,
13
+ CustomerDto, ChannelOrderDto, OrderItemDto,
14
+ OrderBatchRequestResponseDto,
11
15
  CancelOrderDto, ChannelUpdateOrderItemDto)
12
16
  from channel_app.omnitron.constants import ResponseStatus
13
17
 
@@ -72,17 +76,19 @@ class GetOrders(ChannelCommandInterface):
72
76
  yield channel_create_order, report, None
73
77
 
74
78
  def __mocked_request(self, data):
79
+ number = str(int(random() * 1000000))
75
80
  return [{
76
81
  "order": {
77
- "remote_id": "123131",
78
- "number": "12331",
82
+ "status": "400",
83
+ "remote_id": number,
84
+ "number": number,
79
85
  "channel": "1",
80
86
  "currency": "try",
81
87
  "amount": "17",
82
88
  "shipping_amount": "0.0",
83
89
  "shipping_tax_rate": "18",
84
90
  "extra_field": {},
85
- "created_at": datetime.datetime.now(),
91
+ "created_at": str(datetime.datetime.now()),
86
92
  "customer": {
87
93
  "email": "dummy@dummy.com",
88
94
  "phone_number": None,
@@ -110,11 +116,11 @@ class GetOrders(ChannelCommandInterface):
110
116
  "city": "İstanbul",
111
117
  "line": "dummy 3 dummy cd"
112
118
  },
113
- "cargo_company": "aras kargo"
119
+ "cargo_company": "aras"
114
120
  },
115
121
  "order_items": [
116
122
  {
117
- "remote_id": "1234",
123
+ "remote_id": "1234567816",
118
124
  "product": "1234",
119
125
  "price_currency": "try",
120
126
  "price": "17.0",
@@ -351,21 +357,126 @@ class GetUpdatedOrderItems(ChannelCommandInterface):
351
357
  """
352
358
  Convert ChannelUpdateOrderItemDto to the format OmnitronIntegration
353
359
  """
354
- for response_order_data in response:
355
- order_items_data = response_order_data["order_items"]
356
-
357
- report = self.create_report(response_order_data)
358
- for order_item_data in order_items_data:
359
- channel_update_order_item = ChannelUpdateOrderItemDto(
360
- **order_item_data)
360
+ for order_item_data in response:
361
+ report = self.create_report(order_item_data)
362
+ channel_update_order_item = ChannelUpdateOrderItemDto(
363
+ **order_item_data)
361
364
 
362
- yield channel_update_order_item, report, None
365
+ yield channel_update_order_item, report, None
363
366
 
364
367
  def __mocked_request(self, data):
365
- return {
368
+ return [{
366
369
  "remote_id": "XYAD123213",
370
+ "order_remote_id": "1234",
371
+ "order_number": "1234",
367
372
  "status": "550",
368
373
  "invoice_number": "1234",
369
374
  "invoice_date": None,
370
- "tracking_number": "400"
375
+ "tracking_number": "400",
376
+ "extra_field": {"tracking_number": "1231"},
377
+ }]
378
+
379
+
380
+ class GetCancellationRequests(ChannelCommandInterface):
381
+ def get_data(self):
382
+ data = self.objects
383
+ return data
384
+
385
+ def validated_data(self, data) -> object:
386
+ return data
387
+
388
+ def transform_data(self, data) -> object:
389
+ return data
390
+
391
+ def send_request(self, transformed_data) -> object:
392
+ response = self.__mocked_request(data=transformed_data)
393
+ return response
394
+
395
+ def normalize_response(
396
+ self, data, validated_data, transformed_data,
397
+ response) -> Tuple[CancellationRequestDto, ErrorReportDto, Any]:
398
+ report = self.create_report(response)
399
+ for row in response:
400
+ obj = CancellationRequestDto(
401
+ order_item=row["order_item"],
402
+ reason=row["reason"],
403
+ cancellation_type=row["cancellation_type"],
404
+ remote_id=row["remote_id"]
405
+ )
406
+
407
+ yield obj, report, data
408
+
409
+ def __mocked_request(self, data):
410
+ """
411
+ Mock a request and response for the send operation to mimic actual
412
+ channel data
413
+
414
+ :return:
415
+
416
+ [{
417
+ "order_item": "remote_item_1",
418
+ "reason": "remote_reason_code",
419
+ "cancellation_type": "remote_cancellation_type"
420
+ },]
421
+ """
422
+ response_data = [
423
+ {
424
+ 'order_item': "1234567816",
425
+ 'reason': "iptal",
426
+ 'cancellation_type': "refund",
427
+ 'remote_id': "1234567816_1"
428
+ }
429
+ ]
430
+ return response_data
431
+
432
+
433
+ class UpdateCancellationRequest(ChannelCommandInterface):
434
+ def get_data(self) -> ChannelCancellationRequestDto:
435
+ isinstance(self.objects, ChannelCancellationRequestDto)
436
+ data = self.objects
437
+ return data
438
+
439
+ def validated_data(self, data) -> object:
440
+ return data
441
+
442
+ def transform_data(self, data) -> object:
443
+ return data
444
+
445
+ def send_request(self, transformed_data) -> object:
446
+ response = self.__mocked_request(data=transformed_data)
447
+ return response
448
+
449
+ def normalize_response(
450
+ self, data, validated_data, transformed_data,
451
+ response) -> Tuple[BatchRequestResponseDto, ErrorReportDto, Any]:
452
+
453
+ obj = BatchRequestResponseDto(
454
+ status=response["status"],
455
+ remote_id=response["remote_id"],
456
+ sku=response["sku"],
457
+ message=response["message"])
458
+
459
+ report = self.create_report(response)
460
+ return obj, report, data
461
+
462
+ def __mocked_request(self, data):
463
+ """
464
+ Mock a request and response for the send operation to mimic actual
465
+ channel data
466
+
467
+ :return:
468
+
469
+ {
470
+ "status": "SUCCESS",
471
+ "remote_id": "123a1",
472
+ "sku": "1234567",
473
+ "message": ""
474
+ }
475
+ """
476
+ return {
477
+ "status": ResponseStatus.success,
478
+ "remote_id": data.remote_id,
479
+ "sku": data.remote_id,
480
+ "message": data.status
371
481
  }
482
+
@@ -1006,6 +1006,11 @@ class GetChannelConfSchema(ChannelCommandInterface):
1006
1006
  data_type=ChannelConfSchemaDataTypes.text,
1007
1007
  key="setting_name_2",
1008
1008
  label="setting_name_2"),
1009
+ "reason_mapping": ChannelConfSchemaField(
1010
+ required=True,
1011
+ data_type=ChannelConfSchemaDataTypes.json,
1012
+ key="reason_mapping",
1013
+ label="reason_mapping"),
1009
1014
  }
1010
1015
 
1011
1016
  return schema, None, None
@@ -1,8 +1,8 @@
1
1
  import requests
2
2
 
3
3
  from channel_app.channel.commands.orders.orders import (
4
- GetOrders, CheckOrders, SendUpdatedOrders, GetCancelledOrders,
5
- GetUpdatedOrderItems)
4
+ GetCancellationRequests, GetOrders, CheckOrders, SendUpdatedOrders,
5
+ GetCancelledOrders, GetUpdatedOrderItems, UpdateCancellationRequest)
6
6
  from channel_app.channel.commands.product_images import (
7
7
  SendUpdatedImages, SendInsertedImages, CheckImages)
8
8
  from channel_app.channel.commands.product_prices import (
@@ -49,7 +49,9 @@ class ChannelIntegration(BaseIntegration):
49
49
  "get_updated_order_items": GetUpdatedOrderItems,
50
50
  "send_updated_orders": SendUpdatedOrders,
51
51
  "check_orders": CheckOrders,
52
- "get_cancelled_orders": GetCancelledOrders
52
+ "get_cancelled_orders": GetCancelledOrders,
53
+ "get_cancellation_requests": GetCancellationRequests,
54
+ "update_cancellation_request": UpdateCancellationRequest,
53
55
  }
54
56
 
55
57
  def __init__(self):
@@ -11,7 +11,7 @@ from channel_app.core.data import ErrorReportDto
11
11
  from channel_app.core.integration import BaseIntegration
12
12
  from channel_app.omnitron.batch_request import ClientBatchRequest
13
13
  from channel_app.omnitron.constants import BatchRequestStatus, ContentType
14
- from channel_app.omnitron.exceptions import (CountryException, CityException,
14
+ from channel_app.omnitron.exceptions import (AppException, CityException,
15
15
  TownshipException,
16
16
  DistrictException)
17
17
 
@@ -106,17 +106,24 @@ class ChannelCommandInterface(CommandInterface):
106
106
  if not self.is_batch_request:
107
107
  return
108
108
  name = self.__class__.__name__
109
+ if isinstance(response, Response):
110
+ raw_request = f"{response.request.method}-"
111
+ f"{response.request.url}-"
112
+ f"{response.request.body}"
113
+ raw_response = response.text
114
+ else:
115
+ raw_request = str("")
116
+ raw_response = str(response)
117
+
109
118
  report_list = []
110
119
  report = ErrorReportDto(
111
120
  action_content_type=ContentType.batch_request.value,
112
121
  action_object_id=self.batch_request.pk,
113
122
  modified_date=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
114
- error_code=f"{self.batch_request.local_batch_id}-{name}-{datetime.now().timestamp()}",
115
- error_description=f"{self.batch_request.local_batch_id}-{name}",
116
- raw_request=f"{response.request.method}-"
117
- f"{response.request.url}-"
118
- f"{response.request.body}",
119
- raw_response=f"{response.text}"
123
+ error_code=f"{self.batch_request.local_batch_id}-Channel-{name}-{datetime.now().timestamp()}",
124
+ error_description=f"{name}",
125
+ raw_request=raw_request,
126
+ raw_response=raw_response
120
127
  )
121
128
  is_ok = self.check_response_is_ok(response=response)
122
129
  if is_ok:
@@ -130,7 +137,7 @@ class ChannelCommandInterface(CommandInterface):
130
137
  action_object_id=failed_obj[0].pk,
131
138
  modified_date=failed_obj[0].modified_date,
132
139
  error_code=f"{self.batch_request.local_batch_id}-{name}-{datetime.now().timestamp()}",
133
- error_description=f"{self.batch_request.local_batch_id}-{name}",
140
+ error_description=f"{name}",
134
141
  raw_request="",
135
142
  raw_response=f"{failed_obj[0].failed_reason_type}-{failed_obj[2]}",
136
143
  is_ok=False
@@ -139,7 +146,10 @@ class ChannelCommandInterface(CommandInterface):
139
146
  return report_list
140
147
 
141
148
  def check_response_is_ok(self, response):
142
- if str(response.status_code).startswith("2"):
149
+ is_response_obj = isinstance(response, Response)
150
+ if is_response_obj and str(response.status_code).startswith("2"):
151
+ return True
152
+ elif not is_response_obj and response:
143
153
  return True
144
154
  return False
145
155
 
@@ -209,15 +219,15 @@ class OmnitronCommandInterface(CommandInterface):
209
219
  raw_response = e.response.text
210
220
  is_ok = False
211
221
  logger.error(f"{raw_request}-/-{raw_response}")
212
- except CountryException as e:
213
- is_ok = False
214
- raw_response = str(e.params)
215
222
  except (CityException, TownshipException, DistrictException) as e:
216
223
  is_ok = False
217
224
  self.integration.do_action(
218
225
  key='create_address_error_report',
219
226
  objects=e.params)
220
227
  raw_response = str(e.params)
228
+ except AppException as e:
229
+ is_ok = False
230
+ raw_response = str(e.params)
221
231
  except Exception as e:
222
232
  is_ok = False
223
233
  raw_response = f"{str(e)} - {traceback.format_exc()}"
@@ -225,7 +235,6 @@ class OmnitronCommandInterface(CommandInterface):
225
235
  if request:
226
236
  raw_request = f"{request.method} - {request.url} - {request.body}"
227
237
  logger.error(f"{raw_request}-/-{raw_response}")
228
-
229
238
  finally:
230
239
  if not is_ok:
231
240
  self.send_error_report(raw_request, raw_response)
@@ -258,8 +267,8 @@ class OmnitronCommandInterface(CommandInterface):
258
267
  action_content_type=failed_obj[1],
259
268
  action_object_id=failed_obj[0].pk,
260
269
  modified_date=failed_obj[0].modified_date,
261
- error_code=f"{self.integration.batch_request.local_batch_id}-{name}",
262
- error_description=f"{self.integration.batch_request.local_batch_id}-{name}",
270
+ error_code=f"{self.integration.batch_request.local_batch_id}-Omnitron-{name}",
271
+ error_description=f"Omnitron-{name}",
263
272
  raw_request="",
264
273
  raw_response=f"{failed_obj[0].failed_reason_type}-{failed_obj[2]}",
265
274
  is_ok=False
@@ -278,7 +287,7 @@ class OmnitronCommandInterface(CommandInterface):
278
287
  action_object_id=self.integration.batch_request.pk,
279
288
  modified_date=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
280
289
  error_code=f"{self.integration.batch_request.local_batch_id}-{name}-{datetime.now().microsecond}",
281
- error_description=f"{self.integration.batch_request.local_batch_id}-{name}",
290
+ error_description=f"Omnitron-{name}",
282
291
  raw_request=raw_request,
283
292
  raw_response=raw_response
284
293
  )
@@ -3,7 +3,7 @@ from dataclasses import dataclass
3
3
  from decimal import Decimal
4
4
  from typing import List, Optional
5
5
 
6
- from channel_app.omnitron.constants import ResponseStatus, \
6
+ from channel_app.omnitron.constants import CancellationType, ResponseStatus, \
7
7
  ChannelConfSchemaDataTypes
8
8
 
9
9
 
@@ -194,6 +194,14 @@ class CancelOrderDto:
194
194
  refund_invoice_number: Optional[str] = None
195
195
 
196
196
 
197
+ @dataclass
198
+ class CancellationRequestDto:
199
+ order_item: str # remote item number
200
+ reason: str # reason code
201
+ remote_id: str
202
+ cancellation_type: Optional[str] = "cancel"
203
+
204
+
197
205
  @dataclass
198
206
  class CustomerDto:
199
207
  email: str # "john.doe@akinon.com"
@@ -254,3 +262,13 @@ class ChannelUpdateOrderItemDto:
254
262
  invoice_date: Optional[str] = None
255
263
  tracking_number: Optional[str] = None
256
264
  extra_field: Optional[dict] = None
265
+
266
+
267
+ @dataclass
268
+ class ChannelCancellationRequestDto:
269
+ cancellation_type: CancellationType # cancel, refund
270
+ status: str # confirmed, waiting_approval, approved, rejected, completed
271
+ order_item: str # omnitron order item remote id
272
+ reason: str # omnitron reason code
273
+ description: Optional[str] # description for refund
274
+ remote_id: Optional[str] # remote id for cancellation request