Es la entidad dueña de la cuenta (ejemplo GaiaDesign), una organización puede tener multiples máquinas de estado.
Es grafo que representa el estado de un item en un momento dado, una máquina de estados puede tener multiples estados y multiples formas de transicionar entre ellos.
Es un estado del item que transiciona en la máquina de estados, un item puede estar en un solo estado en un momento dado.
Es el cambio de estado, solo se puede ejecutar una transición a la vez, cada transición necesita validar ciertos campos antes de poder aceptar la transición.
Es el objeto que transiciona en la máquina de estados, un item puede tener multiples máquinas de estados, puede ser un producto, un cliente, un pedido, etc.
Un item tiene atributos requeridos, los cuales pueden ser de tipo string o numéricos, todo lo que no sea definido como requerido es opcional aunque no se defina explicitamente en el ItemModel.
Un item puede tener flags, las flags solo se activan o desactivan cuando se transiciona por ciertos estados.
$response = $client->request('POST', '/api/users', [
'headers' => [
'Accept' => 'application/ld+json',
'Content-Type' => 'application/ld+json'
],
'json' => [
'email' => '[email protected]',
'plainPassword' => 'password',
'name' => 'Test',
'lastName' => 'User',
]
]);
$response = $client->request('POST', '/auth/login', [
'headers' => [
'Accept' => 'application/ld+json',
'Content-Type' => 'application/ld+json'
],
'json' => [
'email' => '[email protected]',
'password' => 'password',
]
]);
$data = $response->toArray();
$token = $data['token'];
$response = $client->request('POST', '/api/organizations', [
'headers' => [
'Accept' => 'application/ld+json',
'Content-Type' => 'application/ld+json',
'Authorization' => 'Bearer wegf76sdf8sd899082f3kjk3jhu893'
],
'json' => [
'name' => 'Test Organization',
'code' => 'TORG',
]
]);
$organizationId = $response->toArray()['@id'];
$mapConfig = [
'code' => 'product-map',
'states' => [
'initial' => 'init',
'middle' => [
'pending',
'show',
'hide',
],
'final' => [
'publish'
]
],
'transitions' => [
'pending' => [
'from' => [
'init',
],
'to' => 'pending',
'validators' => [
[
'validator' => 'internal.not_empty',
'config' => [
'sku',
'stars',
'review'
]
]
],
'flags' => [
'active' => [
'active'
]
]
],
'to_high' => [
'from' => [
'pending'
],
'to' => 'high',
'validators' => [
[
'validator' => 'internal.flag',
'config' => [
'true' => ['active']
]
],
[
'validator' => 'internal.regex',
'config' => [
'stars' => '/^[4-5]$/'
]
]
],
],
'to_low' => [
'from' => [
'pending'
],
'to' => 'hide',
'validators' => [
[
'validator' => 'internal.flag',
'config' => [
'true' => ['active']
]
],
[
'validator' => 'internal.regex',
'config' => [
'stars' => '/^[1-3]$/'
]
]
],
],
'to_publish' => [
'from' => [
'high'
],
'to' => 'publish',
'validators' => [
[
'validator' => 'internal.flag',
'config' => [
'true' => ['active']
]
]
],
],
]
];
$stateMachineCode = 'TSTM';
$itemModel = [
'type' => 'object',
'required' => ['sku', 'review', 'stars'],
'properties' => [
'sku' => [
'type' => 'string',
'minLength' => 5
],
'review' => [
'type' => 'string',
'minLength' => 5
],
'stars' => [
'type' => 'integer',
'minimum' => 0,
'maximum' => 5
]
],
'metadata' => [
'flags' => [
'active',
'high',
'low',
]
]
];
$stateMachine = [
'name' => 'Test State Machine',
'organization' => $organizationId,
'code' => $stateMachineCode,
'definition' => $mapConfig,
'itemModel' => $itemModel
];
// Create state machine using the organization from previous test
$response = $client->request('POST', '/api/organization-state-machines', [
'headers' => [
'Accept' => 'application/ld+json',
'Content-Type' => 'application/ld+json',
'Authorization' => 'Bearer wegf76sdf8sd899082f3kjk3jhu893'
],
'json' => $stateMachine
]);
$stateMachineId = $response->toArray()['@id'];
$response = $client->request('POST', '/api/organization-state-machine-items', [
'headers' => [
'Accept' => 'application/ld+json',
'Content-Type' => 'application/ld+json',
'Authorization' => 'Bearer wegf76sdf8sd899082f3kjk3jhu893'
],
'json' => [
'state_machine' => $stateMachineId,
'body' => [
'sku' => 'Producto Silla Replica Eames',
'review' => 'lorem ipsum dolor sit amet',
'stars' => 4
],
]
]);
$itemId = $response->toArray()['@id'];
$response = $client->request('PATCH', $itemId, [
'headers' => [
'Accept' => 'application/ld+json',
'Content-Type' => 'application/merge-patch+json',
'Authorization' => 'Bearer wegf76sdf8sd899082f3kjk3jhu893'
],
'json' => [
'state_machine' => $stateMachineId,
'body' => [
'field' => 'value'
],
]
]);
$item = $response->toArray();
Puedes buscar items usando cualquier campo dentro del body JSON usando la notación body.campo.
El campo puede estar en cualquier nivel del JSON.
// Búsqueda por email
$response = $client->request('GET', '/api/organization-state-machine-items', [
'headers' => $this->getHeaders(),
'query' => [
'body.email' => '[email protected]'
]
]);
// Búsqueda por teléfono
$response = $client->request('GET', '/api/organization-state-machine-items', [
'headers' => $this->getHeaders(),
'query' => [
'body.phone' => '5525675224'
]
]);
// Búsqueda por código de producto
$response = $client->request('GET', '/api/organization-state-machine-items', [
'headers' => $this->getHeaders(),
'query' => [
'body.products.sku' => 'T0123'
]
]);
// Búsqueda por monto total
$response = $client->request('GET', '/api/organization-state-machine-items', [
'headers' => $this->getHeaders(),
'query' => [
'body.total' => '48700.53'
]
]);
Notas importantes:
Los catálogos permiten definir listas de valores predefinidos que pueden ser referenciados en los items. Por ejemplo, tipos de solicitud, categorías de productos, etc.
// Primero definimos el modelo de los items del catálogo
$itemModel = [
'type' => 'object',
'required' => ['name', 'code'],
'properties' => [
'name' => [
'type' => 'string'
],
'code' => [
'type' => 'string',
]
],
'metadata' => [
'flags' => [
'active'
]
]
];
// Creamos el catálogo
$response = $client->request('POST', '/api/organization-catalogs', [
'headers' => [
'Accept' => 'application/ld+json',
'Content-Type' => 'application/ld+json',
'Authorization' => 'Bearer token'
],
'json' => [
'organization' => $organizationId,
'itemModel' => $itemModel
]
]);
$catalog = $response->toArray();
// Ejemplo: Crear tipos de solicitud
$requestTypes = [
'order' => 'Purchase Order',
'service' => 'Service Payment'
];
foreach ($requestTypes as $code => $name) {
$response = $client->request('POST', '/api/organization-catalog-items', [
'headers' => [
'Accept' => 'application/ld+json',
'Content-Type' => 'application/ld+json',
'Authorization' => 'Bearer token'
],
'json' => [
'catalog' => $catalog['@id'],
'body' => [
'name' => $name,
'code' => $code,
]
]
]);
}
$itemModel = [
'type' => 'object',
'required' => ['requestDate', 'requestType', 'project', 'requester', 'department'],
'properties' => [
'requestType' => [
'type' => 'string',
'pattern' => '^/api/organization-catalog-items/[0-9a-fA-F-]{36}$'
],
// ... otras propiedades
]
];
$response = $client->request('POST', '/api/organization-state-machine-items', [
'headers' => [
'Accept' => 'application/ld+json',
'Content-Type' => 'application/ld+json',
'Authorization' => 'Bearer token'
],
'json' => [
'state_machine' => $stateMachineId,
'body' => [
'requestDate' => date('Y-m-d'),
'requestType' => '/api/organization-catalog-items/catalog-item-uuid',
'project' => 'Nombre del Proyecto',
'requester' => [
'name' => 'Juan Pérez',
'position' => 'Gerente'
],
'department' => 'construction'
]
]
]);
Los webhooks permiten recibir notificaciones y actualizar el estado de los items automáticamente cuando ocurren eventos externos.
$mapConfig = [
'transitions' => [
'payment-received' => [
'from' => ['payment-link-created'],
'to' => 'payment-received',
'validators' => [
[
'validator' => 'internal.webhook',
'config' => {
'store' => {
'payment' => [
'amount',
'paid_at',
'payment_id'
],
'webhook_token' => null
}
}
]
]
]
]
];
Al crear el state machine, se genera automáticamente:
/api/webhooks/{code}/{item_code}
Importante: El token debe enviarse en el header nami-webhook-token.
Este token es único para cada webhook y es requerido para que la petición sea procesada.
curl -X POST https://api.example.com/api/webhooks/123e4567-e89b/ITEM-001 \
-H "Content-Type: application/ld+json" \
-H "nami-webhook-token: abc123" \ # Token requerido para autenticación
-d '{
"payment": [{
"amount": 1000,
"paid_at": "2025-03-07",
"payment_id": "PK_123456"
}]
}'
Notas sobre seguridad: