operx-cli 0.8.0__tar.gz → 0.8.1__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.
- {operx_cli-0.8.0 → operx_cli-0.8.1}/PKG-INFO +1 -1
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/AGENTES.md +7 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/__init__.py +1 -1
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/ordenes.py +6 -5
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/preventivos.py +5 -3
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli.egg-info/PKG-INFO +1 -1
- {operx_cli-0.8.0 → operx_cli-0.8.1}/pyproject.toml +1 -1
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_preventivos.py +13 -2
- {operx_cli-0.8.0 → operx_cli-0.8.1}/README.md +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/agent_guide.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/api_fields.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/app.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/browser_login.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/client.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/__init__.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/account.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/ambiental.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/articulos.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/avisos.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/campos.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/common.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/completar.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/empresas.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/inventario.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/lecturas.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/muestreo.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/personas.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/planta.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/raw.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/registros.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/reportes.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/rutinas.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/search.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/sst.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/commands/update.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/lookup.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/output.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/record_completion.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/self_update.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/settings.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/shell.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/spreadsheet.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/updates.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/values.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli/welcome.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli.egg-info/SOURCES.txt +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli.egg-info/dependency_links.txt +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli.egg-info/entry_points.txt +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli.egg-info/requires.txt +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/operx_cli.egg-info/top_level.txt +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/setup.cfg +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_agentes.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_api_campos.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_app.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_articulos.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_campos.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_cards.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_client.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_completar.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_daily_flows.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_inventario_lecturas.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_json_writes.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_login.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_logout_and_routes.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_lookup.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_more_of_the_api.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_muestreo.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_ordenes.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_output.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_personas.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_record_completion.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_registros.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_rutinas.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_self_update.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_settings.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_shell.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_spreadsheet.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_sst_ambiental.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_updates.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_values.py +0 -0
- {operx_cli-0.8.0 → operx_cli-0.8.1}/tests/test_welcome.py +0 -0
|
@@ -57,6 +57,13 @@ llamada queda en el historial del token, marcada como hecha desde la CLI.
|
|
|
57
57
|
(la empresa usa Personas y no ha iniciado su jornada), `assigned` (está en
|
|
58
58
|
un trabajo abierto sin estar en sitio) o `available`. Filtra con
|
|
59
59
|
`operx api GET employees/ -q status=on_site`.
|
|
60
|
+
- Una orden o un plan preventivo que hace un contratista vinculado no tiene a
|
|
61
|
+
nadie de la empresa: «Asignada a» muestra el contratista, y en `--json` va
|
|
62
|
+
en `assigned_company` (`{"name": "Climas del Valle", "kind": "contractor"}`;
|
|
63
|
+
`null` si no lo tiene un contratista). Mientras lo tenga, la API rechaza
|
|
64
|
+
cambiar la orden desde aquí, y el plan no cambia de responsable ni de
|
|
65
|
+
equipo: el 400 dice por qué. Díselo a la persona; no lo intentes de otra
|
|
66
|
+
forma.
|
|
60
67
|
- Los resultados van a stdout y los avisos a stderr:
|
|
61
68
|
`operx equipos listar --todas --json > equipos.json` guarda solo los datos.
|
|
62
69
|
- `--csv` da un CSV para Excel (separado por punto y coma, con decimales con
|
|
@@ -72,9 +72,10 @@ PersonOption = Annotated[
|
|
|
72
72
|
]
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
def
|
|
76
|
-
"""The person doing
|
|
77
|
-
|
|
75
|
+
def assignee(record):
|
|
76
|
+
"""The person doing an order or a plan, or the linked contractor doing it
|
|
77
|
+
instead."""
|
|
78
|
+
return record.get("assigned_to_name") or (record.get("assigned_company") or {}).get("name")
|
|
78
79
|
|
|
79
80
|
|
|
80
81
|
def _in_spanish(order):
|
|
@@ -82,7 +83,7 @@ def _in_spanish(order):
|
|
|
82
83
|
**order,
|
|
83
84
|
"status": STATUS_LABELS.get(order.get("status"), order.get("status")),
|
|
84
85
|
"priority": PRIORITY_LABELS.get(order.get("priority"), order.get("priority")),
|
|
85
|
-
"assigned_to_name":
|
|
86
|
+
"assigned_to_name": assignee(order),
|
|
86
87
|
"due_date": shown_moment(order.get("due_date")),
|
|
87
88
|
}
|
|
88
89
|
|
|
@@ -133,7 +134,7 @@ def ver(ctx: typer.Context, orden: Annotated[int, typer.Argument(help="El númer
|
|
|
133
134
|
("Estado", STATUS_LABELS.get(order.get("status"), order.get("status"))),
|
|
134
135
|
("Prioridad", PRIORITY_LABELS.get(order.get("priority"), order.get("priority"))),
|
|
135
136
|
("Tipo", TYPE_LABELS.get(order.get("work_type"), order.get("work_type"))),
|
|
136
|
-
("Asignada a",
|
|
137
|
+
("Asignada a", assignee(order)),
|
|
137
138
|
("También", order.get("extra_assignee_names")),
|
|
138
139
|
("Equipo", order.get("asset_name")),
|
|
139
140
|
("Lugar", order.get("site_name")),
|
|
@@ -24,7 +24,7 @@ from .common import (
|
|
|
24
24
|
print_result,
|
|
25
25
|
without_empty,
|
|
26
26
|
)
|
|
27
|
-
from .ordenes import PRIORITY_KEYS, PRIORITY_LABELS, Prioridad, account_id
|
|
27
|
+
from .ordenes import PRIORITY_KEYS, PRIORITY_LABELS, Prioridad, account_id, assignee
|
|
28
28
|
|
|
29
29
|
app = typer.Typer(help="Trabajos recurrentes: los planes que crean una orden cada tanto.", no_args_is_help=True)
|
|
30
30
|
|
|
@@ -69,7 +69,9 @@ def every(plan):
|
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
def _shown(plan):
|
|
72
|
-
return {
|
|
72
|
+
return {
|
|
73
|
+
**plan, "every": every(plan), "next": shown_moment(plan.get("next_run")), "assigned_to_name": assignee(plan),
|
|
74
|
+
}
|
|
73
75
|
|
|
74
76
|
|
|
75
77
|
@app.command()
|
|
@@ -106,7 +108,7 @@ def ver(ctx: typer.Context, plan: PlanArgument, as_json: JsonOption = False):
|
|
|
106
108
|
("Cliente", found.get("customer_name")),
|
|
107
109
|
("Orden que crea", found.get("wo_title")),
|
|
108
110
|
("Prioridad", PRIORITY_LABELS.get(found.get("wo_priority"), found.get("wo_priority"))),
|
|
109
|
-
("Asignado a", found
|
|
111
|
+
("Asignado a", assignee(found)),
|
|
110
112
|
("Horas estimadas", found.get("estimated_hours")),
|
|
111
113
|
("Lista de chequeo", f"{len(checklist)} puntos" if checklist else ""),
|
|
112
114
|
("Activo", found.get("is_active")),
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "operx-cli"
|
|
7
|
-
version = "0.8.
|
|
7
|
+
version = "0.8.1"
|
|
8
8
|
description = "La línea de comandos de OperX: tu empresa desde la terminal, con tu token de API."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -14,11 +14,13 @@ PLAN = {
|
|
|
14
14
|
"site_name": "Planta Norte", "customer_id": None, "customer_name": None, "location_description": "",
|
|
15
15
|
"interval": 3, "unit": "months", "last_run": None, "next_run": "2026-11-01T08:00:00-05:00",
|
|
16
16
|
"wo_title": "Lubricar rodamientos Bomba 4", "wo_description": "", "wo_priority": "medium",
|
|
17
|
-
"assigned_to_id": None, "assigned_to_name": None, "assigned_to_avatar": None, "
|
|
18
|
-
"checklist": [], "images": [], "is_active": True, "created_by_id": 1,
|
|
17
|
+
"assigned_to_id": None, "assigned_to_name": None, "assigned_to_avatar": None, "assigned_company": None,
|
|
18
|
+
"estimated_hours": None, "checklist": [], "images": [], "is_active": True, "created_by_id": 1,
|
|
19
19
|
"created_at": "2026-10-23T02:34:02.203781-05:00", "updated_at": "2026-10-23T02:34:02.203781-05:00",
|
|
20
20
|
"last_execution": None,
|
|
21
21
|
}
|
|
22
|
+
# The same plan while a linked contractor has it: nobody of the company is on it.
|
|
23
|
+
HELD_BY_CONTRACTOR = {**PLAN, "assigned_company": {"name": "Climas del Valle", "kind": "contractor"}}
|
|
22
24
|
# GET /v1/pm/schedules/1/notes/ (preventive_maintenance/views.py PMScheduleNoteView)
|
|
23
25
|
NOTES = [{"id": 1, "body": "Usar grasa EP2.", "author_type": "staff", "author_name": "Admin Smoke",
|
|
24
26
|
"created_at": "2026-10-23T07:34:02.284143Z"}]
|
|
@@ -70,6 +72,15 @@ def test_ver_json_is_the_plan_as_it_came():
|
|
|
70
72
|
assert json.loads(run(fake, "preventivos", "ver", "1", "--json").output) == PLAN
|
|
71
73
|
|
|
72
74
|
|
|
75
|
+
def test_a_plan_a_contractor_has_names_the_contractor():
|
|
76
|
+
listed = run(FakeApi({("GET", "pm/schedules/"): page(HELD_BY_CONTRACTOR)}), "preventivos", "listar")
|
|
77
|
+
shown = run(FakeApi({("GET", "pm/schedules/1/"): HELD_BY_CONTRACTOR, ("GET", "pm/schedules/1/notes/"): []}),
|
|
78
|
+
"preventivos", "ver", "1")
|
|
79
|
+
assert listed.exit_code == 0, listed.output
|
|
80
|
+
assert shown.exit_code == 0, shown.output
|
|
81
|
+
assert "Climas del Valle" in listed.output and "Climas del Valle" in shown.output
|
|
82
|
+
|
|
83
|
+
|
|
73
84
|
def test_crear_sends_the_plan_at_the_machine_s_place():
|
|
74
85
|
fake = FakeApi({
|
|
75
86
|
("GET", "assets/"): page(ASSET),
|
|
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
|
|
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
|