aegro 0.2.0__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.
- aegro-0.2.0/.gitignore +37 -0
- aegro-0.2.0/LICENSE +21 -0
- aegro-0.2.0/PKG-INFO +240 -0
- aegro-0.2.0/README.md +207 -0
- aegro-0.2.0/aegro/__init__.py +4 -0
- aegro-0.2.0/aegro/_version.py +34 -0
- aegro-0.2.0/aegro/api_client.py +128 -0
- aegro-0.2.0/aegro/cli/__init__.py +64 -0
- aegro-0.2.0/aegro/cli/_auth.py +110 -0
- aegro-0.2.0/aegro/cli/_client.py +72 -0
- aegro-0.2.0/aegro/cli/_config.py +101 -0
- aegro-0.2.0/aegro/cli/_errors.py +44 -0
- aegro-0.2.0/aegro/cli/_output.py +82 -0
- aegro-0.2.0/aegro/cli/activities.py +276 -0
- aegro-0.2.0/aegro/cli/assets.py +432 -0
- aegro-0.2.0/aegro/cli/auth.py +92 -0
- aegro-0.2.0/aegro/cli/bank_accounts.py +147 -0
- aegro-0.2.0/aegro/cli/catalogs.py +113 -0
- aegro-0.2.0/aegro/cli/companies.py +136 -0
- aegro-0.2.0/aegro/cli/crop_glebes.py +73 -0
- aegro-0.2.0/aegro/cli/crops.py +219 -0
- aegro-0.2.0/aegro/cli/elements.py +311 -0
- aegro-0.2.0/aegro/cli/farms.py +81 -0
- aegro-0.2.0/aegro/cli/financial.py +278 -0
- aegro-0.2.0/aegro/cli/financial_categories.py +180 -0
- aegro-0.2.0/aegro/cli/fuel_supplies.py +184 -0
- aegro-0.2.0/aegro/cli/glebes.py +68 -0
- aegro-0.2.0/aegro/cli/harvest_logs.py +131 -0
- aegro-0.2.0/aegro/cli/maintenances.py +184 -0
- aegro-0.2.0/aegro/cli/purchase_orders.py +153 -0
- aegro-0.2.0/aegro/cli/stock.py +351 -0
- aegro-0.2.0/aegro/cli/tags.py +119 -0
- aegro-0.2.0/aegro/cli/weather.py +116 -0
- aegro-0.2.0/aegro/config.py +34 -0
- aegro-0.2.0/aegro/errors.py +72 -0
- aegro-0.2.0/aegro/validation.py +17 -0
- aegro-0.2.0/pyproject.toml +71 -0
- aegro-0.2.0/tests/__init__.py +0 -0
- aegro-0.2.0/tests/test_api_client.py +100 -0
- aegro-0.2.0/tests/test_cli/__init__.py +0 -0
- aegro-0.2.0/tests/test_cli/conftest.py +40 -0
- aegro-0.2.0/tests/test_cli/test_activities.py +280 -0
- aegro-0.2.0/tests/test_cli/test_assets.py +62 -0
- aegro-0.2.0/tests/test_cli/test_auth.py +82 -0
- aegro-0.2.0/tests/test_cli/test_bank_accounts.py +171 -0
- aegro-0.2.0/tests/test_cli/test_catalogs.py +101 -0
- aegro-0.2.0/tests/test_cli/test_companies.py +178 -0
- aegro-0.2.0/tests/test_cli/test_crop_glebes.py +31 -0
- aegro-0.2.0/tests/test_cli/test_crops.py +128 -0
- aegro-0.2.0/tests/test_cli/test_elements.py +283 -0
- aegro-0.2.0/tests/test_cli/test_farms.py +50 -0
- aegro-0.2.0/tests/test_cli/test_financial.py +289 -0
- aegro-0.2.0/tests/test_cli/test_financial_categories.py +216 -0
- aegro-0.2.0/tests/test_cli/test_fuel_supplies.py +205 -0
- aegro-0.2.0/tests/test_cli/test_glebes.py +38 -0
- aegro-0.2.0/tests/test_cli/test_harvest_logs.py +170 -0
- aegro-0.2.0/tests/test_cli/test_infrastructure.py +312 -0
- aegro-0.2.0/tests/test_cli/test_maintenances.py +203 -0
- aegro-0.2.0/tests/test_cli/test_purchase_orders.py +204 -0
- aegro-0.2.0/tests/test_cli/test_stock.py +432 -0
- aegro-0.2.0/tests/test_cli/test_tags.py +130 -0
- aegro-0.2.0/tests/test_cli/test_weather.py +173 -0
- aegro-0.2.0/tests/test_config.py +54 -0
- aegro-0.2.0/tests/test_errors.py +60 -0
- aegro-0.2.0/tests/test_validation.py +28 -0
aegro-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Environment & secrets
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
.farms.json
|
|
6
|
+
|
|
7
|
+
# Python
|
|
8
|
+
__pycache__/
|
|
9
|
+
*.py[cod]
|
|
10
|
+
*$py.class
|
|
11
|
+
*.egg-info/
|
|
12
|
+
dist/
|
|
13
|
+
build/
|
|
14
|
+
aegro/_version.py
|
|
15
|
+
*.egg
|
|
16
|
+
|
|
17
|
+
# Testing
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
|
|
22
|
+
# IDE
|
|
23
|
+
.vscode/
|
|
24
|
+
.idea/
|
|
25
|
+
*.swp
|
|
26
|
+
*.swo
|
|
27
|
+
|
|
28
|
+
# OS
|
|
29
|
+
.DS_Store
|
|
30
|
+
Thumbs.db
|
|
31
|
+
|
|
32
|
+
# Virtual environments
|
|
33
|
+
.venv/
|
|
34
|
+
venv/
|
|
35
|
+
|
|
36
|
+
# Git worktrees
|
|
37
|
+
.worktrees/
|
aegro-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Aegro
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
aegro-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aegro
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: CLI for Aegro agricultural management API
|
|
5
|
+
Project-URL: Homepage, https://github.com/aegro/tool-aegro-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/aegro/tool-aegro-cli.git
|
|
7
|
+
Project-URL: Issues, https://github.com/aegro/tool-aegro-cli/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/aegro/tool-aegro-cli/releases
|
|
9
|
+
Author-email: Aegro Engineering <pedro@aegro.com.br>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agriculture,api-client,cli,farm-management,typer
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: httpx>=0.27.0
|
|
23
|
+
Requires-Dist: pydantic-settings>=2.0.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Requires-Dist: structlog>=24.0.0
|
|
26
|
+
Requires-Dist: typer[all]>=0.12.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-httpx>=0.34.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.8.0; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# Aegro CLI
|
|
35
|
+
|
|
36
|
+
Command-line interface for the [Aegro](https://aegro.com.br) agricultural management API.
|
|
37
|
+
|
|
38
|
+
[](https://www.python.org/downloads/)
|
|
39
|
+
[](https://pypi.org/project/aegro/)
|
|
40
|
+
[](https://opensource.org/licenses/MIT)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# pipx (recommended)
|
|
48
|
+
pipx install aegro
|
|
49
|
+
|
|
50
|
+
# uv
|
|
51
|
+
uv tool install aegro
|
|
52
|
+
|
|
53
|
+
# Homebrew (macOS)
|
|
54
|
+
brew tap aegro/tap
|
|
55
|
+
brew install aegro
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For development:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/aegro/tool-aegro-cli.git
|
|
62
|
+
cd tool-aegro-cli
|
|
63
|
+
uv sync
|
|
64
|
+
uv run aegro --help
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Quick Start
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# 1. Authenticate
|
|
73
|
+
aegro auth login --farm-name "Fazenda Sul" --api-key "aegro_abc123..."
|
|
74
|
+
|
|
75
|
+
# 2. Select a farm
|
|
76
|
+
aegro farms list
|
|
77
|
+
aegro farms select "Fazenda Sul"
|
|
78
|
+
|
|
79
|
+
# 3. Start working
|
|
80
|
+
aegro crops list --start-date 2025-01-01 --end-date 2025-12-31
|
|
81
|
+
aegro financial installments --status PENDING
|
|
82
|
+
aegro stock items --output table
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Commands
|
|
88
|
+
|
|
89
|
+
| Group | Commands | Domain |
|
|
90
|
+
|-------|----------|--------|
|
|
91
|
+
| `auth` | login, status, logout | Authentication |
|
|
92
|
+
| `farms` | list, select, info | Farm management |
|
|
93
|
+
| `crops` | get, list, prorate, harvest-discounts, prorates, glebes | Harvest management |
|
|
94
|
+
| `activities` | get, list, plan, realizations, get-plan, get-realization, create-plan | Activity planning |
|
|
95
|
+
| `financial` | bill, installment, installments, create/update/delete-installment, realize | Accounts payable/receivable |
|
|
96
|
+
| `stock` | item, location, items, locations, logs, log, transfer, entry, removal | Inventory |
|
|
97
|
+
| `elements` | get, list, create-defensive/fertilizer/item/seed/service, set-categories | Inputs/supplies |
|
|
98
|
+
| `assets` | get, list, create-machine/vehicle/garner/immobilized/pivot/weather-station | Equipment |
|
|
99
|
+
| `fuel-supplies` | get, list, create, update | Fuel management |
|
|
100
|
+
| `maintenances` | get, list, create, update | Maintenance records |
|
|
101
|
+
| `harvest-logs` | get, create | Harvest records |
|
|
102
|
+
| `bank-accounts` | get, list, create | Bank accounts |
|
|
103
|
+
| `companies` | get, list, create | Suppliers/vendors |
|
|
104
|
+
| `fin-categories` | get, list, create, subcategories | Chart of accounts |
|
|
105
|
+
| `catalogs` | list, element-keys, elements | Catalog lookups |
|
|
106
|
+
| `tags` | get, list, create | Tags/labels |
|
|
107
|
+
| `weather` | get, create | Weather data |
|
|
108
|
+
| `purchase-orders` | get, list, create | Purchase orders |
|
|
109
|
+
| `glebes` | get, list | Farm fields |
|
|
110
|
+
| `crop-glebes` | get, list | Crop fields |
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Output Formats
|
|
115
|
+
|
|
116
|
+
All commands support three output formats:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
aegro crops list --output json # JSON (default, for LLMs/scripts)
|
|
120
|
+
aegro crops list --output table # Rich table for humans
|
|
121
|
+
aegro crops list --output csv # CSV export
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Usage Examples
|
|
127
|
+
|
|
128
|
+
### Human workflow
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Morning overview
|
|
132
|
+
aegro farms select "Fazenda Norte"
|
|
133
|
+
aegro crops list --output table
|
|
134
|
+
aegro financial installments --status PENDING --due-date-start 2025-03-01 --output table
|
|
135
|
+
aegro stock items --output table
|
|
136
|
+
|
|
137
|
+
# Register a fuel supply
|
|
138
|
+
aegro fuel-supplies create --asset-key K --date 2025-03-13 --quantity 150 --unit L --cost 900
|
|
139
|
+
|
|
140
|
+
# Check harvest
|
|
141
|
+
aegro harvest-logs get <key>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### LLM/Agent workflow
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Agents use JSON output (default) for structured data
|
|
148
|
+
aegro crops list --start-date 2025-01-01 --end-date 2025-12-31
|
|
149
|
+
aegro activities list --crop-key <key>
|
|
150
|
+
aegro stock items
|
|
151
|
+
aegro financial installments --status PENDING
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## AI Skills
|
|
157
|
+
|
|
158
|
+
The project includes guided workflows for AI assistants in `.claude/skills/`:
|
|
159
|
+
|
|
160
|
+
### Domain skills (personas)
|
|
161
|
+
|
|
162
|
+
| Skill | Purpose |
|
|
163
|
+
|-------|---------|
|
|
164
|
+
| `aegro-agronomo` | Agronomic domain — crops, fields, activities, harvests, weather, inputs |
|
|
165
|
+
| `aegro-estoquista` | Stock domain — items, locations, movements, catalogs, elements |
|
|
166
|
+
| `aegro-financeiro` | Financial domain — bills, installments, categories, bank accounts, companies |
|
|
167
|
+
| `aegro-operacional` | Operational domain — farms, auth, tags, cross-domain orchestration |
|
|
168
|
+
| `aegro-patrimonial` | Asset domain — machines, vehicles, fuel supplies, maintenances |
|
|
169
|
+
|
|
170
|
+
### Workflow skills
|
|
171
|
+
|
|
172
|
+
| Skill | Purpose |
|
|
173
|
+
|-------|---------|
|
|
174
|
+
| `aegro-visao-geral` | Farm overview dashboard |
|
|
175
|
+
| `aegro-fechamento-safra` | Crop season closing checklist |
|
|
176
|
+
| `aegro-lancamento-financeiro` | Financial entry guide |
|
|
177
|
+
| `aegro-reconciliacao-estoque` | Stock reconciliation |
|
|
178
|
+
| `aegro-monitoramento-pragas` | Pest monitoring |
|
|
179
|
+
| `aegro-analise-rentabilidade` | Profitability analysis |
|
|
180
|
+
| `aegro-cadastro-patrimonio` | Asset registration |
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Configuration
|
|
185
|
+
|
|
186
|
+
### Authentication
|
|
187
|
+
|
|
188
|
+
Credential resolution priority:
|
|
189
|
+
|
|
190
|
+
1. `AEGRO_FARMS` env var (JSON) — for CI/CD and scripts
|
|
191
|
+
2. `AEGRO_FARMS_FILE` env var (path) — for Docker/K8s secrets
|
|
192
|
+
3. `~/.config/aegro/credentials.json` — interactive setup via `aegro auth login`
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Option 1: Environment variable
|
|
196
|
+
export AEGRO_FARMS='{"Fazenda Norte": "aegro_key1", "Fazenda Sul": "aegro_key2"}'
|
|
197
|
+
|
|
198
|
+
# Option 2: Interactive login (saves to ~/.config/aegro/credentials.json)
|
|
199
|
+
aegro auth login --farm-name "Fazenda Norte" --api-key "aegro_key1"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Environment Variables
|
|
203
|
+
|
|
204
|
+
| Variable | Default | Purpose |
|
|
205
|
+
|----------|---------|---------|
|
|
206
|
+
| `AEGRO_API_BASE_URL` | `https://app.aegro.com.br` | Aegro API base URL |
|
|
207
|
+
| `AEGRO_FARMS` | — | JSON map of farm name → API key |
|
|
208
|
+
| `AEGRO_FARMS_FILE` | — | Path to JSON credentials file |
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Development
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# Install dependencies
|
|
216
|
+
uv sync
|
|
217
|
+
|
|
218
|
+
# Run tests
|
|
219
|
+
uv run pytest -v
|
|
220
|
+
|
|
221
|
+
# Lint
|
|
222
|
+
uv run ruff check aegro/ tests/
|
|
223
|
+
|
|
224
|
+
# Format
|
|
225
|
+
uv run ruff format aegro/ tests/
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Links
|
|
231
|
+
|
|
232
|
+
- [Aegro](https://aegro.com.br) — Agricultural management platform
|
|
233
|
+
- [Typer](https://typer.tiangolo.com/) — CLI framework
|
|
234
|
+
- [PyPI: aegro](https://pypi.org/project/aegro/) — Package page
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
[MIT](LICENSE)
|
aegro-0.2.0/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Aegro CLI
|
|
2
|
+
|
|
3
|
+
Command-line interface for the [Aegro](https://aegro.com.br) agricultural management API.
|
|
4
|
+
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
[](https://pypi.org/project/aegro/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# pipx (recommended)
|
|
15
|
+
pipx install aegro
|
|
16
|
+
|
|
17
|
+
# uv
|
|
18
|
+
uv tool install aegro
|
|
19
|
+
|
|
20
|
+
# Homebrew (macOS)
|
|
21
|
+
brew tap aegro/tap
|
|
22
|
+
brew install aegro
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
For development:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/aegro/tool-aegro-cli.git
|
|
29
|
+
cd tool-aegro-cli
|
|
30
|
+
uv sync
|
|
31
|
+
uv run aegro --help
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# 1. Authenticate
|
|
40
|
+
aegro auth login --farm-name "Fazenda Sul" --api-key "aegro_abc123..."
|
|
41
|
+
|
|
42
|
+
# 2. Select a farm
|
|
43
|
+
aegro farms list
|
|
44
|
+
aegro farms select "Fazenda Sul"
|
|
45
|
+
|
|
46
|
+
# 3. Start working
|
|
47
|
+
aegro crops list --start-date 2025-01-01 --end-date 2025-12-31
|
|
48
|
+
aegro financial installments --status PENDING
|
|
49
|
+
aegro stock items --output table
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Commands
|
|
55
|
+
|
|
56
|
+
| Group | Commands | Domain |
|
|
57
|
+
|-------|----------|--------|
|
|
58
|
+
| `auth` | login, status, logout | Authentication |
|
|
59
|
+
| `farms` | list, select, info | Farm management |
|
|
60
|
+
| `crops` | get, list, prorate, harvest-discounts, prorates, glebes | Harvest management |
|
|
61
|
+
| `activities` | get, list, plan, realizations, get-plan, get-realization, create-plan | Activity planning |
|
|
62
|
+
| `financial` | bill, installment, installments, create/update/delete-installment, realize | Accounts payable/receivable |
|
|
63
|
+
| `stock` | item, location, items, locations, logs, log, transfer, entry, removal | Inventory |
|
|
64
|
+
| `elements` | get, list, create-defensive/fertilizer/item/seed/service, set-categories | Inputs/supplies |
|
|
65
|
+
| `assets` | get, list, create-machine/vehicle/garner/immobilized/pivot/weather-station | Equipment |
|
|
66
|
+
| `fuel-supplies` | get, list, create, update | Fuel management |
|
|
67
|
+
| `maintenances` | get, list, create, update | Maintenance records |
|
|
68
|
+
| `harvest-logs` | get, create | Harvest records |
|
|
69
|
+
| `bank-accounts` | get, list, create | Bank accounts |
|
|
70
|
+
| `companies` | get, list, create | Suppliers/vendors |
|
|
71
|
+
| `fin-categories` | get, list, create, subcategories | Chart of accounts |
|
|
72
|
+
| `catalogs` | list, element-keys, elements | Catalog lookups |
|
|
73
|
+
| `tags` | get, list, create | Tags/labels |
|
|
74
|
+
| `weather` | get, create | Weather data |
|
|
75
|
+
| `purchase-orders` | get, list, create | Purchase orders |
|
|
76
|
+
| `glebes` | get, list | Farm fields |
|
|
77
|
+
| `crop-glebes` | get, list | Crop fields |
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Output Formats
|
|
82
|
+
|
|
83
|
+
All commands support three output formats:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
aegro crops list --output json # JSON (default, for LLMs/scripts)
|
|
87
|
+
aegro crops list --output table # Rich table for humans
|
|
88
|
+
aegro crops list --output csv # CSV export
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Usage Examples
|
|
94
|
+
|
|
95
|
+
### Human workflow
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Morning overview
|
|
99
|
+
aegro farms select "Fazenda Norte"
|
|
100
|
+
aegro crops list --output table
|
|
101
|
+
aegro financial installments --status PENDING --due-date-start 2025-03-01 --output table
|
|
102
|
+
aegro stock items --output table
|
|
103
|
+
|
|
104
|
+
# Register a fuel supply
|
|
105
|
+
aegro fuel-supplies create --asset-key K --date 2025-03-13 --quantity 150 --unit L --cost 900
|
|
106
|
+
|
|
107
|
+
# Check harvest
|
|
108
|
+
aegro harvest-logs get <key>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### LLM/Agent workflow
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Agents use JSON output (default) for structured data
|
|
115
|
+
aegro crops list --start-date 2025-01-01 --end-date 2025-12-31
|
|
116
|
+
aegro activities list --crop-key <key>
|
|
117
|
+
aegro stock items
|
|
118
|
+
aegro financial installments --status PENDING
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## AI Skills
|
|
124
|
+
|
|
125
|
+
The project includes guided workflows for AI assistants in `.claude/skills/`:
|
|
126
|
+
|
|
127
|
+
### Domain skills (personas)
|
|
128
|
+
|
|
129
|
+
| Skill | Purpose |
|
|
130
|
+
|-------|---------|
|
|
131
|
+
| `aegro-agronomo` | Agronomic domain — crops, fields, activities, harvests, weather, inputs |
|
|
132
|
+
| `aegro-estoquista` | Stock domain — items, locations, movements, catalogs, elements |
|
|
133
|
+
| `aegro-financeiro` | Financial domain — bills, installments, categories, bank accounts, companies |
|
|
134
|
+
| `aegro-operacional` | Operational domain — farms, auth, tags, cross-domain orchestration |
|
|
135
|
+
| `aegro-patrimonial` | Asset domain — machines, vehicles, fuel supplies, maintenances |
|
|
136
|
+
|
|
137
|
+
### Workflow skills
|
|
138
|
+
|
|
139
|
+
| Skill | Purpose |
|
|
140
|
+
|-------|---------|
|
|
141
|
+
| `aegro-visao-geral` | Farm overview dashboard |
|
|
142
|
+
| `aegro-fechamento-safra` | Crop season closing checklist |
|
|
143
|
+
| `aegro-lancamento-financeiro` | Financial entry guide |
|
|
144
|
+
| `aegro-reconciliacao-estoque` | Stock reconciliation |
|
|
145
|
+
| `aegro-monitoramento-pragas` | Pest monitoring |
|
|
146
|
+
| `aegro-analise-rentabilidade` | Profitability analysis |
|
|
147
|
+
| `aegro-cadastro-patrimonio` | Asset registration |
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Configuration
|
|
152
|
+
|
|
153
|
+
### Authentication
|
|
154
|
+
|
|
155
|
+
Credential resolution priority:
|
|
156
|
+
|
|
157
|
+
1. `AEGRO_FARMS` env var (JSON) — for CI/CD and scripts
|
|
158
|
+
2. `AEGRO_FARMS_FILE` env var (path) — for Docker/K8s secrets
|
|
159
|
+
3. `~/.config/aegro/credentials.json` — interactive setup via `aegro auth login`
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# Option 1: Environment variable
|
|
163
|
+
export AEGRO_FARMS='{"Fazenda Norte": "aegro_key1", "Fazenda Sul": "aegro_key2"}'
|
|
164
|
+
|
|
165
|
+
# Option 2: Interactive login (saves to ~/.config/aegro/credentials.json)
|
|
166
|
+
aegro auth login --farm-name "Fazenda Norte" --api-key "aegro_key1"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Environment Variables
|
|
170
|
+
|
|
171
|
+
| Variable | Default | Purpose |
|
|
172
|
+
|----------|---------|---------|
|
|
173
|
+
| `AEGRO_API_BASE_URL` | `https://app.aegro.com.br` | Aegro API base URL |
|
|
174
|
+
| `AEGRO_FARMS` | — | JSON map of farm name → API key |
|
|
175
|
+
| `AEGRO_FARMS_FILE` | — | Path to JSON credentials file |
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Development
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# Install dependencies
|
|
183
|
+
uv sync
|
|
184
|
+
|
|
185
|
+
# Run tests
|
|
186
|
+
uv run pytest -v
|
|
187
|
+
|
|
188
|
+
# Lint
|
|
189
|
+
uv run ruff check aegro/ tests/
|
|
190
|
+
|
|
191
|
+
# Format
|
|
192
|
+
uv run ruff format aegro/ tests/
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Links
|
|
198
|
+
|
|
199
|
+
- [Aegro](https://aegro.com.br) — Agricultural management platform
|
|
200
|
+
- [Typer](https://typer.tiangolo.com/) — CLI framework
|
|
201
|
+
- [PyPI: aegro](https://pypi.org/project/aegro/) — Package page
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '0.2.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 2, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
|
|
5
|
+
import structlog
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
from aegro.errors import AegroAPIError, translate_api_error
|
|
9
|
+
|
|
10
|
+
logger = structlog.get_logger()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AegroClient:
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
base_url: str = "https://app.aegro.com.br",
|
|
17
|
+
timeout: float = 30.0,
|
|
18
|
+
max_retries: int = 3,
|
|
19
|
+
):
|
|
20
|
+
self._base_url = base_url.rstrip("/")
|
|
21
|
+
self._timeout = timeout
|
|
22
|
+
self._max_retries = max_retries
|
|
23
|
+
self._http: httpx.AsyncClient | None = None
|
|
24
|
+
|
|
25
|
+
def _get_http(self) -> httpx.AsyncClient:
|
|
26
|
+
if self._http is None or self._http.is_closed:
|
|
27
|
+
self._http = httpx.AsyncClient(timeout=self._timeout)
|
|
28
|
+
return self._http
|
|
29
|
+
|
|
30
|
+
async def close(self) -> None:
|
|
31
|
+
if self._http is not None and not self._http.is_closed:
|
|
32
|
+
await self._http.aclose()
|
|
33
|
+
self._http = None
|
|
34
|
+
|
|
35
|
+
def _headers(self, api_key: str) -> dict[str, str]:
|
|
36
|
+
return {
|
|
37
|
+
"Aegro-Public-API-Key": api_key,
|
|
38
|
+
"Accept": "application/json",
|
|
39
|
+
"Content-Type": "application/json",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async def _request(
|
|
43
|
+
self, method: str, path: str, api_key: str, json_body: dict | None = None
|
|
44
|
+
) -> dict | list | None:
|
|
45
|
+
url = f"{self._base_url}{path}"
|
|
46
|
+
attempt = 0
|
|
47
|
+
last_response = None
|
|
48
|
+
http = self._get_http()
|
|
49
|
+
|
|
50
|
+
while attempt <= self._max_retries:
|
|
51
|
+
try:
|
|
52
|
+
response = await http.request(
|
|
53
|
+
method, url, headers=self._headers(api_key), json=json_body
|
|
54
|
+
)
|
|
55
|
+
last_response = response
|
|
56
|
+
if response.status_code == 204:
|
|
57
|
+
return None
|
|
58
|
+
if response.status_code in (200, 201):
|
|
59
|
+
return response.json()
|
|
60
|
+
if response.status_code >= 500 and attempt < self._max_retries:
|
|
61
|
+
attempt += 1
|
|
62
|
+
logger.warning(
|
|
63
|
+
"aegro_api_retry", path=path, status=response.status_code, attempt=attempt
|
|
64
|
+
)
|
|
65
|
+
await asyncio.sleep(2**attempt)
|
|
66
|
+
continue
|
|
67
|
+
body = {}
|
|
68
|
+
try:
|
|
69
|
+
body = response.json()
|
|
70
|
+
except Exception:
|
|
71
|
+
pass
|
|
72
|
+
raise translate_api_error(response.status_code, body)
|
|
73
|
+
except httpx.TimeoutException:
|
|
74
|
+
if attempt < self._max_retries:
|
|
75
|
+
attempt += 1
|
|
76
|
+
logger.warning("aegro_api_timeout", path=path, attempt=attempt)
|
|
77
|
+
await asyncio.sleep(2**attempt)
|
|
78
|
+
continue
|
|
79
|
+
raise AegroAPIError(
|
|
80
|
+
504, "Timeout ao conectar com o servico Aegro. Tente novamente.", retryable=True
|
|
81
|
+
)
|
|
82
|
+
except AegroAPIError:
|
|
83
|
+
raise
|
|
84
|
+
except httpx.HTTPError as exc:
|
|
85
|
+
raise AegroAPIError(
|
|
86
|
+
502,
|
|
87
|
+
f"Erro de conexao com o servico Aegro: {type(exc).__name__}",
|
|
88
|
+
retryable=True,
|
|
89
|
+
) from exc
|
|
90
|
+
|
|
91
|
+
if last_response is not None:
|
|
92
|
+
body = {}
|
|
93
|
+
try:
|
|
94
|
+
body = last_response.json()
|
|
95
|
+
except Exception:
|
|
96
|
+
pass
|
|
97
|
+
raise translate_api_error(last_response.status_code, body)
|
|
98
|
+
raise AegroAPIError(502, "Erro inesperado de conexao.", retryable=True)
|
|
99
|
+
|
|
100
|
+
async def get(self, path: str, *, api_key: str) -> dict | list | None:
|
|
101
|
+
return await self._request("GET", path, api_key)
|
|
102
|
+
|
|
103
|
+
async def post(
|
|
104
|
+
self, path: str, *, api_key: str, json_body: dict | None = None
|
|
105
|
+
) -> dict | list | None:
|
|
106
|
+
return await self._request("POST", path, api_key, json_body)
|
|
107
|
+
|
|
108
|
+
async def put(
|
|
109
|
+
self, path: str, *, api_key: str, json_body: dict | None = None
|
|
110
|
+
) -> dict | list | None:
|
|
111
|
+
return await self._request("PUT", path, api_key, json_body)
|
|
112
|
+
|
|
113
|
+
async def delete(self, path: str, *, api_key: str) -> dict | list | None:
|
|
114
|
+
return await self._request("DELETE", path, api_key)
|
|
115
|
+
|
|
116
|
+
async def get_user_identity(self, api_key: str) -> str | None:
|
|
117
|
+
"""Return the email address associated with the given API key.
|
|
118
|
+
|
|
119
|
+
Calls ``/pub/v1/users/me`` and extracts the ``email`` field.
|
|
120
|
+
Returns ``None`` when the endpoint does not return a usable email.
|
|
121
|
+
"""
|
|
122
|
+
try:
|
|
123
|
+
data = await self.get("/pub/v1/users/me", api_key=api_key)
|
|
124
|
+
if isinstance(data, dict):
|
|
125
|
+
return data.get("email")
|
|
126
|
+
except (AegroAPIError, httpx.HTTPError):
|
|
127
|
+
logger.warning("identity_lookup_failed", exc_info=True)
|
|
128
|
+
return None
|