layrz-sdk 4.0.11__py3-none-any.whl → 4.1.8__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.
Files changed (104) hide show
  1. layrz_sdk/decorators/__init__.py +5 -0
  2. layrz_sdk/decorators/func_timing.py +103 -0
  3. layrz_sdk/entities/__init__.py +19 -0
  4. layrz_sdk/entities/action.py +28 -16
  5. layrz_sdk/entities/action_geofence_ownership.py +0 -2
  6. layrz_sdk/entities/action_kind.py +0 -2
  7. layrz_sdk/entities/action_subkind.py +0 -2
  8. layrz_sdk/entities/asset.py +20 -9
  9. layrz_sdk/entities/asset_constants.py +10 -9
  10. layrz_sdk/entities/asset_contact.py +7 -3
  11. layrz_sdk/entities/asset_operation_mode.py +0 -2
  12. layrz_sdk/entities/ats_entry.py +11 -4
  13. layrz_sdk/entities/ats_exit_history.py +21 -19
  14. layrz_sdk/entities/ats_operation.py +87 -0
  15. layrz_sdk/entities/ats_possible_entry.py +10 -7
  16. layrz_sdk/entities/ats_possible_exit.py +19 -9
  17. layrz_sdk/entities/ats_purchaseorder.py +106 -0
  18. layrz_sdk/entities/ats_reception.py +16 -4
  19. layrz_sdk/entities/broadcast/__init__.py +2 -1
  20. layrz_sdk/entities/broadcast/payload.py +40 -8
  21. layrz_sdk/entities/broadcast/result.py +72 -1
  22. layrz_sdk/entities/broadcast/service.py +12 -2
  23. layrz_sdk/entities/broadcast/status.py +2 -2
  24. layrz_sdk/entities/case.py +51 -8
  25. layrz_sdk/entities/case_ignored_status.py +1 -0
  26. layrz_sdk/entities/charts/axis_config.py +13 -5
  27. layrz_sdk/entities/charts/bar_chart.py +12 -1
  28. layrz_sdk/entities/charts/chart_data_serie.py +17 -1
  29. layrz_sdk/entities/charts/column_chart.py +12 -1
  30. layrz_sdk/entities/charts/html_chart.py +8 -4
  31. layrz_sdk/entities/charts/line_chart.py +12 -3
  32. layrz_sdk/entities/charts/map_chart.py +14 -5
  33. layrz_sdk/entities/charts/map_point.py +7 -1
  34. layrz_sdk/entities/charts/number_chart.py +8 -4
  35. layrz_sdk/entities/charts/pie_chart.py +11 -3
  36. layrz_sdk/entities/charts/radar_chart.py +11 -3
  37. layrz_sdk/entities/charts/radial_bar_chart.py +11 -3
  38. layrz_sdk/entities/charts/scatter_chart.py +12 -3
  39. layrz_sdk/entities/charts/scatter_serie.py +11 -1
  40. layrz_sdk/entities/charts/scatter_serie_item.py +7 -1
  41. layrz_sdk/entities/charts/table_chart.py +7 -3
  42. layrz_sdk/entities/charts/table_header.py +7 -1
  43. layrz_sdk/entities/charts/table_row.py +7 -1
  44. layrz_sdk/entities/charts/timeline_chart.py +11 -3
  45. layrz_sdk/entities/charts/timeline_serie.py +7 -1
  46. layrz_sdk/entities/charts/timeline_serie_item.py +7 -1
  47. layrz_sdk/entities/checkpoint.py +20 -13
  48. layrz_sdk/entities/command_series_ticket.py +29 -4
  49. layrz_sdk/entities/comment.py +22 -5
  50. layrz_sdk/entities/custom_field.py +12 -4
  51. layrz_sdk/entities/custom_report_page.py +3 -0
  52. layrz_sdk/entities/destination_phone.py +7 -1
  53. layrz_sdk/entities/device.py +11 -4
  54. layrz_sdk/entities/event.py +20 -4
  55. layrz_sdk/entities/exchange_service.py +12 -4
  56. layrz_sdk/entities/function.py +11 -4
  57. layrz_sdk/entities/geofence.py +20 -5
  58. layrz_sdk/entities/geofence_category.py +0 -2
  59. layrz_sdk/entities/last_message.py +7 -3
  60. layrz_sdk/entities/locator.py +95 -0
  61. layrz_sdk/entities/message.py +16 -9
  62. layrz_sdk/entities/modbus/config.py +7 -1
  63. layrz_sdk/entities/modbus/parameter.py +7 -1
  64. layrz_sdk/entities/modbus/wait.py +11 -1
  65. layrz_sdk/entities/notification_type.py +0 -2
  66. layrz_sdk/entities/operation.py +37 -16
  67. layrz_sdk/entities/operation_case_payload.py +39 -13
  68. layrz_sdk/entities/operation_payload.py +63 -26
  69. layrz_sdk/entities/operation_type.py +0 -2
  70. layrz_sdk/entities/outbound_service.py +11 -4
  71. layrz_sdk/entities/parameter_update.py +25 -0
  72. layrz_sdk/entities/platform.py +0 -2
  73. layrz_sdk/entities/position.py +7 -3
  74. layrz_sdk/entities/preset.py +15 -9
  75. layrz_sdk/entities/report.py +9 -5
  76. layrz_sdk/entities/report_col.py +17 -3
  77. layrz_sdk/entities/report_configuration.py +7 -1
  78. layrz_sdk/entities/report_data_type.py +1 -3
  79. layrz_sdk/entities/report_format.py +1 -5
  80. layrz_sdk/entities/report_header.py +12 -29
  81. layrz_sdk/entities/report_page.py +7 -3
  82. layrz_sdk/entities/report_row.py +7 -19
  83. layrz_sdk/entities/request_type.py +0 -2
  84. layrz_sdk/entities/sensor.py +21 -3
  85. layrz_sdk/entities/sensor_mask.py +28 -0
  86. layrz_sdk/entities/sound_effect.py +0 -2
  87. layrz_sdk/entities/static_position.py +6 -1
  88. layrz_sdk/entities/telemetry/assetmessage.py +14 -15
  89. layrz_sdk/entities/telemetry/devicemessage.py +19 -9
  90. layrz_sdk/entities/text_alignment.py +0 -2
  91. layrz_sdk/entities/timezone.py +12 -4
  92. layrz_sdk/entities/trigger.py +102 -17
  93. layrz_sdk/entities/trigger_kind.py +2 -5
  94. layrz_sdk/entities/user.py +11 -4
  95. layrz_sdk/entities/waypoint.py +38 -16
  96. layrz_sdk/entities/weekday.py +1 -3
  97. layrz_sdk/helpers/color.py +1 -6
  98. layrz_sdk/lcl/core.py +0 -1
  99. {layrz_sdk-4.0.11.dist-info → layrz_sdk-4.1.8.dist-info}/METADATA +2 -2
  100. layrz_sdk-4.1.8.dist-info/RECORD +123 -0
  101. layrz_sdk-4.0.11.dist-info/RECORD +0 -116
  102. {layrz_sdk-4.0.11.dist-info → layrz_sdk-4.1.8.dist-info}/WHEEL +0 -0
  103. {layrz_sdk-4.0.11.dist-info → layrz_sdk-4.1.8.dist-info}/licenses/LICENSE +0 -0
  104. {layrz_sdk-4.0.11.dist-info → layrz_sdk-4.1.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,106 @@
1
+ from datetime import datetime
2
+ from enum import StrEnum
3
+ from typing import Any
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer
6
+
7
+ from .asset import Asset
8
+
9
+
10
+ class OrderStatus(StrEnum):
11
+ GENERATED = 'GENERATED'
12
+ IN_TRANSIT = 'IN_TRANSIT'
13
+ WAITING_TO_DISPATCH = 'WAITING_TO_DISPATCH' # For trucks
14
+ DELIVERED = 'DELIVERED'
15
+ # For the purchase order status in the port
16
+ READY_TO_OPERATE = 'READY_TO_OPERATE'
17
+ UNLOADING_OPERATION = 'UNLOADING_OPERATION'
18
+ UNLOADING_FUEL = 'UNLOADING_FUEL'
19
+ UNLOADING_FUEL_INTERRUPTED = 'UNLOADING_FUEL_INTERRUPTED'
20
+ DESTINATION_BERTH_EXIT = 'DESTINATION_BERTH_EXIT'
21
+ ORIGIN_BERTH_EXIT = 'ORIGIN_BERTH_EXIT'
22
+
23
+
24
+ class OrderCategories(StrEnum):
25
+ PICKUP = 'PICKUP'
26
+ PICKUP_TO_SUPPLIER = 'PICKUP_TO_SUPPLIER'
27
+ TRANSFER = 'TRANSFER'
28
+ DELIVERY_TO_SUPPLIER = 'DELIVERY_TO_SUPPLIER'
29
+ DELIVERY_TO_RESELLER = 'DELIVERY_TO_RESELLER'
30
+ FOR_SALE_OUTSIDE = 'FOR_SALE_OUTSIDE'
31
+ DELIVERY_TO_STORAGE = 'DELIVERY_TO_STORAGE'
32
+ RETURN_FROM_STORAGE = 'RETURN_FROM_STORAGE'
33
+ NOT_DEFINED = 'NOT_DEFINED'
34
+
35
+
36
+ class DeliveryCategories(StrEnum):
37
+ SAME_STATE = 'SAME_STATE'
38
+ OTHER_STATE = 'OTHER_STATE'
39
+ NOT_DEFINED = 'NOT_DEFINED'
40
+
41
+
42
+ class AtsPurchaseOrder(BaseModel):
43
+ """Entry entity"""
44
+
45
+ model_config = ConfigDict(
46
+ validate_by_name=False,
47
+ validate_by_alias=True,
48
+ serialize_by_alias=True,
49
+ )
50
+ pk: int = Field(
51
+ description='Defines the primary key of the Function',
52
+ alias='id',
53
+ )
54
+ purchased_at: datetime = Field(description='Timestamp when the operation was purchased')
55
+
56
+ @field_serializer('purchased_at', when_used='always')
57
+ def serialize_purchased_at(self, purchased_at: datetime) -> float:
58
+ return purchased_at.timestamp()
59
+
60
+ order_status: OrderStatus = Field(..., description='Current status of the order')
61
+
62
+ @field_serializer('order_status', when_used='always')
63
+ def serialize_order_status(self, order_status: OrderStatus) -> str:
64
+ return order_status.value
65
+
66
+ order_id: int = Field(description='ID of the order')
67
+ category: OrderCategories | None = Field(description='Category of the operation', default=None)
68
+
69
+ @field_serializer('category', when_used='always')
70
+ def serialize_category(self, category: OrderCategories | None) -> str | None:
71
+ return category.value if category else None
72
+
73
+ deliver_category: DeliveryCategories | None = Field(description='Delivery category of the operation', default=None)
74
+
75
+ @field_serializer('deliver_category', when_used='always')
76
+ def serialize_deliver_category(self, deliver_category: DeliveryCategories | None) -> str | None:
77
+ return deliver_category.value if deliver_category else None
78
+
79
+ seller_asset_id: int = Field(description='ID of the seller asset')
80
+ transport_asset_id: int | None = Field(description='ID of the transport asset', default=None)
81
+ asset_id: int = Field(description='ID of the asset')
82
+
83
+ seller_asset: Asset | None = Field(description='Seller asset details', default=None)
84
+ transport_asset: Asset | None = Field(description='Transport asset details', default=None)
85
+ asset: Asset | None = Field(description='Destination asset details', default=None)
86
+ delivered_at: datetime | None = Field(description='Timestamp when the operation was delivered', default=None)
87
+
88
+ @field_serializer('delivered_at', when_used='always')
89
+ def serialize_delivered_at(self, delivered_at: datetime | None) -> float | None:
90
+ return delivered_at.timestamp() if delivered_at else None
91
+
92
+ eta: datetime | None = Field(description='Estimated time of arrival to the destination', default=None)
93
+
94
+ @field_serializer('eta', when_used='always')
95
+ def serialize_eta(self, eta: datetime | None) -> float | None:
96
+ return eta.timestamp() if eta else None
97
+
98
+ eta_updated_at: datetime | None = Field(description='Timestamp when the ETA was last updated', default=None)
99
+
100
+ @field_serializer('eta_updated_at', when_used='always')
101
+ def serialize_eta_updated_at(self, eta_updated_at: datetime | None) -> float | None:
102
+ return eta_updated_at.timestamp() if eta_updated_at else None
103
+
104
+ invoice_type: str = Field(description='Type of the invoice')
105
+ operation_id: int | None = Field(description='ID of the operation', default=None)
106
+ products_information: list[dict[str, Any]] = Field(description='List of products information', default_factory=list)
@@ -1,8 +1,6 @@
1
- """Ats Reception entity"""
2
-
3
1
  from datetime import datetime
4
2
 
5
- from pydantic import BaseModel, Field
3
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer
6
4
 
7
5
  from layrz_sdk.constants import UTC
8
6
 
@@ -10,7 +8,16 @@ from layrz_sdk.constants import UTC
10
8
  class AtsReception(BaseModel):
11
9
  """AtsReception entity"""
12
10
 
13
- pk: int = Field(description='Defines the primary key of the AtsReception')
11
+ model_config = ConfigDict(
12
+ validate_by_name=False,
13
+ validate_by_alias=True,
14
+ serialize_by_alias=True,
15
+ )
16
+
17
+ pk: int = Field(
18
+ description='Defines the primary key of the AtsReception',
19
+ alias='id',
20
+ )
14
21
  volume_bought: float = Field(
15
22
  description='Volume bought in liters',
16
23
  default=0.0,
@@ -24,6 +31,11 @@ class AtsReception(BaseModel):
24
31
  description='Date and time when the reception was made',
25
32
  default_factory=lambda: datetime.now(UTC),
26
33
  )
34
+
35
+ @field_serializer('received_at', when_used='always')
36
+ def serialize_received_at(self, received_at: datetime) -> float:
37
+ return received_at.timestamp()
38
+
27
39
  fuel_type: str = Field(
28
40
  description='Type of fuel used in the reception',
29
41
  default='',
@@ -1,7 +1,7 @@
1
1
  from .payload import BroadcastPayload
2
2
  from .request import BroadcastRequest
3
3
  from .response import BroadcastResponse
4
- from .result import BroadcastResult
4
+ from .result import BroadcastResult, RawBroadcastResult
5
5
  from .service import BroadcastService
6
6
  from .status import BroadcastStatus
7
7
 
@@ -10,6 +10,7 @@ __all__ = [
10
10
  'BroadcastRequest',
11
11
  'BroadcastResponse',
12
12
  'BroadcastResult',
13
+ 'RawBroadcastResult',
13
14
  'BroadcastService',
14
15
  'BroadcastStatus',
15
16
  ]
@@ -3,11 +3,12 @@
3
3
  from datetime import datetime
4
4
  from typing import Any
5
5
 
6
- from pydantic import BaseModel, Field
6
+ from pydantic import BaseModel, Field, field_serializer
7
7
 
8
8
  from layrz_sdk.constants import UTC
9
9
  from layrz_sdk.entities.asset import Asset
10
10
  from layrz_sdk.entities.device import Device
11
+ from layrz_sdk.entities.locator import Locator
11
12
  from layrz_sdk.entities.trigger import Trigger
12
13
 
13
14
  from .service import BroadcastService
@@ -16,18 +17,37 @@ from .service import BroadcastService
16
17
  class BroadcastPayload(BaseModel):
17
18
  """Broadcast payload data, structure that is sent to the Outbound MQTT and other services"""
18
19
 
19
- model_config = {
20
- 'loc_by_alias': True,
21
- 'json_encoders': {
22
- datetime: lambda v: v.timestamp(),
23
- },
24
- }
25
-
26
20
  asset: Asset = Field(..., description='Asset object')
21
+
22
+ @field_serializer('asset', when_used='always')
23
+ def serialize_asset(self, v: Asset) -> dict[str, Any]:
24
+ return v.model_dump(mode='json', by_alias=True)
25
+
27
26
  primary_device: Device | None = Field(default=None, description='Primary device object')
27
+
28
+ @field_serializer('primary_device', when_used='always')
29
+ def serialize_primary_device(self, v: Device | None) -> dict[str, Any] | None:
30
+ if v is None:
31
+ return None
32
+ return v.model_dump(mode='json', by_alias=True)
33
+
28
34
  trigger: Trigger | None = Field(default=None, description='Trigger object, if available')
35
+
36
+ @field_serializer('trigger', when_used='always')
37
+ def serialize_trigger(self, v: Trigger | None) -> dict[str, Any] | None:
38
+ if v is None:
39
+ return None
40
+ return v.model_dump(mode='json', by_alias=True)
41
+
29
42
  message_id: int | str = Field(..., description='Message ID')
30
43
  service: BroadcastService | None = Field(default=None, description='Broadcast service object')
44
+
45
+ @field_serializer('service', when_used='always')
46
+ def serialize_service(self, v: BroadcastService | None) -> dict[str, Any] | None:
47
+ if v is None:
48
+ return None
49
+ return v.model_dump(mode='json', by_alias=True)
50
+
31
51
  position: dict[str, Any] = Field(default_factory=dict, description='Position data, if available')
32
52
  sensors: dict[str, Any] = Field(default_factory=dict, description='Sensors data, if available')
33
53
  payload: dict[str, Any] = Field(default_factory=dict, description='Payload data, if available')
@@ -35,3 +55,15 @@ class BroadcastPayload(BaseModel):
35
55
  default_factory=lambda: datetime.now(UTC),
36
56
  description='Broadcast payload received date',
37
57
  )
58
+
59
+ @field_serializer('received_at', when_used='always')
60
+ def serialize_received_at(self, v: datetime) -> float:
61
+ return v.timestamp()
62
+
63
+ locator: Locator | None = Field(default=None, description='Locator object, if available')
64
+
65
+ @field_serializer('locator', when_used='always')
66
+ def serialize_locator(self, v: Locator | None) -> dict[str, Any] | None:
67
+ if v is None:
68
+ return None
69
+ return v.model_dump(mode='json', by_alias=True)
@@ -1,8 +1,9 @@
1
1
  """Broadcast result"""
2
2
 
3
3
  from datetime import datetime
4
+ from typing import Any
4
5
 
5
- from pydantic import BaseModel, Field
6
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer
6
7
 
7
8
  from .request import BroadcastRequest
8
9
  from .response import BroadcastResponse
@@ -18,3 +19,73 @@ class BroadcastResult(BaseModel):
18
19
  request: BroadcastRequest = Field(description='Broadcast request')
19
20
  response: BroadcastResponse = Field(description='Broadcast response')
20
21
  submitted_at: datetime = Field(description='Broadcast submission date')
22
+
23
+
24
+ class RawBroadcastResult(BaseModel):
25
+ """Broadcast result data"""
26
+
27
+ model_config = ConfigDict(
28
+ validate_by_name=False,
29
+ validate_by_alias=True,
30
+ serialize_by_alias=True,
31
+ )
32
+
33
+ pk: int | None = Field(
34
+ default=None,
35
+ description='Broadcast result ID',
36
+ alias='id',
37
+ )
38
+
39
+ trigger_id: int | None = Field(default=None, description='Trigger ID')
40
+ service_id: int | None = Field(description='Service ID')
41
+ asset_id: int | None = Field(description='Asset ID')
42
+
43
+ status: BroadcastStatus = Field(description='Broadcast status')
44
+
45
+ @field_serializer('status', when_used='always')
46
+ def serialize_status(self, status: BroadcastStatus) -> str:
47
+ return status.value
48
+
49
+ algorithm: str | None = Field(
50
+ default=None,
51
+ description='Algorithm used for the broadcast, if any',
52
+ )
53
+
54
+ request: dict[str, Any] = Field(
55
+ default_factory=dict,
56
+ description='Broadcast request data',
57
+ )
58
+
59
+ response: dict[str, Any] = Field(
60
+ default_factory=dict,
61
+ description='Broadcast response data',
62
+ )
63
+
64
+ error: dict[str, Any] = Field(
65
+ default_factory=dict,
66
+ description='Error message if the broadcast failed',
67
+ )
68
+
69
+ service: dict[str, Any] = Field(
70
+ default_factory=dict,
71
+ description='Service details at the time of the broadcast',
72
+ )
73
+
74
+ asset: dict[str, Any] = Field(
75
+ default_factory=dict,
76
+ description='Asset details at the time of the broadcast',
77
+ )
78
+
79
+ trigger: dict[str, Any] = Field(
80
+ default_factory=dict,
81
+ description='Trigger details at the time of the broadcast',
82
+ )
83
+
84
+ submitted_at: datetime = Field(
85
+ description='Broadcast submission date',
86
+ alias='at',
87
+ )
88
+
89
+ @field_serializer('submitted_at', when_used='always')
90
+ def serialize_submitted_at(self, v: datetime) -> float:
91
+ return v.timestamp()
@@ -2,12 +2,22 @@
2
2
 
3
3
  from typing import Any
4
4
 
5
- from pydantic import BaseModel, Field
5
+ from pydantic import BaseModel, ConfigDict, Field
6
6
 
7
7
 
8
8
  class BroadcastService(BaseModel):
9
9
  """Broadcast Service object"""
10
10
 
11
- pk: int = Field(..., description='Service ID', alias='id')
11
+ model_config = ConfigDict(
12
+ validate_by_name=False,
13
+ validate_by_alias=True,
14
+ serialize_by_alias=True,
15
+ )
16
+
17
+ pk: int = Field(
18
+ ...,
19
+ description='Service ID',
20
+ alias='id',
21
+ )
12
22
  name: str = Field(..., description='Service name')
13
23
  credentials: dict[str, Any] = Field(default_factory=dict, description='Service credentials')
@@ -8,8 +8,8 @@ class BroadcastStatus(StrEnum):
8
8
  """Broadcast result status"""
9
9
 
10
10
  OK = 'OK'
11
- BADREQUEST = 'BADREQUEST'
12
- INTERNALERROR = 'INTERNALERROR'
11
+ BAD_REQUEST = 'BADREQUEST'
12
+ INTERNAL_ERROR = 'INTERNALERROR'
13
13
  UNAUTHORIZED = 'UNAUTHORIZED'
14
14
  UNPROCESSABLE = 'UNPROCESSABLE'
15
15
  DISCONNECTED = 'DISCONNECTED'
@@ -1,9 +1,7 @@
1
- """Events entities"""
2
-
3
1
  from datetime import datetime
4
- from typing import Any, Optional, Self
2
+ from typing import Any, Self
5
3
 
6
- from pydantic import BaseModel, Field, model_validator
4
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer, model_validator
7
5
 
8
6
  from .case_ignored_status import CaseIgnoredStatus
9
7
  from .case_status import CaseStatus
@@ -14,22 +12,56 @@ from .trigger import Trigger
14
12
  class Case(BaseModel):
15
13
  """Case entity"""
16
14
 
17
- pk: int = Field(description='Defines the primary key of the case', alias='id')
15
+ model_config = ConfigDict(
16
+ validate_by_name=False,
17
+ validate_by_alias=True,
18
+ serialize_by_alias=True,
19
+ )
20
+
21
+ pk: int = Field(
22
+ description='Defines the primary key of the case',
23
+ alias='id',
24
+ )
18
25
  trigger: Trigger = Field(description='Defines the trigger of the case')
19
26
  asset_id: int = Field(description='Defines the asset ID of the case')
20
27
  comments: list[Comment] = Field(default_factory=list, description='Defines the comments of the case')
21
28
  opened_at: datetime = Field(description='Defines the date when the case was opened')
22
- closed_at: Optional[datetime] = Field(default=None, description='Defines the date when the case was closed')
29
+
30
+ @field_serializer('opened_at', when_used='always')
31
+ def serialize_opened_at(self, opened_at: datetime) -> float:
32
+ return opened_at.timestamp()
33
+
34
+ closed_at: datetime | None = Field(default=None, description='Defines the date when the case was closed')
35
+
36
+ @field_serializer('closed_at', when_used='always')
37
+ def serialize_closed_at(self, closed_at: datetime | None) -> float | None:
38
+ return closed_at.timestamp() if closed_at else None
39
+
23
40
  status: CaseStatus = Field(description='Defines the status of the case', default=CaseStatus.CLOSED)
41
+
42
+ @field_serializer('status', when_used='always')
43
+ def serialize_status(self, status: CaseStatus) -> str:
44
+ return status.value
45
+
24
46
  ignored_status: CaseIgnoredStatus = Field(
25
47
  description='Defines the ignored status of the case',
26
48
  default=CaseIgnoredStatus.NORMAL,
27
49
  )
28
- sequence: Optional[int | str] = Field(
50
+
51
+ @field_serializer('ignored_status', when_used='always')
52
+ def serialize_ignored_status(self, ignored_status: CaseIgnoredStatus) -> str:
53
+ return ignored_status.value
54
+
55
+ sequence: int | str | None = Field(
29
56
  default=None,
30
57
  description='Defines the sequence of the case. This is a unique identifier for the case',
31
58
  )
32
59
 
60
+ stack_count: int = Field(
61
+ default=1,
62
+ description='Defines how many cases are stacked together. Only applicable if the trigger allows stacking',
63
+ )
64
+
33
65
  @model_validator(mode='before')
34
66
  def _validate_model(cls: Self, data: dict[str, Any]) -> dict[str, Any]:
35
67
  """Validate model"""
@@ -37,10 +69,21 @@ class Case(BaseModel):
37
69
  if sequence is not None and isinstance(sequence, int):
38
70
  trigger = data['trigger']
39
71
  if not isinstance(trigger, Trigger):
40
- data['sequence'] = f'{trigger["code"]}/{data["pk"]}'
72
+ if pk := data.get('pk'):
73
+ data['sequence'] = f'{trigger["code"]}/{pk}'
74
+ elif id_ := data.get('id'):
75
+ data['sequence'] = f'{trigger["code"]}/{id_}'
76
+ else:
77
+ data['sequence'] = f'{trigger["code"]}/{sequence}'
41
78
  else:
42
79
  data['sequence'] = f'{trigger.code}/{sequence}'
43
80
  else:
44
81
  data['sequence'] = f'GENERIC/{data["pk"]}'
45
82
 
83
+ if stack_count := data.get('stack_count'):
84
+ if not isinstance(stack_count, int) or stack_count < 1:
85
+ data['stack_count'] = 1
86
+ else:
87
+ data['stack_count'] = 1
88
+
46
89
  return data
@@ -11,6 +11,7 @@ class CaseIgnoredStatus(StrEnum):
11
11
  IGNORED = 'IGNORED'
12
12
  PRESET = 'PRESET'
13
13
  AUTO = 'AUTO'
14
+ EXPIRED = 'EXPIRED'
14
15
 
15
16
  def __str__(self: Self) -> str:
16
17
  """Readable property"""
@@ -1,6 +1,4 @@
1
- from typing import Optional
2
-
3
- from pydantic import BaseModel, Field
1
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer
4
2
 
5
3
  from .chart_data_type import ChartDataType
6
4
 
@@ -8,8 +6,18 @@ from .chart_data_type import ChartDataType
8
6
  class AxisConfig(BaseModel):
9
7
  """Axis configuration"""
10
8
 
9
+ model_config = ConfigDict(
10
+ validate_by_name=False,
11
+ validate_by_alias=True,
12
+ serialize_by_alias=True,
13
+ )
14
+
11
15
  label: str = Field(default='', description='Label of the axis')
12
16
  measure_unit: str = Field(default='', description='Measure unit of the axis')
13
- min_value: Optional[float] = Field(default=None, description='Minimum value of the axis')
14
- max_value: Optional[float] = Field(default=None, description='Maximum value of the axis')
17
+ min_value: float | None = Field(default=None, description='Minimum value of the axis')
18
+ max_value: float | None = Field(default=None, description='Maximum value of the axis')
15
19
  data_type: ChartDataType = Field(default=ChartDataType.DATETIME, description='Data type of the axis')
20
+
21
+ @field_serializer('data_type', when_used='always')
22
+ def serialize_data_type(self, data_type: ChartDataType) -> str:
23
+ return data_type.value
@@ -2,7 +2,7 @@
2
2
 
3
3
  from typing import Any, Self
4
4
 
5
- from pydantic import BaseModel, Field
5
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer
6
6
 
7
7
  from .axis_config import AxisConfig
8
8
  from .chart_alignment import ChartAlignment
@@ -14,10 +14,21 @@ from .chart_render_technology import ChartRenderTechnology
14
14
  class BarChart(BaseModel):
15
15
  """Bar chart configuration"""
16
16
 
17
+ model_config = ConfigDict(
18
+ validate_by_name=False,
19
+ validate_by_alias=True,
20
+ serialize_by_alias=True,
21
+ )
22
+
17
23
  x_axis: ChartDataSerie = Field(description='Defines the X Axis of the chart')
18
24
  y_axis: list[ChartDataSerie] = Field(description='Defines the Y Axis of the chart', default_factory=list)
19
25
  title: str = Field(default='Chart', description='Title of the chart')
20
26
  align: ChartAlignment = Field(default=ChartAlignment.CENTER, description='Alignment of the title')
27
+
28
+ @field_serializer('align', when_used='always')
29
+ def serialize_align(self, align: ChartAlignment) -> str:
30
+ return align.value
31
+
21
32
  x_axis_config: AxisConfig = Field(
22
33
  default_factory=lambda: AxisConfig(),
23
34
  description='Configuration of the X Axis',
@@ -2,7 +2,7 @@
2
2
 
3
3
  from typing import Any
4
4
 
5
- from pydantic import BaseModel, Field
5
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer
6
6
 
7
7
  from .chart_data_serie_type import ChartDataSerieType
8
8
  from .chart_data_type import ChartDataType
@@ -11,9 +11,25 @@ from .chart_data_type import ChartDataType
11
11
  class ChartDataSerie(BaseModel):
12
12
  """Chart Serie"""
13
13
 
14
+ model_config = ConfigDict(
15
+ validate_by_name=False,
16
+ validate_by_alias=True,
17
+ serialize_by_alias=True,
18
+ )
19
+
14
20
  data: Any = Field(description='Data of the serie')
15
21
  color: str = Field(description='Color of the serie', default='#000000')
16
22
  label: str = Field(description='Label of the serie', default='')
17
23
  serie_type: ChartDataSerieType = Field(description='Type of the serie', default=ChartDataSerieType.LINE)
24
+
25
+ @field_serializer('serie_type', when_used='always')
26
+ def serialize_serie_type(self, serie_type: ChartDataSerieType) -> str:
27
+ return serie_type.value
28
+
18
29
  data_type: ChartDataType = Field(description='Type of the data', default=ChartDataType.NUMBER)
30
+
31
+ @field_serializer('data_type', when_used='always')
32
+ def serialize_data_type(self, data_type: ChartDataType) -> str:
33
+ return data_type.value
34
+
19
35
  dashed: bool = Field(description='If the serie should be dashed', default=False)
@@ -2,7 +2,7 @@
2
2
 
3
3
  from typing import Any, Self
4
4
 
5
- from pydantic import BaseModel, Field
5
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer
6
6
 
7
7
  from layrz_sdk.helpers import convert_to_rgba
8
8
 
@@ -16,10 +16,21 @@ from .chart_render_technology import ChartRenderTechnology
16
16
  class ColumnChart(BaseModel):
17
17
  """Column chart configuration"""
18
18
 
19
+ model_config = ConfigDict(
20
+ validate_by_name=False,
21
+ validate_by_alias=True,
22
+ serialize_by_alias=True,
23
+ )
24
+
19
25
  x_axis: ChartDataSerie = Field(description='Defines the X Axis of the chart')
20
26
  y_axis: list[ChartDataSerie] = Field(description='Defines the Y Axis of the chart', default_factory=list)
21
27
  title: str = Field(default='Chart', description='Title of the chart')
22
28
  align: ChartAlignment = Field(default=ChartAlignment.CENTER, description='Alignment of the title')
29
+
30
+ @field_serializer('align', when_used='always')
31
+ def serialize_align(self, align: ChartAlignment) -> str:
32
+ return align.value
33
+
23
34
  x_axis_config: AxisConfig = Field(
24
35
  default_factory=lambda: AxisConfig(),
25
36
  description='Configuration of the X Axis',
@@ -1,13 +1,17 @@
1
- """HTML chart"""
1
+ from typing import Any, Self
2
2
 
3
- from typing import Any, Dict, Self
4
-
5
- from pydantic import BaseModel, Field
3
+ from pydantic import BaseModel, ConfigDict, Field
6
4
 
7
5
 
8
6
  class HTMLChart(BaseModel):
9
7
  """HTML chart configuration"""
10
8
 
9
+ model_config = ConfigDict(
10
+ validate_by_name=False,
11
+ validate_by_alias=True,
12
+ serialize_by_alias=True,
13
+ )
14
+
11
15
  content: str = Field(description='HTML content of the chart', default='<p>N/A</p>')
12
16
  title: str = Field(description='Title of the chart', default='Chart')
13
17
 
@@ -1,9 +1,7 @@
1
- """Line chart"""
2
-
3
1
  import logging
4
2
  from typing import Any, Self
5
3
 
6
- from pydantic import BaseModel, Field
4
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer
7
5
 
8
6
  from .axis_config import AxisConfig
9
7
  from .chart_alignment import ChartAlignment
@@ -18,10 +16,21 @@ log = logging.getLogger(__name__)
18
16
  class LineChart(BaseModel):
19
17
  """Line chart configuration"""
20
18
 
19
+ model_config = ConfigDict(
20
+ validate_by_name=False,
21
+ validate_by_alias=True,
22
+ serialize_by_alias=True,
23
+ )
24
+
21
25
  x_axis: ChartDataSerie = Field(description='Defines the X Axis of the chart')
22
26
  y_axis: list[ChartDataSerie] = Field(description='Defines the Y Axis of the chart', default_factory=list)
23
27
  title: str = Field(default='Chart', description='Title of the chart')
24
28
  align: ChartAlignment = Field(default=ChartAlignment.CENTER, description='Alignment of the title')
29
+
30
+ @field_serializer('align', when_used='always')
31
+ def serialize_align(self, align: ChartAlignment) -> str:
32
+ return align.value
33
+
25
34
  x_axis_config: AxisConfig = Field(
26
35
  default_factory=lambda: AxisConfig(),
27
36
  description='Configuration of the X Axis',