layrz-sdk 4.0.9__tar.gz → 4.0.11__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.

Potentially problematic release.


This version of layrz-sdk might be problematic. Click here for more details.

Files changed (132) hide show
  1. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/CHANGELOG.md +9 -0
  2. {layrz_sdk-4.0.9/layrz_sdk.egg-info → layrz_sdk-4.0.11}/PKG-INFO +6 -5
  3. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/ats_possible_exit.py +0 -1
  4. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/message.py +22 -8
  5. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/position.py +6 -6
  6. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/report.py +46 -30
  7. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/report_col.py +1 -0
  8. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/telemetry/assetmessage.py +1 -1
  9. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/lcl/core.py +137 -117
  10. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11/layrz_sdk.egg-info}/PKG-INFO +6 -5
  11. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk.egg-info/requires.txt +3 -4
  12. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/manual_deploy.py +0 -2
  13. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/pyproject.toml +7 -5
  14. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/uv.lock +18 -6
  15. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/.github/workflows/checks.yml +0 -0
  16. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/.github/workflows/deploy.yml +0 -0
  17. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/.gitignore +0 -0
  18. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/.vscode/extensions.json +0 -0
  19. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/CODE_OF_CONDUCT.md +0 -0
  20. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/CONTRIBUTING.md +0 -0
  21. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/LICENSE +0 -0
  22. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/README.md +0 -0
  23. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/__init__.py +0 -0
  24. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/constants.py +0 -0
  25. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/__init__.py +0 -0
  26. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/action.py +0 -0
  27. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/action_geofence_ownership.py +0 -0
  28. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/action_kind.py +0 -0
  29. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/action_subkind.py +0 -0
  30. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/asset.py +0 -0
  31. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/asset_constants.py +0 -0
  32. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/asset_contact.py +0 -0
  33. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/asset_operation_mode.py +0 -0
  34. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/ats_entry.py +0 -0
  35. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/ats_exit_history.py +0 -0
  36. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/ats_possible_entry.py +0 -0
  37. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/ats_reception.py +0 -0
  38. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/broadcast/__init__.py +0 -0
  39. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/broadcast/payload.py +0 -0
  40. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/broadcast/request.py +0 -0
  41. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/broadcast/response.py +0 -0
  42. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/broadcast/result.py +0 -0
  43. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/broadcast/service.py +0 -0
  44. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/broadcast/status.py +0 -0
  45. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/case.py +0 -0
  46. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/case_ignored_status.py +0 -0
  47. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/case_status.py +0 -0
  48. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/axis_config.py +0 -0
  49. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/bar_chart.py +0 -0
  50. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/chart_alignment.py +0 -0
  51. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/chart_color.py +0 -0
  52. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/chart_configuration.py +0 -0
  53. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/chart_data_serie.py +0 -0
  54. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/chart_data_serie_type.py +0 -0
  55. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/chart_data_type.py +0 -0
  56. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/chart_render_technology.py +0 -0
  57. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/column_chart.py +0 -0
  58. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/html_chart.py +0 -0
  59. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/line_chart.py +0 -0
  60. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/map_center_type.py +0 -0
  61. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/map_chart.py +0 -0
  62. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/map_point.py +0 -0
  63. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/number_chart.py +0 -0
  64. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/pie_chart.py +0 -0
  65. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/radar_chart.py +0 -0
  66. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/radial_bar_chart.py +0 -0
  67. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/scatter_chart.py +0 -0
  68. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/scatter_serie.py +0 -0
  69. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/scatter_serie_item.py +0 -0
  70. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/table_chart.py +0 -0
  71. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/table_header.py +0 -0
  72. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/table_row.py +0 -0
  73. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/timeline_chart.py +0 -0
  74. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/timeline_serie.py +0 -0
  75. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/charts/timeline_serie_item.py +0 -0
  76. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/checkpoint.py +0 -0
  77. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/command_series_ticket.py +0 -0
  78. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/comment.py +0 -0
  79. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/custom_field.py +0 -0
  80. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/custom_report_page.py +0 -0
  81. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/destination_phone.py +0 -0
  82. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/device.py +0 -0
  83. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/event.py +0 -0
  84. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/exchange_service.py +0 -0
  85. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/function.py +0 -0
  86. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/geofence.py +0 -0
  87. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/geofence_category.py +0 -0
  88. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/last_message.py +0 -0
  89. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/modbus/__init__.py +0 -0
  90. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/modbus/config.py +0 -0
  91. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/modbus/parameter.py +0 -0
  92. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/modbus/schema.py +0 -0
  93. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/modbus/status.py +0 -0
  94. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/modbus/wait.py +0 -0
  95. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/notification_type.py +0 -0
  96. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/operation.py +0 -0
  97. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/operation_case_payload.py +0 -0
  98. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/operation_payload.py +0 -0
  99. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/operation_type.py +0 -0
  100. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/outbound_service.py +0 -0
  101. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/platform.py +0 -0
  102. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/presence_type.py +0 -0
  103. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/preset.py +0 -0
  104. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/report_configuration.py +0 -0
  105. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/report_data_type.py +0 -0
  106. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/report_format.py +0 -0
  107. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/report_header.py +0 -0
  108. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/report_page.py +0 -0
  109. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/report_row.py +0 -0
  110. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/request_type.py +0 -0
  111. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/sensor.py +0 -0
  112. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/sound_effect.py +0 -0
  113. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/static_position.py +0 -0
  114. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/telemetry/__init__.py +0 -0
  115. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/telemetry/devicemessage.py +0 -0
  116. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/text_alignment.py +0 -0
  117. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/timezone.py +0 -0
  118. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/trigger.py +0 -0
  119. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/trigger_kind.py +0 -0
  120. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/user.py +0 -0
  121. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/waypoint.py +0 -0
  122. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/entities/weekday.py +0 -0
  123. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/helpers/__init__.py +0 -0
  124. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/helpers/color.py +0 -0
  125. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/lcl/__init__.py +0 -0
  126. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk/py.typed +0 -0
  127. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk.egg-info/SOURCES.txt +0 -0
  128. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk.egg-info/dependency_links.txt +0 -0
  129. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/layrz_sdk.egg-info/top_level.txt +0 -0
  130. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/setup.cfg +0 -0
  131. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/tests/__init__.py +0 -0
  132. {layrz_sdk-4.0.9 → layrz_sdk-4.0.11}/tests/test_lcl.py +0 -0
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.0.11
4
+
5
+ - Added protection of worksheets in `Report` entity when exporting to Microsoft Excel to enable cell locking.
6
+
7
+ ## 4.0.10
8
+
9
+ - Added support for lock cells in `ReportCol` entity and their export to Microsoft Excel.
10
+ - Added support for `list[Geofence]` on `Message` entity for presence in geofences.
11
+
3
12
  ## 4.0.9
4
13
 
5
14
  - Added validation for `destination_phones` field in `Operation` entity to ensure it is a list of `DestinationPhone` objects.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: layrz-sdk
3
- Version: 4.0.9
3
+ Version: 4.0.11
4
4
  Summary: Layrz SDK for Python
5
5
  Author-email: "Golden M, Inc." <software@goldenm.com>
6
6
  Maintainer-email: Kenny Mochizuki <kenny@goldenm.com>, Luis Reyes <lreyes@goldenm.com>, Kasen Li <kli@goldenm.com>, Miguel Zauzich <miguel@goldenm.com>, Angel Prieto <aprieto@goldenm.com>
@@ -12,17 +12,18 @@ Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.13
13
13
  Classifier: Programming Language :: Python :: 3.14
14
14
  Classifier: Operating System :: OS Independent
15
+ Classifier: Development Status :: 5 - Production/Stable
16
+ Classifier: Intended Audience :: Developers
15
17
  Requires-Python: >=3.13
16
18
  Description-Content-Type: text/markdown
17
19
  License-File: LICENSE
18
- Requires-Dist: requests
19
- Requires-Dist: xlsxwriter
20
- Requires-Dist: tzdata
20
+ Requires-Dist: xlsxwriter<4.0.0,>=3.2.5
21
21
  Requires-Dist: pydantic>=2.10.6
22
- Requires-Dist: typing-extensions>=4.10.0
23
22
  Requires-Dist: geopy>=2.4.1
24
23
  Requires-Dist: shapely>=2.1.1
25
24
  Requires-Dist: strenum>=0.4.15
25
+ Requires-Dist: requests>=2.32.4
26
+ Requires-Dist: tzdata>=2025.2
26
27
  Dynamic: license-file
27
28
 
28
29
  # Layrz SDK
@@ -19,7 +19,6 @@ class AtsPossibleExit(BaseModel):
19
19
  identifier: int | None = Field(
20
20
  default=None,
21
21
  description='Nullable positive big integer identifier for the exit',
22
- ge=0,
23
22
  )
24
23
 
25
24
  # Volume / gauge snapshots
@@ -1,15 +1,13 @@
1
1
  """Message entity"""
2
2
 
3
3
  from datetime import datetime
4
- from typing import Any, TypeAlias
4
+ from typing import Any
5
5
 
6
- from pydantic import BaseModel, Field
6
+ from pydantic import BaseModel, Field, field_validator
7
7
 
8
8
  from layrz_sdk.constants import UTC
9
-
10
- from .position import Position
11
-
12
- PayloadType: TypeAlias = dict[str, Any]
9
+ from layrz_sdk.entities.geofence import Geofence
10
+ from layrz_sdk.entities.position import Position
13
11
 
14
12
 
15
13
  class Message(BaseModel):
@@ -27,11 +25,11 @@ class Message(BaseModel):
27
25
  default_factory=lambda: Position(),
28
26
  description='Current position of the device',
29
27
  )
30
- payload: PayloadType = Field(
28
+ payload: dict[str, Any] = Field(
31
29
  default_factory=dict,
32
30
  description='Payload data of the device message',
33
31
  )
34
- sensors: PayloadType = Field(
32
+ sensors: dict[str, Any] = Field(
35
33
  default_factory=dict,
36
34
  description='Sensor data of the device message',
37
35
  )
@@ -39,3 +37,19 @@ class Message(BaseModel):
39
37
  default_factory=lambda: datetime.now(UTC),
40
38
  description='Timestamp when the message was received',
41
39
  )
40
+
41
+ geofences: list[Geofence] = Field(
42
+ default_factory=list,
43
+ description='List of geofences associated with the message',
44
+ )
45
+
46
+ @field_validator('geofences', mode='before')
47
+ def _validate_geofences(cls, value: Any) -> list[Geofence]:
48
+ """Validate geofences"""
49
+ if value is None:
50
+ return []
51
+
52
+ if not isinstance(value, list):
53
+ return []
54
+
55
+ return value
@@ -1,6 +1,6 @@
1
1
  """Position entity"""
2
2
 
3
- from typing import Any, Self
3
+ from typing import Any, Self, cast
4
4
 
5
5
  from pydantic import BaseModel, Field, field_validator
6
6
 
@@ -32,7 +32,7 @@ class Position(BaseModel):
32
32
  value = float(value)
33
33
 
34
34
  if -90 <= value <= 90:
35
- return value
35
+ return cast(float, value)
36
36
 
37
37
  return None
38
38
 
@@ -49,7 +49,7 @@ class Position(BaseModel):
49
49
  value = float(value)
50
50
 
51
51
  if -180 <= value <= 180:
52
- return value
52
+ return cast(float, value)
53
53
 
54
54
  return None
55
55
 
@@ -76,7 +76,7 @@ class Position(BaseModel):
76
76
  if isinstance(value, int):
77
77
  value = float(value)
78
78
 
79
- return value
79
+ return cast(float, value)
80
80
 
81
81
  @field_validator('speed', mode='before')
82
82
  def _validate_speed(cls: Self, value: Any) -> None | float:
@@ -90,7 +90,7 @@ class Position(BaseModel):
90
90
  if isinstance(value, int):
91
91
  value = float(value)
92
92
 
93
- return abs(value)
93
+ return cast(float, abs(value))
94
94
 
95
95
  @field_validator('direction', mode='before')
96
96
  def _validate_direction(cls: Self, value: Any) -> None | float:
@@ -105,6 +105,6 @@ class Position(BaseModel):
105
105
  value = float(value)
106
106
 
107
107
  if 0 <= value <= 360:
108
- return value
108
+ return cast(float, value)
109
109
 
110
110
  return None
@@ -10,13 +10,12 @@ from typing import Any, Optional, Self
10
10
  import xlsxwriter
11
11
  from pydantic import BaseModel, Field, field_validator
12
12
 
13
+ from layrz_sdk.entities.custom_report_page import CustomReportPage
14
+ from layrz_sdk.entities.report_data_type import ReportDataType
15
+ from layrz_sdk.entities.report_format import ReportFormat
16
+ from layrz_sdk.entities.report_page import ReportPage
13
17
  from layrz_sdk.helpers.color import use_black
14
18
 
15
- from .custom_report_page import CustomReportPage
16
- from .report_data_type import ReportDataType
17
- from .report_format import ReportFormat
18
- from .report_page import ReportPage
19
-
20
19
  log = logging.getLogger(__name__)
21
20
 
22
21
 
@@ -87,6 +86,7 @@ class Report(BaseModel):
87
86
  else:
88
87
  raise AttributeError(f'Unsupported export format: {self.export_format}')
89
88
 
89
+ @warnings.deprecated('export_as_json is deprecated, use export with export_format=ReportFormat.JSON instead')
90
90
  def export_as_json(self: Self) -> dict[str, Any]:
91
91
  """Returns the report as a JSON dict"""
92
92
  return self._export_json()
@@ -98,7 +98,7 @@ class Report(BaseModel):
98
98
  if isinstance(page, CustomReportPage):
99
99
  continue
100
100
 
101
- headers = []
101
+ headers: list[dict[str, Any]] = []
102
102
  for header in page.headers:
103
103
  headers.append(
104
104
  {
@@ -215,6 +215,7 @@ class Report(BaseModel):
215
215
  )
216
216
  sheet.write(0, i, header.content, style)
217
217
 
218
+ should_protect = False
218
219
  for i, row in enumerate(page.rows):
219
220
  for j, cell in enumerate(row.content):
220
221
  style = {
@@ -231,34 +232,46 @@ class Report(BaseModel):
231
232
  'font_name': 'Aptos Narrow',
232
233
  }
233
234
 
235
+ format_ = book.add_format(style)
236
+
237
+ if cell.lock:
238
+ if not should_protect:
239
+ should_protect = True
240
+ format_.set_locked(True)
241
+
234
242
  value: Any = None
235
243
 
236
- if cell.data_type == ReportDataType.BOOL:
237
- value = 'Yes' if cell.content else 'No'
238
- elif cell.data_type == ReportDataType.DATETIME:
239
- value = cell.content.strftime(cell.datetime_format)
240
- elif cell.data_type == ReportDataType.INT:
241
- try:
242
- value = int(cell.content)
243
- except ValueError:
244
- value = cell.content
245
- log.warning(f'Invalid int value: {cell.content} in cell {i + 1}, {j}')
246
- elif cell.data_type == ReportDataType.FLOAT:
247
- try:
244
+ match cell.data_type:
245
+ case ReportDataType.BOOL:
246
+ value = 'Yes' if cell.content else 'No'
247
+
248
+ case ReportDataType.DATETIME:
249
+ value = cell.content.strftime(cell.datetime_format)
250
+
251
+ case ReportDataType.INT:
252
+ try:
253
+ value = int(cell.content)
254
+ except ValueError:
255
+ value = cell.content
256
+ log.warning(f'Invalid int value: {cell.content} in cell {i + 1}, {j}')
257
+
258
+ case ReportDataType.FLOAT:
259
+ try:
260
+ value = float(cell.content)
261
+ format_.set_num_format('0.00')
262
+
263
+ except ValueError:
264
+ value = cell.content
265
+ log.warning(f'Invalid float value: {cell.content} in cell {i + 1}, {j}')
266
+
267
+ case ReportDataType.CURRENCY:
248
268
  value = float(cell.content)
249
- style.update({'num_format': '0.00'})
250
- except ValueError:
251
- value = cell.content
252
- log.warning(f'Invalid float value: {cell.content} in cell {i + 1}, {j}')
253
- elif cell.data_type == ReportDataType.CURRENCY:
254
- value = float(cell.content)
255
- style.update(
256
- {'num_format': f'"{cell.currency_symbol}" * #,##0.00;[Red]"{cell.currency_symbol}" * #,##0.00'}
257
- )
258
- else:
259
- value = cell.content
269
+ format_.set_num_format(f'"{cell.currency_symbol}" * #,##0.00;[Red]"{cell.currency_symbol}" * #,##0.00')
260
270
 
261
- sheet.write(i + 1, j, value, book.add_format(style))
271
+ case _:
272
+ value = str(cell.content)
273
+
274
+ sheet.write(i + 1, j, value, format_)
262
275
 
263
276
  if row.compact:
264
277
  sheet.set_row(i + 1, None, None, {'level': 1, 'hidden': True})
@@ -266,6 +279,9 @@ class Report(BaseModel):
266
279
  sheet.set_row(i + 1, None, None, {'collapsed': True})
267
280
 
268
281
  sheet.autofit()
282
+
283
+ if should_protect:
284
+ sheet.protect()
269
285
  book.close()
270
286
 
271
287
  if password and msoffice_crypt_path:
@@ -20,6 +20,7 @@ class ReportCol(BaseModel):
20
20
  datetime_format: str = Field(description='Datetime format', default='%Y-%m-%d %H:%M:%S')
21
21
  currency_symbol: str = Field(description='Currency symbol', default='')
22
22
  bold: bool = Field(description='Bold text', default=False)
23
+ lock: bool = Field(description='Lock column', default=False)
23
24
 
24
25
  @field_validator('text_color', mode='before')
25
26
  def _validate_text_color(cls: Self, value: Any) -> Any:
@@ -117,7 +117,7 @@ class AssetMessage(BaseModel):
117
117
  case AssetOperationMode.STATIC:
118
118
  obj.position = asset.static_position.model_dump(exclude_none=True) if asset.static_position else {}
119
119
  case AssetOperationMode.ZONE:
120
- points = MultiPoint([(p.longitude, p.latitude) for p in asset.points])
120
+ points: MultiPoint = MultiPoint([(p.longitude, p.latitude) for p in asset.points])
121
121
  obj.position = {'latitude': points.centroid.y, 'longitude': points.centroid.x}
122
122
  case _:
123
123
  obj.position = device_message.position