80 lines
3.1 KiB
Python
80 lines
3.1 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Add worker active/inactive status, preserving existing status on repeat runs.
|
||
|
|
|
||
|
|
Only previously unclassified employees are set active. No rates, timesheets,
|
||
|
|
clock events or assignments are modified. Run with credentials from .env.local:
|
||
|
|
python3 scripts/pb-add-worker-status.py
|
||
|
|
"""
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import tempfile
|
||
|
|
from pb_env import http, superuser_token
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
token = superuser_token()
|
||
|
|
def get(path):
|
||
|
|
code, result = http("GET", path, token=token)
|
||
|
|
if code != 200:
|
||
|
|
raise RuntimeError(f"Read failed: HTTP {code}")
|
||
|
|
return result
|
||
|
|
|
||
|
|
def workers():
|
||
|
|
rows = []
|
||
|
|
page = 1
|
||
|
|
while True:
|
||
|
|
result = get(f"/api/collections/employees/records?perPage=500&page={page}&sort=id")
|
||
|
|
rows.extend(result["items"])
|
||
|
|
if page >= result["totalPages"]:
|
||
|
|
return rows
|
||
|
|
page += 1
|
||
|
|
|
||
|
|
schema = get("/api/collections/employees")
|
||
|
|
before = workers()
|
||
|
|
fd, backup = tempfile.mkstemp(prefix="mega-before-worker-status-", suffix=".json")
|
||
|
|
with os.fdopen(fd, "w") as file:
|
||
|
|
json.dump({"schema": schema, "employees": before}, file)
|
||
|
|
print("Private backup:", backup)
|
||
|
|
expected = [
|
||
|
|
{"name": "employment_status", "type": "select", "required": False,
|
||
|
|
"values": ["active", "inactive"], "maxSelect": 1},
|
||
|
|
{"name": "inactive_from", "type": "date", "required": False},
|
||
|
|
]
|
||
|
|
fields = schema["fields"]
|
||
|
|
by_name = {f["name"]: f for f in fields}
|
||
|
|
missing = []
|
||
|
|
for wanted in expected:
|
||
|
|
if wanted["name"] not in by_name:
|
||
|
|
missing.append(wanted)
|
||
|
|
elif any(by_name[wanted["name"]].get(k) != v for k, v in wanted.items()):
|
||
|
|
raise RuntimeError("Existing worker-status field is incompatible")
|
||
|
|
if missing:
|
||
|
|
code, result = http("PATCH", f"/api/collections/{schema['id']}", {"fields": fields + missing}, token)
|
||
|
|
if code != 200:
|
||
|
|
raise RuntimeError(f"Schema update failed: HTTP {code}")
|
||
|
|
changed = 0
|
||
|
|
for row in before:
|
||
|
|
if row.get("employment_status"):
|
||
|
|
continue
|
||
|
|
code, result = http("PATCH", f"/api/collections/employees/records/{row['id']}", {"employment_status": "active"}, token)
|
||
|
|
if code != 200:
|
||
|
|
raise RuntimeError(f"Worker status update failed: HTTP {code}")
|
||
|
|
changed += 1
|
||
|
|
after = workers()
|
||
|
|
by_id = {row["id"]: row for row in after}
|
||
|
|
assert len(after) == len(before)
|
||
|
|
for row in before:
|
||
|
|
current = by_id[row["id"]]
|
||
|
|
assert current["employment_status"] == (row.get("employment_status") or "active")
|
||
|
|
for key, value in row.items():
|
||
|
|
if key not in ("employment_status", "updated"):
|
||
|
|
assert current.get(key) == value, f"Unexpected change: {key}"
|
||
|
|
actual = {f["name"]: f for f in get("/api/collections/employees")["fields"]}
|
||
|
|
for wanted in expected:
|
||
|
|
assert all(actual[wanted["name"]].get(k) == v for k, v in wanted.items())
|
||
|
|
print(f"Verified {len(after)} workers; {changed} set active; all other fields preserved.")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|