perfact-api-pd 1.2__tar.gz → 1.4__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.
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/PKG-INFO +1 -1
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/oee/trend.py +91 -15
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact_api_pd.egg-info/PKG-INFO +1 -1
- perfact_api_pd-1.4/src/perfact_api_pd.egg-info/scm_version.json +8 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/test_s_oee_trend.py +77 -31
- perfact_api_pd-1.2/src/perfact_api_pd.egg-info/scm_version.json +0 -8
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/README.md +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/pyproject.toml +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/setup.cfg +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/__init__.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/__init__.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdbom.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdord.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdordhd.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdordhdlc.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdordlc.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdordlch.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdordlct.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdordprd.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdordprdxtool.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdordtype.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdplant.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdtool.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdunit.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdunitgroup.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdunitlc.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdunitlch.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdunitlct.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/pdunitxitreport.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/policy.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/model/py.typed +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/py.typed +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/__init__.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/grafana.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/oee/__init__.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/oee/availability.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/oee/breakdown.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/oee/prod_metrics.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/oee/prod_records.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/oee/state_spans.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/oee/summary.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/pdunitdowntime.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/pdunitlch.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/pdunitperformance_orm.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/pdunitperformance_plainsql.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact_api_pd.egg-info/SOURCES.txt +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact_api_pd.egg-info/dependency_links.txt +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact_api_pd.egg-info/entry_points.txt +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact_api_pd.egg-info/requires.txt +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact_api_pd.egg-info/scm_file_list.json +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact_api_pd.egg-info/top_level.txt +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/conftest.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/test_grafana.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/test_models.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/test_pdunitdowntime.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/test_policy.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/test_s_oee_availability.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/test_s_oee_breakdown.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/test_s_oee_prod_metrics.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/test_s_oee_summary.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/test_s_pdunitperformance.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tests/test_services_pdunitlch.py +0 -0
- {perfact_api_pd-1.2 → perfact_api_pd-1.4}/tox.ini +0 -0
|
@@ -11,11 +11,20 @@ from perfact.api.pd.services.oee.prod_metrics import (
|
|
|
11
11
|
)
|
|
12
12
|
from perfact.api.pd.services.oee.prod_records import get_prod_records
|
|
13
13
|
from perfact.api.pd.services.oee.state_spans import get_state_spans
|
|
14
|
-
from sqlalchemy import Date, func,
|
|
14
|
+
from sqlalchemy import Date, func, select, union_all
|
|
15
15
|
from sqlalchemy.engine.row import Row
|
|
16
16
|
from sqlalchemy.orm import InstrumentedAttribute, Session
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
def get_local_timezone():
|
|
20
|
+
"""
|
|
21
|
+
Function to get local system timezone
|
|
22
|
+
In the future, to be replaced with a specific field in the database
|
|
23
|
+
Currently returning local timezone, or UTC as fallback
|
|
24
|
+
"""
|
|
25
|
+
return datetime.now().astimezone().tzinfo or timezone.utc
|
|
26
|
+
|
|
27
|
+
|
|
19
28
|
def get_dgkpi_id_by_plugin_name(session: Session, plugin: str) -> int:
|
|
20
29
|
"""
|
|
21
30
|
Getter for the dgkpi id by requested plugin name
|
|
@@ -41,14 +50,31 @@ def parse_stored_modtime(value: object) -> datetime | None:
|
|
|
41
50
|
return None
|
|
42
51
|
|
|
43
52
|
|
|
53
|
+
def compute_window_start(value: date, lookback_months: int) -> date:
|
|
54
|
+
year = value.year
|
|
55
|
+
month = value.month - lookback_months
|
|
56
|
+
while month <= 0:
|
|
57
|
+
month += 12
|
|
58
|
+
year -= 1
|
|
59
|
+
|
|
60
|
+
if month == 12:
|
|
61
|
+
next_month_start = date(year + 1, 1, 1)
|
|
62
|
+
else:
|
|
63
|
+
next_month_start = date(year, month + 1, 1)
|
|
64
|
+
|
|
65
|
+
last_day_of_month = (next_month_start - timedelta(days=1)).day
|
|
66
|
+
day = min(value.day, last_day_of_month)
|
|
67
|
+
return date(year, month, day)
|
|
68
|
+
|
|
69
|
+
|
|
44
70
|
def get_oee_trend_candidate_days(session: Session, lookback_months: int = 6):
|
|
45
71
|
"""
|
|
46
72
|
Distinct past (pdunit_id, day) candidates for OEE.
|
|
47
73
|
Query involving entries from PdOrdPrd and PdOrdLch
|
|
48
74
|
lookback_months is capped into [0, 6] and measured back from yesterday.
|
|
49
75
|
"""
|
|
50
|
-
window_end =
|
|
51
|
-
window_start = window_end
|
|
76
|
+
window_end = datetime.now(get_local_timezone()).date()
|
|
77
|
+
window_start = compute_window_start(window_end, lookback_months)
|
|
52
78
|
|
|
53
79
|
pdordprd_start = (
|
|
54
80
|
select(
|
|
@@ -116,6 +142,7 @@ def _upsert_latest_dgval(
|
|
|
116
142
|
identstring: str,
|
|
117
143
|
reftime: datetime,
|
|
118
144
|
value: float | None,
|
|
145
|
+
current_session_time: datetime | None = None,
|
|
119
146
|
existing: DgVal | None = None,
|
|
120
147
|
) -> DgVal:
|
|
121
148
|
"""
|
|
@@ -129,6 +156,9 @@ def _upsert_latest_dgval(
|
|
|
129
156
|
).scalar_one_or_none()
|
|
130
157
|
if existing is not None:
|
|
131
158
|
existing.reftime = reftime
|
|
159
|
+
if current_session_time:
|
|
160
|
+
# specifically modify modtime if requested
|
|
161
|
+
existing.modtime = current_session_time
|
|
132
162
|
existing.value = value
|
|
133
163
|
stats.updated += 1
|
|
134
164
|
return existing
|
|
@@ -172,6 +202,18 @@ def compute_trend_for_candidates(
|
|
|
172
202
|
skipped = 0
|
|
173
203
|
impacted_days: dict[str, set[int]] = defaultdict(set)
|
|
174
204
|
|
|
205
|
+
local_tz = get_local_timezone()
|
|
206
|
+
tz_name = datetime.now(local_tz).tzname()
|
|
207
|
+
current_transaction_time = session.scalar(
|
|
208
|
+
select(func.timezone(tz_name, func.now()))
|
|
209
|
+
)
|
|
210
|
+
if not current_transaction_time:
|
|
211
|
+
raise ValueError(
|
|
212
|
+
"Could not communicate with db to get \
|
|
213
|
+
current transaction time"
|
|
214
|
+
)
|
|
215
|
+
current_transaction_day = current_transaction_time.date().isoformat()
|
|
216
|
+
|
|
175
217
|
for pdunit_id_c, day_value in candidates:
|
|
176
218
|
pdunit_id = int(pdunit_id_c) if pdunit_id_c is not None else None
|
|
177
219
|
if pdunit_id is None or not isinstance(day_value, date):
|
|
@@ -183,7 +225,7 @@ def compute_trend_for_candidates(
|
|
|
183
225
|
skipped += 1
|
|
184
226
|
continue
|
|
185
227
|
|
|
186
|
-
day_start = datetime.combine(day_value, time.min, tzinfo=
|
|
228
|
+
day_start = datetime.combine(day_value, time.min, tzinfo=local_tz)
|
|
187
229
|
day_stop = day_start + timedelta(days=1)
|
|
188
230
|
day_mid = day_start + timedelta(hours=12)
|
|
189
231
|
identstring = day_value.isoformat()
|
|
@@ -200,18 +242,50 @@ def compute_trend_for_candidates(
|
|
|
200
242
|
identstring,
|
|
201
243
|
)
|
|
202
244
|
).scalar_one_or_none()
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
245
|
+
|
|
246
|
+
if existing_oee:
|
|
247
|
+
# check if dgval entry needs update
|
|
248
|
+
# first check if the stored modtime is older than the candidate modtime
|
|
249
|
+
# get the stored modtime from the dgval.data field
|
|
250
|
+
stored_max_modtime = (
|
|
251
|
+
parse_stored_modtime(
|
|
252
|
+
(existing_oee.data or {}).get("max_pdordprd_modtime")
|
|
253
|
+
)
|
|
254
|
+
if isinstance(existing_oee.data, dict)
|
|
255
|
+
else None
|
|
256
|
+
)
|
|
257
|
+
# check if the new_max_pdordprd candidate modtime
|
|
258
|
+
# is higher than the stored one
|
|
259
|
+
is_new_max_modtime = max_pdordprd_modtime is not None and (
|
|
212
260
|
stored_max_modtime is None or stored_max_modtime < max_pdordprd_modtime
|
|
213
261
|
)
|
|
214
|
-
|
|
262
|
+
|
|
263
|
+
# check if the existing entry has the same day as the current day
|
|
264
|
+
is_current_day = existing_oee.identstring == current_transaction_day
|
|
265
|
+
|
|
266
|
+
# next, check if the next day in transaction time
|
|
267
|
+
# is syncronized with the data
|
|
268
|
+
# get the start of the next day based on the identstring
|
|
269
|
+
current_identstring_day = date.fromisoformat(existing_oee.identstring)
|
|
270
|
+
next_day_start = datetime.combine(
|
|
271
|
+
current_identstring_day + timedelta(days=1),
|
|
272
|
+
time.min,
|
|
273
|
+
tzinfo=local_tz,
|
|
274
|
+
)
|
|
275
|
+
# check if the day has already started, but the data is not syncronized yet
|
|
276
|
+
# by checking the identstring against the current_transaction_day
|
|
277
|
+
# and the modtime against the next_day_start
|
|
278
|
+
is_day_later = (
|
|
279
|
+
existing_oee.identstring < current_transaction_day
|
|
280
|
+
and existing_oee.modtime < next_day_start
|
|
281
|
+
)
|
|
282
|
+
# compute the necessity of updating the existing dgval entry
|
|
283
|
+
# based on criteria
|
|
284
|
+
needs_refresh = is_new_max_modtime or is_current_day or is_day_later
|
|
285
|
+
else:
|
|
286
|
+
# needs creation
|
|
287
|
+
needs_refresh = True
|
|
288
|
+
|
|
215
289
|
if not needs_refresh:
|
|
216
290
|
skipped += 1
|
|
217
291
|
continue
|
|
@@ -246,6 +320,7 @@ def compute_trend_for_candidates(
|
|
|
246
320
|
identstring=identstring,
|
|
247
321
|
reftime=day_mid,
|
|
248
322
|
value=oee,
|
|
323
|
+
current_session_time=current_transaction_time,
|
|
249
324
|
existing=existing_oee,
|
|
250
325
|
).data = oee_data
|
|
251
326
|
|
|
@@ -358,11 +433,12 @@ def compute_trend_for_collections(session: Session, impacted_days: dict[str, set
|
|
|
358
433
|
pdunitgroup_updated = 0
|
|
359
434
|
pdplant_created = 0
|
|
360
435
|
pdplant_updated = 0
|
|
436
|
+
local_tz = get_local_timezone()
|
|
361
437
|
|
|
362
438
|
# compute for pdunitgroup and pdplant
|
|
363
439
|
for identstring, changed_pdunits in impacted_days.items():
|
|
364
440
|
day_value = date.fromisoformat(identstring)
|
|
365
|
-
day_mid = datetime.combine(day_value, time(hour=12), tzinfo=
|
|
441
|
+
day_mid = datetime.combine(day_value, time(hour=12), tzinfo=local_tz)
|
|
366
442
|
|
|
367
443
|
memberships = session.execute(
|
|
368
444
|
select(PdUnit.id, PdUnit.pdunitgroup_id, PdUnit.pdplant_id).where(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from collections.abc import Iterator
|
|
2
|
-
from datetime import date, datetime, timedelta
|
|
2
|
+
from datetime import date, datetime, timedelta
|
|
3
3
|
from typing import Any, cast
|
|
4
4
|
|
|
5
5
|
import psycopg
|
|
@@ -16,6 +16,8 @@ from sqlalchemy.orm import Session
|
|
|
16
16
|
postgresql_proc = factories.postgresql_proc()
|
|
17
17
|
postgresql = factories.postgresql("postgresql_proc")
|
|
18
18
|
|
|
19
|
+
local_timezone = trend.get_local_timezone()
|
|
20
|
+
|
|
19
21
|
|
|
20
22
|
@pytest.fixture
|
|
21
23
|
def db_session(postgresql: psycopg.Connection[Any]) -> Iterator[Session]:
|
|
@@ -152,7 +154,7 @@ def test_get_dgkpi_id_by_plugin_name_returns_int(db_session: Session) -> None:
|
|
|
152
154
|
"INSERT INTO dgkpi (dgkpi_id, dgkpi_plugin, dgkpi_lastcheck) \
|
|
153
155
|
VALUES (42, 'OEE', :now)"
|
|
154
156
|
),
|
|
155
|
-
{"now": datetime.now(
|
|
157
|
+
{"now": datetime.now(local_timezone)},
|
|
156
158
|
)
|
|
157
159
|
db_session.commit()
|
|
158
160
|
|
|
@@ -172,8 +174,9 @@ def test_get_dgkpi_id_by_plugin_name_raises_when_missing(db_session: Session) ->
|
|
|
172
174
|
(123, None),
|
|
173
175
|
("not-a-date", None),
|
|
174
176
|
(
|
|
175
|
-
"2025-01-01T12:30:00+00:00",
|
|
176
|
-
datetime(2025, 1, 1, 12, 30, tzinfo=
|
|
177
|
+
# "2025-01-01T12:30:00+00:00",
|
|
178
|
+
f"{datetime(2025, 1, 1, 12, 30, tzinfo=local_timezone).isoformat()}",
|
|
179
|
+
datetime(2025, 1, 1, 12, 30, tzinfo=local_timezone),
|
|
177
180
|
),
|
|
178
181
|
],
|
|
179
182
|
)
|
|
@@ -181,10 +184,51 @@ def test_parse_stored_modtime(value: object, expected: datetime | None) -> None:
|
|
|
181
184
|
assert trend.parse_stored_modtime(value) == expected
|
|
182
185
|
|
|
183
186
|
|
|
187
|
+
@pytest.mark.parametrize(
|
|
188
|
+
("value", "lookback_months", "expected"),
|
|
189
|
+
[
|
|
190
|
+
(date(2025, 1, 15), 1, date(2024, 12, 15)),
|
|
191
|
+
(date(2025, 1, 15), 13, date(2023, 12, 15)),
|
|
192
|
+
(date(2025, 6, 15), 0, date(2025, 6, 15)),
|
|
193
|
+
(date(2025, 5, 31), 1, date(2025, 4, 30)),
|
|
194
|
+
(date(2025, 3, 31), 1, date(2025, 2, 28)),
|
|
195
|
+
(date(2024, 3, 31), 1, date(2024, 2, 29)),
|
|
196
|
+
(date(2025, 12, 1), 1, date(2025, 11, 1)),
|
|
197
|
+
],
|
|
198
|
+
)
|
|
199
|
+
def test_compute_window_start(
|
|
200
|
+
value: date, lookback_months: int, expected: date
|
|
201
|
+
) -> None:
|
|
202
|
+
assert trend.compute_window_start(value, lookback_months) == expected
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def test_compute_trend_for_candidates_raises_when_current_transaction_time_missing(
|
|
206
|
+
db_session: Session,
|
|
207
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
208
|
+
) -> None:
|
|
209
|
+
db_session.add_all(
|
|
210
|
+
[
|
|
211
|
+
DgKpi(id=20, plugin="OEE", lastcheck=datetime.now(local_timezone)),
|
|
212
|
+
DgKpi(id=21, plugin="OEE.A", lastcheck=datetime.now(local_timezone)),
|
|
213
|
+
DgKpi(id=22, plugin="OEE.P", lastcheck=datetime.now(local_timezone)),
|
|
214
|
+
DgKpi(id=23, plugin="OEE.Q", lastcheck=datetime.now(local_timezone)),
|
|
215
|
+
]
|
|
216
|
+
)
|
|
217
|
+
db_session.commit()
|
|
218
|
+
|
|
219
|
+
monkeypatch.setattr(db_session, "scalar", lambda *_args, **_kwargs: None)
|
|
220
|
+
|
|
221
|
+
with pytest.raises(
|
|
222
|
+
ValueError,
|
|
223
|
+
match="Could not communicate with db to get .*current transaction time",
|
|
224
|
+
):
|
|
225
|
+
trend.compute_trend_for_candidates(db_session, [])
|
|
226
|
+
|
|
227
|
+
|
|
184
228
|
def test_get_oee_trend_candidate_days_returns_rows_from_query(
|
|
185
229
|
db_session: Session,
|
|
186
230
|
) -> None:
|
|
187
|
-
now = datetime.now(
|
|
231
|
+
now = datetime.now(local_timezone)
|
|
188
232
|
db_session.execute(text("INSERT INTO pdunit (pdunit_id) VALUES (1), (2)"))
|
|
189
233
|
db_session.execute(
|
|
190
234
|
text(
|
|
@@ -217,16 +261,16 @@ def test_compute_trend_for_candidates_creates_new_dgval(
|
|
|
217
261
|
monkeypatch: pytest.MonkeyPatch,
|
|
218
262
|
) -> None:
|
|
219
263
|
day = date(2025, 1, 15)
|
|
220
|
-
day_start = datetime(2025, 1, 15, 0, 0, tzinfo=
|
|
264
|
+
day_start = datetime(2025, 1, 15, 0, 0, tzinfo=local_timezone)
|
|
221
265
|
day_stop = day_start + timedelta(days=1)
|
|
222
|
-
max_mod = datetime(2025, 1, 15, 9, 0, tzinfo=
|
|
266
|
+
max_mod = datetime(2025, 1, 15, 9, 0, tzinfo=local_timezone)
|
|
223
267
|
|
|
224
268
|
db_session.add_all(
|
|
225
269
|
[
|
|
226
|
-
DgKpi(id=20, plugin="OEE", lastcheck=datetime.now(
|
|
227
|
-
DgKpi(id=21, plugin="OEE.A", lastcheck=datetime.now(
|
|
228
|
-
DgKpi(id=22, plugin="OEE.P", lastcheck=datetime.now(
|
|
229
|
-
DgKpi(id=23, plugin="OEE.Q", lastcheck=datetime.now(
|
|
270
|
+
DgKpi(id=20, plugin="OEE", lastcheck=datetime.now(local_timezone)),
|
|
271
|
+
DgKpi(id=21, plugin="OEE.A", lastcheck=datetime.now(local_timezone)),
|
|
272
|
+
DgKpi(id=22, plugin="OEE.P", lastcheck=datetime.now(local_timezone)),
|
|
273
|
+
DgKpi(id=23, plugin="OEE.Q", lastcheck=datetime.now(local_timezone)),
|
|
230
274
|
]
|
|
231
275
|
)
|
|
232
276
|
db_session.execute(
|
|
@@ -295,7 +339,7 @@ def test_compute_trend_for_candidates_creates_new_dgval(
|
|
|
295
339
|
assert oee_row.value is None
|
|
296
340
|
assert (
|
|
297
341
|
datetime.fromisoformat(oee_row.data["max_pdordprd_modtime"]).astimezone(
|
|
298
|
-
|
|
342
|
+
local_timezone
|
|
299
343
|
)
|
|
300
344
|
== max_mod
|
|
301
345
|
)
|
|
@@ -324,16 +368,16 @@ def test_compute_trend_for_candidates_updates_existing_dgval(
|
|
|
324
368
|
monkeypatch: pytest.MonkeyPatch,
|
|
325
369
|
) -> None:
|
|
326
370
|
day = date(2025, 1, 16)
|
|
327
|
-
day_start = datetime(2025, 1, 16, 0, 0, tzinfo=
|
|
371
|
+
day_start = datetime(2025, 1, 16, 0, 0, tzinfo=local_timezone)
|
|
328
372
|
day_stop = day_start + timedelta(days=1)
|
|
329
|
-
new_max_mod = datetime(2025, 1, 16, 10, 0, tzinfo=
|
|
373
|
+
new_max_mod = datetime(2025, 1, 16, 10, 0, tzinfo=local_timezone)
|
|
330
374
|
|
|
331
375
|
db_session.add_all(
|
|
332
376
|
[
|
|
333
|
-
DgKpi(id=20, plugin="OEE", lastcheck=datetime.now(
|
|
334
|
-
DgKpi(id=21, plugin="OEE.A", lastcheck=datetime.now(
|
|
335
|
-
DgKpi(id=22, plugin="OEE.P", lastcheck=datetime.now(
|
|
336
|
-
DgKpi(id=23, plugin="OEE.Q", lastcheck=datetime.now(
|
|
377
|
+
DgKpi(id=20, plugin="OEE", lastcheck=datetime.now(local_timezone)),
|
|
378
|
+
DgKpi(id=21, plugin="OEE.A", lastcheck=datetime.now(local_timezone)),
|
|
379
|
+
DgKpi(id=22, plugin="OEE.P", lastcheck=datetime.now(local_timezone)),
|
|
380
|
+
DgKpi(id=23, plugin="OEE.Q", lastcheck=datetime.now(local_timezone)),
|
|
337
381
|
]
|
|
338
382
|
)
|
|
339
383
|
db_session.execute(
|
|
@@ -357,6 +401,8 @@ def test_compute_trend_for_candidates_updates_existing_dgval(
|
|
|
357
401
|
),
|
|
358
402
|
{"mod": new_max_mod, "start": day_start, "stop": day_stop},
|
|
359
403
|
)
|
|
404
|
+
|
|
405
|
+
max_prd_modtime = datetime(2025, 1, 16, 9, 30, tzinfo=local_timezone).isoformat()
|
|
360
406
|
db_session.add(
|
|
361
407
|
DgVal(
|
|
362
408
|
dgkpi_id=20,
|
|
@@ -365,7 +411,7 @@ def test_compute_trend_for_candidates_updates_existing_dgval(
|
|
|
365
411
|
identstring="2025-01-16",
|
|
366
412
|
reftime=day_start,
|
|
367
413
|
value=0.1,
|
|
368
|
-
data={"max_pdordprd_modtime": "
|
|
414
|
+
data={"max_pdordprd_modtime": f"{max_prd_modtime}"},
|
|
369
415
|
)
|
|
370
416
|
)
|
|
371
417
|
db_session.commit()
|
|
@@ -408,14 +454,14 @@ def test_compute_trend_for_candidates_skips_invalid_and_not_needing_refresh(
|
|
|
408
454
|
monkeypatch: pytest.MonkeyPatch,
|
|
409
455
|
) -> None:
|
|
410
456
|
day = date(2025, 1, 17)
|
|
411
|
-
day_start = datetime(2025, 1, 17, 0, 0, tzinfo=
|
|
457
|
+
day_start = datetime(2025, 1, 17, 0, 0, tzinfo=local_timezone)
|
|
412
458
|
|
|
413
459
|
db_session.add_all(
|
|
414
460
|
[
|
|
415
|
-
DgKpi(id=20, plugin="OEE", lastcheck=datetime.now(
|
|
416
|
-
DgKpi(id=21, plugin="OEE.A", lastcheck=datetime.now(
|
|
417
|
-
DgKpi(id=22, plugin="OEE.P", lastcheck=datetime.now(
|
|
418
|
-
DgKpi(id=23, plugin="OEE.Q", lastcheck=datetime.now(
|
|
461
|
+
DgKpi(id=20, plugin="OEE", lastcheck=datetime.now(local_timezone)),
|
|
462
|
+
DgKpi(id=21, plugin="OEE.A", lastcheck=datetime.now(local_timezone)),
|
|
463
|
+
DgKpi(id=22, plugin="OEE.P", lastcheck=datetime.now(local_timezone)),
|
|
464
|
+
DgKpi(id=23, plugin="OEE.Q", lastcheck=datetime.now(local_timezone)),
|
|
419
465
|
]
|
|
420
466
|
)
|
|
421
467
|
db_session.execute(
|
|
@@ -428,7 +474,7 @@ def test_compute_trend_for_candidates_skips_invalid_and_not_needing_refresh(
|
|
|
428
474
|
VALUES (4, :mod, FALSE, tstzrange(:start, :stop, '[)'), 4)"
|
|
429
475
|
),
|
|
430
476
|
{
|
|
431
|
-
"mod": datetime(2025, 1, 17, 10, 0, tzinfo=
|
|
477
|
+
"mod": datetime(2025, 1, 17, 10, 0, tzinfo=local_timezone),
|
|
432
478
|
"start": day_start,
|
|
433
479
|
"stop": day_start + timedelta(days=1),
|
|
434
480
|
},
|
|
@@ -478,7 +524,7 @@ def test_compute_trend_for_collection_returns_zero_when_no_impacted_ids(
|
|
|
478
524
|
assert trend.compute_trend_for_collection(
|
|
479
525
|
db_session,
|
|
480
526
|
identstring="2025-01-20",
|
|
481
|
-
day_mid=datetime(2025, 1, 20, 12, tzinfo=
|
|
527
|
+
day_mid=datetime(2025, 1, 20, 12, tzinfo=local_timezone),
|
|
482
528
|
collection_reftable="pdunitgroup",
|
|
483
529
|
pdunit_collection_fk="pdunitgroup_id",
|
|
484
530
|
impacted_collection_ids=set(),
|
|
@@ -487,14 +533,14 @@ def test_compute_trend_for_collection_returns_zero_when_no_impacted_ids(
|
|
|
487
533
|
|
|
488
534
|
def test_compute_trend_for_collection_creates_and_updates(db_session: Session) -> None:
|
|
489
535
|
identstring = "2025-01-20"
|
|
490
|
-
day_mid = datetime(2025, 1, 20, 12, tzinfo=
|
|
536
|
+
day_mid = datetime(2025, 1, 20, 12, tzinfo=local_timezone)
|
|
491
537
|
|
|
492
538
|
db_session.add_all(
|
|
493
539
|
[
|
|
494
|
-
DgKpi(id=20, plugin="OEE", lastcheck=datetime.now(
|
|
495
|
-
DgKpi(id=21, plugin="OEE.A", lastcheck=datetime.now(
|
|
496
|
-
DgKpi(id=22, plugin="OEE.P", lastcheck=datetime.now(
|
|
497
|
-
DgKpi(id=23, plugin="OEE.Q", lastcheck=datetime.now(
|
|
540
|
+
DgKpi(id=20, plugin="OEE", lastcheck=datetime.now(local_timezone)),
|
|
541
|
+
DgKpi(id=21, plugin="OEE.A", lastcheck=datetime.now(local_timezone)),
|
|
542
|
+
DgKpi(id=22, plugin="OEE.P", lastcheck=datetime.now(local_timezone)),
|
|
543
|
+
DgKpi(id=23, plugin="OEE.Q", lastcheck=datetime.now(local_timezone)),
|
|
498
544
|
]
|
|
499
545
|
)
|
|
500
546
|
db_session.execute(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/pdunitperformance_orm.py
RENAMED
|
File without changes
|
{perfact_api_pd-1.2 → perfact_api_pd-1.4}/src/perfact/api/pd/services/pdunitperformance_plainsql.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|