layrz-sdk 4.0.23__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 (100) hide show
  1. layrz_sdk/decorators/func_timing.py +14 -7
  2. layrz_sdk/entities/__init__.py +7 -0
  3. layrz_sdk/entities/action.py +28 -16
  4. layrz_sdk/entities/action_geofence_ownership.py +0 -2
  5. layrz_sdk/entities/action_kind.py +0 -2
  6. layrz_sdk/entities/action_subkind.py +0 -2
  7. layrz_sdk/entities/asset.py +15 -9
  8. layrz_sdk/entities/asset_constants.py +10 -9
  9. layrz_sdk/entities/asset_contact.py +7 -3
  10. layrz_sdk/entities/asset_operation_mode.py +0 -2
  11. layrz_sdk/entities/ats_entry.py +11 -4
  12. layrz_sdk/entities/ats_exit_history.py +21 -19
  13. layrz_sdk/entities/ats_operation.py +57 -17
  14. layrz_sdk/entities/ats_possible_entry.py +9 -4
  15. layrz_sdk/entities/ats_possible_exit.py +19 -9
  16. layrz_sdk/entities/ats_purchaseorder.py +53 -12
  17. layrz_sdk/entities/ats_reception.py +16 -4
  18. layrz_sdk/entities/broadcast/payload.py +40 -8
  19. layrz_sdk/entities/broadcast/result.py +21 -2
  20. layrz_sdk/entities/broadcast/service.py +12 -2
  21. layrz_sdk/entities/case.py +34 -7
  22. layrz_sdk/entities/charts/axis_config.py +13 -5
  23. layrz_sdk/entities/charts/bar_chart.py +12 -1
  24. layrz_sdk/entities/charts/chart_data_serie.py +17 -1
  25. layrz_sdk/entities/charts/column_chart.py +12 -1
  26. layrz_sdk/entities/charts/html_chart.py +8 -4
  27. layrz_sdk/entities/charts/line_chart.py +12 -3
  28. layrz_sdk/entities/charts/map_chart.py +14 -5
  29. layrz_sdk/entities/charts/map_point.py +7 -1
  30. layrz_sdk/entities/charts/number_chart.py +8 -4
  31. layrz_sdk/entities/charts/pie_chart.py +11 -3
  32. layrz_sdk/entities/charts/radar_chart.py +11 -3
  33. layrz_sdk/entities/charts/radial_bar_chart.py +11 -3
  34. layrz_sdk/entities/charts/scatter_chart.py +12 -3
  35. layrz_sdk/entities/charts/scatter_serie.py +11 -1
  36. layrz_sdk/entities/charts/scatter_serie_item.py +7 -1
  37. layrz_sdk/entities/charts/table_chart.py +7 -3
  38. layrz_sdk/entities/charts/table_header.py +7 -1
  39. layrz_sdk/entities/charts/table_row.py +7 -1
  40. layrz_sdk/entities/charts/timeline_chart.py +11 -3
  41. layrz_sdk/entities/charts/timeline_serie.py +7 -1
  42. layrz_sdk/entities/charts/timeline_serie_item.py +7 -1
  43. layrz_sdk/entities/checkpoint.py +20 -13
  44. layrz_sdk/entities/command_series_ticket.py +29 -4
  45. layrz_sdk/entities/comment.py +15 -4
  46. layrz_sdk/entities/custom_field.py +12 -4
  47. layrz_sdk/entities/custom_report_page.py +3 -0
  48. layrz_sdk/entities/destination_phone.py +7 -1
  49. layrz_sdk/entities/device.py +11 -4
  50. layrz_sdk/entities/event.py +20 -4
  51. layrz_sdk/entities/exchange_service.py +12 -4
  52. layrz_sdk/entities/function.py +11 -4
  53. layrz_sdk/entities/geofence.py +12 -4
  54. layrz_sdk/entities/geofence_category.py +0 -2
  55. layrz_sdk/entities/last_message.py +7 -3
  56. layrz_sdk/entities/locator.py +95 -0
  57. layrz_sdk/entities/message.py +16 -9
  58. layrz_sdk/entities/modbus/config.py +7 -1
  59. layrz_sdk/entities/modbus/parameter.py +7 -1
  60. layrz_sdk/entities/modbus/wait.py +11 -1
  61. layrz_sdk/entities/notification_type.py +0 -2
  62. layrz_sdk/entities/operation.py +37 -16
  63. layrz_sdk/entities/operation_case_payload.py +39 -13
  64. layrz_sdk/entities/operation_payload.py +63 -26
  65. layrz_sdk/entities/operation_type.py +0 -2
  66. layrz_sdk/entities/outbound_service.py +11 -4
  67. layrz_sdk/entities/parameter_update.py +25 -0
  68. layrz_sdk/entities/platform.py +0 -2
  69. layrz_sdk/entities/position.py +7 -3
  70. layrz_sdk/entities/preset.py +15 -9
  71. layrz_sdk/entities/report.py +9 -5
  72. layrz_sdk/entities/report_col.py +17 -3
  73. layrz_sdk/entities/report_configuration.py +7 -1
  74. layrz_sdk/entities/report_data_type.py +1 -3
  75. layrz_sdk/entities/report_format.py +1 -5
  76. layrz_sdk/entities/report_header.py +12 -29
  77. layrz_sdk/entities/report_page.py +7 -3
  78. layrz_sdk/entities/report_row.py +7 -19
  79. layrz_sdk/entities/request_type.py +0 -2
  80. layrz_sdk/entities/sensor.py +11 -4
  81. layrz_sdk/entities/sensor_mask.py +16 -5
  82. layrz_sdk/entities/sound_effect.py +0 -2
  83. layrz_sdk/entities/static_position.py +6 -1
  84. layrz_sdk/entities/telemetry/assetmessage.py +14 -15
  85. layrz_sdk/entities/telemetry/devicemessage.py +19 -9
  86. layrz_sdk/entities/text_alignment.py +0 -2
  87. layrz_sdk/entities/timezone.py +12 -4
  88. layrz_sdk/entities/trigger.py +46 -13
  89. layrz_sdk/entities/trigger_kind.py +1 -5
  90. layrz_sdk/entities/user.py +11 -4
  91. layrz_sdk/entities/waypoint.py +38 -16
  92. layrz_sdk/entities/weekday.py +1 -3
  93. layrz_sdk/helpers/color.py +1 -6
  94. layrz_sdk/lcl/core.py +0 -1
  95. {layrz_sdk-4.0.23.dist-info → layrz_sdk-4.1.8.dist-info}/METADATA +2 -2
  96. layrz_sdk-4.1.8.dist-info/RECORD +123 -0
  97. layrz_sdk-4.0.23.dist-info/RECORD +0 -121
  98. {layrz_sdk-4.0.23.dist-info → layrz_sdk-4.1.8.dist-info}/WHEEL +0 -0
  99. {layrz_sdk-4.0.23.dist-info → layrz_sdk-4.1.8.dist-info}/licenses/LICENSE +0 -0
  100. {layrz_sdk-4.0.23.dist-info → layrz_sdk-4.1.8.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,7 @@
1
- """Message entity"""
2
-
3
1
  from datetime import datetime
4
2
  from typing import Any
5
3
 
6
- from pydantic import BaseModel, Field, field_validator
4
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator
7
5
 
8
6
  from layrz_sdk.constants import UTC
9
7
  from layrz_sdk.entities.geofence import Geofence
@@ -13,13 +11,17 @@ from layrz_sdk.entities.position import Position
13
11
  class Message(BaseModel):
14
12
  """Message definition"""
15
13
 
16
- model_config = {
17
- 'json_encoders': {
18
- datetime: lambda v: v.timestamp(),
19
- }
20
- }
14
+ model_config = ConfigDict(
15
+ validate_by_name=False,
16
+ validate_by_alias=True,
17
+ serialize_by_alias=True,
18
+ )
21
19
 
22
- pk: int = Field(..., description='Message ID', alias='id')
20
+ pk: int = Field(
21
+ ...,
22
+ description='Message ID',
23
+ alias='id',
24
+ )
23
25
  asset_id: int = Field(..., description='Asset ID')
24
26
  position: Position = Field(
25
27
  default_factory=lambda: Position(),
@@ -38,6 +40,11 @@ class Message(BaseModel):
38
40
  description='Timestamp when the message was received',
39
41
  )
40
42
 
43
+ @field_serializer('received_at', when_used='always')
44
+ def serialize_received_at(self, value: datetime) -> float:
45
+ """Serialize received_at to a timestamp."""
46
+ return value.timestamp()
47
+
41
48
  geofences: list[Geofence] = Field(
42
49
  default_factory=list,
43
50
  description='List of geofences associated with the message',
@@ -1,9 +1,15 @@
1
- from pydantic import BaseModel, Field
1
+ from pydantic import BaseModel, ConfigDict, Field
2
2
 
3
3
  from .parameter import ModbusParameter
4
4
 
5
5
 
6
6
  class ModbusConfig(BaseModel):
7
+ model_config = ConfigDict(
8
+ validate_by_name=False,
9
+ validate_by_alias=True,
10
+ serialize_by_alias=True,
11
+ )
12
+
7
13
  port_id: str = Field(
8
14
  ...,
9
15
  description='Port ID for Modbus communication',
@@ -1,6 +1,6 @@
1
1
  from typing import Any
2
2
 
3
- from pydantic import BaseModel, Field, field_validator
3
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
4
4
 
5
5
  from .schema import ModbusSchema
6
6
 
@@ -8,6 +8,12 @@ from .schema import ModbusSchema
8
8
  class ModbusParameter(BaseModel):
9
9
  """Modbus parameter model"""
10
10
 
11
+ model_config = ConfigDict(
12
+ validate_by_name=False,
13
+ validate_by_alias=True,
14
+ serialize_by_alias=True,
15
+ )
16
+
11
17
  schema_: ModbusSchema = Field(
12
18
  ...,
13
19
  description='Modbus schema',
@@ -1,6 +1,6 @@
1
1
  from typing import Any
2
2
 
3
- from pydantic import BaseModel, Field, field_validator
3
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator
4
4
 
5
5
  from .schema import ModbusSchema
6
6
  from .status import ModbusStatus
@@ -9,11 +9,21 @@ from .status import ModbusStatus
9
9
  class ModbusWait(BaseModel):
10
10
  """Modbus parameter model"""
11
11
 
12
+ model_config = ConfigDict(
13
+ validate_by_name=False,
14
+ validate_by_alias=True,
15
+ serialize_by_alias=True,
16
+ )
17
+
12
18
  status: ModbusStatus = Field(
13
19
  ...,
14
20
  description='Status of the Modbus command',
15
21
  )
16
22
 
23
+ @field_serializer('status', when_used='always')
24
+ def serialize_status(self, status: ModbusStatus) -> str:
25
+ return status.value
26
+
17
27
  structure: ModbusSchema = Field(
18
28
  ...,
19
29
  description='Modbus structure schema',
@@ -1,5 +1,3 @@
1
- """Twilio Notification Type Enum"""
2
-
3
1
  from enum import StrEnum
4
2
  from typing import Self
5
3
 
@@ -1,9 +1,7 @@
1
- """Operation entity"""
2
-
3
- from datetime import time, timedelta
1
+ from datetime import timedelta
4
2
  from typing import Any, Self
5
3
 
6
- from pydantic import BaseModel, Field, field_validator
4
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator
7
5
 
8
6
  from .destination_phone import DestinationPhone
9
7
  from .notification_type import TwilioNotificationType
@@ -17,18 +15,16 @@ from .timezone import Timezone
17
15
  class Operation(BaseModel):
18
16
  """Operation entity"""
19
17
 
20
- model_config = {
21
- 'json_encoders': {
22
- timedelta: lambda v: v.total_seconds(),
23
- OperationType: lambda v: v.value,
24
- HttpRequestType: lambda v: v.value,
25
- TwilioNotificationType: lambda v: v.value,
26
- SoundEffect: lambda v: v.value,
27
- Platform: lambda v: v.value,
28
- },
29
- }
30
-
31
- pk: int = Field(description='Defines the primary key of the trigger', alias='id')
18
+ model_config = ConfigDict(
19
+ validate_by_name=False,
20
+ validate_by_alias=True,
21
+ serialize_by_alias=True,
22
+ )
23
+
24
+ pk: int = Field(
25
+ description='Defines the primary key of the trigger',
26
+ alias='id',
27
+ )
32
28
  name: str = Field(description='Defines the name of the trigger')
33
29
 
34
30
  cooldown_time: timedelta = Field(
@@ -36,11 +32,19 @@ class Operation(BaseModel):
36
32
  description='Defines the cooldown time of the trigger',
37
33
  )
38
34
 
35
+ @field_serializer('cooldown_time', when_used='always')
36
+ def serialize_cooldown_time(self, value: timedelta) -> float:
37
+ return value.total_seconds()
38
+
39
39
  operation_type: OperationType = Field(
40
40
  ...,
41
41
  description='Defines the kind of the operation',
42
42
  )
43
43
 
44
+ @field_serializer('operation_type', when_used='always')
45
+ def serialize_operation_type(self, value: OperationType) -> str:
46
+ return value.value
47
+
44
48
  @property
45
49
  def kind(self: Self) -> OperationType:
46
50
  """Get the kind of the operation"""
@@ -51,6 +55,10 @@ class Operation(BaseModel):
51
55
  description='Defines the HTTP method of the operation',
52
56
  )
53
57
 
58
+ @field_serializer('request_type', when_used='always')
59
+ def serialize_request_type(self, value: HttpRequestType | None) -> str | None:
60
+ return value.value if value else None
61
+
54
62
  @property
55
63
  def http_method(self: Self) -> HttpRequestType | None:
56
64
  """Get the HTTP method of the operation"""
@@ -125,6 +133,11 @@ class Operation(BaseModel):
125
133
  description='Defines the Twilio notification type of the operation',
126
134
  )
127
135
 
136
+ @field_serializer('notification_type', when_used='always')
137
+ def serialize_notification_type(self, value: TwilioNotificationType) -> str:
138
+ """Serialize notification_type to its value."""
139
+ return value.value
140
+
128
141
  @property
129
142
  def twilio_notification_type(self: Self) -> TwilioNotificationType:
130
143
  """Get the Twilio notification type of the operation"""
@@ -201,6 +214,10 @@ class Operation(BaseModel):
201
214
  description='Defines the sound effect for the operation',
202
215
  )
203
216
 
217
+ @field_serializer('sound_effect', when_used='always')
218
+ def serialize_sound_effect(self, value: SoundEffect) -> str:
219
+ return value.value
220
+
204
221
  sound_effect_uri: str | None = Field(
205
222
  default=None,
206
223
  description='Defines the URI for the sound effect of the operation. Only when sound_effect is set to CUSTOM.',
@@ -211,6 +228,10 @@ class Operation(BaseModel):
211
228
  description='Defines the duration of the operation',
212
229
  )
213
230
 
231
+ @field_serializer('duration', when_used='always')
232
+ def serialize_duration(self, value: timedelta | None) -> float | None:
233
+ return value.total_seconds() if value else None
234
+
214
235
  @field_validator('duration', mode='before')
215
236
  def validate_duration(cls, value: Any) -> timedelta:
216
237
  if value is None:
@@ -1,9 +1,7 @@
1
- """Operation case payload entity"""
2
-
3
1
  from datetime import datetime, timedelta
4
2
  from typing import Any
5
3
 
6
- from pydantic import BaseModel, Field, field_validator
4
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator
7
5
 
8
6
  from layrz_sdk.constants import UTC
9
7
  from layrz_sdk.entities.trigger import Trigger
@@ -12,7 +10,17 @@ from layrz_sdk.entities.trigger import Trigger
12
10
  class OperationCaseCommentPayload(BaseModel):
13
11
  """Operation case comment payload entity"""
14
12
 
15
- pk: int = Field(..., description='Defines the primary key of the operation case comment', alias='id')
13
+ model_config = ConfigDict(
14
+ validate_by_name=False,
15
+ validate_by_alias=True,
16
+ serialize_by_alias=True,
17
+ )
18
+
19
+ pk: int = Field(
20
+ ...,
21
+ description='Defines the primary key of the operation case comment',
22
+ alias='id',
23
+ )
16
24
  user: str = Field(..., description='Defines the user who created the operation case comment')
17
25
  content: str = Field(..., description='Defines the content of the operation case comment')
18
26
  created_at: datetime = Field(
@@ -20,28 +28,42 @@ class OperationCaseCommentPayload(BaseModel):
20
28
  description='Defines the creation date of the operation case comment',
21
29
  )
22
30
 
31
+ @field_serializer('created_at', when_used='always')
32
+ def serialize_created_at(self, created_at: datetime) -> float:
33
+ return created_at.timestamp()
34
+
23
35
 
24
36
  class OperationCasePayload(BaseModel):
25
37
  """Operation case payload entity"""
26
38
 
27
- model_config = {
28
- 'json_encoders': {
29
- timedelta: lambda v: v.total_seconds(),
30
- datetime: lambda v: v.timestamp(),
31
- Trigger: lambda v: v.model_dump(by_alias=True, exclude_none=True),
32
- },
33
- }
39
+ model_config = ConfigDict(
40
+ validate_by_name=False,
41
+ validate_by_alias=True,
42
+ serialize_by_alias=True,
43
+ )
34
44
 
35
- pk: int = Field(description='Defines the primary key of the operation case payload', alias='id')
45
+ pk: int = Field(
46
+ description='Defines the primary key of the operation case payload',
47
+ alias='id',
48
+ )
36
49
  created_at: datetime = Field(
37
50
  default_factory=lambda: datetime.now(UTC),
38
51
  description='Defines the creation date of the operation case payload',
39
52
  )
53
+
54
+ @field_serializer('created_at', when_used='always')
55
+ def serialize_created_at(self, created_at: datetime) -> float:
56
+ return created_at.timestamp()
57
+
40
58
  updated_at: datetime = Field(
41
59
  default_factory=lambda: datetime.now(UTC),
42
60
  description='Defines the last update date of the operation case payload',
43
61
  )
44
62
 
63
+ @field_serializer('updated_at', when_used='always')
64
+ def serialize_updated_at(self, updated_at: datetime) -> float:
65
+ return updated_at.timestamp()
66
+
45
67
  trigger: Trigger = Field(
46
68
  ...,
47
69
  description='Defines the trigger associated with the operation case payload',
@@ -52,7 +74,7 @@ class OperationCasePayload(BaseModel):
52
74
  """Serialize trigger to a dictionary"""
53
75
  if isinstance(value, Trigger):
54
76
  return Trigger(
55
- id=value.pk,
77
+ id=value.pk, # ty: ignore
56
78
  name=value.name,
57
79
  code=value.code,
58
80
  )
@@ -71,6 +93,10 @@ class OperationCasePayload(BaseModel):
71
93
  description='Defines the creation date of the file associated with the operation case payload',
72
94
  )
73
95
 
96
+ @field_serializer('file_created_at', when_used='always')
97
+ def serialize_file_created_at(self, file_created_at: datetime | None) -> float | None:
98
+ return file_created_at.timestamp() if file_created_at else None
99
+
74
100
  comment: OperationCaseCommentPayload | None = Field(
75
101
  default=None,
76
102
  description='Defines the comment associated with the operation case payload',
@@ -1,13 +1,12 @@
1
- """Operation Payload entity"""
2
-
3
1
  from datetime import datetime, timedelta
4
- from typing import Any, Self
2
+ from typing import Any
5
3
 
6
- from pydantic import BaseModel, Field, field_validator
4
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator
7
5
 
8
6
  from layrz_sdk.entities.asset import Asset
9
7
  from layrz_sdk.entities.destination_phone import DestinationPhone
10
8
  from layrz_sdk.entities.geofence import Geofence
9
+ from layrz_sdk.entities.locator import Locator
11
10
  from layrz_sdk.entities.notification_type import TwilioNotificationType
12
11
  from layrz_sdk.entities.operation import Operation
13
12
  from layrz_sdk.entities.operation_case_payload import OperationCasePayload
@@ -22,22 +21,11 @@ from layrz_sdk.entities.trigger import Trigger
22
21
  class OperationPayload(BaseModel):
23
22
  """Operation Payload entity"""
24
23
 
25
- model_config = {
26
- 'json_encoders': {
27
- timedelta: lambda v: v.total_seconds(),
28
- datetime: lambda v: v.timestamp(),
29
- Asset: lambda v: v.model_dump(by_alias=True, exclude_none=True),
30
- Trigger: lambda v: v.model_dump(by_alias=True, exclude_none=True),
31
- Operation: lambda v: v.model_dump(by_alias=True, exclude_none=True),
32
- Geofence: lambda v: v.model_dump(by_alias=True, exclude_none=True),
33
- OperationType: lambda v: v.value,
34
- HttpRequestType: lambda v: v.value,
35
- TwilioNotificationType: lambda v: v.value,
36
- SoundEffect: lambda v: v.value,
37
- Platform: lambda v: v.value,
38
- PresenceType: lambda v: v.value,
39
- },
40
- }
24
+ model_config = ConfigDict(
25
+ validate_by_name=False,
26
+ validate_by_alias=True,
27
+ serialize_by_alias=True,
28
+ )
41
29
 
42
30
  kind: OperationType = Field(
43
31
  ...,
@@ -45,14 +33,18 @@ class OperationPayload(BaseModel):
45
33
  alias='operationType',
46
34
  )
47
35
 
36
+ @field_serializer('kind', when_used='always')
37
+ def serialize_kind(self, value: OperationType) -> str:
38
+ return value.value
39
+
48
40
  asset: Asset = Field(..., description='Defines the asset associated with the operation')
49
41
 
50
42
  @field_validator('asset', mode='before')
51
- def serialize_asset(cls, value: Any) -> Asset:
43
+ def validate_asset(cls, value: Any) -> Asset:
52
44
  """Serialize asset to a dictionary"""
53
45
  if isinstance(value, Asset):
54
46
  return Asset(
55
- id=value.pk,
47
+ id=value.pk, # ty: ignore
56
48
  name=value.name,
57
49
  operation_mode=value.operation_mode,
58
50
  vin=value.vin,
@@ -69,11 +61,11 @@ class OperationPayload(BaseModel):
69
61
  trigger: Trigger = Field(..., description='Defines the trigger associated with the operation')
70
62
 
71
63
  @field_validator('trigger', mode='before')
72
- def serialize_trigger(cls, value: Any) -> Trigger:
64
+ def validate_trigger(cls, value: Any) -> Trigger:
73
65
  """Serialize trigger to a dictionary"""
74
66
  if isinstance(value, Trigger):
75
67
  return Trigger(
76
- id=value.pk,
68
+ id=value.pk, # ty: ignore
77
69
  name=value.name,
78
70
  code=value.code,
79
71
  )
@@ -86,11 +78,11 @@ class OperationPayload(BaseModel):
86
78
  operation: Operation = Field(..., description='Defines the operation associated with the payload')
87
79
 
88
80
  @field_validator('operation', mode='before')
89
- def serialize_operation(cls, value: Any) -> Operation:
81
+ def validate_operation(cls, value: Any) -> Operation:
90
82
  """Serialize operation to a dictionary"""
91
83
  if isinstance(value, Operation):
92
84
  return Operation(
93
- id=value.pk,
85
+ id=value.pk, # ty: ignore
94
86
  name=value.name,
95
87
  operation_type=value.kind,
96
88
  timezone=value.timezone,
@@ -107,6 +99,10 @@ class OperationPayload(BaseModel):
107
99
  alias='activatedAt',
108
100
  )
109
101
 
102
+ @field_serializer('activated_at', when_used='always')
103
+ def serialize_activated_at(self, value: datetime) -> float:
104
+ return value.timestamp()
105
+
110
106
  position: dict[str, Any] = Field(
111
107
  default_factory=dict,
112
108
  description='Defines the position of the operation',
@@ -128,6 +124,10 @@ class OperationPayload(BaseModel):
128
124
  alias='presenceType',
129
125
  )
130
126
 
127
+ @field_serializer('presence_type', when_used='always')
128
+ def serialize_presence_type(self, value: PresenceType | None) -> Any:
129
+ return value.value if value else None
130
+
131
131
  case_: OperationCasePayload | None = Field(
132
132
  default=None,
133
133
  description='Defines the case of the operation',
@@ -167,6 +167,11 @@ class OperationPayload(BaseModel):
167
167
  description='Defines the HTTP method of the operation',
168
168
  alias='method',
169
169
  )
170
+
171
+ @field_serializer('http_method', when_used='always')
172
+ def serialize_http_method(self, value: HttpRequestType | None) -> Any:
173
+ return value.value if value else None
174
+
170
175
  http_headers: list[dict[str, Any]] = Field(
171
176
  default_factory=list,
172
177
  description='Defines the headers of the operation',
@@ -221,12 +226,27 @@ class OperationPayload(BaseModel):
221
226
  alias='hostPhone',
222
227
  )
223
228
 
229
+ @field_validator('twilio_host_phone', mode='before')
230
+ def serialize_twilio_host_phone(cls, value: Any) -> DestinationPhone | None:
231
+ """Serialize host phone to a DestinationPhone"""
232
+ if isinstance(value, DestinationPhone):
233
+ return value
234
+
235
+ if isinstance(value, dict):
236
+ return DestinationPhone.model_validate(value)
237
+
238
+ return None
239
+
224
240
  twilio_notification_type: TwilioNotificationType = Field(
225
241
  default=TwilioNotificationType.SMS,
226
242
  description='Defines the Twilio notification type of the operation',
227
243
  alias='notificationType',
228
244
  )
229
245
 
246
+ @field_serializer('twilio_notification_type', when_used='always')
247
+ def serialize_twilio_notification_type(self, value: TwilioNotificationType) -> str:
248
+ return value.value
249
+
230
250
  username: str | None = Field(
231
251
  default=None,
232
252
  description='Defines the username for the operation',
@@ -262,6 +282,10 @@ class OperationPayload(BaseModel):
262
282
  alias='pushPlatforms',
263
283
  )
264
284
 
285
+ @field_serializer('push_platforms', when_used='always')
286
+ def serialize_push_platforms(self, value: list[Platform]) -> list[str]:
287
+ return [platform.value for platform in value]
288
+
265
289
  ## For usage of In-app notifications operations
266
290
  destinations_ids: list[int] = Field(
267
291
  default_factory=list,
@@ -274,6 +298,10 @@ class OperationPayload(BaseModel):
274
298
  alias='soundEffect',
275
299
  )
276
300
 
301
+ @field_serializer('sound_effect', when_used='always')
302
+ def serialize_sound_effect(self, value: SoundEffect) -> str:
303
+ return value.value
304
+
277
305
  sound_effect_uri: str | None = Field(
278
306
  default=None,
279
307
  description='Defines the sound effect URI for the operation',
@@ -301,3 +329,12 @@ class OperationPayload(BaseModel):
301
329
  if isinstance(value, (int, float)):
302
330
  return timedelta(seconds=value)
303
331
  return timedelta(seconds=0)
332
+
333
+ @field_serializer('duration', when_used='always')
334
+ def serialize_duration(self, value: timedelta) -> float:
335
+ return value.total_seconds()
336
+
337
+ locator: Locator | None = Field(
338
+ default=None,
339
+ description='Defines the generated locator for the operation',
340
+ )
@@ -1,5 +1,3 @@
1
- """Operation type"""
2
-
3
1
  from enum import StrEnum
4
2
  from typing import Self
5
3
 
@@ -1,14 +1,21 @@
1
- """Service entity"""
2
-
3
1
  from typing import Any
4
2
 
5
- from pydantic import BaseModel, Field
3
+ from pydantic import BaseModel, ConfigDict, Field
6
4
 
7
5
 
8
6
  class OutboundService(BaseModel):
9
7
  """Outbound service definition"""
10
8
 
11
- pk: int = Field(description='Service ID', alias='id')
9
+ model_config = ConfigDict(
10
+ validate_by_name=False,
11
+ validate_by_alias=True,
12
+ serialize_by_alias=True,
13
+ )
14
+
15
+ pk: int = Field(
16
+ description='Service ID',
17
+ alias='id',
18
+ )
12
19
  name: str = Field(description='Service name')
13
20
 
14
21
  protocol_name: str | None = Field(
@@ -0,0 +1,25 @@
1
+ from datetime import datetime
2
+ from typing import Any
3
+
4
+ from pydantic import BaseModel, Field, field_serializer, field_validator
5
+
6
+
7
+ class ParamData(BaseModel):
8
+ value: Any | None = Field(default=None, description='The current value of the parameter.')
9
+ updated_at: datetime = Field(..., description='The timestamp when the parameter was updated.')
10
+
11
+ @field_serializer('updated_at', when_used='always')
12
+ def serialize_updated_at(self, value: datetime) -> float:
13
+ return value.timestamp()
14
+
15
+
16
+ class ParameterUpdate(BaseModel):
17
+ asset_id: int = Field(..., description='The unique identifier for the asset.')
18
+ parameters: dict[str, ParamData] = Field(
19
+ default_factory=dict,
20
+ description='A mapping of parameter names to their data.',
21
+ )
22
+
23
+ @field_validator('parameters', mode='before')
24
+ def validate_parameter(cls, value: dict[str, Any]) -> dict[str, Any]:
25
+ return {k.replace('__', '.'): v for k, v in value.items()}
@@ -1,5 +1,3 @@
1
- """Platform"""
2
-
3
1
  from enum import StrEnum
4
2
  from typing import Self
5
3
 
@@ -1,13 +1,17 @@
1
- """Position entity"""
2
-
3
1
  from typing import Any, Self, cast
4
2
 
5
- from pydantic import BaseModel, Field, field_validator
3
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
6
4
 
7
5
 
8
6
  class Position(BaseModel):
9
7
  """Geographic position definition"""
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
  latitude: float | None = Field(default=None, description='Defines the latitude of the position')
12
16
  longitude: float | None = Field(default=None, description='Defines the longitude of the position')
13
17
  altitude: float | None = Field(default=None, description='Defines the altitude of the position')
@@ -1,25 +1,31 @@
1
- """Preset 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
 
8
6
  class Preset(BaseModel):
9
7
  """Preset entity"""
10
8
 
11
- model_config = {
12
- 'json_encoders': {
13
- datetime: lambda v: v.timestamp(),
14
- },
15
- }
9
+ model_config = ConfigDict(
10
+ validate_by_name=False,
11
+ validate_by_alias=True,
12
+ serialize_by_alias=True,
13
+ )
16
14
 
17
- pk: int = Field(description='Defines the primary key of the preset', alias='id')
15
+ pk: int = Field(
16
+ description='Defines the primary key of the preset',
17
+ alias='id',
18
+ )
18
19
  name: str = Field(description='Defines the name of the preset')
19
20
  valid_before: datetime = Field(
20
21
  ...,
21
22
  description='Defines the date and time before which the preset is valid',
22
23
  )
24
+
25
+ @field_serializer('valid_before', when_used='always')
26
+ def serialize_valid_before(self, valid_before: datetime) -> float:
27
+ return valid_before.timestamp()
28
+
23
29
  comment: str = Field(
24
30
  default='',
25
31
  description='Defines the comment of the preset',
@@ -1,5 +1,3 @@
1
- """Report class"""
2
-
3
1
  import logging
4
2
  import os
5
3
  import time
@@ -8,7 +6,7 @@ from pathlib import Path
8
6
  from typing import Any, Optional, Self
9
7
 
10
8
  import xlsxwriter
11
- from pydantic import BaseModel, Field, field_validator
9
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
12
10
 
13
11
  from layrz_sdk.entities.custom_report_page import CustomReportPage
14
12
  from layrz_sdk.entities.report_data_type import ReportDataType
@@ -22,6 +20,12 @@ log = logging.getLogger(__name__)
22
20
  class Report(BaseModel):
23
21
  """Report definition"""
24
22
 
23
+ model_config = ConfigDict(
24
+ validate_by_name=False,
25
+ validate_by_alias=True,
26
+ serialize_by_alias=True,
27
+ )
28
+
25
29
  name: str = Field(description='Name of the report. Length should be less than 60 characters')
26
30
  pages: list[ReportPage | CustomReportPage] = Field(
27
31
  description='List of report pages',
@@ -113,10 +117,10 @@ class Report(BaseModel):
113
117
  for cell in row.content:
114
118
  cells.append(
115
119
  {
116
- 'content': cell.content,
120
+ 'content': cell.content.timestamp() if cell.data_type == ReportDataType.DATETIME else cell.content,
117
121
  'text_color': '#000000' if use_black(cell.color) else '#ffffff',
118
122
  'color': cell.color,
119
- 'data_type': cell.data_type.value,
123
+ 'data_type': cell.data_type.name,
120
124
  }
121
125
  )
122
126
  rows.append(