operx-cli 0.7.7__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.
Files changed (81) hide show
  1. {operx_cli-0.7.7 → operx_cli-0.8.1}/PKG-INFO +1 -1
  2. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/AGENTES.md +8 -1
  3. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/__init__.py +1 -1
  4. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/ambiental.py +3 -22
  5. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/ordenes.py +8 -1
  6. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/preventivos.py +5 -3
  7. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli.egg-info/PKG-INFO +1 -1
  8. {operx_cli-0.7.7 → operx_cli-0.8.1}/pyproject.toml +1 -1
  9. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_cards.py +1 -1
  10. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_json_writes.py +1 -4
  11. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_ordenes.py +14 -1
  12. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_preventivos.py +13 -2
  13. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_sst_ambiental.py +0 -17
  14. {operx_cli-0.7.7 → operx_cli-0.8.1}/README.md +0 -0
  15. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/agent_guide.py +0 -0
  16. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/api_fields.py +0 -0
  17. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/app.py +0 -0
  18. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/browser_login.py +0 -0
  19. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/client.py +0 -0
  20. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/__init__.py +0 -0
  21. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/account.py +0 -0
  22. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/articulos.py +0 -0
  23. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/avisos.py +0 -0
  24. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/campos.py +0 -0
  25. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/common.py +0 -0
  26. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/completar.py +0 -0
  27. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/empresas.py +0 -0
  28. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/inventario.py +0 -0
  29. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/lecturas.py +0 -0
  30. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/muestreo.py +0 -0
  31. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/personas.py +0 -0
  32. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/planta.py +0 -0
  33. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/raw.py +0 -0
  34. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/registros.py +0 -0
  35. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/reportes.py +0 -0
  36. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/rutinas.py +0 -0
  37. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/search.py +0 -0
  38. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/sst.py +0 -0
  39. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/commands/update.py +0 -0
  40. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/lookup.py +0 -0
  41. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/output.py +0 -0
  42. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/record_completion.py +0 -0
  43. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/self_update.py +0 -0
  44. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/settings.py +0 -0
  45. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/shell.py +0 -0
  46. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/spreadsheet.py +0 -0
  47. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/updates.py +0 -0
  48. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/values.py +0 -0
  49. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli/welcome.py +0 -0
  50. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli.egg-info/SOURCES.txt +0 -0
  51. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli.egg-info/dependency_links.txt +0 -0
  52. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli.egg-info/entry_points.txt +0 -0
  53. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli.egg-info/requires.txt +0 -0
  54. {operx_cli-0.7.7 → operx_cli-0.8.1}/operx_cli.egg-info/top_level.txt +0 -0
  55. {operx_cli-0.7.7 → operx_cli-0.8.1}/setup.cfg +0 -0
  56. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_agentes.py +0 -0
  57. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_api_campos.py +0 -0
  58. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_app.py +0 -0
  59. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_articulos.py +0 -0
  60. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_campos.py +0 -0
  61. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_client.py +0 -0
  62. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_completar.py +0 -0
  63. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_daily_flows.py +0 -0
  64. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_inventario_lecturas.py +0 -0
  65. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_login.py +0 -0
  66. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_logout_and_routes.py +0 -0
  67. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_lookup.py +0 -0
  68. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_more_of_the_api.py +0 -0
  69. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_muestreo.py +0 -0
  70. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_output.py +0 -0
  71. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_personas.py +0 -0
  72. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_record_completion.py +0 -0
  73. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_registros.py +0 -0
  74. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_rutinas.py +0 -0
  75. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_self_update.py +0 -0
  76. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_settings.py +0 -0
  77. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_shell.py +0 -0
  78. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_spreadsheet.py +0 -0
  79. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_updates.py +0 -0
  80. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_values.py +0 -0
  81. {operx_cli-0.7.7 → operx_cli-0.8.1}/tests/test_welcome.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: operx-cli
3
- Version: 0.7.7
3
+ Version: 0.8.1
4
4
  Summary: La línea de comandos de OperX: tu empresa desde la terminal, con tu token de API.
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -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
@@ -79,7 +86,7 @@ llamada queda en el historial del token, marcada como hecha desde la CLI.
79
86
  `rutinas crear`, `cambiar` y `quitar`; `campos crear`, `cambiar`,
80
87
  `quitar` y `guardar`.
81
88
  - SG-SST y Ambiental: `sst nueva-accion` y `accion-hecha`;
82
- `ambiental nueva-accion`, `accion-hecha`, `residuo` y `lectura`.
89
+ `ambiental nueva-accion`, `accion-hecha` y `residuo`.
83
90
  - `avisos --marcar-leidos`, y `operx api` con POST, PUT, PATCH o DELETE.
84
91
  - Un error se corrige con su contrario, nunca borrando: `inventario revertir`
85
92
  deshace un movimiento, `lecturas anular` una lectura. La excepción es
@@ -2,4 +2,4 @@
2
2
  API (backend/users/api_allowlist.py) from a terminal, with a personal API
3
3
  token."""
4
4
 
5
- __version__ = "0.7.7"
5
+ __version__ = "0.8.1"
@@ -1,6 +1,7 @@
1
1
  """`operx ambiental`: Ambiental, per company: its action plan, permits and
2
- obligations, and the two records made most often, waste and meter
3
- readings. A wrong record is voided in the app, never edited."""
2
+ obligations, and the record made most often, waste. Consumption is kept
3
+ by the month in the app (no meter readings). A wrong record is voided in
4
+ the app, never edited."""
4
5
 
5
6
  from datetime import date
6
7
  from typing import Annotated, Optional
@@ -158,23 +159,3 @@ def _stream(client, path, corriente, sede):
158
159
  if not streams:
159
160
  raise CliError("Esta empresa aún no tiene corrientes de residuos: créalas en la app, en Ambiental › Residuos.")
160
161
  return find_in(streams, corriente, ["name"], "corriente")
161
-
162
-
163
- @app.command()
164
- def lectura(
165
- ctx: typer.Context,
166
- medidor: Annotated[str, typer.Option("--medidor", help="El nombre del medidor o de lo que mide: Acueducto.")],
167
- valor: Annotated[str, typer.Option("--valor", help="Lo que marca: 1.234,5.")],
168
- fecha: FechaOption = None,
169
- empresa: EmpresaOption = None,
170
- si: YesOption = False,
171
- as_json: JsonOption = False,
172
- ):
173
- """Registra la lectura de un medidor (agua, energía, gas)."""
174
- client = client_of(ctx)
175
- path = company_path(client, ENVIRONMENT, empresa)
176
- meter = find_in(client.get(f"{path}/consumption/meters"), medidor, ["name", "meter_name"], "medidor")
177
- reading = {"source": meter["id"], "read_on": day(fecha) or date.today().isoformat(), "value": number(valor)}
178
- confirm_write(f"Lectura {valor} en «{meter['name']}» el {shown_moment(reading['read_on'])}.", si)
179
- recorded = answer_of(client.send("POST", f"{path}/consumption/readings", json=reading))
180
- print_result(recorded, as_json, f"Lectura registrada: {valor} en {meter['name']}.")
@@ -72,11 +72,18 @@ PersonOption = Annotated[
72
72
  ]
73
73
 
74
74
 
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")
79
+
80
+
75
81
  def _in_spanish(order):
76
82
  return {
77
83
  **order,
78
84
  "status": STATUS_LABELS.get(order.get("status"), order.get("status")),
79
85
  "priority": PRIORITY_LABELS.get(order.get("priority"), order.get("priority")),
86
+ "assigned_to_name": assignee(order),
80
87
  "due_date": shown_moment(order.get("due_date")),
81
88
  }
82
89
 
@@ -127,7 +134,7 @@ def ver(ctx: typer.Context, orden: Annotated[int, typer.Argument(help="El númer
127
134
  ("Estado", STATUS_LABELS.get(order.get("status"), order.get("status"))),
128
135
  ("Prioridad", PRIORITY_LABELS.get(order.get("priority"), order.get("priority"))),
129
136
  ("Tipo", TYPE_LABELS.get(order.get("work_type"), order.get("work_type"))),
130
- ("Asignada a", order.get("assigned_to_name")),
137
+ ("Asignada a", assignee(order)),
131
138
  ("También", order.get("extra_assignee_names")),
132
139
  ("Equipo", order.get("asset_name")),
133
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 {**plan, "every": every(plan), "next": shown_moment(plan.get("next_run"))}
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.get("assigned_to_name")),
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")),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: operx-cli
3
- Version: 0.7.7
3
+ Version: 0.8.1
4
4
  Summary: La línea de comandos de OperX: tu empresa desde la terminal, con tu token de API.
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "operx-cli"
7
- version = "0.7.7"
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"
@@ -17,7 +17,7 @@ ORDER = {
17
17
  "site_name": "Planta Norte",
18
18
  "site_arrival": {"address": "", "city": "", "latitude": None, "longitude": None, "directions": ""},
19
19
  "customer_id": None, "customer_name": None, "assigned_to_name": None, "assigned_to_avatar": None,
20
- "extra_assignee_names": [], "location_description": "", "custom_fields": {}, "signature": None,
20
+ "assigned_company": None, "extra_assignee_names": [], "location_description": "", "custom_fields": {}, "signature": None,
21
21
  "signed_by_name": "", "signed_at": None, "created_at": "2026-10-23T02:19:42.253068-05:00",
22
22
  "updated_at": "2026-10-23T02:19:42.253068-05:00",
23
23
  "comments": [{
@@ -12,7 +12,7 @@ from operx_cli.app import app
12
12
  from .fake_api import FakeApi, page, run
13
13
  from .test_more_of_the_api import FINDING, MOVEMENT, REASONS, STOP
14
14
  from .test_preventivos import ASSET, NOTES, PLAN
15
- from .test_sst_ambiental import EMPLOYEES, ENV_ACTION, ENV_COMPANIES, METERS, SST_ACTION, SST_COMPANIES, STREAMS
15
+ from .test_sst_ambiental import EMPLOYEES, ENV_ACTION, ENV_COMPANIES, SST_ACTION, SST_COMPANIES, STREAMS
16
16
 
17
17
  FILTER = {"id": 3, "code": "FIL-010", "name": "Filtro de aceite"}
18
18
  STORE = {"id": 2, "name": "Bodega central"}
@@ -74,9 +74,6 @@ CASES = [
74
74
  (["ambiental", "residuo", "--corriente", "aceite usado", "--kg", "12,5"],
75
75
  {("GET", "environment/companies/"): ENV_COMPANIES, ("GET", "environment/companies/1/waste/streams/"): STREAMS},
76
76
  ("POST", "environment/companies/1/waste/entries/"), (201, {"id": 9, "kg": "12.500"})),
77
- (["ambiental", "lectura", "--medidor", "Acueducto", "--valor", "1.234,5"],
78
- {("GET", "environment/companies/"): ENV_COMPANIES, ("GET", "environment/companies/1/consumption/meters/"): METERS},
79
- ("POST", "environment/companies/1/consumption/readings/"), (201, {"id": 3})),
80
77
  (["avisos", "--marcar-leidos"], {}, ("POST", "notifications/mark-read/"), {"marked": 4}),
81
78
  ]
82
79
 
@@ -6,7 +6,12 @@ from .fake_api import FakeApi, page, run
6
6
 
7
7
  ORDER = {
8
8
  "id": 15, "title": "Cambio de rodamiento", "status": "in_progress", "priority": "high",
9
- "assigned_to_name": "Pedro Pérez", "asset_name": "Bomba 4", "site_name": "Planta", "due_date": "2026-10-30T00:00:00-05:00",
9
+ "assigned_to_name": "Pedro Pérez", "assigned_company": None, "asset_name": "Bomba 4", "site_name": "Planta",
10
+ "due_date": "2026-10-30T00:00:00-05:00",
11
+ }
12
+ # The same order while a linked contractor does it: nobody of the company is on it.
13
+ HELD_BY_CONTRACTOR = {
14
+ **ORDER, "assigned_to_name": None, "assigned_company": {"name": "Climas del Valle", "kind": "contractor"},
10
15
  }
11
16
  PEOPLE = page({"id": 3, "user_id": 21, "user_name": "Pedro Pérez", "employee_code": "T-01"})
12
17
 
@@ -102,3 +107,11 @@ def test_ver_shows_one_order():
102
107
  result = run(FakeApi({("GET", "work-orders/15/"): ORDER}), "ordenes", "ver", "15")
103
108
  assert result.exit_code == 0, result.output
104
109
  assert "Cambio de rodamiento" in result.output
110
+
111
+
112
+ def test_an_order_a_contractor_has_names_the_contractor():
113
+ listed = run(FakeApi({("GET", "work-orders/"): page(HELD_BY_CONTRACTOR)}), "ordenes", "listar")
114
+ shown = run(FakeApi({("GET", "work-orders/15/"): HELD_BY_CONTRACTOR}), "ordenes", "ver", "15")
115
+ assert listed.exit_code == 0, listed.output
116
+ assert shown.exit_code == 0, shown.output
117
+ assert "Climas del Valle" in listed.output and "Climas del Valle" in shown.output
@@ -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, "estimated_hours": 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),
@@ -52,9 +52,6 @@ STREAMS = {
52
52
  "moving_average_kg": None, "storage_alert_months": [], "certificate_days": 30,
53
53
  "streams": [{"id": 11, "name": "Aceite usado", "kind": "hazardous", "hazardous": True}],
54
54
  }
55
- METERS = [{"id": 21, "name": "Acueducto", "meter_name": "Contador principal", "qr_code": "x", "establishment": "Planta Norte"}]
56
-
57
-
58
55
  @pytest.fixture(autouse=True)
59
56
  def signed_in(monkeypatch):
60
57
  monkeypatch.setenv("OPERX_TOKEN", "opx_test")
@@ -224,20 +221,6 @@ def test_ambiental_residuo_finds_the_stream_by_its_name():
224
221
  assert fake.sent("POST", "environment/companies/1/waste/entries/") == {"stream": 11, "date": "2026-10-22", "kg": "12.5"}
225
222
 
226
223
 
227
- def test_ambiental_lectura_of_a_meter():
228
- fake = FakeApi({
229
- ("GET", "environment/companies/"): ENV_COMPANIES,
230
- ("GET", "environment/companies/1/consumption/meters/"): METERS,
231
- ("POST", "environment/companies/1/consumption/readings/"): (201, {"id": 3}),
232
- })
233
- result = run(fake, "ambiental", "lectura", "--medidor", "Acueducto", "--valor", "1.234,5", "--fecha", "22/10/2026", "--si")
234
-
235
- assert result.exit_code == 0, result.output
236
- assert fake.sent("POST", "environment/companies/1/consumption/readings/") == {
237
- "source": 21, "read_on": "2026-10-22", "value": "1234.5",
238
- }
239
-
240
-
241
224
  # ── Personas ──────────────────────────────────────────────────────────────
242
225
 
243
226
 
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