inputs-manager-api
Inputs Manager API Documentation
Overview
This document describes the Inputs Manager API endpoints that allow workspace administrators to search, filter, and manage inputs (fertilizers, phytosanitary products, and seeds) within their workspace.
Recent Changes
Bug Fixes (2026-04-20)
POST /api/workspaces/configs/inputs/manager/sheets
Fixed Issues:
- Component/Concentration Order: Fixed Excel template headers where concentration appeared before component name. Now shows "Componente 1" followed by "Concentración componente 1" for better user experience
- Seed Name Validation: Fixed "Missing seed name" error where the validation was looking for incorrect field key. Now properly maps "name" column from Excel to seed validation
Technical Details:
- Reordered headers in both fitosanitario and fertilizantes templates to show component name before concentration
- Updated header mapping to correctly handle "Nombre" column from Excel templates for seed processing
- Maintained backward compatibility with existing field mappings
Impact:
- Excel templates now have logical component/concentration ordering
- Seed bulk upload now correctly processes "Nombre" column from Excel files
- Reduced user confusion when filling out Excel templates
POST /api/insumos/new_inputs
Fixed Issues:
- NoneType Error: Fixed
'NoneType' object has no attribute 'strip'error caused by incorrect field mapping in the API layer - UUID Constraint Violation: Fixed
null value in column "uuid" violates not-null constrainterror by ensuring UUID is properly passed to the database layer - Presentation Field Not Saved: Fixed issue where
presentationfield from request was not being saved to thepresentacioncolumn in the database
Technical Details:
- Corrected field mapping from API schema to repository constructor parameters
- Added missing
uuidfield to the data mapping - Added
presentationfield to constructor and INSERT query to properly save topresentacioncolumn - Simplified components handling to pass data directly to the repository layer
Impact:
- The endpoint now properly creates new agricultural inputs without validation errors
- All required fields (name, uuid, type_id) are correctly processed and stored
- Components are properly associated with the created input
POST /api/workspaces/configs/inputs/manager
Fixed Issues:
- Array Filters: Fixed filters to accept arrays for brand, company, components, presentation, and subtype fields to allow filtering by multiple values
- Components Field: Renamed components_array to components in response for consistency
- Components Filtering: Fixed components array filtering to search in both str_composicion and components table
Technical Details:
- Updated INPUTS_MANAGER_SCHEMA to accept both string and array types for brand, company, components, presentation, and subtype filters
- Modified InputsManagerRepository.get_inputs() to handle array filters with OR conditions
- Fixed components filtering to search in both insumos.str_composicion and componentes table via JOIN
- Renamed components_array field to components in response transformation
Impact:
- Filters now support multiple brands:
{"brand": ["Brand1", "Brand2"]} - Filters now support multiple companies:
{"company": ["Company1", "Company2"]} - Filters now support multiple components:
{"components": ["Component1", "Component2"]} - Filters now support multiple presentations:
{"presentation": ["Presentation1", "Presentation2"]} - Filters now support multiple subtypes:
{"subtype": ["Subtype1", "Subtype2"]} - Components filtering now works correctly with arrays
- Response field components_array is now consistently named components
POST /api/workspaces/configs/inputs/manager/filters
Fixed Issues:
- Components in All Filters: Fixed issue where all filter types (brand, company, presentation, etc.) were incorrectly including components from the componentes table in their results. Now only the components filter returns components data.
Technical Details:
- Modified get_filters query to only include UNION with componentes table when filter_type is specifically 'components'
- Other filter types (brand, company, presentation) now return only their respective data without components
- Unified components key throughout the flow - only 'components' is accepted, 'componentes' support removed
Impact:
- Brand filter now returns only brands, not brands + components
- Company filter now returns only companies, not companies + components
- Presentation filter now returns only presentations, not presentations + components
- Components filter continues to work correctly, returning both str_composicion and componentes table data
Internal User Management APIs
GET /api/internal/userlist
Added Field:
- input_master (boolean): Returns
trueif user has permission 153 inusuarios.permisos_agregararray
Response Example:
[
{
"id_escritorio": 1,
"dashboard_user": true,
"id_estado": 1,
"apellido": "auravant",
"admin": true,
"escritorio": "Aura2",
"id": 50891,
"internal": true,
"can_have_dashboard": true,
"suspended": false,
"nombre": "desarrollador",
"email": "devhelp@auravant.com",
"sudo_authorization": false,
"input_master": true
}
]
PATCH /api/internal/workspace_admin/user/{user_id}
Added Field:
- input_master (boolean):
true: Adds permission 153 tousuarios.permisos_agregararrayfalse: Removes permission 153 fromusuarios.permisos_agregararray
Request Example:
{
"input_master": true
}
Response: Returns updated user object including the input_master field showing current status.
Enhanced Input Management
POST /api/workspaces/configs/inputs/manager now supports all fields from GET endpoint:
- valid (boolean) - NEW
- type (integer) - NEW
Input Types API Enhancement
GET /api/insumos/types now includes:
- category_id (integer): Category identifier for input type classification
Response Example:
[
{
"uuid": "a8be547e-d5bc-11eb-8340-dbacd56dac49",
"tipo": "bioestimulante",
"id": 8,
"category_id": 2
}
]
Event Logging
All CRUD operations on inputs and seeds are automatically logged using the event system:
Logged Events
- input_creation: When a new input is created
- input_update: When an input is updated
- input_deletion: When an input is deleted
- seed_creation: When a new seed variety is created
- seed_update: When a seed variety is updated
- seed_deletion: When a seed variety is deleted
Event Data
Each event logs:
- user_id: ID of the user performing the action
- workspace_id: ID of the workspace
- item_uuid: UUID of the affected input/seed
- action_details: Specific details about the operation
Base URL
All endpoints are prefixed with: /api/workspaces/configs
Authentication
All endpoints require:
- Valid authentication token
- Admin privileges for the workspace
Error Codes
| Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad Request - Invalid input data or validation errors |
| 401 | Unauthorized - Invalid or missing authentication token |
| 403 | Forbidden - User lacks admin privileges or ownership |
| 500 | Internal Server Error |
Error Response Format
{
"info": {
"field_name": ["Error message"]
}
}
1. Inputs Manager (Fertilizers, Phytosanitary & Seeds)
Search, filter, and manage fertilizers, phytosanitary products, and seeds.
Endpoint
POST /api/workspaces/configs/inputs/manager
Request Body
Search/Filter Operations
{
"input": "fertilizantes" | "fitosanitario",
"search": "string (optional)",
"subtype": "string (optional)",
"brand": "string (optional)",
"company": "string (optional)",
"components": "string (optional)",
"presentation": "string (optional)",
"page": 1,
"page_size": 100,
"country": "string (optional)"
}
Seeds Management Operations
{
"action": "create",
"input": "seeds",
"crop": 123,
"variety": "Corn Hybrid DKC64-87"
}
{
"action": "update",
"input": "seeds",
"uuid": "456e7890-e89b-12d3-a456-426614174001",
"crop": 123,
"variety": "Updated Corn Hybrid"
}
{
"action": "delete",
"input": "seeds",
"uuid": "456e7890-e89b-12d3-a456-426614174001"
}
Inputs Management Operations (Fertilizers/Phytosanitary)
Create Input:
{
"action": "create",
"input": "fertilizantes",
"name": "Premium Nitrogen Fertilizer",
"type_id": 1,
"company": "Acme Agro",
"brand": "UreaMax",
"presentation": "25kg bag",
"density": 1.2,
"toxicological_class": "III",
"unit_default": "kg/ha",
"expiration_date": "2025-12-31T00:00:00Z",
"registration_code": "REG-12345",
"components": [
{
"uuid": "123e4567-e89b-12d3-a456-426614174002",
"concentration": 46.0
}
]
}
Update Input:
{
"action": "update",
"input": "fertilizantes",
"uuid": "123e4567-e89b-12d3-a456-426614174000",
"name": "Updated Fertilizer Name",
"brand": "Updated Brand",
"company": "Updated Company",
"presentation": "Updated Presentation",
"density": 1.5,
"toxicological_class": "II",
"unit_default": "L/ha",
"expiration_date": "2026-06-30T00:00:00Z",
"registration_code": "REG-54321",
"components": [
{
"uuid": "123e4567-e89b-12d3-a456-426614174003",
"concentration": 50.0
}
]
}
Delete Input:
{
"action": "delete",
"input": "fertilizantes",
"uuid": "123e4567-e89b-12d3-a456-426614174000"
}
Field Descriptions
Search/Filter Fields:
| Field | Type | Required | Description |
|---|---|---|---|
input | string | Yes | Type of input: "fertilizantes", "fitosanitario" |
search | string | No | Search term for product name (case-insensitive, partial match) |
subtype | string/array | No | Filter by subtype (case-insensitive, partial match). Can be a single string or array of strings |
brand | string/array | No | Filter by brand name(s) (case-insensitive, partial match). Can be a single string or array of strings |
company | string/array | No | Filter by company name(s) (case-insensitive, partial match). Can be a single string or array of strings |
components | string/array | No | Filter by components/composition (case-insensitive, partial match). Can be a single string or array of strings |
presentation | string/array | No | Filter by presentation (case-insensitive, partial match). Can be a single string or array of strings |
page | integer | No | Page number (default: 1, or use next_page token from previous response) |
page_size | integer | No | Number of items per page (default: 100) |
country | string | No | Country filter |
Management Fields:
| Field | Type | Required | Description |
|---|---|---|---|
action | string | Yes* | Action to perform: "create", "update", "delete" |
input | string | Yes | Type of input: "seeds", "fertilizantes", "fitosanitario" |
uuid | string | Yes** | UUID of item to update/delete |
id | string/integer | Yes** | Alternative ID for seeds update/delete (can use instead of uuid) |
crop | integer | Yes*** | Crop ID (for seeds operations) |
variety | string | Yes*** | Variety name (for seeds operations) |
name | string | Yes**** | Input name (for fertilizer/phytosanitary create, optional for update) |
type_id | integer | Yes**** | Input type ID (for fertilizer/phytosanitary create, optional for update) |
company | string | No | Company name (for fertilizer/phytosanitary operations) |
brand | string | No | Brand name (for fertilizer/phytosanitary operations) |
presentation | string | No | Presentation format (for fertilizer/phytosanitary operations) |
density | float | No | Density value (for fertilizer/phytosanitary operations) |
toxicological_class | string | No | Toxicological classification (for fertilizer/phytosanitary operations) |
unit_default | string | No | Default unit (for fertilizer/phytosanitary operations, default: "kg/ha") |
expiration_date | datetime | No | Expiration date (for fertilizer/phytosanitary operations) |
registration_code | string | No | Registration code (for fertilizer/phytosanitary operations) |
components | array | No | Components with uuid and concentration (for fertilizer/phytosanitary operations) |
*Required for management operations
**Required for update/delete operations (can use either uuid or id for seeds)
***Required for seeds create/update operations
****Required for fertilizer/phytosanitary create operations
Response
Search/Filter Response
{
"data": [
{
"uuid": "string",
"nombre": "string",
"marca": "string",
"empresa": "string",
"presentacion": "string",
"str_composicion": "string",
"subtipo": "string",
"components": "string"
}
],
"next_page": "base64_encoded_token_or_null",
"estimated pages": 5
}
Management Response
{
"data": {
"msg": "Seed created successfully" | "Seed updated successfully" | "Seed deleted successfully" | "Input created successfully" | "Input updated successfully" | "Input deleted successfully",
"uuid": "string",
"crop": "string (seeds only)",
"name": "string"
}
}
Response Fields
Search/Filter Response:
| Field | Type | Description |
|---|---|---|
data | array | Array of input products |
uuid | string | Unique identifier for the input |
nombre | string | Input name |
marca | string | Brand name |
empresa | string | Company name |
presentacion | string | Presentation format |
str_composicion | string | Original composition string |
subtipo | string | Input subtype |
components | string | Components (fallback from str_composicion or joined from components table) |
next_page | string/null | Base64 encoded token for next page, null if last page |
estimated pages | integer | Total estimated pages (only on first page) |
Management Response:
| Field | Type | Description |
|---|---|---|
data.msg | string | Success message |
data.uuid | string | UUID of the created/updated/deleted item |
data.crop | string | Crop name (seeds operations only) |
data.name | string | Item name |
Example Requests and Responses
Search Fertilizers
Request:
{
"input": "fertilizantes",
"search": "nitrogen",
"brand": ["Yara", "Nutrien"],
"company": ["Yara International", "Nutrien Ltd"],
"components": ["N", "P"],
"page": 1,
"page_size": 10
}
Response:
{
"data": [
{
"uuid": "123e4567-e89b-12d3-a456-426614174000",
"nombre": "Nitrogen Fertilizer Premium",
"marca": "Yara",
"empresa": "Yara International",
"presentacion": "50kg bag",
"str_composicion": "N: 46%",
"subtipo": "fertilizante",
"components": "N: 46%"
}
],
"next_page": "eyJwYWdlIjoyLCJsYXN0X2lkIjoxMjN9",
"estimated pages": 3
}
Create Seed
Request:
{
"action": "create",
"input": "seeds",
"crop": 10,
"variety": "Corn Hybrid DKC64-87"
}
Response:
{
"data": {
"msg": "Seed created successfully",
"uuid": "456e7890-e89b-12d3-a456-426614174001",
"crop": "Maize",
"name": "Corn Hybrid DKC64-87"
}
}
Create Input
Request:
{
"action": "create",
"input": "fertilizantes",
"name": "Premium Nitrogen Fertilizer",
"type_id": 1,
"company": "Acme Agro",
"brand": "UreaMax",
"presentation": "25kg bag",
"density": 1.2,
"toxicological_class": "III",
"unit_default": "kg/ha",
"expiration_date": "2025-12-31T00:00:00Z",
"registration_code": "REG-12345",
"components": [
{
"uuid": "123e4567-e89b-12d3-a456-426614174002",
"concentration": 46.0
}
]
}
Response:
{
"data": {
"msg": "Input created successfully",
"uuid": "123e4567-e89b-12d3-a456-426614174000",
"name": "Premium Nitrogen Fertilizer"
}
}
Update Input
Request:
{
"action": "update",
"input": "fertilizantes",
"uuid": "123e4567-e89b-12d3-a456-426614174000",
"name": "Updated Nitrogen Fertilizer",
"brand": "Updated Brand",
"company": "Updated Company",
"presentation": "Updated Presentation",
"density": 1.5,
"toxicological_class": "II",
"unit_default": "L/ha",
"expiration_date": "2026-06-30T00:00:00Z",
"registration_code": "REG-54321",
"components": [
{
"uuid": "123e4567-e89b-12d3-a456-426614174003",
"concentration": 50.0
}
]
}
Response:
{
"data": {
"msg": "Input updated successfully",
"uuid": "123e4567-e89b-12d3-a456-426614174000",
"name": "Updated Nitrogen Fertilizer"
}
}
Delete Seed
Request:
{
"action": "delete",
"input": "seeds",
"uuid": "456e7890-e89b-12d3-a456-426614174001"
}
Response:
{
"data": {
"msg": "Seed deleted successfully",
"uuid": "456e7890-e89b-12d3-a456-426614174001"
}
}
Ownership and Permissions
- Seeds: Only the user who created a seed variety can update or delete it
- Inputs (Fertilizers/Phytosanitary):
- Owner permissions: The user who created an input can update or delete it completely
- Admin permissions: Workspace admins can update or remove inputs from their workspace
- Create operations: New items are automatically linked to the current workspace
- Delete operations:
- Owner delete: Soft deletes the entire input (sets
insumos.fecha_fin) - Admin delete: Removes input from workspace only (sets
escritorios_insumos.fecha_fin)
- Owner delete: Soft deletes the entire input (sets
- Update operations: Both owners and workspace admins can update input details
Error Responses
Ownership Error (Not Owner and Not in Workspace)
{
"info": "Failed to update input or not owner"
}
Input Not Found
{
"info": "Failed to delete input or not owner"
}
Missing Required Fields
{
"info": "crop and variety are required for create"
}
Invalid Action
{
"info": "Create action for inputs already exists in other endpoint"
}
2. Seeds Manager
Search and filter seed varieties available in the workspace.
Endpoint
POST /api/workspaces/configs/manager/inputs/seeds
Request Body
{
"variety": "string (optional)",
"crop": "integer or array of integers (optional)",
"name": "string (optional)",
"page": 1,
"page_size": 100
}
Field Descriptions
| Field | Type | Required | Description |
|---|---|---|---|
variety | string/array | No | Filter by variety name(s) (case-insensitive, partial match). Can be a single string or array of strings |
crop | integer/array | No | Filter by crop ID(s). Can be a single integer or array of integers |
name | string | No | Search by seed name (case-insensitive, partial match) |
page | integer | Yes | Page number (use 1 for first page) |
page_size | integer | Yes | Number of items per page |
Response
{
"pagination": {
"last_page": true,
"total_pages": 1
},
"data": [
{
"uuid": "string",
"crop": "string",
"name": "string"
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
pagination.last_page | boolean | True if this is the last page |
pagination.total_pages | integer | Total number of pages |
data | array | Array of seed varieties |
uuid | string | Unique identifier for the seed |
crop | string | Crop name |
name | string | Seed variety name |
Example Request
{
"variety": "corn",
"crop": [10, 15],
"name": "hybrid",
"page": 1,
"page_size": 20
}
Example Response
{
"pagination": {
"last_page": false,
"total_pages": 3
},
"data": [
{
"uuid": "456e7890-e89b-12d3-a456-426614174001",
"crop": "Maize",
"brand": "Pioneer",
"company": "Corteva",
"name": "Corn Hybrid DKC64-87"
}
]
}
3. Filters Manager
Get available filter options for a specific filter type within an input category.
Endpoint
POST /api/workspaces/configs/inputs/manager/filters
Request Body
{
"input": "fertilizantes" | "fitosanitario" | "semillas",
"filter": "subtype" | "brand" | "company" | "components" | "presentation" | "variety" | "crop"
}
Field Descriptions
| Field | Type | Required | Description |
|---|---|---|---|
input | string | Yes | Type of input: "fertilizantes", "fitosanitario", or "semillas" |
filter | string | Yes | Specific filter type to retrieve options for |
Filter Type Validation
For Seeds ("input": "semillas"):
- variety: Get all available seed varieties in the workspace
- crop: Get all crop types (uses agrupador or nombre from cultivos table)
- company: Returns empty array (not applicable for seeds)
- brand: Returns empty array (not applicable for seeds)
For Fertilizers/Phytosanitary ("input": "fertilizantes" or "fitosanitario"):
- subtype: Get input subtypes from tipos_insumos table
- brand: Get all available brands (marca column)
- company: Get all available companies (empresa column)
- components: Get all available components/compositions (str_composicion column)
- presentation: Get all available presentations (presentacion column)
Response
{
"data": [
{
"uuid": "string",
"filter": "string",
"description": "string"
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
data | array | Array of available filter options for the specified filter type |
uuid | string | Unique identifier for the filter option |
filter | string | Filter value |
description | string | Human-readable description (same as filter value) |
Example Requests and Responses
Get Fertilizer Brands
Request:
{
"input": "fertilizantes",
"filter": "brand"
}
Response:
{
"data": [
{
"uuid": "789e0123-e89b-12d3-a456-426614174002",
"filter": "Yara",
"description": "Yara"
},
{
"uuid": "abc1234-e89b-12d3-a456-426614174003",
"filter": "Nutrien",
"description": "Nutrien"
}
]
}
Get Fertilizer Subtypes
Request:
{
"input": "fertilizantes",
"filter": "subtype"
}
Response:
{
"data": [
{
"uuid": "1",
"filter": "Nitrogen Fertilizer",
"description": "Nitrogen Fertilizer"
},
{
"uuid": "2",
"filter": "Phosphorus Fertilizer",
"description": "Phosphorus Fertilizer"
}
]
}
Get Seed Varieties
Request:
{
"input": "semillas",
"filter": "variety"
}
Response:
{
"data": [
{
"uuid": "456",
"filter": "Corn Hybrid DKC64-87",
"description": "Corn Hybrid DKC64-87"
},
{
"uuid": "789",
"filter": "Soybean Variety RR2",
"description": "Soybean Variety RR2"
}
]
}
Get Crop Types for Seeds
Request:
{
"input": "semillas",
"filter": "crop"
}
Response:
{
"data": [
{
"uuid": "10",
"filter": "Maize",
"description": "Maize"
},
{
"uuid": "20",
"filter": "Soybean",
"description": "Soybean"
}
]
}
Error Responses
Invalid Filter Type for Input
{
"info": "Invalid filter 'subtype' for input type 'semillas'. Valid filters: variety, crop, company, brand"
}
Pagination
First Page Request
For the first page, use "page": 1 or omit the page parameter.
Subsequent Pages
Use the next_page token from the previous response:
- For inputs manager: Use the base64 token in the
pagefield - For seeds manager: Increment the page number
Example Pagination Flow
- First Request:
{
"input": "fertilizantes",
"page": 1,
"page_size": 10
}
- First Response:
{
"data": [...],
"next_page": "eyJwYWdlIjoyLCJsYXN0X2lkIjoxMjN9"
}
- Second Request:
{
"input": "fertilizantes",
"page": "eyJwYWdlIjoyLCJsYXN0X2lkIjoxMjN9",
"page_size": 10
}
Validation Rules
Common Validations
- All endpoints require admin authentication
- Request body must be valid JSON
- Required fields must be present and non-empty
Input Type Validation
inputfield must be one of: "fertilizantes", "fitosanitario", "semillas"- Invalid input types will return 400 error
Filter Type Validation (Filters Endpoint)
filterfield must be valid for the specifiedinputtype- Invalid combinations will return 400 error with specific message
- Seeds: only
variety,crop,company,brandallowed - Fertilizers/Phytosanitary: only
subtype,brand,company,components,presentationallowed
Pagination Validation
pagemust be positive integer or valid base64 tokenpage_sizemust be positive integer (max recommended: 1000)
Search/Filter Validation
- All search and filter fields are optional
- Empty strings are treated as no filter
- Partial matching is case-insensitive
4. Inputs Manager Sheets Generator
Generate Excel template sheets for importing inputs data or handle bulk upload of inputs. The templates are automatically translated based on the user's locale using translation files from /translations/dictionaries/.
Endpoint
POST /api/workspaces/configs/inputs/manager/sheets
Request Body
{
"input": "fitosanitario" | "fertilizantes" | "semillas",
"action": "download" | "upload"
}
Field Descriptions
| Field | Type | Required | Description |
|---|---|---|---|
input | string | Yes | Type of input sheet to generate: "fitosanitario", "fertilizantes", or "semillas" |
action | string | Yes | Action to perform: "download" for template generation, "upload" for bulk processing |
Download Action
Returns an Excel file (.xlsx) with the appropriate template sheet in the user's configured language. The system automatically loads translations from .po files in /translations/dictionaries/ (reading only the first 1000 lines per file for performance).
Supported Languages
es_ES- Spanish (Spain) - Defaultpt_BR- Portuguese (Brazil)en_US- English (United States)es_AR- Spanish (Argentina)fr_FR- French (France)
Translation System
The system dynamically translates headers using:
- Translation files from
/translations/dictionaries/dictionary_{locale}.po - All lines of each
.pofile are processed for complete translation coverage - Dynamic path resolution for production environments
- Fallback to Spanish (es_ES) if translation not found
- Context-aware translations using
msgctxtwhen available
Sheet Templates
Fitosanitarios Sheet:
- Nombre de insumo / Input name
- Subtipo de fitosanitario* (coadyuvante, fungicida, herbicida, inhibidor, pesticida, protector, curasemilla, agua)
- Marca / Brand
- Empresa / Company
- Presentación / Presentation
- Densidad / Density
- Clase toxicológica / Toxicological class
- Unidades / Units
- Fecha caducidad / Expiration date
- Código de registro / Registration code
- Concentración componente 1 / Component 1 concentration
- Componente 1 / Component 1
- Concentración componente 2 / Component 2 concentration
- Componente 2 / Component 2
- Concentración componente N / Component N concentration
- Componente N / Component N
Fertilizantes Sheet:
- Nombre de insumo / Input name
- Subtipo de fertilizante* (bioestimulante, fertilizante, fertilizante organico, enmienda, fitoregulador, feromona, organico, inoculante)
- Empresa / Company
- N (Nitrogen)
- P (Phosphorus)
- K (Potassium)
- Presentación / Presentation
- Densidad / Density
- Unidades default / Default units
- Código de registro / Registration code
- Concentración componente 1 / Component 1 concentration
- Componente 1 / Component 1
- Concentración componente 2 / Component 2 concentration
- Componente 2 / Component 2
- Concentración componente N / Component N concentration
- Componente N / Component N
Semillas Sheet:
- Nombre / Name
- Cultivo / Crop
- País / Country
Upload Action
Handles bulk upload of inputs from CSV or XLSX files. Processes each row with sanitization to prevent SQL injection and returns detailed results of created and failed items.
File Format Requirements
Supported formats: .xlsx, .xls, .csv
Column Headers (case-insensitive):
For Semillas:
- Nombre/Name: Seed variety name (required)
- Cultivo/Crop: Crop name - will be matched against cultivos.nombre or cultivos.agrupador (required)
- País/Country: Country (optional)
For Fertilizantes:
- Nombre de insumo/Input name: Input name (required)
- Subtipo de fertilizante/Subtype: Must match tipos_insumos.tipo (required)
- Empresa/Company: Company name (optional)
- Marca/Brand: Brand name (optional)
- Presentación/Presentation: Presentation format (optional)
- Densidad/Density: Density value (optional)
- Unidades/Units: Default units (optional, defaults to kg/ha)
- Código de registro/Registration code: Registration code (optional)
- Componente 1-N/Component 1-N: Components (optional)
For Fitosanitarios:
- Nombre de insumo/Input name: Input name (required)
- Subtipo de fitosanitario/Subtype: Must match tipos_insumos.tipo (required)
- Marca/Brand: Brand name (optional)
- Empresa/Company: Company name (optional)
- Presentación/Presentation: Presentation format (optional)
- Densidad/Density: Density value (optional)
- Clase toxicológica/Toxicological class: Toxicological classification (optional)
- Unidades/Units: Default units (optional)
- Código de registro/Registration code: Registration code (optional)
- Componente 1-N/Component 1-N: Components (optional)
Security Features
- Input Sanitization: All column values are sanitized using regex to prevent SQL injection
- Length Limits: Values are truncated to 255 characters maximum
- Character Filtering: Only alphanumeric, spaces, hyphens, underscores, dots, commas, parentheses, percentage signs, and accented characters are allowed
- Explicit Validation: Invalid subtypes cause explicit failures rather than silent data corruption
- Type Safety: Subtype validation ensures only valid tipos_insumos.tipo values are accepted
- Detailed Error Messages: Failed validations include lists of valid options for user guidance
Crop Name Matching with Translation Support
For seeds, the "Cultivo/Crop" column supports multi-language input using the same translation system as the Excel download functionality:
Translation Flow:
- Direct Match: First attempts direct match with input crop name
- Translation Lookup: If user locale ≠ Spanish, translates using
.pofiles from/translations/dictionaries/ - Common Translations: Falls back to built-in common crop translations
- Database Normalization: Both input and database values are normalized for comparison
Supported Translation Sources:
.po Files: Uses same translation files as Excel download (dictionary_{locale}.po)- Reverse Translation: Translates from user language back to Spanish for DB matching
- Common Crops: Built-in translations for major crops (corn→maíz, soybean→soja, etc.)
- Multiple Languages: English, Portuguese, French → Spanish
Matching Process:
- Case-insensitive comparison: All text converted to lowercase
- Accent-insensitive comparison: Accents removed using SQL TRANSLATE function
- Trimmed whitespace: Leading/trailing spaces removed
- Dual field matching: Matches against both
cultivos.nombreand crop grouper name viaid_cultivo_agrupador - Smart prioritization: Exact matches prioritized over partial matches
Translation Examples:
- English: "corn" → "maíz" → Matches DB
- Portuguese: "milho" → "maíz" → Matches DB
- French: "maïs" → "maíz" → Matches DB
- User input: "Corn" → Normalized: "corn" → Translated: "maíz" → DB match
Bulk Processing
- High Performance: Uses
pandas.itertuples()instead ofiterrows()for significantly faster processing - Column Name Normalization: Automatically handles spaces and accents in column headers
- Single Transaction Per Item: Each valid row is processed in its own database transaction
- Workspace Integration: Each item is automatically linked to the current workspace
- Fault Tolerance: Failed items don't prevent successful items from being created
- Detailed Error Reporting: Specific error messages are provided for failed items
- Audit Logging: Events are logged for audit purposes with
bulk_upload: trueflag - Memory Efficient: Processes rows sequentially without loading entire dataset into memory
Example Requests
Download Template
{
"input": "fertilizantes",
"action": "download"
}
Upload File
{
"input": "fitosanitario",
"action": "upload"
}
Note: Upload requests must include a file in the request using multipart/form-data with the file field named "file".
Example Response (Download)
Returns an Excel file with filename {input_type}_template.xlsx containing a sheet with the appropriate column headers in the user's language.
Example Response (Upload)
{
"data": {
"created": [
{
"name": "Fertilizer A"
},
{
"name": "Fertilizer B"
}
],
"failed": [
{
"name": "Fertilizer C",
"error": "Invalid subtype: \"unknown_type\". Valid options: bioestimulante, fertilizante, fertilizante organico, enmienda"
},
{
"name": "Row 5",
"error": "Missing input name"
}
]
}
}
Response Headers (Download)
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment; filename="{input_type}_template.xlsx"
Error Responses
Invalid Input Type
{
"info": "'invalid_type' is not one of ['fitosanitario', 'fertilizantes', 'semillas']"
}
Invalid Action
{
"info": "'invalid_action' is not one of ['download', 'upload']"
}
Missing Required Field
{
"info": "'action' is a required property"
}
5. Workspace Inputs Filter API
Filter workspace inputs with enhanced filtering capabilities including brand, company, and subtype filters.
Endpoints
GET /api/workspaces/configs/inputs
GET /api/workspaces/configs/inputs?country=AR&brand=AGRUCON&page=1&page_size=50&search=fertilizer
POST /api/workspaces/configs/inputs
POST /api/workspaces/configs/inputs
Request Parameters (GET)
| Parameter | Type | Required | Description |
|---|---|---|---|
country | string | No | Filter by country code (e.g., "AR", "BR") |
brand | string | No | Filter by brand name (case-insensitive, partial match) |
page | integer | No | Page number (default: 1) |
page_size | integer | No | Items per page (default: 50) |
search | string | No | Search term for input name |
Request Body (POST)
Filter Request
{
"country": "AR",
"brand": "AGRUCON",
"company": "Yara International",
"subtype": "herbicida",
"category_id": 1,
"page": 1,
"page_size": 50,
"search": "fertilizer"
}
Input Creation Request
{
"nombre": "New Fertilizer",
"id_tipo": 1,
"marca": "Brand Name",
"empresa": "Company Name",
"presentacion": "50kg bag",
"str_composicion": "N: 46%"
}
Field Descriptions
Filter Fields:
| Field | Type | Required | Description |
|---|---|---|---|
country | string | No | Filter by country code (e.g., "AR", "BR") |
brand | string/array | No | Filter by brand name(s) (case-insensitive, partial match). Can be a single string or array of strings |
company | string/array | No | Filter by company name(s) (case-insensitive, partial match). Can be a single string or array of strings |
subtype | string/array | No | Filter by input subtype(s) (case-insensitive, partial match). Can be a single string or array of strings |
category_id | integer | No | Filter by input category ID |
page | integer | No | Page number (default: 1) |
page_size | integer | No | Items per page (default: 50, max: 1000) |
search | string | No | Search term for input name (case-insensitive, partial match) |
Input Creation Fields:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Input name |
uuid | string | Yes | UUID for the input |
type_id | integer | Yes | Input type ID |
company | string | No | Company name |
brand | string | No | Brand name |
presentation | string | No | Presentation format |
density | float | No | Density value |
toxicological_class | string | No | Toxicological classification |
unit_default | string | No | Default unit (default: "kg/ha") |
expiration_date | datetime | No | Expiration date |
registration_code | string | No | Registration code |
components | array | No | Components with uuid and concentration |
Response
Filter Response
{
"pagination": {
"last_page": true,
"total_pages": 1
},
"data": [
{
"id": 47216,
"uuid": "f19f4762-d80e-11eb-8340-47b30b2a4222",
"name": "fertilizer name",
"user_input": false,
"composition": "N: 16%",
"type": "fertilizante",
"category_id": 2,
"state": "crystal",
"company": "company name",
"density": null,
"code": "16345",
"country": "AR",
"unit": "kg",
"brand": "AGRUCON",
"valid": true,
"valid_until": null,
"has_pdf": false,
"input_settings": null,
"components": [
{
"uuid": "ea1c5d6c-e2e7-11ea-932a-b79f3cedb7f3",
"active_principle": true,
"eiq_1": null,
"concentration": 0.16,
"id": 1,
"name": "n"
}
]
}
]
}
Input Creation Response
{
"data": {
"input_id": 12345
}
}
Example Requests
Filter by Brand and Country (GET)
GET /api/workspaces/configs/inputs?country=AR&brand=AGRUCON&page=1&page_size=50
Filter by Multiple Criteria (POST)
{
"country": "AR",
"brand": "AGRUCON",
"company": "Yara",
"subtype": "herbicida",
"category_id": 1,
"page": 1,
"page_size": 100,
"search": "nitrogen"
}
Create New Input (POST)
{
"name": "Premium Nitrogen Fertilizer",
"uuid": "123e4567-e89b-12d3-a456-426614174000",
"type_id": 1,
"company": "Acme Agro",
"brand": "UreaMax",
"presentation": "25kg bag",
"density": 1.2,
"toxicological_class": "III",
"unit_default": "kg/ha",
"expiration_date": "2025-12-31T00:00:00Z",
"registration_code": "REG-12345",
"components": [
{
"uuid": "123e4567-e89b-12d3-a456-426614174002",
"concentration": 46.0
}
]
}
Filter Behavior
- Admin Mode: When
admin=true, the API includes both country-specific inputs and master inputs (NULL country) - Brand Filter: Case-insensitive partial matching on the
marcafield - Company Filter: Case-insensitive partial matching on the
empresafield - Subtype Filter: Case-insensitive partial matching on the
tipofield fromtipos_insumostable - Category ID Filter: Exact matching on the
category_idfield fromtipos_insumostable - Search Filter: Case-insensitive partial matching on the input name with accent normalization
- Pagination: Proper offset calculation (page 1 = offset 0, page 2 = offset page_size, etc.)
Error Responses
Invalid Page Size
{
"info": "page_size must be between 1 and 1000"
}
Invalid Page Number
{
"info": "page must be greater than 0"
}
Best Practices
Performance
- Use appropriate
page_size(recommended: 50-100 items) - Implement client-side caching for filter options
- Use specific filters to reduce result sets
Error Handling
- Always check response status codes
- Handle validation errors gracefully
- Implement retry logic for 500 errors
UX Recommendations
- Show loading states during API calls
- Implement debounced search (300ms delay)
- Cache filter options to avoid repeated calls for the same filter type
- Show pagination controls when
next_pageis present - For filters endpoint: call once per filter type and cache results
- Validate filter combinations client-side before API calls
6. Copy Inputs and Varieties to Tenant
Copy all inputs and seed varieties from the current workspace to all other workspaces within the same tenant.
Endpoint
POST /api/workspaces/inputs/copy-to-tenant
Authentication
- Requires login token
- Requires admin privileges for the workspace
Request Body
None required (uses workspace from token)
Response
{
"data": {
"inputs_copied": 15,
"varieties_copied": 8,
"target_workspaces": 5,
"source_workspace": 123
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
inputs_copied | integer | Number of inputs copied to other workspaces |
varieties_copied | integer | Number of seed varieties copied to other workspaces |
target_workspaces | integer | Number of target workspaces (other workspaces in same tenant) |
source_workspace | integer | ID of the source workspace |
Error Responses
No other workspaces in tenant
{
"info": "No other workspaces found in this tenant"
}
No inputs or varieties to copy
{
"info": "No inputs or varieties to copy from this workspace"
}
Security Notes
- Only workspace admins can execute this endpoint
- Does not copy to the same workspace (excludes current workspace)
- Only copies to workspaces in the same tenant
- Uses
ON CONFLICT DO NOTHINGto avoid duplicates
Event Logging
This action is logged with event name input_seed_copy containing:
source_workspace_id: Source workspace IDtarget_workspaces_count: Number of target workspacesinputs_copied: Count of inputs copiedvarieties_copied: Count of varieties copiedtenant: Tenant name
Example Request
curl -X POST /api/workspaces/inputs/copy-to-tenant \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN"
Example Response
{
"data": {
"inputs_copied": 12,
"varieties_copied": 5,
"target_workspaces": 3,
"source_workspace": 45
}
}
Code Examples
JavaScript/Fetch Example
// Search fertilizers
const searchInputs = async (searchTerm, page = 1) => {
try {
const response = await fetch('/api/workspaces/configs/inputs/manager', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authToken}`
},
body: JSON.stringify({
input: 'fertilizantes',
search: searchTerm,
page: page,
page_size: 50
})
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.info);
}
return await response.json();
} catch (error) {
console.error('Search failed:', error);
throw error;
}
};
// Create seed
const createSeed = async (cropId, varietyName) => {
try {
const response = await fetch('/api/workspaces/configs/inputs/manager', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authToken}`
},
body: JSON.stringify({
action: 'create',
input: 'seeds',
crop: cropId,
variety: varietyName
})
});
return await response.json();
} catch (error) {
console.error('Create seed failed:', error);
throw error;
}
};
// Get filter options
const getFilters = async (inputType, filterType) => {
try {
const response = await fetch('/api/workspaces/configs/inputs/manager/filters', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authToken}`
},
body: JSON.stringify({
input: inputType,
filter: filterType
})
});
return await response.json();
} catch (error) {
console.error('Failed to get filters:', error);
throw error;
}
};
cURL Examples
# Search fertilizers
curl -X POST /api/workspaces/configs/inputs/manager \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"input": "fertilizantes",
"search": "nitrogen",
"page": 1,
"page_size": 10
}'
# Create seed
curl -X POST /api/workspaces/configs/inputs/manager \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"action": "create",
"input": "seeds",
"crop": 10,
"variety": "Corn Hybrid DKC64-87"
}'
# Update input
curl -X POST /api/workspaces/configs/inputs/manager \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"action": "update",
"input": "fertilizantes",
"uuid": "123e4567-e89b-12d3-a456-426614174000",
"nombre": "Updated Fertilizer Name"
}'
# Delete seed
curl -X POST /api/workspaces/configs/inputs/manager \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"action": "delete",
"input": "seeds",
"uuid": "456e7890-e89b-12d3-a456-426614174001"
}'
# Get seeds
curl -X POST /api/workspaces/configs/manager/inputs/seeds \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"variety": "corn",
"page": 1,
"page_size": 20
}'
# Get filter options for fertilizer brands
curl -X POST /api/workspaces/configs/inputs/manager/filters \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"input": "fertilizantes",
"filter": "brand"
}'
# Get seed varieties
curl -X POST /api/workspaces/configs/inputs/manager/filters \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"input": "semillas",
"filter": "variety"
}'
# Get fertilizer subtypes
curl -X POST /api/workspaces/configs/inputs/manager/filters \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"input": "fertilizantes",
"filter": "subtype"
}'
Database Changes (2024-12-19):
- Crop Grouping: The system now uses
id_cultivo_agrupadorinstead of the deprecatedagrupadortext field - Default Crops: The default crop for each group is the one where
id_cultivo_agrupadorequals its ownid - Backward Compatibility: All existing crop search and filtering functionality continues to work with the new structure