mpt-extension-sdk 4.0.6__tar.gz → 4.1.1__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.
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/PKG-INFO +1 -1
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/key_vault/base.py +2 -2
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/mpt_http/mpt.py +59 -2
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/djapp/conf/default.py +6 -6
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/djapp/management/commands/consume_events.py +1 -1
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/djapp/middleware.py +1 -1
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/events/producers.py +2 -3
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/master.py +4 -4
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/pyproject.toml +1 -1
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/LICENSE +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/README.md +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/airtable/wrap_http_error.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/constants.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/core/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/core/events/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/core/events/dataclasses.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/core/events/registry.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/core/extension.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/core/security.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/core/utils.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/flows/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/flows/context.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/flows/pipeline.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/key_vault/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/mpt_http/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/mpt_http/base.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/mpt_http/utils.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/mpt_http/wrap_http_error.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/commands/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/commands/django.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/commands/run.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/djapp/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/djapp/apps.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/djapp/conf/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/djapp/management/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/djapp/management/commands/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/events/__init__.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/events/dispatcher.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/events/utils.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/initializer.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/logging.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/swoext.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/utils.py +0 -0
- {mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/workers.py +0 -0
|
@@ -74,7 +74,7 @@ class KeyVault(Session):
|
|
|
74
74
|
)
|
|
75
75
|
return None
|
|
76
76
|
|
|
77
|
-
def _get_key_vault_url(self, key_vault_name: str):
|
|
77
|
+
def _get_key_vault_url(self, key_vault_name: str): # pragma: no cover
|
|
78
78
|
"""
|
|
79
79
|
Construct the Key Vault URL using the provided Key Vault name.
|
|
80
80
|
|
|
@@ -88,7 +88,7 @@ class KeyVault(Session):
|
|
|
88
88
|
# Construct the Key Vault URL
|
|
89
89
|
return f"https://{key_vault_name}.vault.azure.net/"
|
|
90
90
|
|
|
91
|
-
def _get_key_vault_client(self, key_vault_name: str):
|
|
91
|
+
def _get_key_vault_client(self, key_vault_name: str): # pragma: no cover
|
|
92
92
|
"""
|
|
93
93
|
Create a Key Vault client using the provided Key Vault URL and secret name.
|
|
94
94
|
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from datetime import date
|
|
3
|
+
from enum import Enum
|
|
3
4
|
from functools import cache
|
|
5
|
+
from itertools import batched
|
|
4
6
|
|
|
5
7
|
from django.conf import settings
|
|
6
8
|
|
|
9
|
+
from mpt_extension_sdk.mpt_http.base import MPTClient
|
|
7
10
|
from mpt_extension_sdk.mpt_http.wrap_http_error import wrap_mpt_http_error
|
|
8
11
|
|
|
9
12
|
logger = logging.getLogger(__name__)
|
|
10
13
|
|
|
14
|
+
NotifyCategories = Enum("NotifyCategories", settings.MPT_NOTIFY_CATEGORIES)
|
|
15
|
+
|
|
11
16
|
|
|
12
17
|
def _has_more_pages(page):
|
|
13
18
|
if not page:
|
|
@@ -16,10 +21,9 @@ def _has_more_pages(page):
|
|
|
16
21
|
return pagination["total"] > pagination["limit"] + pagination["offset"]
|
|
17
22
|
|
|
18
23
|
|
|
19
|
-
def _paginated(mpt_client, url):
|
|
24
|
+
def _paginated(mpt_client, url, limit=10):
|
|
20
25
|
items = []
|
|
21
26
|
page = None
|
|
22
|
-
limit = 10
|
|
23
27
|
offset = 0
|
|
24
28
|
while _has_more_pages(page):
|
|
25
29
|
response = mpt_client.get(f"{url}&limit={limit}&offset={offset}")
|
|
@@ -374,3 +378,56 @@ def get_buyer(mpt_client, buyer_id):
|
|
|
374
378
|
response = mpt_client.get(f"/accounts/buyers/{buyer_id}")
|
|
375
379
|
response.raise_for_status()
|
|
376
380
|
return response.json()
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
@wrap_mpt_http_error
|
|
384
|
+
def notify(
|
|
385
|
+
mpt_client: MPTClient,
|
|
386
|
+
category_id: str,
|
|
387
|
+
account_id: str,
|
|
388
|
+
buyer_id: str,
|
|
389
|
+
subject: str,
|
|
390
|
+
message_body: str,
|
|
391
|
+
limit: int = 1000,
|
|
392
|
+
):
|
|
393
|
+
"""
|
|
394
|
+
Sends notifications to multiple recipients in batches for a specific buyer and
|
|
395
|
+
category through the MPTClient service. The function retrieves recipients,
|
|
396
|
+
groups them into manageable batches, and sends notifications using the provided
|
|
397
|
+
message details.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
mpt_client (MPTClient): Client object for interacting with MPT service.
|
|
401
|
+
category_id (str): Identifier for the category of recipients or messages.
|
|
402
|
+
account_id (str): Identifier for the associated account.
|
|
403
|
+
buyer_id (str): Identifier for the buyer related to the notification.
|
|
404
|
+
subject (str): Subject/title of the notification to be sent.
|
|
405
|
+
message_body (str): Content/body of the notification message.
|
|
406
|
+
limit (int): Maximum number of recipients to process per batch. Defaults
|
|
407
|
+
to 1000.
|
|
408
|
+
|
|
409
|
+
Returns:
|
|
410
|
+
None
|
|
411
|
+
"""
|
|
412
|
+
recipients = _paginated(
|
|
413
|
+
mpt_client,
|
|
414
|
+
url=(
|
|
415
|
+
f"notifications/accounts/{account_id}/categories/{category_id}/contacts?"
|
|
416
|
+
f"select=id,-email,-name,-status,-user&"
|
|
417
|
+
f"filter(group.buyers.id,{buyer_id})"
|
|
418
|
+
),
|
|
419
|
+
limit=limit,
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
for contacts in batched(recipients, limit):
|
|
423
|
+
response = mpt_client.post(
|
|
424
|
+
"notifications/batches",
|
|
425
|
+
json={
|
|
426
|
+
"category": {"id": category_id},
|
|
427
|
+
"subject": subject,
|
|
428
|
+
"body": message_body,
|
|
429
|
+
"contacts": contacts,
|
|
430
|
+
"buyer": {"id": buyer_id},
|
|
431
|
+
},
|
|
432
|
+
)
|
|
433
|
+
response.raise_for_status()
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/djapp/conf/default.py
RENAMED
|
@@ -10,6 +10,7 @@ For the full list of settings and their values, see
|
|
|
10
10
|
https://docs.djangoproject.com/en/4.2/ref/settings/
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
+
import json
|
|
13
14
|
import os
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
|
|
@@ -25,12 +26,6 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|
|
25
26
|
# Quick-start development settings - unsuitable for production
|
|
26
27
|
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
|
27
28
|
|
|
28
|
-
# SECURITY WARNING: keep the secret key used in production secret!
|
|
29
|
-
SECRET_KEY = os.getenv(
|
|
30
|
-
"MPT_DJANGO_SECRET_KEY",
|
|
31
|
-
"django-insecure-6r_%9ku+bg0=@xw1ah$wh+liwbsyhwpn#6alt*ppjn8t_uyp-u",
|
|
32
|
-
)
|
|
33
|
-
|
|
34
29
|
# SECURITY WARNING: don't run with debug turned on in production!
|
|
35
30
|
DEBUG = True
|
|
36
31
|
|
|
@@ -213,6 +208,11 @@ MPT_ORDERS_API_POLLING_INTERVAL_SECS = int(
|
|
|
213
208
|
os.getenv("MPT_ORDERS_API_POLLING_INTERVAL_SECS", "120")
|
|
214
209
|
)
|
|
215
210
|
|
|
211
|
+
# TODO: Should be synced with the initializer.py::initialize function
|
|
212
|
+
MPT_NOTIFY_CATEGORIES = json.loads(
|
|
213
|
+
os.getenv("MPT_NOTIFY_CATEGORIES", '{"ORDERS": "NTC-0000-0006"}')
|
|
214
|
+
)
|
|
215
|
+
|
|
216
216
|
EXTENSION_CONFIG = {
|
|
217
217
|
"DUE_DATE_DAYS": "30",
|
|
218
218
|
}
|
|
@@ -8,7 +8,7 @@ from mpt_extension_sdk.runtime.events.dispatcher import Dispatcher
|
|
|
8
8
|
from mpt_extension_sdk.runtime.events.producers import OrderEventProducer
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
class Command(BaseCommand):
|
|
11
|
+
class Command(BaseCommand): # pragma: no cover
|
|
12
12
|
help = CONSUME_EVENTS_HELP_TEXT
|
|
13
13
|
producer_classes = [
|
|
14
14
|
OrderEventProducer,
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/events/producers.py
RENAMED
|
@@ -32,7 +32,7 @@ class EventProducer(ABC):
|
|
|
32
32
|
self.producer.join()
|
|
33
33
|
|
|
34
34
|
@contextmanager
|
|
35
|
-
def sleep(self, secs, interval=0.5):
|
|
35
|
+
def sleep(self, secs, interval=0.5): # pragma: no cover
|
|
36
36
|
yield
|
|
37
37
|
sleeped = 0
|
|
38
38
|
while sleeped < secs and self.running_event.is_set():
|
|
@@ -61,7 +61,7 @@ class OrderEventProducer(EventProducer):
|
|
|
61
61
|
for order in orders:
|
|
62
62
|
self.dispatcher.dispatch_event(Event(order["id"], "orders", order))
|
|
63
63
|
|
|
64
|
-
def produce_events_with_context(self):
|
|
64
|
+
def produce_events_with_context(self): # pragma: no cover
|
|
65
65
|
while self.running:
|
|
66
66
|
with self.sleep(settings.MPT_ORDERS_API_POLLING_INTERVAL_SECS):
|
|
67
67
|
orders = self.get_processing_orders()
|
|
@@ -89,7 +89,6 @@ class OrderEventProducer(EventProducer):
|
|
|
89
89
|
except requests.RequestException:
|
|
90
90
|
logger.exception("Cannot retrieve orders")
|
|
91
91
|
return []
|
|
92
|
-
|
|
93
92
|
if response.status_code == 200:
|
|
94
93
|
page = response.json()
|
|
95
94
|
orders.extend(page["data"])
|
|
@@ -79,7 +79,7 @@ class Master:
|
|
|
79
79
|
self.workers[worker_type] = p
|
|
80
80
|
logger.info(f"{worker_type.capitalize()} worker pid: {p.pid}")
|
|
81
81
|
|
|
82
|
-
def monitor_processes(self):
|
|
82
|
+
def monitor_processes(self): # pragma: no cover
|
|
83
83
|
while self.monitor_event.is_set():
|
|
84
84
|
exited_workers = []
|
|
85
85
|
for worker_type, p in self.workers.items():
|
|
@@ -112,16 +112,16 @@ class Master:
|
|
|
112
112
|
self.stop()
|
|
113
113
|
self.start()
|
|
114
114
|
|
|
115
|
-
def __iter__(self):
|
|
115
|
+
def __iter__(self): # pragma: no cover
|
|
116
116
|
return self
|
|
117
117
|
|
|
118
|
-
def __next__(self):
|
|
118
|
+
def __next__(self): # pragma: no cover
|
|
119
119
|
changes = next(self.watcher)
|
|
120
120
|
if changes:
|
|
121
121
|
return list({Path(c[1]) for c in changes})
|
|
122
122
|
return None
|
|
123
123
|
|
|
124
|
-
def run(self):
|
|
124
|
+
def run(self): # pragma: no cover
|
|
125
125
|
self.start()
|
|
126
126
|
if self.options.get("reload"):
|
|
127
127
|
for files_changed in self:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/airtable/wrap_http_error.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/core/events/__init__.py
RENAMED
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/core/events/dataclasses.py
RENAMED
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/core/events/registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/mpt_http/wrap_http_error.py
RENAMED
|
File without changes
|
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/commands/__init__.py
RENAMED
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/commands/django.py
RENAMED
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/commands/run.py
RENAMED
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/djapp/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/djapp/conf/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/events/__init__.py
RENAMED
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/events/dispatcher.py
RENAMED
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/events/utils.py
RENAMED
|
File without changes
|
{mpt_extension_sdk-4.0.6 → mpt_extension_sdk-4.1.1}/mpt_extension_sdk/runtime/initializer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|