orchestrator-core 2.9.1__py3-none-any.whl → 2.9.2rc1__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.
orchestrator/__init__.py CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  """This is the orchestrator workflow engine."""
15
15
 
16
- __version__ = "2.9.1"
16
+ __version__ = "2.9.2rc1"
17
17
 
18
18
  from orchestrator.app import OrchestratorCore
19
19
  from orchestrator.settings import app_settings
@@ -133,7 +133,7 @@ def delete(process_id: UUID) -> None:
133
133
  status_code=HTTPStatus.CREATED,
134
134
  dependencies=[Depends(check_global_lock, use_cache=False)],
135
135
  )
136
- def new_process(
136
+ async def new_process(
137
137
  workflow_key: str,
138
138
  request: Request,
139
139
  json_data: list[dict[str, Any]] | None = Body(...),
@@ -26,6 +26,8 @@ from orchestrator.domain.customer_description import (
26
26
  update_subscription_customer_description,
27
27
  )
28
28
  from orchestrator.schemas import SubscriptionDescriptionBaseSchema, SubscriptionDescriptionSchema
29
+ from orchestrator.schemas.subscription_descriptions import UpdateSubscriptionDescriptionSchema
30
+ from orchestrator.utils.errors import StaleDataError
29
31
  from orchestrator.utils.redis import delete_from_redis
30
32
 
31
33
  router = APIRouter()
@@ -37,10 +39,15 @@ async def save_subscription_customer_description_endpoint(data: SubscriptionDesc
37
39
 
38
40
 
39
41
  @router.put("/", response_model=None, status_code=HTTPStatus.NO_CONTENT)
40
- async def update_subscription_customer_description_endpoint(data: SubscriptionDescriptionSchema = Body(...)) -> None:
42
+ async def update_subscription_customer_description_endpoint(
43
+ data: UpdateSubscriptionDescriptionSchema = Body(...),
44
+ ) -> None:
41
45
  description = get_customer_description_by_customer_subscription(data.customer_id, data.subscription_id)
42
46
  if description:
43
- await update_subscription_customer_description(description, data.description, data.created_at)
47
+ try:
48
+ await update_subscription_customer_description(description, data.description, data.created_at, data.version)
49
+ except StaleDataError as error:
50
+ raise_status(HTTPStatus.BAD_REQUEST, str(error))
44
51
 
45
52
 
46
53
  @router.delete("/{_id}", response_model=None, status_code=HTTPStatus.NO_CONTENT)
orchestrator/db/models.py CHANGED
@@ -554,6 +554,7 @@ class SubscriptionCustomerDescriptionTable(BaseModel):
554
554
  customer_id = mapped_column(String, nullable=False, index=True)
555
555
  description = mapped_column(Text(), nullable=False)
556
556
  created_at = mapped_column(UtcTimestamp, nullable=False, server_default=text("current_timestamp()"))
557
+ version = mapped_column(Integer, nullable=False, server_default="1")
557
558
 
558
559
  subscription = relationship("SubscriptionTable", back_populates="customer_descriptions")
559
560
 
@@ -572,6 +573,7 @@ class SubscriptionTable(BaseModel):
572
573
  start_date = mapped_column(UtcTimestamp, nullable=True)
573
574
  end_date = mapped_column(UtcTimestamp)
574
575
  note = mapped_column(Text())
576
+ version = mapped_column(Integer, nullable=False, server_default="1")
575
577
 
576
578
  product = relationship("ProductTable", foreign_keys=[product_id])
577
579
  instances = relationship(
@@ -435,16 +435,29 @@ class Populator:
435
435
  self.log.info("Providing user input.")
436
436
 
437
437
  user_inputs: list[State] = [self.get_form_data(form)] if form else []
438
+ # Keep submitting the form until it has been successfully submitted
438
439
  while True:
439
440
  self.log.info("Submitting user input", data=user_inputs)
440
441
  response = self.session.request(method, url, json=user_inputs)
441
- if not response.ok and "MigrationSummary" in response.text:
442
- user_inputs[-1] = {}
443
- continue
442
+ self.log.debug("Response", response=response.content)
443
+
444
+ # Return the response if the form has been successfully submitted
444
445
  if response.status_code != HTTPStatus.NOT_EXTENDED:
445
446
  return response
446
- input_fields = response.json()["form"]
447
- user_inputs.append(self.get_form_data(input_fields))
447
+
448
+ response_json = response.json()
449
+ meta = response_json.get("meta", {}) or {}
450
+ no_next = meta.get("hasNext") is False
451
+ is_summary_form = response_json.get("form", {}).get("title", "").endswith("Summary")
452
+
453
+ # If there are no next pages and a summary form is expected then append an empty form/dict
454
+ if no_next and is_summary_form:
455
+ self.log.info("Append empty form", response=response_json)
456
+ user_inputs.append({})
457
+ # Otherwise resolve the values for the input fields on the form
458
+ else:
459
+ input_fields = response_json["form"]
460
+ user_inputs.append(self.get_form_data(input_fields))
448
461
 
449
462
  def reset(self) -> None:
450
463
  """Reset internal state."""
@@ -1017,6 +1017,7 @@ class SubscriptionModel(DomainModel):
1017
1017
  start_date: datetime | None = None # pragma: no mutate
1018
1018
  end_date: datetime | None = None # pragma: no mutate
1019
1019
  note: str | None = None # pragma: no mutate
1020
+ version: int = 1 # pragma: no mutate
1020
1021
 
1021
1022
  def __new__(cls, *args: Any, status: SubscriptionLifecycle | None = None, **kwargs: Any) -> "SubscriptionModel":
1022
1023
  # status can be none if created during change_lifecycle
@@ -1108,6 +1109,7 @@ class SubscriptionModel(DomainModel):
1108
1109
  start_date: datetime | None = None,
1109
1110
  end_date: datetime | None = None,
1110
1111
  note: str | None = None,
1112
+ version: int = 1,
1111
1113
  ) -> S:
1112
1114
  """Use product_id (and customer_id) to return required fields of a new empty subscription."""
1113
1115
  # Caller wants a new instance and provided a product_id and customer_id
@@ -1140,6 +1142,7 @@ class SubscriptionModel(DomainModel):
1140
1142
  start_date=start_date,
1141
1143
  end_date=end_date,
1142
1144
  note=note,
1145
+ version=version,
1143
1146
  )
1144
1147
  db.session.add(subscription)
1145
1148
 
@@ -1156,6 +1159,7 @@ class SubscriptionModel(DomainModel):
1156
1159
  start_date=start_date,
1157
1160
  end_date=end_date,
1158
1161
  note=note,
1162
+ version=version,
1159
1163
  **fixed_inputs,
1160
1164
  **instances,
1161
1165
  )
@@ -1270,6 +1274,7 @@ class SubscriptionModel(DomainModel):
1270
1274
  start_date=subscription.start_date,
1271
1275
  end_date=subscription.end_date,
1272
1276
  note=subscription.note,
1277
+ version=subscription.version,
1273
1278
  **fixed_inputs,
1274
1279
  **instances,
1275
1280
  )
@@ -1320,6 +1325,7 @@ class SubscriptionModel(DomainModel):
1320
1325
  start_date=subscription.start_date,
1321
1326
  end_date=subscription.end_date,
1322
1327
  note=subscription.note,
1328
+ version=subscription.version,
1323
1329
  **fixed_inputs,
1324
1330
  **instances,
1325
1331
  )
@@ -20,7 +20,9 @@ from sqlalchemy import select
20
20
 
21
21
  from orchestrator.api.models import delete
22
22
  from orchestrator.db import SubscriptionCustomerDescriptionTable, db
23
+ from orchestrator.utils.errors import StaleDataError
23
24
  from orchestrator.utils.redis import delete_subscription_from_redis
25
+ from orchestrator.utils.validate_data_version import validate_data_version
24
26
  from orchestrator.websocket import invalidate_subscription_cache
25
27
 
26
28
  router = APIRouter()
@@ -53,8 +55,14 @@ async def create_subscription_customer_description(
53
55
 
54
56
  @delete_subscription_from_redis()
55
57
  async def update_subscription_customer_description(
56
- customer_description: SubscriptionCustomerDescriptionTable, description: str, created_at: datetime | None = None
58
+ customer_description: SubscriptionCustomerDescriptionTable,
59
+ description: str,
60
+ created_at: datetime | None = None,
61
+ version: int | None = None,
57
62
  ) -> SubscriptionCustomerDescriptionTable:
63
+ if not validate_data_version(customer_description.version, version):
64
+ raise StaleDataError(customer_description.version, version)
65
+
58
66
  customer_description.description = description
59
67
  customer_description.created_at = created_at if created_at else datetime.now(tz=timezone("UTC"))
60
68
  db.session.commit()
@@ -25,25 +25,28 @@ from orchestrator.domain.customer_description import (
25
25
  )
26
26
  from orchestrator.graphql.schemas.customer_description import CustomerDescription
27
27
  from orchestrator.graphql.types import MutationError, NotFoundError
28
+ from orchestrator.utils.errors import StaleDataError
28
29
 
29
30
  logger = structlog.get_logger(__name__)
30
31
 
31
32
 
32
33
  async def upsert_customer_description(
33
- customer_id: str, subscription_id: UUID, description: str
34
+ customer_id: str, subscription_id: UUID, description: str, version: int | None
34
35
  ) -> SubscriptionCustomerDescriptionTable | NotFoundError:
35
36
  current_description = get_customer_description_by_customer_subscription(customer_id, subscription_id)
36
37
 
37
38
  if current_description:
38
- return await update_subscription_customer_description(current_description, description)
39
+ return await update_subscription_customer_description(current_description, description, version=version)
39
40
  return await create_subscription_customer_description(customer_id, subscription_id, description)
40
41
 
41
42
 
42
43
  async def resolve_upsert_customer_description(
43
- customer_id: str, subscription_id: UUID, description: str
44
+ customer_id: str, subscription_id: UUID, description: str, version: int | None = None
44
45
  ) -> CustomerDescription | NotFoundError | MutationError:
45
46
  try:
46
- customer_description = await upsert_customer_description(customer_id, subscription_id, description)
47
+ customer_description = await upsert_customer_description(customer_id, subscription_id, description, version)
48
+ except StaleDataError as error:
49
+ return MutationError(message=str(error))
47
50
  except Exception:
48
51
  return NotFoundError(message="Subscription not found")
49
52
  return CustomerDescription.from_pydantic(customer_description) # type: ignore
@@ -77,6 +77,7 @@ class SubscriptionInterface:
77
77
  status: SubscriptionLifecycle
78
78
  insync: bool
79
79
  note: str | None
80
+ version: int
80
81
 
81
82
  @strawberry.field(description="Product information") # type: ignore
82
83
  async def product(self) -> ProductModelGraphql:
@@ -0,0 +1,64 @@
1
+ """Add version column to subscription and subscription customer descriptions.
2
+
3
+ Revision ID: 4c5859620539
4
+ Revises: 460ec6748e37
5
+ Create Date: 2025-01-08 15:07:41.957937
6
+
7
+ """
8
+
9
+ import sqlalchemy as sa
10
+ from alembic import op
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = "4c5859620539"
14
+ down_revision = "460ec6748e37"
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ conn = op.get_bind()
21
+ op.add_column(
22
+ "subscription_customer_descriptions", sa.Column("version", sa.Integer(), server_default="1", nullable=False)
23
+ )
24
+ op.add_column("subscriptions", sa.Column("version", sa.Integer(), server_default="1", nullable=False))
25
+
26
+ conn.execute(
27
+ sa.text(
28
+ """
29
+ CREATE OR REPLACE FUNCTION increment_version()
30
+ RETURNS TRIGGER AS $$
31
+ BEGIN
32
+ NEW.version := OLD.version + 1;
33
+ RETURN NEW;
34
+ END;
35
+ $$ LANGUAGE plpgsql;
36
+
37
+ CREATE TRIGGER subscriptions_increment_version_trigger
38
+ BEFORE UPDATE ON subscriptions
39
+ FOR EACH ROW
40
+ EXECUTE FUNCTION increment_version();
41
+
42
+ CREATE TRIGGER subscription_customer_descriptions_increment_version_trigger
43
+ BEFORE UPDATE ON subscription_customer_descriptions
44
+ FOR EACH ROW
45
+ EXECUTE FUNCTION increment_version();
46
+ """
47
+ )
48
+ )
49
+
50
+
51
+ def downgrade() -> None:
52
+ conn = op.get_bind()
53
+ op.drop_column("subscriptions", "version")
54
+ op.drop_column("subscription_customer_descriptions", "version")
55
+
56
+ conn.execute(
57
+ sa.text(
58
+ """
59
+ DROP TRIGGER IF EXISTS subscriptions_increment_version_trigger on subscriptions;
60
+ DROP TRIGGER IF EXISTS subscription_customer_descriptions_increment_version_trigger on subscription_customer_descriptions;
61
+ DROP FUNCTION IF EXISTS increment_version;
62
+ """
63
+ )
64
+ )
@@ -84,6 +84,7 @@ class SubscriptionSchema(SubscriptionBaseSchema):
84
84
  product: ProductBaseSchema | None = None
85
85
  customer_descriptions: list[SubscriptionDescriptionSchema] | None = None
86
86
  tag: str | None = None
87
+ version: int
87
88
  model_config = ConfigDict(from_attributes=True)
88
89
 
89
90
 
@@ -28,4 +28,12 @@ class SubscriptionDescriptionBaseSchema(OrchestratorBaseModel):
28
28
  class SubscriptionDescriptionSchema(SubscriptionDescriptionBaseSchema):
29
29
  id: UUID
30
30
  created_at: datetime | None = None
31
+ version: int
32
+ model_config = ConfigDict(from_attributes=True)
33
+
34
+
35
+ class UpdateSubscriptionDescriptionSchema(SubscriptionDescriptionBaseSchema):
36
+ id: UUID
37
+ created_at: datetime | None = None
38
+ version: int | None = None
31
39
  model_config = ConfigDict(from_attributes=True)
@@ -33,6 +33,7 @@ def format_subscription(subscription: SubscriptionTable) -> dict:
33
33
  "note": subscription.note,
34
34
  "start_date": subscription.start_date if subscription.start_date else None,
35
35
  "end_date": subscription.end_date if subscription.end_date else None,
36
+ "version": subscription.version,
36
37
  "product": {
37
38
  "product_id": prod.product_id,
38
39
  "description": prod.description,
@@ -74,6 +74,14 @@ class InconsistentDataError(ProcessFailureError):
74
74
  pass
75
75
 
76
76
 
77
+ class StaleDataError(ValueError):
78
+ """The version of the update payload does not match the version in the database."""
79
+
80
+ def __init__(self, current_version: int, new_version: int | None = None) -> None:
81
+ message = f"Stale data: given version ({new_version}) does not match the current version ({current_version})"
82
+ super().__init__(message)
83
+
84
+
77
85
  def is_api_exception(ex: Exception) -> bool:
78
86
  """Test for swagger-codegen ApiException.
79
87
 
@@ -0,0 +1,2 @@
1
+ def validate_data_version(current_version: int, new_version: int | None = None) -> bool:
2
+ return (new_version is not None and new_version == current_version) or new_version is None
@@ -4,6 +4,7 @@
4
4
  "note": "Notes",
5
5
  "note_info": "Notes, reminders and feedback about this description.",
6
6
  "subscription_id": "Subscription",
7
+ "version": "Version",
7
8
  "subscription_id_info": "The subscription for this action"
8
9
  }
9
10
  },
@@ -13,11 +13,11 @@
13
13
 
14
14
  from collections.abc import Callable
15
15
  from inspect import isgeneratorfunction
16
- from typing import cast
16
+ from typing import Self, cast
17
17
  from uuid import UUID
18
18
 
19
19
  from more_itertools import first_true
20
- from pydantic import field_validator
20
+ from pydantic import field_validator, model_validator
21
21
  from sqlalchemy import select
22
22
 
23
23
  from orchestrator.db import ProductTable, SubscriptionTable, db
@@ -26,8 +26,10 @@ from orchestrator.services import subscriptions
26
26
  from orchestrator.settings import app_settings
27
27
  from orchestrator.targets import Target
28
28
  from orchestrator.types import State, SubscriptionLifecycle
29
+ from orchestrator.utils.errors import StaleDataError
29
30
  from orchestrator.utils.redis import caching_models_enabled
30
31
  from orchestrator.utils.state import form_inject_args
32
+ from orchestrator.utils.validate_data_version import validate_data_version
31
33
  from orchestrator.workflow import StepList, Workflow, conditional, done, init, make_workflow, step
32
34
  from orchestrator.workflows.steps import (
33
35
  cache_domain_models,
@@ -116,6 +118,7 @@ def _generate_modify_form(workflow_target: str, workflow_name: str) -> InputForm
116
118
  # We use UUID instead of SubscriptionId here because we don't want the allowed_status check and
117
119
  # we do our own validation here.
118
120
  subscription_id: UUID
121
+ version: int | None = None
119
122
 
120
123
  @field_validator("subscription_id")
121
124
  @classmethod
@@ -140,6 +143,15 @@ def _generate_modify_form(workflow_target: str, workflow_name: str) -> InputForm
140
143
 
141
144
  return subscription_id
142
145
 
146
+ @model_validator(mode="after")
147
+ def version_validator(self) -> Self:
148
+ current_version = db.session.scalars(
149
+ select(SubscriptionTable.version).where(SubscriptionTable.subscription_id == self.subscription_id)
150
+ ).one()
151
+ if not validate_data_version(current_version, self.version):
152
+ raise StaleDataError(current_version, self.version)
153
+ return self
154
+
143
155
  return ModifySubscriptionPage
144
156
 
145
157
 
@@ -157,11 +169,11 @@ def wrap_modify_initial_input_form(initial_input_form: InputStepFunc | None) ->
157
169
  user_input = yield _generate_modify_form(workflow_target, workflow_name)
158
170
 
159
171
  subscription = SubscriptionTable.query.get(user_input.subscription_id)
160
-
161
172
  begin_state = {
162
173
  "subscription_id": str(subscription.subscription_id),
163
174
  "product": str(subscription.product_id),
164
175
  "customer_id": subscription.customer_id,
176
+ "version": subscription.version,
165
177
  }
166
178
 
167
179
  if initial_input_form is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: orchestrator-core
3
- Version: 2.9.1
3
+ Version: 2.9.2rc1
4
4
  Summary: This is the orchestrator workflow engine.
5
5
  Requires-Python: >=3.11,<3.14
6
6
  Classifier: Intended Audience :: Information Technology
@@ -1,4 +1,4 @@
1
- orchestrator/__init__.py,sha256=PuifbutifTAHifhqKu6mqINk4gDyL_60h_JxkXIiFOE,1055
1
+ orchestrator/__init__.py,sha256=uaK-K8eDckfC2-j5UCP7FLkLp1C-yjYFRIzbLwrrUak,1058
2
2
  orchestrator/app.py,sha256=_2e3JMYgH_egOScokFVpFuTlJWGGwH0KYgZajDdm--0,11563
3
3
  orchestrator/exception_handlers.py,sha256=UsW3dw8q0QQlNLcV359bIotah8DYjMsj2Ts1LfX4ClY,1268
4
4
  orchestrator/log_config.py,sha256=1tPRX5q65e57a6a_zEii_PFK8SzWT0mnA5w2sKg4hh8,1853
@@ -17,10 +17,10 @@ orchestrator/api/api_v1/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n
17
17
  orchestrator/api/api_v1/api.py,sha256=zGPSCX-nCebZXN2OT9QA_ChAtpsK53hpxZ7F2x_0gjI,2332
18
18
  orchestrator/api/api_v1/endpoints/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
19
19
  orchestrator/api/api_v1/endpoints/health.py,sha256=iaxs1XX1_250_gKNsspuULCV2GEMBjbtjsmfQTOvMAI,1284
20
- orchestrator/api/api_v1/endpoints/processes.py,sha256=neold6wWt-QJuGmC6GB6GI5B0zZSncNgUAXgYc41wzQ,12710
20
+ orchestrator/api/api_v1/endpoints/processes.py,sha256=bsS8CqpfE3q5uIYZeZYiKjlbwHYSliFJQu130ov8cL8,12716
21
21
  orchestrator/api/api_v1/endpoints/products.py,sha256=Qyj9OzlfWfgsWe9Homd60LFco91VaJ1gkgXxn0AmP6Q,2143
22
22
  orchestrator/api/api_v1/endpoints/settings.py,sha256=QiSih8zOUombxXk5Hd7MACq5BC5Y9w-BrmgBdTPRIDg,6141
23
- orchestrator/api/api_v1/endpoints/subscription_customer_descriptions.py,sha256=udd14XR3WqlndP70Y8O9h6LVB-lB5r3hFMTpJlgJSm8,3105
23
+ orchestrator/api/api_v1/endpoints/subscription_customer_descriptions.py,sha256=Elu4DVJoNtUFq_b3pG1Ws8StrUIo_jTViff2TJqe6ZU,3398
24
24
  orchestrator/api/api_v1/endpoints/subscriptions.py,sha256=s0nzWY1n8J1Ep-f6LuhRj_LX3shfCq7PsMmHf0_Rzsw,8716
25
25
  orchestrator/api/api_v1/endpoints/translations.py,sha256=dIWh_fCnZZUxJoGiNeJ49DK_xpf75IpR_0EIMSvzIvY,963
26
26
  orchestrator/api/api_v1/endpoints/user.py,sha256=RyI32EXVu6I-IxWjz0XB5zQWzzLL60zKXLgLqLH02xU,1827
@@ -102,7 +102,7 @@ orchestrator/db/database.py,sha256=MU_w_e95ho2dVb2JDnt_KFYholx___XDkiQXbc8wCkI,1
102
102
  orchestrator/db/helpers.py,sha256=L8kEdnSSNGnUpZhdeGx2arCodakWN8vSpKdfjoLuHdY,831
103
103
  orchestrator/db/listeners.py,sha256=UBPYcH0FE3a7aZQu_D0O_JMXpXIRYXC0gjSAvlv5GZo,1142
104
104
  orchestrator/db/loaders.py,sha256=escBOUNf5bHmjIuNH37fGgNSeZLzMiJvQgQFy4r4MYY,6244
105
- orchestrator/db/models.py,sha256=NlGVWyhHGmSk9HFuCdCanfSQhLGasCLXz66XWMSWBeE,25933
105
+ orchestrator/db/models.py,sha256=weG4oVgFzetaQQe3dCULiV62nwrbMnCpx7oNGQzIHjw,26079
106
106
  orchestrator/db/filters/__init__.py,sha256=RUj6P0XxEBhYj0SN5wH5-Vf_Wt_ilZR_n9DSar5m9oM,371
107
107
  orchestrator/db/filters/filters.py,sha256=55RtpQwM2rhrk4A6CCSeSXoo-BT9GnQoNTryA8CtLEg,5020
108
108
  orchestrator/db/filters/process.py,sha256=xvGhyfo_MZ1xhLvFC6yULjcT4mJk0fKc1glJIYgsWLE,4018
@@ -124,7 +124,7 @@ orchestrator/db/sorting/sorting.py,sha256=WpwImCDRKiOp4Tr54vovWpHkoJIov8SNQNPods
124
124
  orchestrator/db/sorting/subscription.py,sha256=uepBMyfRFLZz5yoYK4VK3mdRBvO1Gc-6jSQXQ41fR-8,1441
125
125
  orchestrator/db/sorting/workflow.py,sha256=6-JceMyB99M994Re58E0MX5uhlpnTW5OJCxmXopEfRU,576
126
126
  orchestrator/devtools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
- orchestrator/devtools/populator.py,sha256=s3acJmuQvls4rqg4oIpON9f430_LtDgaff8T5ejINg0,18981
127
+ orchestrator/devtools/populator.py,sha256=gCw-U4gDAdCQ1P-YOG_NgDducql8he1Vdjw_P8L6okA,19678
128
128
  orchestrator/devtools/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
129
129
  orchestrator/devtools/scripts/migrate_20.py,sha256=WiDyOjeYh7sPufrbrc33BBmJRYWwxPqJOqhHApjuBoI,8359
130
130
  orchestrator/distlock/__init__.py,sha256=0uCW-4efWGbU4RXSb7t3U1yA2T8z77OGgb9SDNebdmA,2491
@@ -133,8 +133,8 @@ orchestrator/distlock/managers/__init__.py,sha256=ImIkNsrXcyE7-NgRWqEhUXUuUzda9K
133
133
  orchestrator/distlock/managers/memory_distlock_manager.py,sha256=HWQafcVKBF-Cka_wukZZ1GM69AWPVOpJPje3quIebQ8,3114
134
134
  orchestrator/distlock/managers/redis_distlock_manager.py,sha256=Lk0Krw7dQD58uleAz3Eancc4La-xSCFHxB8ymg3qWf0,3271
135
135
  orchestrator/domain/__init__.py,sha256=Rnt9XXHasAgieQiLT0JhUFRrysa9EIubvzcd5kk3Gvc,894
136
- orchestrator/domain/base.py,sha256=0dvsFjZmif_gd0GlPtXyOU9X3Je_vWE-dYpLd4u53ks,61710
137
- orchestrator/domain/customer_description.py,sha256=8Pn8Vnf2X9Ou5p8UQ_krBPjByQDmXVCxDQ2ngjJLAgs,3049
136
+ orchestrator/domain/base.py,sha256=8iiz1IP6CSrr5pz_0oqRNj5MoHY4PR9E30hx8Zrlrq4,61928
137
+ orchestrator/domain/customer_description.py,sha256=v7o6TTN4oc6bWHZU-jCT-fUYvkeYahbpXOwlKXofuI8,3360
138
138
  orchestrator/domain/helpers.py,sha256=2j2j_7J8qvniHxxpdoEQsoVpC-llkn0tbww2eCA0K1A,989
139
139
  orchestrator/domain/lifecycle.py,sha256=ROYJ5t6JFy5PwE9nmApS54NIEw0dwk-2iZC-OzW18-U,2882
140
140
  orchestrator/forms/__init__.py,sha256=bw_1238HKy_T0gvfA5oEjJFwkALzvWU4O_VJ0xE8UyU,1168
@@ -153,7 +153,7 @@ orchestrator/graphql/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
153
153
  orchestrator/graphql/extensions/stats.py,sha256=pGhEBQg45XvqZhRobcrCSGwt5AGmR3gflsm1dYiIg5g,2018
154
154
  orchestrator/graphql/loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
155
155
  orchestrator/graphql/loaders/subscriptions.py,sha256=31zE2WC7z-tPIUmVpU1QWOJvNbLvF7sYgY7JAQ6OPJg,1856
156
- orchestrator/graphql/mutations/customer_description.py,sha256=Q-CfBd5rnTY_Shk6l5tpamdI2S7LBiThBY9lB5d2HTU,3130
156
+ orchestrator/graphql/mutations/customer_description.py,sha256=37yX92fE1Sc51O9i-gP8JfD3HdsvpR3TtbgYqKtGC-w,3343
157
157
  orchestrator/graphql/mutations/start_process.py,sha256=8vLVvmBwL1ujbZJoI_8YE3VAgI-J2RTzgrTZJC8THZ4,1576
158
158
  orchestrator/graphql/resolvers/__init__.py,sha256=v6G9OboMuqEdZAB4RfCNjQZhJyXcvuZ_gC7RN9gTSrU,941
159
159
  orchestrator/graphql/resolvers/customer.py,sha256=tq06MtMoaqFwqn3YQvSv0VmROW7QJZRJp1ykO4tUhck,934
@@ -177,7 +177,7 @@ orchestrator/graphql/schemas/product_block.py,sha256=Qk9cbA6vm7ZPrhdgPHatKRuy6Ty
177
177
  orchestrator/graphql/schemas/resource_type.py,sha256=s5d_FwQXL2-Sc-IDUxTJun5qFQ4zOP4-XcHF9ql-t1g,898
178
178
  orchestrator/graphql/schemas/settings.py,sha256=drhm5VcLmUbiYAk6WUSJcyJqjNM96E6GvpxVdPAobnA,999
179
179
  orchestrator/graphql/schemas/strawberry_pydantic_patch.py,sha256=CjNUhTKdYmLiaem-WY_mzw4HASIeaZitxGF8pPocqVw,1602
180
- orchestrator/graphql/schemas/subscription.py,sha256=uGq1yV4qcZKb4ciB-N-DvHqlriLuW3nZszd9W1jZumY,9556
180
+ orchestrator/graphql/schemas/subscription.py,sha256=_ra7MG9P2w7_WMiMx-zTOaAMinGlTKN4gwE9vej-5V8,9573
181
181
  orchestrator/graphql/schemas/workflow.py,sha256=0UWU0HGTiAC_5Wzh16clBd74JoYHrr38YIGV86q-si0,1276
182
182
  orchestrator/graphql/utils/__init__.py,sha256=1JvenzEVW1CBa1sGVI9I8IWnnoXIkb1hneDqph9EEZY,524
183
183
  orchestrator/graphql/utils/create_resolver_error_handler.py,sha256=PpQMVwGrE9t0nZ12TwoxPxksXxEwQM7lSNPeh7qW3vk,1233
@@ -214,6 +214,7 @@ orchestrator/migrations/versions/schema/2023-09-25_da5c9f4cce1c_add_subscription
214
214
  orchestrator/migrations/versions/schema/2023-12-06_048219045729_add_workflow_id_to_processes_table.py,sha256=nCeZKWdb856ob8bE_glpNyIDzKkh9hwq7hY5FXB1TP8,2246
215
215
  orchestrator/migrations/versions/schema/2024-09-27_460ec6748e37_add_uuid_search_workaround.py,sha256=GzHBzOwOc6FaO1kYwoSNIhb8sKstXo8Cfxdqy3Rmeg4,972
216
216
  orchestrator/migrations/versions/schema/2024-09-27_460ec6748e37_add_uuid_search_workaround.sql,sha256=mhPnqjG5H3W8_BD7w5tYzXUQSxFOM7Rahn_MudEPTIE,5383
217
+ orchestrator/migrations/versions/schema/2025-01-08_4c5859620539_add_version_column_to_subscription.py,sha256=xAhe74U0ZiVRo9Z8Uq7491RBbATMMUnYpTBjbG-BYL0,1690
217
218
  orchestrator/schedules/__init__.py,sha256=JnnaglfK1qYUBKI6Dd9taV-tCZIPlAdAkHtnkJDMXxY,1066
218
219
  orchestrator/schedules/resume_workflows.py,sha256=kSotzTAXjX7p9fpSYiGOpuxuTQfv54eRFAe0YSG0DHc,832
219
220
  orchestrator/schedules/scheduling.py,sha256=ehtwgpbvMOk1jhn-hHgVzg_9wLJkI6l3mRY3DcO9ZVY,1526
@@ -229,8 +230,8 @@ orchestrator/schemas/process.py,sha256=NgS1eBRtO2GUCRNsvbvYyjNkR2aBdH-kwcsR_y8Df
229
230
  orchestrator/schemas/product.py,sha256=bIgeLGIsrRiQZ7J36S2Bym8CkV-xhPjn8QoHhZkEBa0,1484
230
231
  orchestrator/schemas/product_block.py,sha256=mKX9FwQ5TGo9SrrAtDJOhB_nji1LHJ3-mKBrEEoQ-No,1428
231
232
  orchestrator/schemas/resource_type.py,sha256=z1UQTaW79UlLDzVQtstNo0trXQVT8-GDisxieJPUeYo,973
232
- orchestrator/schemas/subscription.py,sha256=oZpPAXigveYXNBUWXPB0VReG2p_sMsxokW4YpCmy5cQ,3366
233
- orchestrator/schemas/subscription_descriptions.py,sha256=8rO1RpOf-VK4gBKZKz43khRNSCJ2VLxJtMFa34Q7cCc,1030
233
+ orchestrator/schemas/subscription.py,sha256=zNy7bb-ww-MEN4QW9xIwxzcNSyFPEgjt5tt1T4Ah0hQ,3383
234
+ orchestrator/schemas/subscription_descriptions.py,sha256=Ft_jw1U0bf9Z0U8O4OWfLlcl0mXCVT_qYVagBP3GbIQ,1262
234
235
  orchestrator/schemas/workflow.py,sha256=YvjidAaYz1MsqVsA7DynOlW4kChBO-47M-JCkpSOro4,1890
235
236
  orchestrator/services/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
236
237
  orchestrator/services/celery.py,sha256=uvXSKuq_XHcF4BgEpt2QgGUfUnpopApF74FsgAQdnFY,4634
@@ -250,8 +251,8 @@ orchestrator/utils/crypt.py,sha256=18eNamYWMllPkxyRtWIde3FDr3rSF74R5SAL6WsCj9Y,5
250
251
  orchestrator/utils/datetime.py,sha256=a1WQ_yvu7MA0TiaRpC5avwbOSFdrj4eMrV4a7I2sD5Q,1477
251
252
  orchestrator/utils/deprecation_logger.py,sha256=oqju7ecJcB_r7cMnldaOAA79QUZYS_h69IkDrFV9nAg,875
252
253
  orchestrator/utils/docs.py,sha256=GbyD61oKn1yVYaphUKHCBvrWEWJDTQfRc_VEbVb-zgU,6172
253
- orchestrator/utils/enrich_process.py,sha256=n22kj8UUwC0c1kzCTsiWtIjZYBldY6mAlLhPl_A6d8I,4658
254
- orchestrator/utils/errors.py,sha256=QtZFQFJksq5OpTeUvgMrZdp5z6DbBm88vz1FzGSR13s,4250
254
+ orchestrator/utils/enrich_process.py,sha256=o_QSy5Q4wn1SMHhzVOw6bp7uhDXr7GhAIWRDDMWUVO4,4699
255
+ orchestrator/utils/errors.py,sha256=LCYn2OEBCxQBWCYIbJeO8vv6IjK1Dp4195TulD5nJzU,4613
255
256
  orchestrator/utils/fixed_inputs.py,sha256=pnL6I_19VMp_Bny8SYjSzVFNvTFDyeCxFFOWGhTnDiQ,2665
256
257
  orchestrator/utils/functional.py,sha256=w_iqB8zppLMnUaioyRjsZAAYC4y5kLw3zih5NKkEFoM,8063
257
258
  orchestrator/utils/get_subscription_dict.py,sha256=fkgDM54hn5YGUP9_2MOcJApJK1Z6c_Rl6sJERsrOy6M,686
@@ -262,6 +263,7 @@ orchestrator/utils/redis.py,sha256=WZiTjjQIO5TZIRllm-a6cQbndKE7hAxxj6mus_gToOs,7
262
263
  orchestrator/utils/search_query.py,sha256=ncJlynwtW-qwL0RcNq4DuAUx9KUMI6llwGAEwLO2QCA,17097
263
264
  orchestrator/utils/state.py,sha256=gPYHOWDxPvoYZ83WwKPCpeBAsNWOTlkwZz5kAZcM9rw,13011
264
265
  orchestrator/utils/strings.py,sha256=N0gWjmQaMjE9_99VtRvRaU8IBLTKMgBKSXcTZ9TpWAg,1077
266
+ orchestrator/utils/validate_data_version.py,sha256=3Eioy2wE2EWKSgkyMKcEKrkCAfUIAq-eb73iRcpgppw,184
265
267
  orchestrator/websocket/__init__.py,sha256=V79jskk1z3uPIYgu0Gt6JLzuqr7NGfNeAZ-hbBqoUv4,5745
266
268
  orchestrator/websocket/websocket_manager.py,sha256=Vw5GW67rP_RYoPUhfPp9Fi8_M9E9SoHOHmCQVibkSWc,2755
267
269
  orchestrator/websocket/managers/broadcast_websocket_manager.py,sha256=fwoSgTjkHJ2GmsLTU9dqQpAA9i8b1McPu7gLNzxtfG4,5401
@@ -270,13 +272,13 @@ orchestrator/workflows/__init__.py,sha256=TOZ7Q5_DolCsW6dl5RRndbNFkBHLeGk_R5c4W7
270
272
  orchestrator/workflows/modify_note.py,sha256=OkouKVZDinjWSN3J3_0gbvOMScvcKlWvPCkban45HxE,2438
271
273
  orchestrator/workflows/removed_workflow.py,sha256=V0Da5TEdfLdZZKD38ig-MTp3_IuE7VGqzHHzvPYQmLI,909
272
274
  orchestrator/workflows/steps.py,sha256=8dnB4HlqBWZ4JlP1eQVnHdinzoM0ZlgFL0KYn_3k8x4,9762
273
- orchestrator/workflows/utils.py,sha256=jSYaBPab74xeiY84rbNTFWI8eGvi6-Pfb9U0dmEyNPE,12860
275
+ orchestrator/workflows/utils.py,sha256=inWbR-44B0jj8YZMFBxndpcsfk5IC0MnlCnGB2dy5BU,13525
274
276
  orchestrator/workflows/tasks/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
275
277
  orchestrator/workflows/tasks/cleanup_tasks_log.py,sha256=JNx2lCIxdhTPD33EgwQUsQjoLeyKH2RKZR_e5eh80Ls,1614
276
278
  orchestrator/workflows/tasks/resume_workflows.py,sha256=wZGNHHQYL7wociSTmoNdDdh5CJkVOkvu3kCUg9uY_88,2349
277
279
  orchestrator/workflows/tasks/validate_products.py,sha256=j_aOyxcH8DymlGupSS6XRwQdWx2Ab-c8f8iUvAXBTes,8511
278
- orchestrator/workflows/translations/en-GB.json,sha256=tqZkg1bD2GxEVZQIUoev2XeK1Jr1iWzfMoDOowj0YzA,684
279
- orchestrator_core-2.9.1.dist-info/LICENSE,sha256=b-aA5OZQuuBATmLKo_mln8CQrDPPhg3ghLzjPjLn4Tg,11409
280
- orchestrator_core-2.9.1.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
281
- orchestrator_core-2.9.1.dist-info/METADATA,sha256=Gz_ceFthjADoxo-D4H7Umqo1pgGkZsFAY9LFei29b-E,4921
282
- orchestrator_core-2.9.1.dist-info/RECORD,,
280
+ orchestrator/workflows/translations/en-GB.json,sha256=e6uKt70KLSCmCSWQF9HpmVTLQM4YYO-9xFaMYcc58Ic,718
281
+ orchestrator_core-2.9.2rc1.dist-info/LICENSE,sha256=b-aA5OZQuuBATmLKo_mln8CQrDPPhg3ghLzjPjLn4Tg,11409
282
+ orchestrator_core-2.9.2rc1.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
283
+ orchestrator_core-2.9.2rc1.dist-info/METADATA,sha256=zUOL3E-Vk0quv01_5iO6Z4AAEgmeXIwFLvadLsXK_kY,4924
284
+ orchestrator_core-2.9.2rc1.dist-info/RECORD,,