perfact-api-pd 0.2__py2.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.
File without changes
@@ -0,0 +1,16 @@
1
+ from .pdord import PdOrd, PdOrd_TimeStat
2
+ from .pdordlc import PdOrdLc
3
+ from .pdordlch import PdOrdLch
4
+ from .pdordlct import PdOrdLct
5
+ from .pdordprd import PdOrdPrd
6
+ from .pdunit import PdUnit
7
+
8
+ __all__ = [
9
+ "PdUnit",
10
+ "PdOrdLch",
11
+ "PdOrdLct",
12
+ "PdOrdLc",
13
+ "PdOrdPrd",
14
+ "PdOrd_TimeStat",
15
+ "PdOrd",
16
+ ]
@@ -0,0 +1,47 @@
1
+ from datetime import datetime, timedelta
2
+ from typing import Optional
3
+
4
+ from perfact.api.base.model import Base, ForeignKey, Mapped, View
5
+ from sqlalchemy import (
6
+ BigInteger,
7
+ DateTime,
8
+ Interval,
9
+ )
10
+ from sqlalchemy.orm import mapped_column
11
+
12
+
13
+ class PdOrd(Base):
14
+ # COLS
15
+ planmachinetime: Mapped[timedelta | None] = mapped_column(Interval)
16
+ planstarttime: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
17
+ starttime: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
18
+ planstoptime: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
19
+ stoptime: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
20
+ qty: Mapped[float]
21
+ plancycletime: Mapped[timedelta | None] = mapped_column(Interval)
22
+ plansetuptime: Mapped[timedelta | None] = mapped_column(Interval)
23
+
24
+ # FKS
25
+ pdunit_id: Mapped[int | None] = mapped_column(ForeignKey("pdunit.id"))
26
+ pdordlc_id: Mapped[int | None] = mapped_column(ForeignKey("pdordlc.id"))
27
+ # RELATIONSHIPS
28
+
29
+
30
+ # VIEWS
31
+ class PdOrd_TimeStat(View):
32
+ __tablename__ = "pdord_timestat"
33
+ id: Mapped[int] = mapped_column(
34
+ "pdordtimestat_pdord_id", BigInteger, primary_key=True
35
+ )
36
+ activetime: Mapped[Optional[timedelta]] = mapped_column(
37
+ "pdordtimestat_activetime", Interval, nullable=True
38
+ )
39
+ cycle_time: Mapped[Optional[timedelta]] = mapped_column(
40
+ "pdordtimestat_cycle_time", Interval, nullable=True
41
+ )
42
+ setuptime: Mapped[Optional[timedelta]] = mapped_column(
43
+ "pdordtimestat_setuptime", Interval, nullable=True
44
+ )
45
+ spentindowntime: Mapped[Optional[timedelta]] = mapped_column(
46
+ "pdordtimestat_spentindowntime", Interval, nullable=True
47
+ )
@@ -0,0 +1,8 @@
1
+ from perfact.api.base.model import Base, Mapped
2
+ from sqlalchemy.orm import mapped_column
3
+
4
+
5
+ class PdOrdLc(Base):
6
+ isexecution: Mapped[bool] = mapped_column(default=False)
7
+ isactive: Mapped[bool] = mapped_column(default=False)
8
+ isfinal: Mapped[bool] = mapped_column(default=False)
@@ -0,0 +1,195 @@
1
+ from datetime import datetime
2
+ from typing import cast
3
+
4
+ from perfact.api.base.model import Base, ForeignKey, Mapped, relationship
5
+ from perfact.api.pp.model import PpRsrc, PpShft
6
+ from psycopg.types.range import Range
7
+ from sqlalchemy import DateTime, and_, case, func, select
8
+ from sqlalchemy.dialects.postgresql import TSTZRANGE
9
+ from sqlalchemy.ext.hybrid import hybrid_method
10
+ from sqlalchemy.orm import mapped_column
11
+ from sqlalchemy.sql import ColumnElement
12
+
13
+ from .pdord import PdOrd
14
+ from .pdordlct import PdOrdLct
15
+
16
+
17
+ class PdOrdLch(Base):
18
+ # COLS
19
+ createtime: Mapped[datetime] = mapped_column(
20
+ DateTime(timezone=True), default=func.now()
21
+ )
22
+ lchtimerange: Mapped[Range[datetime]] = mapped_column(TSTZRANGE)
23
+
24
+ # FKS
25
+ pdunit_id: Mapped[int | None] = mapped_column(ForeignKey("pdunit.id"))
26
+ pdord_id: Mapped[int] = mapped_column(ForeignKey("pdord.id"))
27
+ pdordlct_id: Mapped[int] = mapped_column(ForeignKey("pdordlct.id"))
28
+
29
+ # RELATIONSHIPS
30
+ pdordlct: Mapped["PdOrdLct"] = relationship("PdOrdLct")
31
+ pdord: Mapped["PdOrd"] = relationship("PdOrd")
32
+
33
+ @hybrid_method
34
+ def availability_nominator_eligible_def(self, pdunit_id, /) -> bool:
35
+ """Python level - boils down to check if this operation history
36
+ is linked to the workcenter and represents a status change
37
+ from a status with pdordlc_isexecution"""
38
+ raise NotImplementedError("Sql expression level only")
39
+
40
+ @availability_nominator_eligible_def.expression
41
+ @classmethod
42
+ def availability_nominator_eligible(cls, pdunit_id, /) -> ColumnElement[bool]:
43
+ """SQL level - check definition"""
44
+ return and_(
45
+ cls.pdunit_id == pdunit_id,
46
+ cls.pdordlct.has(PdOrdLct.availability_nominator_eligible.is_(True)),
47
+ )
48
+
49
+ @hybrid_method
50
+ def availability_denominator_eligible_def(self, pdunit_id, /) -> bool:
51
+ """Python level - boils down to check if this operation history
52
+ is linked to the workcenter and represents a status change
53
+ from a status with pdordlc_isactive(True) and pdordlc_isexecution(False)"""
54
+ raise NotImplementedError("Sql expression level only")
55
+
56
+ @availability_denominator_eligible_def.expression
57
+ @classmethod
58
+ def availability_denominator_eligible(cls, pdunit_id, /) -> ColumnElement[bool]:
59
+ """SQL level - check definition"""
60
+ return and_(
61
+ cls.pdunit_id == pdunit_id,
62
+ cls.pdordlct.has(PdOrdLct.availability_denominator_eligible.is_(True)),
63
+ )
64
+
65
+ @classmethod
66
+ def availability_valid_intersection_seconds(
67
+ cls, starttime, stoptime, /
68
+ ) -> tuple[ColumnElement, ColumnElement[float | None]]:
69
+ search_range = func.tstzrange(cls.modtime, func.now())
70
+ intersection = search_range.op("*")(func.tstzrange(starttime, stoptime))
71
+
72
+ valid_intersection = cast(
73
+ ColumnElement[float | None],
74
+ case(
75
+ (func.isempty(intersection), None),
76
+ else_=func.extract(
77
+ "epoch", func.upper(intersection) - func.lower(intersection)
78
+ ),
79
+ ),
80
+ )
81
+ return intersection, valid_intersection
82
+
83
+ @classmethod
84
+ def availability_missing_active_operations_nominator(
85
+ cls, pdunit_id, starttime, stoptime, /
86
+ ) -> ColumnElement[float | None]:
87
+ """To be used only as SQL method.
88
+ Check if any missing active operations have to be added to availability
89
+ nominator"""
90
+ _, valid_intersection = cls.availability_valid_intersection_seconds(
91
+ starttime, stoptime
92
+ )
93
+
94
+ latest_by_operation = (
95
+ select(
96
+ case(
97
+ (
98
+ cls.pdordlct.has(
99
+ PdOrdLct.availability_active_operation_nominator.is_(True)
100
+ ),
101
+ valid_intersection,
102
+ ),
103
+ else_=None,
104
+ ).label("eligible_seconds"),
105
+ )
106
+ .select_from(cls)
107
+ .join(cls.pdord)
108
+ .where(cls.pdunit_id == pdunit_id)
109
+ .distinct(PdOrd.id)
110
+ .order_by(PdOrd.id, cls.id.desc())
111
+ .subquery()
112
+ )
113
+
114
+ return cast(
115
+ ColumnElement[float | None],
116
+ select(func.sum(latest_by_operation.c.eligible_seconds)).scalar_subquery(),
117
+ )
118
+
119
+ @classmethod
120
+ def availability_missing_active_operations_denominator(
121
+ cls, pdunit_id, starttime, stoptime, /
122
+ ) -> ColumnElement[float | None]:
123
+ """To be used only as SQL method.
124
+ Check if any missing active operations have to be added to availability
125
+ denominator"""
126
+ intersection, _ = cls.availability_valid_intersection_seconds(
127
+ starttime, stoptime
128
+ )
129
+
130
+ shift_intersection = intersection.op("*")(PpShft.shiftrange)
131
+ shift_overlap_seconds = cast(
132
+ ColumnElement[float],
133
+ select(
134
+ func.coalesce(
135
+ func.sum(
136
+ case(
137
+ (
138
+ func.isempty(shift_intersection),
139
+ 0.0,
140
+ ),
141
+ else_=func.extract(
142
+ "epoch",
143
+ func.upper(shift_intersection)
144
+ - func.lower(shift_intersection),
145
+ ),
146
+ )
147
+ ),
148
+ 0.0,
149
+ )
150
+ )
151
+ .select_from(PpRsrc)
152
+ .join(PpShft, PpShft.pprsrc_id == PpRsrc.id)
153
+ .where(PpRsrc.pdunit_id == pdunit_id)
154
+ .where(intersection.op("&&")(PpShft.shiftrange))
155
+ .scalar_subquery(),
156
+ )
157
+
158
+ # ONLY entries that are in range of:
159
+ # intersection between (modtime, func.now()) and given_range
160
+ # can be removed, used only for ease to read
161
+ has_shift_overlap = (
162
+ select(PpShft.id)
163
+ .select_from(PpRsrc)
164
+ .join(PpShft, PpShft.pprsrc_id == PpRsrc.id)
165
+ .where(PpRsrc.pdunit_id == pdunit_id)
166
+ .where(intersection.op("&&")(PpShft.shiftrange))
167
+ .exists()
168
+ )
169
+
170
+ latest_by_operation = (
171
+ select(
172
+ case(
173
+ (
174
+ cls.pdordlct.has(
175
+ PdOrdLct.availability_active_operation_denominator.is_(True)
176
+ )
177
+ & has_shift_overlap,
178
+ shift_overlap_seconds,
179
+ ),
180
+ else_=None,
181
+ ).label("eligible_seconds"),
182
+ )
183
+ .select_from(cls)
184
+ .join(cls.pdord)
185
+ .where(cls.pdunit_id == pdunit_id)
186
+ .where(has_shift_overlap)
187
+ .distinct(PdOrd.id)
188
+ .order_by(PdOrd.id, cls.id.desc())
189
+ .subquery()
190
+ )
191
+
192
+ return cast(
193
+ ColumnElement[float | None],
194
+ select(func.sum(latest_by_operation.c.eligible_seconds)).scalar_subquery(),
195
+ )
@@ -0,0 +1,74 @@
1
+ from typing import Any, cast
2
+
3
+ from perfact.api.base.model import Base, ForeignKey, Mapped, relationship
4
+ from sqlalchemy import and_
5
+ from sqlalchemy.ext.hybrid import hybrid_property
6
+ from sqlalchemy.orm import mapped_column
7
+ from sqlalchemy.sql import ColumnElement
8
+
9
+ from .pdordlc import PdOrdLc
10
+
11
+
12
+ class PdOrdLct(Base):
13
+ # COLS
14
+ # FKS
15
+ from_pdordlc_id: Mapped[int] = mapped_column(ForeignKey("pdordlc.id"))
16
+ to_pdordlc_id: Mapped[int] = mapped_column(ForeignKey("pdordlc.id"))
17
+
18
+ # RELATIONSHIPS
19
+ from_pdordlc: Mapped["PdOrdLc"] = relationship(
20
+ "PdOrdLc", foreign_keys=[from_pdordlc_id]
21
+ )
22
+ to_pdordlc: Mapped["PdOrdLc"] = relationship(
23
+ "PdOrdLc", foreign_keys=[to_pdordlc_id]
24
+ )
25
+
26
+ @hybrid_property
27
+ def availability_nominator_eligible_def(self) -> bool:
28
+ """Python level - check if entry is eligible for availability
29
+ computation"""
30
+ raise NotImplementedError("Sql expression level only")
31
+
32
+ @availability_nominator_eligible_def.expression
33
+ def availability_nominator_eligible(cls) -> ColumnElement[bool]:
34
+ """SQL level - check definition"""
35
+ return cast(Any, cls.from_pdordlc).has(PdOrdLc.isexecution.is_(True))
36
+
37
+ @hybrid_property
38
+ def availability_denominator_eligible_def(self) -> bool:
39
+ """Python level - this takes in cosideration that the entries with
40
+ isexecution(True) have been already computed and added to the denominator"""
41
+ raise NotImplementedError("Sql expression level only")
42
+
43
+ @availability_denominator_eligible_def.expression
44
+ def availability_denominator_eligible(cls) -> ColumnElement[bool]:
45
+ """SQL level - check definition"""
46
+ return and_(
47
+ cast(Any, cls.from_pdordlc).has(PdOrdLc.isactive.is_(True)),
48
+ cast(Any, cls.from_pdordlc).has(PdOrdLc.isexecution.is_(False)),
49
+ )
50
+
51
+ @hybrid_property
52
+ def availability_active_operation_nominator_def(self) -> bool:
53
+ """Python level - check if the entry has a valid TO_PDORDLC which
54
+ would then be added to the availability."""
55
+ raise NotImplementedError("Sql expression level only")
56
+
57
+ @availability_active_operation_nominator_def.expression
58
+ def availability_active_operation_nominator(cls) -> ColumnElement[bool]:
59
+ """SQL level - check definition"""
60
+ return cast(Any, cls.to_pdordlc).has(PdOrdLc.isexecution.is_(True))
61
+
62
+ @hybrid_property
63
+ def availability_active_operation_denominator_def(self) -> bool:
64
+ """Python level - check if the entry has a valid TO_PDORDLC which
65
+ would then be added to the availability."""
66
+ raise NotImplementedError("Sql expression level only")
67
+
68
+ @availability_active_operation_denominator_def.expression
69
+ def availability_active_operation_denominator(cls) -> ColumnElement[bool]:
70
+ """SQL level - check definition"""
71
+ return and_(
72
+ cast(Any, cls.to_pdordlc).has(PdOrdLc.isactive.is_(True)),
73
+ cast(Any, cls.to_pdordlc).has(PdOrdLc.isexecution.is_(False)),
74
+ )
@@ -0,0 +1,206 @@
1
+ from datetime import datetime
2
+ from typing import Any, Literal, cast, overload
3
+
4
+ from perfact.api.base.model import Base, ForeignKey, Mapped, relationship
5
+ from psycopg.types.range import Range
6
+ from sqlalchemy import and_, case, func, select
7
+ from sqlalchemy.dialects.postgresql import TSTZRANGE
8
+ from sqlalchemy.ext.hybrid import hybrid_method, hybrid_property
9
+ from sqlalchemy.orm import mapped_column
10
+ from sqlalchemy.sql import ColumnElement
11
+ from sqlalchemy.sql.elements import SQLCoreOperations
12
+ from sqlalchemy.sql.expression import Extract
13
+
14
+ from .pdord import PdOrd
15
+
16
+
17
+ class PdOrdPrd(Base):
18
+ # COLS
19
+ deleted: Mapped[bool]
20
+ refrange: Mapped[Range[datetime]] = mapped_column(TSTZRANGE, index=True)
21
+ quantity: Mapped[float]
22
+ quantitywaste: Mapped[float | None]
23
+
24
+ # FKS
25
+ pdord_id: Mapped[int] = mapped_column(ForeignKey("pdord.id"))
26
+ pdunit_id: Mapped[int | None] = mapped_column(ForeignKey("pdunit.id"))
27
+
28
+ # RELATIONSHIPS
29
+ pdord: Mapped["PdOrd"] = relationship("PdOrd")
30
+
31
+ @hybrid_method
32
+ def refrange_intersection_def(
33
+ self, starttime: datetime, stoptime: datetime, seconds: bool = False, /
34
+ ) -> float | Range[datetime] | None:
35
+ """Python-level: intersection of the refrance with the given range"""
36
+ raise NotImplementedError("Sql expression level only")
37
+
38
+ _refrange_intersection_def_hybrid = cast(Any, refrange_intersection_def)
39
+
40
+ @overload
41
+ @classmethod
42
+ def refrange_intersection(
43
+ cls, starttime: datetime, stoptime: datetime, seconds: Literal[False], /
44
+ ) -> SQLCoreOperations[Range[datetime] | None]: ...
45
+ @overload
46
+ @classmethod
47
+ def refrange_intersection(
48
+ cls, starttime: datetime, stoptime: datetime, seconds: Literal[True], /
49
+ ) -> SQLCoreOperations[float]: ...
50
+ @_refrange_intersection_def_hybrid.inplace.expression
51
+ @classmethod
52
+ def refrange_intersection(
53
+ cls,
54
+ starttime: datetime,
55
+ stoptime: datetime,
56
+ seconds: bool = False,
57
+ /,
58
+ ) -> SQLCoreOperations[float | Range[datetime] | None]:
59
+ """SQL-level: intersection of the refrance with the given range"""
60
+ search_range = func.tstzrange(starttime, stoptime, "[)")
61
+ condition = and_(
62
+ cast(Any, cls.refrange).is_not(None),
63
+ cls.refrange.op("&&")(search_range),
64
+ )
65
+ intersection = cls.refrange.op("*")(search_range)
66
+
67
+ if seconds:
68
+ length = func.upper(intersection) - func.lower(intersection)
69
+ return case((condition, func.extract("epoch", length)), else_=0.0)
70
+ else:
71
+ return case((condition, intersection), else_=None)
72
+
73
+ @hybrid_method
74
+ def total_quantity_def(self, /) -> float:
75
+ """Python-level: get total quantity (good + scrap)"""
76
+ raise NotImplementedError("Sql expression level only")
77
+
78
+ @total_quantity_def.expression
79
+ @classmethod
80
+ def total_quantity(cls, /) -> ColumnElement[float]:
81
+ """SQL-level: get total quantity (good + scrap)"""
82
+ return case(
83
+ (cls.quantitywaste.is_not(None), cls.quantity + cls.quantitywaste),
84
+ else_=cls.quantity,
85
+ )
86
+
87
+ @hybrid_method
88
+ def good_quantity_over_range_def(
89
+ self, starttime: datetime, stoptime: datetime, /
90
+ ) -> float:
91
+ """Python-level: get good quantity over time range"""
92
+ raise NotImplementedError("Sql expression level only")
93
+
94
+ @good_quantity_over_range_def.expression
95
+ def good_quantity_over_range(
96
+ cls, starttime: datetime, stoptime: datetime, /
97
+ ) -> ColumnElement[float]:
98
+ """SQL-level: get good quantity over time range"""
99
+ return (
100
+ cls.refrange_intersection(starttime, stoptime, True)
101
+ * cls.quantity
102
+ / cls.actual_time_seconds
103
+ )
104
+
105
+ @hybrid_method
106
+ def total_quantity_over_range_def(
107
+ self, starttime: datetime, stoptime: datetime, /
108
+ ) -> float:
109
+ """Python-level: get total quantity (good + scrap) over time range"""
110
+ raise NotImplementedError("Sql expression level only")
111
+
112
+ @total_quantity_over_range_def.expression
113
+ def total_quantity_over_range(
114
+ cls, starttime: datetime, stoptime: datetime, /
115
+ ) -> ColumnElement[float]:
116
+ """SQL-level: get total quantity (good + scrap) over time range"""
117
+ return (
118
+ cls.refrange_intersection(starttime, stoptime, True)
119
+ * cls.total_quantity()
120
+ / cls.actual_time_seconds
121
+ )
122
+
123
+ @hybrid_method
124
+ def ideal_time_over_time_range_def(
125
+ self, starttime: datetime, stoptime: datetime, /
126
+ ) -> float:
127
+ """Python-level: how many units would ideally be produced in the timeframe"""
128
+ raise NotImplementedError("Sql expression level only")
129
+
130
+ @ideal_time_over_time_range_def.expression
131
+ @classmethod
132
+ def ideal_time_over_time_range(
133
+ cls, starttime: datetime, stoptime: datetime, /
134
+ ) -> ColumnElement[float]:
135
+ """SQL-level: how many units would ideally be produced in the timeframe"""
136
+ total_q = cls.total_quantity_over_range(starttime, stoptime)
137
+
138
+ planmachinetime_q = (
139
+ select(PdOrd.planmachinetime)
140
+ .where(PdOrd.id == cls.pdord_id)
141
+ .correlate(cls)
142
+ .scalar_subquery()
143
+ )
144
+ return case(
145
+ (
146
+ planmachinetime_q.is_not(None),
147
+ func.extract("epoch", planmachinetime_q) * total_q,
148
+ ),
149
+ else_=0.0,
150
+ )
151
+
152
+ @hybrid_property
153
+ def actual_time_seconds_def(self, /) -> Extract:
154
+ """Python-level: get total actual prod time"""
155
+ raise NotImplementedError("Sql expression level only")
156
+
157
+ @actual_time_seconds_def.expression
158
+ def actual_time_seconds(cls, /) -> Extract:
159
+ """SQL-level: get total actual prod time"""
160
+ return func.extract(
161
+ "epoch", (func.upper(cls.refrange) - func.lower(cls.refrange))
162
+ )
163
+
164
+ @hybrid_method
165
+ def actual_time_over_time_range_def(
166
+ self, starttime: datetime, stoptime: datetime, /
167
+ ) -> float:
168
+ """Python-level: get actual prod time in seconds"""
169
+ raise NotImplementedError("Sql expression level only")
170
+
171
+ @actual_time_over_time_range_def.expression
172
+ def actual_time_over_time_range(
173
+ cls, starttime: datetime, stoptime: datetime, /
174
+ ) -> SQLCoreOperations[float]:
175
+ """SQL-level: get actual prod time in seconds"""
176
+ return cls.refrange_intersection(starttime, stoptime, True)
177
+
178
+ @hybrid_method
179
+ def performance_eligible_def(self, pdunit_id: int, /) -> bool:
180
+ """Python-level: check if entry is eligible
181
+ to be taken in account for performance"""
182
+ raise NotImplementedError("Sql expression level only")
183
+
184
+ @performance_eligible_def.expression
185
+ def performance_eligible(cls, pdunit_id: int, /) -> ColumnElement[bool]:
186
+ """SQL-level: check if entry is eligible
187
+ to be taken in account for performance"""
188
+ return and_(
189
+ cast(Any, cls.deleted).is_(False),
190
+ cast(Any, cls.pdunit_id) == pdunit_id,
191
+ cast(Any, cls.pdord).has(PdOrd.pdunit_id == pdunit_id),
192
+ )
193
+
194
+ @hybrid_method
195
+ def quality_eligible_def(self, pdunit_id: int, /) -> bool:
196
+ """Python-level: check if entry is eligible
197
+ to be taken in account for quality"""
198
+ raise NotImplementedError("Sql expression level only")
199
+
200
+ @quality_eligible_def.expression
201
+ def quality_eligible(cls, pdunit_id: int, /) -> ColumnElement[bool]:
202
+ """SQL-level: check if entry is eligible
203
+ to be taken in account for quality"""
204
+ return and_(
205
+ cast(Any, cls.deleted).is_(False), cast(Any, cls.pdunit_id) == pdunit_id
206
+ )
@@ -0,0 +1,14 @@
1
+ from datetime import datetime
2
+
3
+ from perfact.api.base import VisibilityAwareModel
4
+ from perfact.api.base.model import Base, Mapped
5
+
6
+
7
+ class PdUnit(Base, VisibilityAwareModel):
8
+ modtime: Mapped[datetime]
9
+ author: Mapped[str]
10
+ name: Mapped[str]
11
+ num: Mapped[str]
12
+ overprodmay: Mapped[bool]
13
+ overprodfactor: Mapped[float]
14
+ seqnum: Mapped[int]
@@ -0,0 +1,23 @@
1
+ from perfact.api.base import AuthInfo, VisibilityPolicy
2
+ from sqlalchemy import literal
3
+ from sqlalchemy.sql.elements import ColumnElement
4
+
5
+ from .pdunit import PdUnit
6
+
7
+
8
+ class PdUnitVisibilityPolicy(VisibilityPolicy):
9
+ """PdUnit is open by default."""
10
+
11
+ model = PdUnit
12
+
13
+ def filter(self, auth: AuthInfo) -> ColumnElement[bool]:
14
+ return literal(True)
15
+
16
+
17
+ def register_policies(registry: object) -> None:
18
+ from perfact.api.base import VisibilityPolicyRegistry
19
+
20
+ if isinstance(registry, VisibilityPolicyRegistry):
21
+ registry.register(PdUnit, PdUnitVisibilityPolicy)
22
+ else:
23
+ raise RuntimeError("The Policy Registry was not initialized correctly.")
File without changes
File without changes
@@ -0,0 +1,24 @@
1
+ Metadata-Version: 2.4
2
+ Name: perfact-api-pd
3
+ Version: 0.2
4
+ Summary: PerFact API - pd domain models and services
5
+ Author-email: Viktor Dick <viktor.dick@perfact.de>
6
+ License-Expression: GPL-2.0-or-later
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: SQL
9
+ Classifier: Operating System :: POSIX :: Linux
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: psycopg[binary]
13
+ Requires-Dist: sqlalchemy
14
+ Requires-Dist: perfact-api-base-model
15
+ Requires-Dist: perfact-api-app
16
+ Requires-Dist: perfact-api-pp
17
+
18
+ # PerFact API - pd - model
19
+
20
+ This repository contains the model related to the Pd-module ('Production Execution') of the PerFact software.
21
+
22
+ ## getting started
23
+ As this repository does not contain an own main entrypoint, you have to install this package into the base and run that one.
24
+ Please referer the documentation of the *API Base* to get more informations about how the discovery works and how to include this module to your app bundle.
@@ -0,0 +1,16 @@
1
+ perfact/api/pd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ perfact/api/pd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ perfact/api/pd/model/__init__.py,sha256=IokxoiLRN8YgL3zfXH8sUipq2mNpzsAUfAZsSq6fp0s,317
4
+ perfact/api/pd/model/pdord.py,sha256=hSSPWS50A6w9pKXioGJAkvtdkTfMalf5lX4c9d_sh3M,1721
5
+ perfact/api/pd/model/pdordlc.py,sha256=nYLM2XTp7uk3nbEWn7Jij1FNaBQrsL3trnzV4Tdt2R4,288
6
+ perfact/api/pd/model/pdordlch.py,sha256=Ei9AATHC3YR5g9nNUQAVX9rCuvLWeVolPOLR0WBv9IQ,7163
7
+ perfact/api/pd/model/pdordlct.py,sha256=8SNoSMwn4plHnlJM7miK3EONVZPZ9qrmtyG0ZGZ0PC4,3033
8
+ perfact/api/pd/model/pdordprd.py,sha256=GK9xx-4iLF7dym8-TJX-34LbfP7FKTzUv8HDI3ojCds,7703
9
+ perfact/api/pd/model/pdunit.py,sha256=AlKjZA495PRlJfzOBK5BB44FwRlD4F1FfTw7-BFIJHc,358
10
+ perfact/api/pd/model/policy.py,sha256=ymyVWlZwMkNMEET69sW_HQcunErnNFGl4mBzWaTf0Ys,677
11
+ perfact/api/pd/model/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ perfact_api_pd-0.2.dist-info/METADATA,sha256=_V5R78dgymKJN4XKMzPvUxgW5_H18QHm59i5rZWN4tg,993
13
+ perfact_api_pd-0.2.dist-info/WHEEL,sha256=TdQ5LtNwLuxTCjgxN51AgdU5w-KkB9ttmLbzjTH02pg,109
14
+ perfact_api_pd-0.2.dist-info/entry_points.txt,sha256=qG_YI5UUSP_r0rcHtVJQCDfUPnq3Z2IJdjxGq2JxdzI,89
15
+ perfact_api_pd-0.2.dist-info/top_level.txt,sha256=1odO3B1JiDF2Lqgnop8k7K4Xs1y_LdwehM53l1NDOnc,8
16
+ perfact_api_pd-0.2.dist-info/RECORD,,
@@ -0,0 +1,6 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any
6
+
@@ -0,0 +1,2 @@
1
+ [perfact.api.visibility_policies]
2
+ pdunit = perfact.api.pd.model.policy:register_policies
@@ -0,0 +1 @@
1
+ perfact