Saltar al contenido principal

inputs-manager-api

Ver en Git


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 constraint error by ensuring UUID is properly passed to the database layer
  • Presentation Field Not Saved: Fixed issue where presentation field from request was not being saved to the presentacion column in the database

Technical Details:

  • Corrected field mapping from API schema to repository constructor parameters
  • Added missing uuid field to the data mapping
  • Added presentation field to constructor and INSERT query to properly save to presentacion column
  • 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 true if user has permission 153 in usuarios.permisos_agregar array

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 to usuarios.permisos_agregar array
    • false: Removes permission 153 from usuarios.permisos_agregar array

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

CodeDescription
200Success
400Bad Request - Invalid input data or validation errors
401Unauthorized - Invalid or missing authentication token
403Forbidden - User lacks admin privileges or ownership
500Internal 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:

FieldTypeRequiredDescription
inputstringYesType of input: "fertilizantes", "fitosanitario"
searchstringNoSearch term for product name (case-insensitive, partial match)
subtypestring/arrayNoFilter by subtype (case-insensitive, partial match). Can be a single string or array of strings
brandstring/arrayNoFilter by brand name(s) (case-insensitive, partial match). Can be a single string or array of strings
companystring/arrayNoFilter by company name(s) (case-insensitive, partial match). Can be a single string or array of strings
componentsstring/arrayNoFilter by components/composition (case-insensitive, partial match). Can be a single string or array of strings
presentationstring/arrayNoFilter by presentation (case-insensitive, partial match). Can be a single string or array of strings
pageintegerNoPage number (default: 1, or use next_page token from previous response)
page_sizeintegerNoNumber of items per page (default: 100)
countrystringNoCountry filter

Management Fields:

FieldTypeRequiredDescription
actionstringYes*Action to perform: "create", "update", "delete"
inputstringYesType of input: "seeds", "fertilizantes", "fitosanitario"
uuidstringYes**UUID of item to update/delete
idstring/integerYes**Alternative ID for seeds update/delete (can use instead of uuid)
cropintegerYes***Crop ID (for seeds operations)
varietystringYes***Variety name (for seeds operations)
namestringYes****Input name (for fertilizer/phytosanitary create, optional for update)
type_idintegerYes****Input type ID (for fertilizer/phytosanitary create, optional for update)
companystringNoCompany name (for fertilizer/phytosanitary operations)
brandstringNoBrand name (for fertilizer/phytosanitary operations)
presentationstringNoPresentation format (for fertilizer/phytosanitary operations)
densityfloatNoDensity value (for fertilizer/phytosanitary operations)
toxicological_classstringNoToxicological classification (for fertilizer/phytosanitary operations)
unit_defaultstringNoDefault unit (for fertilizer/phytosanitary operations, default: "kg/ha")
expiration_datedatetimeNoExpiration date (for fertilizer/phytosanitary operations)
registration_codestringNoRegistration code (for fertilizer/phytosanitary operations)
componentsarrayNoComponents 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:

FieldTypeDescription
dataarrayArray of input products
uuidstringUnique identifier for the input
nombrestringInput name
marcastringBrand name
empresastringCompany name
presentacionstringPresentation format
str_composicionstringOriginal composition string
subtipostringInput subtype
componentsstringComponents (fallback from str_composicion or joined from components table)
next_pagestring/nullBase64 encoded token for next page, null if last page
estimated pagesintegerTotal estimated pages (only on first page)

Management Response:

FieldTypeDescription
data.msgstringSuccess message
data.uuidstringUUID of the created/updated/deleted item
data.cropstringCrop name (seeds operations only)
data.namestringItem 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)
  • 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

FieldTypeRequiredDescription
varietystring/arrayNoFilter by variety name(s) (case-insensitive, partial match). Can be a single string or array of strings
cropinteger/arrayNoFilter by crop ID(s). Can be a single integer or array of integers
namestringNoSearch by seed name (case-insensitive, partial match)
pageintegerYesPage number (use 1 for first page)
page_sizeintegerYesNumber of items per page

Response

{
"pagination": {
"last_page": true,
"total_pages": 1
},
"data": [
{
"uuid": "string",
"crop": "string",
"name": "string"
}
]
}

Response Fields

FieldTypeDescription
pagination.last_pagebooleanTrue if this is the last page
pagination.total_pagesintegerTotal number of pages
dataarrayArray of seed varieties
uuidstringUnique identifier for the seed
cropstringCrop name
namestringSeed 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

FieldTypeRequiredDescription
inputstringYesType of input: "fertilizantes", "fitosanitario", or "semillas"
filterstringYesSpecific 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

FieldTypeDescription
dataarrayArray of available filter options for the specified filter type
uuidstringUnique identifier for the filter option
filterstringFilter value
descriptionstringHuman-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 page field
  • For seeds manager: Increment the page number

Example Pagination Flow

  1. First Request:
{
"input": "fertilizantes",
"page": 1,
"page_size": 10
}
  1. First Response:
{
"data": [...],
"next_page": "eyJwYWdlIjoyLCJsYXN0X2lkIjoxMjN9"
}
  1. 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

  • input field must be one of: "fertilizantes", "fitosanitario", "semillas"
  • Invalid input types will return 400 error

Filter Type Validation (Filters Endpoint)

  • filter field must be valid for the specified input type
  • Invalid combinations will return 400 error with specific message
  • Seeds: only variety, crop, company, brand allowed
  • Fertilizers/Phytosanitary: only subtype, brand, company, components, presentation allowed

Pagination Validation

  • page must be positive integer or valid base64 token
  • page_size must 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

FieldTypeRequiredDescription
inputstringYesType of input sheet to generate: "fitosanitario", "fertilizantes", or "semillas"
actionstringYesAction 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) - Default
  • pt_BR - Portuguese (Brazil)
  • en_US - English (United States)
  • es_AR - Spanish (Argentina)
  • fr_FR - French (France)

Translation System

The system dynamically translates headers using:

  1. Translation files from /translations/dictionaries/dictionary_{locale}.po
  2. All lines of each .po file are processed for complete translation coverage
  3. Dynamic path resolution for production environments
  4. Fallback to Spanish (es_ES) if translation not found
  5. Context-aware translations using msgctxt when 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:

  1. Direct Match: First attempts direct match with input crop name
  2. Translation Lookup: If user locale ≠ Spanish, translates using .po files from /translations/dictionaries/
  3. Common Translations: Falls back to built-in common crop translations
  4. 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.nombre and crop grouper name via id_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 of iterrows() 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: true flag
  • 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)

ParameterTypeRequiredDescription
countrystringNoFilter by country code (e.g., "AR", "BR")
brandstringNoFilter by brand name (case-insensitive, partial match)
pageintegerNoPage number (default: 1)
page_sizeintegerNoItems per page (default: 50)
searchstringNoSearch 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:

FieldTypeRequiredDescription
countrystringNoFilter by country code (e.g., "AR", "BR")
brandstring/arrayNoFilter by brand name(s) (case-insensitive, partial match). Can be a single string or array of strings
companystring/arrayNoFilter by company name(s) (case-insensitive, partial match). Can be a single string or array of strings
subtypestring/arrayNoFilter by input subtype(s) (case-insensitive, partial match). Can be a single string or array of strings
category_idintegerNoFilter by input category ID
pageintegerNoPage number (default: 1)
page_sizeintegerNoItems per page (default: 50, max: 1000)
searchstringNoSearch term for input name (case-insensitive, partial match)

Input Creation Fields:

FieldTypeRequiredDescription
namestringYesInput name
uuidstringYesUUID for the input
type_idintegerYesInput type ID
companystringNoCompany name
brandstringNoBrand name
presentationstringNoPresentation format
densityfloatNoDensity value
toxicological_classstringNoToxicological classification
unit_defaultstringNoDefault unit (default: "kg/ha")
expiration_datedatetimeNoExpiration date
registration_codestringNoRegistration code
componentsarrayNoComponents 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 marca field
  • Company Filter: Case-insensitive partial matching on the empresa field
  • Subtype Filter: Case-insensitive partial matching on the tipo field from tipos_insumos table
  • Category ID Filter: Exact matching on the category_id field from tipos_insumos table
  • 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_page is 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

FieldTypeDescription
inputs_copiedintegerNumber of inputs copied to other workspaces
varieties_copiedintegerNumber of seed varieties copied to other workspaces
target_workspacesintegerNumber of target workspaces (other workspaces in same tenant)
source_workspaceintegerID 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 NOTHING to avoid duplicates

Event Logging

This action is logged with event name input_seed_copy containing:

  • source_workspace_id: Source workspace ID
  • target_workspaces_count: Number of target workspaces
  • inputs_copied: Count of inputs copied
  • varieties_copied: Count of varieties copied
  • tenant: 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_agrupador instead of the deprecated agrupador text field
  • Default Crops: The default crop for each group is the one where id_cultivo_agrupador equals its own id
  • Backward Compatibility: All existing crop search and filtering functionality continues to work with the new structure