mpt-extension-sdk 4.0.2__py3-none-any.whl → 4.0.3__py3-none-any.whl
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.
- mpt_extension_sdk/flows/__init__.py +0 -0
- mpt_extension_sdk/flows/context.py +39 -0
- mpt_extension_sdk/flows/pipeline.py +51 -0
- mpt_extension_sdk/mpt_http/mpt.py +7 -0
- mpt_extension_sdk/mpt_http/utils.py +2 -0
- mpt_extension_sdk/mpt_http/wrap_http_error.py +6 -0
- mpt_extension_sdk/runtime/events/producers.py +17 -2
- mpt_extension_sdk/runtime/events/utils.py +15 -0
- mpt_extension_sdk/runtime/initializer.py +3 -3
- mpt_extension_sdk/runtime/utils.py +4 -12
- {mpt_extension_sdk-4.0.2.dist-info → mpt_extension_sdk-4.0.3.dist-info}/METADATA +1 -1
- {mpt_extension_sdk-4.0.2.dist-info → mpt_extension_sdk-4.0.3.dist-info}/RECORD +15 -11
- {mpt_extension_sdk-4.0.2.dist-info → mpt_extension_sdk-4.0.3.dist-info}/LICENSE +0 -0
- {mpt_extension_sdk-4.0.2.dist-info → mpt_extension_sdk-4.0.3.dist-info}/WHEEL +0 -0
- {mpt_extension_sdk-4.0.2.dist-info → mpt_extension_sdk-4.0.3.dist-info}/entry_points.txt +0 -0
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from dataclasses import asdict, dataclass
|
|
2
|
+
|
|
3
|
+
ORDER_TYPE_PURCHASE = "Purchase"
|
|
4
|
+
ORDER_TYPE_CHANGE = "Change"
|
|
5
|
+
ORDER_TYPE_TERMINATION = "Termination"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class Context:
|
|
10
|
+
order: dict
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def order_id(self):
|
|
14
|
+
return self.order.get("id", None)
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def order_type(self):
|
|
18
|
+
return self.order.get("type", None)
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def product_id(self):
|
|
22
|
+
return self.order.get("product", {}).get("id", None)
|
|
23
|
+
|
|
24
|
+
def is_purchase_order(self):
|
|
25
|
+
return self.order["type"] == ORDER_TYPE_PURCHASE
|
|
26
|
+
|
|
27
|
+
def is_change_order(self):
|
|
28
|
+
return self.order["type"] == ORDER_TYPE_CHANGE
|
|
29
|
+
|
|
30
|
+
def is_termination_order(self):
|
|
31
|
+
return self.order["type"] == ORDER_TYPE_TERMINATION
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def from_context(cls, context):
|
|
35
|
+
base_data = asdict(context)
|
|
36
|
+
return cls(**base_data)
|
|
37
|
+
|
|
38
|
+
def __str__(self):
|
|
39
|
+
return f"Context: {self.order.get("id", None)} {self.order.get("type", None)}"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Callable
|
|
3
|
+
|
|
4
|
+
from swo.mpt.client import MPTClient
|
|
5
|
+
from swo.mpt.extensions.flows.context import Context
|
|
6
|
+
|
|
7
|
+
NextStep = Callable[[MPTClient, Context], None]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Step(ABC):
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def __call__(
|
|
13
|
+
self,
|
|
14
|
+
client: MPTClient,
|
|
15
|
+
context: Context,
|
|
16
|
+
next_step: NextStep,
|
|
17
|
+
) -> None:
|
|
18
|
+
raise NotImplementedError() # pragma: no cover
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _default_error_handler(error: Exception, context: Context, next_step: NextStep):
|
|
22
|
+
raise error
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Cursor:
|
|
26
|
+
def __init__(self, steps, error_handler):
|
|
27
|
+
self.queue = steps
|
|
28
|
+
self.error_handler = error_handler
|
|
29
|
+
|
|
30
|
+
def __call__(self, client: MPTClient, context: Context):
|
|
31
|
+
if not self.queue:
|
|
32
|
+
return
|
|
33
|
+
current_step = self.queue[0]
|
|
34
|
+
next_step = Cursor(self.queue[1:], self.error_handler)
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
current_step(client, context, next_step)
|
|
38
|
+
except Exception as error:
|
|
39
|
+
self.error_handler(error, context, next_step)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Pipeline:
|
|
43
|
+
def __init__(self, *steps):
|
|
44
|
+
self.queue = steps
|
|
45
|
+
|
|
46
|
+
def run(self, client: MPTClient, context: Context, error_handler=None):
|
|
47
|
+
execute = Cursor(self.queue, error_handler or _default_error_handler)
|
|
48
|
+
return execute(client, context)
|
|
49
|
+
|
|
50
|
+
def __len__(self):
|
|
51
|
+
return len(self.queue)
|
|
@@ -367,3 +367,10 @@ def get_agreements_by_customer_deployments(
|
|
|
367
367
|
url = f"/commerce/agreements?{rql_query}"
|
|
368
368
|
|
|
369
369
|
return _paginated(mpt_client, url)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
@wrap_mpt_http_error
|
|
373
|
+
def get_buyer(mpt_client, buyer_id):
|
|
374
|
+
response = mpt_client.get(f"/accounts/buyers/{buyer_id}")
|
|
375
|
+
response.raise_for_status()
|
|
376
|
+
return response.json()
|
|
@@ -43,6 +43,10 @@ class EventProducer(ABC):
|
|
|
43
43
|
def produce_events(self):
|
|
44
44
|
pass
|
|
45
45
|
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def produce_events_with_context(self):
|
|
48
|
+
pass
|
|
49
|
+
|
|
46
50
|
|
|
47
51
|
class OrderEventProducer(EventProducer):
|
|
48
52
|
def __init__(self, dispatcher):
|
|
@@ -57,13 +61,24 @@ class OrderEventProducer(EventProducer):
|
|
|
57
61
|
for order in orders:
|
|
58
62
|
self.dispatcher.dispatch_event(Event(order["id"], "orders", order))
|
|
59
63
|
|
|
64
|
+
def produce_events_with_context(self):
|
|
65
|
+
while self.running:
|
|
66
|
+
with self.sleep(settings.MPT_ORDERS_API_POLLING_INTERVAL_SECS):
|
|
67
|
+
orders = self.get_processing_orders()
|
|
68
|
+
orders, contexts = self.filter_and_enrich(self.client, orders)
|
|
69
|
+
logger.info(f"{len(orders)} orders found for processing...")
|
|
70
|
+
for order, context in zip(orders, contexts):
|
|
71
|
+
self.dispatcher.dispatch_event(
|
|
72
|
+
Event(order["id"], "orders", order, context)
|
|
73
|
+
)
|
|
74
|
+
|
|
60
75
|
def get_processing_orders(self):
|
|
61
76
|
products = ",".join(settings.MPT_PRODUCTS_IDS)
|
|
62
77
|
orders = []
|
|
63
78
|
rql_query = f"and(in(agreement.product.id,({products})),eq(status,processing))"
|
|
64
79
|
url = (
|
|
65
|
-
f"/commerce/orders?{rql_query}"
|
|
66
|
-
"
|
|
80
|
+
f"/commerce/orders?{rql_query}&select=audit,parameters,lines,subscriptions,"
|
|
81
|
+
f"subscriptions.lines,agreement,buyer&order=audit.created.at"
|
|
67
82
|
)
|
|
68
83
|
page = None
|
|
69
84
|
limit = 10
|
|
@@ -12,6 +12,8 @@ from opentelemetry.instrumentation.requests import RequestsInstrumentor
|
|
|
12
12
|
from opentelemetry.sdk.trace import TracerProvider
|
|
13
13
|
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
14
14
|
|
|
15
|
+
from mpt_extension_sdk.flows.context import Context
|
|
16
|
+
|
|
15
17
|
logger = logging.getLogger(__name__)
|
|
16
18
|
|
|
17
19
|
|
|
@@ -68,3 +70,16 @@ def wrap_for_trace(func, event_type): # pragma: no cover
|
|
|
68
70
|
logger.exception("Unhandled exception!")
|
|
69
71
|
|
|
70
72
|
return opentelemetry_wrapper if settings.USE_APPLICATIONINSIGHTS else wrapper
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def setup_contexts(mpt_client, orders):
|
|
76
|
+
"""
|
|
77
|
+
List of contexts from orders
|
|
78
|
+
Args:
|
|
79
|
+
mpt_client (MPTClient): MPT client
|
|
80
|
+
orders (list): List of orders
|
|
81
|
+
|
|
82
|
+
Returns: List of contexts
|
|
83
|
+
|
|
84
|
+
"""
|
|
85
|
+
return [Context(order=order) for order in orders]
|
|
@@ -28,10 +28,10 @@ def initialize(options):
|
|
|
28
28
|
rich.reconfigure(theme=Theme({"repr.mpt_id": "bold light_salmon3"}))
|
|
29
29
|
group = options.get("app_config_group", DEFAULT_APP_CONFIG_GROUP)
|
|
30
30
|
name = options.get("app_config_name", DEFAULT_APP_CONFIG_NAME)
|
|
31
|
-
django_settings_module = options.get(
|
|
32
|
-
|
|
33
|
-
"DJANGO_SETTINGS_MODULE", django_settings_module
|
|
31
|
+
django_settings_module = options.get(
|
|
32
|
+
"django_settings_module", DJANGO_SETTINGS_MODULE
|
|
34
33
|
)
|
|
34
|
+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", django_settings_module)
|
|
35
35
|
import django
|
|
36
36
|
from django.conf import settings
|
|
37
37
|
|
|
@@ -15,8 +15,7 @@ from mpt_extension_sdk.constants import (
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def get_extension_app_config_name(
|
|
18
|
-
group=DEFAULT_APP_CONFIG_GROUP,
|
|
19
|
-
name=DEFAULT_APP_CONFIG_NAME
|
|
18
|
+
group=DEFAULT_APP_CONFIG_GROUP, name=DEFAULT_APP_CONFIG_NAME
|
|
20
19
|
):
|
|
21
20
|
eps = entry_points()
|
|
22
21
|
(app_config_ep,) = eps.select(group=group, name=name)
|
|
@@ -25,8 +24,7 @@ def get_extension_app_config_name(
|
|
|
25
24
|
|
|
26
25
|
|
|
27
26
|
def get_extension_app_config(
|
|
28
|
-
group=DEFAULT_APP_CONFIG_GROUP,
|
|
29
|
-
name=DEFAULT_APP_CONFIG_NAME
|
|
27
|
+
group=DEFAULT_APP_CONFIG_GROUP, name=DEFAULT_APP_CONFIG_NAME
|
|
30
28
|
):
|
|
31
29
|
app_config_name = get_extension_app_config_name(group=group, name=name)
|
|
32
30
|
return next(
|
|
@@ -39,17 +37,11 @@ def get_extension_app_config(
|
|
|
39
37
|
)
|
|
40
38
|
|
|
41
39
|
|
|
42
|
-
def get_extension(
|
|
43
|
-
group=DEFAULT_APP_CONFIG_GROUP,
|
|
44
|
-
name=DEFAULT_APP_CONFIG_NAME
|
|
45
|
-
):
|
|
40
|
+
def get_extension(group=DEFAULT_APP_CONFIG_GROUP, name=DEFAULT_APP_CONFIG_NAME):
|
|
46
41
|
return get_extension_app_config(group=group, name=name).extension
|
|
47
42
|
|
|
48
43
|
|
|
49
|
-
def get_events_registry(
|
|
50
|
-
group=DEFAULT_APP_CONFIG_GROUP,
|
|
51
|
-
name=DEFAULT_APP_CONFIG_NAME
|
|
52
|
-
):
|
|
44
|
+
def get_events_registry(group=DEFAULT_APP_CONFIG_GROUP, name=DEFAULT_APP_CONFIG_NAME):
|
|
53
45
|
return get_extension(group=group, name=name).events
|
|
54
46
|
|
|
55
47
|
|
|
@@ -8,10 +8,14 @@ mpt_extension_sdk/core/events/registry.py,sha256=RbiAem_FZk4W137xTILm0hRav46pII1
|
|
|
8
8
|
mpt_extension_sdk/core/extension.py,sha256=s0QE2s99RMywfKQRZrYqOdWxELQvlFFVZMwm0xo2hhw,266
|
|
9
9
|
mpt_extension_sdk/core/security.py,sha256=0eCed1cmaNK1rCpgnsN9zw6wzr4m_Qb9aKxscO0uyYk,1419
|
|
10
10
|
mpt_extension_sdk/core/utils.py,sha256=LsvciwlVBJCBbd7L1rIWrTo_8Fi-W_SkL6IEezKUb4s,362
|
|
11
|
+
mpt_extension_sdk/flows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
mpt_extension_sdk/flows/context.py,sha256=J_U9nTtY89mUvrcOqdgpk-21F8f6YENSmjxgpVK6XWs,964
|
|
13
|
+
mpt_extension_sdk/flows/pipeline.py,sha256=XOzxl2vRYr7TL3-XVuGvhOpQAvIC-9snsiseaaFHldc,1358
|
|
11
14
|
mpt_extension_sdk/mpt_http/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
15
|
mpt_extension_sdk/mpt_http/base.py,sha256=3qgo9BW-uTRAbex26urMvLZU0fwnYnBprDRIJCHvTOk,1284
|
|
13
|
-
mpt_extension_sdk/mpt_http/mpt.py,sha256=
|
|
14
|
-
mpt_extension_sdk/mpt_http/
|
|
16
|
+
mpt_extension_sdk/mpt_http/mpt.py,sha256=FatFnbAgyV42N2hJ14n09-WE3V1ioL-lYxuid6vd4Wo,10580
|
|
17
|
+
mpt_extension_sdk/mpt_http/utils.py,sha256=3wJTT84CXYGjZw6FksNDX8tIHijkL3Wcmld9r6Iz0xc,95
|
|
18
|
+
mpt_extension_sdk/mpt_http/wrap_http_error.py,sha256=j8K6Ddx7NiM-FPRMQi25vuULAW8LXxzZ4EwuIJufxis,1801
|
|
15
19
|
mpt_extension_sdk/runtime/__init__.py,sha256=PQSAz9qvXHbxrn4KvuXSHB8y-A4Jpgbm6ZV-wPiNPyw,194
|
|
16
20
|
mpt_extension_sdk/runtime/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
21
|
mpt_extension_sdk/runtime/commands/django.py,sha256=VHszc3KctzSkhewAqbQMkRBG7cuMPWxzn7dHrRGm8y8,892
|
|
@@ -26,16 +30,16 @@ mpt_extension_sdk/runtime/djapp/management/commands/consume_events.py,sha256=r5a
|
|
|
26
30
|
mpt_extension_sdk/runtime/djapp/middleware.py,sha256=MES6-bK64pX1B1XGXC3nGPzPSld6xrQfmF1vYQv2Eeg,535
|
|
27
31
|
mpt_extension_sdk/runtime/events/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
32
|
mpt_extension_sdk/runtime/events/dispatcher.py,sha256=GYICBuA9bO38TgDk0FKS_Z9D-8YB-tmNf4O_pUxuomc,2801
|
|
29
|
-
mpt_extension_sdk/runtime/events/producers.py,sha256=
|
|
30
|
-
mpt_extension_sdk/runtime/events/utils.py,sha256=
|
|
31
|
-
mpt_extension_sdk/runtime/initializer.py,sha256=
|
|
33
|
+
mpt_extension_sdk/runtime/events/producers.py,sha256=EiR3MgwEw6Z5cwMh4xBo9JBsd4oSEYi0U1iNYNxK7P4,3551
|
|
34
|
+
mpt_extension_sdk/runtime/events/utils.py,sha256=bxFo-iQUqEJDqcIotC88Ty3Xt0K2FyYjA9UMWFEyMKI,2663
|
|
35
|
+
mpt_extension_sdk/runtime/initializer.py,sha256=3gX9OAeTp2lsgsP0h3HVzkEUvCTa9fBIsBGVo7E6JFY,2229
|
|
32
36
|
mpt_extension_sdk/runtime/logging.py,sha256=wJ6KyvnuvMZELI1Hd0fYbuHr7YiP3GIXFBvvSdmd7nQ,885
|
|
33
37
|
mpt_extension_sdk/runtime/master.py,sha256=oBI3WHpf2YkTRsRyT1SFIyvCM7gGQpbtXvI1lYe6-jg,4390
|
|
34
38
|
mpt_extension_sdk/runtime/swoext.py,sha256=LS0YZXwQsHDaYjalDGfYQi5cAL3aKQhphf3chrNmNBk,1665
|
|
35
|
-
mpt_extension_sdk/runtime/utils.py,sha256
|
|
39
|
+
mpt_extension_sdk/runtime/utils.py,sha256=ZnRWIBwYzOerx30KFmBXLUe19qzwE4JFNkNMGVqjuyk,3365
|
|
36
40
|
mpt_extension_sdk/runtime/workers.py,sha256=k25jFlh-NdHVqeMV2AgoC6IHIlbRHcDoRB5xqWwMPFg,2411
|
|
37
|
-
mpt_extension_sdk-4.0.
|
|
38
|
-
mpt_extension_sdk-4.0.
|
|
39
|
-
mpt_extension_sdk-4.0.
|
|
40
|
-
mpt_extension_sdk-4.0.
|
|
41
|
-
mpt_extension_sdk-4.0.
|
|
41
|
+
mpt_extension_sdk-4.0.3.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
42
|
+
mpt_extension_sdk-4.0.3.dist-info/METADATA,sha256=nM1_7QslDTSmFMecQxaJG4S1Ygvy3qg1VddDQnz4PSI,1563
|
|
43
|
+
mpt_extension_sdk-4.0.3.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
|
44
|
+
mpt_extension_sdk-4.0.3.dist-info/entry_points.txt,sha256=8uZQihFseK4Kp5XWHl9EDYneg-CLS8BFO-ygp0h34nc,143
|
|
45
|
+
mpt_extension_sdk-4.0.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|