feat: add repair parts tracking

This commit is contained in:
lussierj committed 2026-08-02 21:26:15 +00:00
1 parent 6e550c1c13
commit eab9646960
23 files changed
+2386 -4

No files matched your search

+178
View File
@@ -597,6 +597,184 @@ class RepairRepository:
row = cur.fetchone()
return dict(row)
def lock_component_for_update(self, component_id: UUID) -> dict | None:
with self._connection_scope() as connection:
with connection.cursor(row_factory=dict_row) as cur:
cur.execute(
"""
SELECT
id,
component_type,
asset_id,
manufacturer,
model,
manufacturer_serial
FROM components
WHERE id = %s
FOR UPDATE
""",
(component_id,),
)
row = cur.fetchone()
return dict(row) if row else None
def create_repair_part(
self,
*,
repair_part_id: UUID,
repair_id: UUID,
consumable_description: str | None,
quantity: object | None,
unit: str | None,
component: Mapping[str, Any] | None,
notes: str | None,
recorded_event: Mapping[str, Any],
) -> dict:
with self._connection_scope(write=True) as connection:
with connection.cursor(row_factory=dict_row) as cur:
cur.execute(
"""
INSERT INTO repair_parts (
id,
repair_id,
consumable_description,
quantity,
unit,
component_id,
component_type_snapshot,
component_asset_id_snapshot,
component_manufacturer_snapshot,
component_model_snapshot,
component_manufacturer_serial_snapshot,
notes,
recorded_by,
recorded_at,
recorded_event_id
)
VALUES (
%s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, %s, %s
)
RETURNING *
""",
(
repair_part_id,
repair_id,
consumable_description,
quantity,
unit,
component.get("id") if component else None,
component.get("component_type") if component else None,
component.get("asset_id") if component else None,
component.get("manufacturer") if component else None,
component.get("model") if component else None,
component.get("manufacturer_serial") if component else None,
notes,
recorded_event["created_by"],
recorded_event["created_at"],
recorded_event["id"],
),
)
return dict(cur.fetchone())
def get_repair_part(
self,
repair_id: UUID,
repair_part_id: UUID,
) -> dict | None:
with self._connection_scope() as connection:
with connection.cursor(row_factory=dict_row) as cur:
cur.execute(
"""
SELECT part.*, event.sequence AS recorded_event_sequence
FROM repair_parts AS part
JOIN repair_events AS event
ON event.id = part.recorded_event_id
WHERE part.repair_id = %s AND part.id = %s
""",
(repair_id, repair_part_id),
)
row = cur.fetchone()
return dict(row) if row else None
def get_repair_parts(self, repair_id: UUID) -> list[dict] | None:
with self._connection_scope() as connection:
with connection.cursor(row_factory=dict_row) as cur:
cur.execute(
"""
SELECT
repair.id AS existing_repair_id,
part.*,
event.sequence AS recorded_event_sequence
FROM repairs AS repair
LEFT JOIN repair_parts AS part
ON part.repair_id = repair.id
LEFT JOIN repair_events AS event
ON event.id = part.recorded_event_id
WHERE repair.id = %s
ORDER BY event.sequence ASC, part.id ASC
""",
(repair_id,),
)
rows = [dict(row) for row in cur.fetchall()]
if not rows:
return None
return [row for row in rows if row.get("id") is not None]
def lock_repair_part_for_update(
self,
repair_id: UUID,
repair_part_id: UUID,
) -> dict | None:
with self._connection_scope() as connection:
with connection.cursor(row_factory=dict_row) as cur:
cur.execute(
"""
SELECT *
FROM repair_parts
WHERE repair_id = %s AND id = %s
FOR UPDATE
""",
(repair_id, repair_part_id),
)
row = cur.fetchone()
return dict(row) if row else None
def void_repair_part(
self,
repair_id: UUID,
repair_part_id: UUID,
*,
reason: str,
void_event: Mapping[str, Any],
) -> dict | None:
with self._connection_scope(write=True) as connection:
with connection.cursor(row_factory=dict_row) as cur:
cur.execute(
"""
UPDATE repair_parts
SET voided_by = %s,
voided_at = %s,
void_reason = %s,
void_event_id = %s
WHERE repair_id = %s
AND id = %s
AND voided_at IS NULL
RETURNING *
""",
(
void_event["created_by"],
void_event["created_at"],
reason,
void_event["id"],
repair_id,
repair_part_id,
),
)
row = cur.fetchone()
return dict(row) if row else None
def get_repair_detail(self, repair_id: UUID) -> dict | None:
with self._connection_scope() as connection:
with connection.cursor(row_factory=dict_row) as cur: