---
# System prepended metadata

title: Mak - Indicadores de Avance
tags: [gql, mak, doc, testing, indicadores]

---

---
title: 'Mak - Indicadores de Avance'
---

Mak - Indicadores de Avance
===


Obj: Mostrar un resumen acciones con los siguientes elementos


- Pendientes: Recupera la cantidad de acciones pendientes para un determinado rango de fechas `(start-end)` y algún otro filtro como usuario o valor extra del cliente

- Hechas: Son las acciones que tiene respuesta y que están en un rango de fechas `(start-end)` 

- Vencidas: Son las acciones que no tienen respuesta y que su fecha de expiración está entre una fecha pasada y el start. 
    e.g. 
    - si start: `2020-06-01` y end: `2020-06-10` y past_date: `2020-05-25` entonces se filtrarían las acciones cuyo valor expire sea gte: `2020-05-25` y lte: `2020-06-01`
    
- Sin actividad: Son todos objects (clientes) que no tienen acciones
 


UI:

```
      320 / 43     |      150 / 32     |      62 / 13       |        183
   actions objects |   actions objects |  actions objects   |      objects
-------------------|-------------------|--------------------|------------------------
     Pendientes    |      Hechas       |     Vencidas       |     Sin Actividad
```


> object: Representa a un cliente
> action: Representa a una misión/foco rojo


URL: http://api.staging.kimetrics.com/



#### Crear consultas sql para recuperar estadísticas de accionables, filtrados por cliente, usuario, fechas (start y end)
- [X] total de acciones/objetos pendientes
- [ ] total de acciones/objetos hechas
- [ ] total de acciones/objetos vencidas
- [ ] total de objetos sin acciones
- [ ] validación de datos
- [x] pruebas para consumir datos desde el cliente
- [x] consumir los datos con el API de Hasura.
- [ ] pruebas manuales en dashboard




Total de acciones/objetos pendientes
---

### Intro

En esta sección se describen las tareas para obtener las acciones/objetos pendientes.

Definimos una acción pendiente como aquella acción que no tiene un registro de resultados en la tabla `actions` del schema `results` 

Los resultados están delimitados por el rando de fecha `start` y `end` que inicialmente corresponde a la semana actual

Solo se contabilizan las acciones que SI tienen asignado un objeto unico por accion




### Tareas

- Vistas en SQL
    - [X] uv_objects_with_users
    - [x] uv_pending_actions
- Validación de datos
    -  [ ] **Modelo de datos** `uv_pending_actions`, `uv_objects_with_users` 
    
    #### `uv_pending_actions`
    
    -  [X] Parametros Default; start: lunes, end: termina domingo, actor_uuid= NULL, **intervalo**: `start <= data.actions.expire <= end`
        -  **output**:
            - [X] los actions deben ser unicos
            - [X] los actions devueltos no existen en la tabla results.actions
            - [X] el campo expire de los data.actions devueltos estan dentro del rango de los parametros de start, end
    -  [X] Parametros Default: start: lunes - 8 dias, end: lunes, actor_uuid= NULL, **intervalo**: `start <= data.actions.expire <= end`
        -  **output**:
            - [X] los actions deben ser unicos
            - [X] los actions devueltos no existen en la tabla results.actions
            - [X] el campo expire de los data.actions devueltos estan dentro del rango de los parametros de start, end
    -  [X] Parametros: start < end, actor_uuid=some-actor-uuid, **intervalo**: `start <= data.actions.expire <= end`
        -  **output**:
            - [X] la lista de `objects` devueltos son un subconjunto propio de los `objetos` asignados al empleado filtrado
            - [X] los actions deben ser unicos
            - [X] los actions devueltos no existen en la tabla results.actions
    -  [X] Parametros: start < end, actor_uuid=some-actor-uuid, el actor no tiene ningun object asignado, **intervalo**: `start <= data.actions.expire <= end`
        -  **output**:
        -  [X] debe devolver una lista vacia.
    -  [X] Parametros: start < end, actor_uuid=some-actor-uuid, Filtra los objetos unicos, **intervalo**: `start <= data.actions.expire <= end`
        -  **output**:
            - [X] la lista de `objects` devueltos son un subconjunto propio de los objetos asignados al empleado filtrado
    #### `uv_objects_with_users`
    - [X] Parametros Default; actor_uuid = NULL
        - ***output:***
            - [X] Devuelve una lista de `objects_uuid` unicos, todos los `objects` con `object_status`=1
    - [X] Parametros Default; actor_uuid = some_unexisting_actor_uuid
        - ***output:***
            - [X] Devuelve una lista vacia
    - [X] Parametros Default; actor_uuid = some_existing_actor_uuid
        - ***output:***
            - [X] Devuelve la lista de TODOS los `objects` asignados a dicho actor.
    - **GraphQL**
        - [ ] Validar veracidad de los records devueltos por el SQL propuesto por hasura
        - [ ] Validar las agregaciones, resultado del SQL propuesto por hasura
        - [ ] Comprobacion del filtro por campo `extra:JSON`
            - [ ] extra->cadena
            - [ ] extra->canal
            - [ ] extra->formato
            - [ ] usar schema de object_types
- Implementación de consulta de graphql (Hasura)
    - Filtros: 
        - [x] fecha de inicio
        - [ ] fecha de fin
        - [x] usuario
        - [ ] extra
    - paginación
        - [ ] total de acciones
        - [ ] página actual
        - [ ] total de páginas
        - [ ] obtener siguiente página
        - 
- Implementación en frontend
    - [ ] crear constante para gql
    - [ ] crear listado de objetos con filtro de status=pending 
    - [ ] conectar con indicador de pendientes
    - [ ] mostrar datos con paginación


Componentes
---
#### uv_pending_actions
Vista que nos entrega todos los `actions` pendientes, salida:
``` 
id(INT) | object(UUID) | expire(TIMESTAMP WITH TZ) | actor(UUID)     | uv_owu.name(TEXT) | extra(JSONB) 
--------|--------------|---------------------------|-----------------|-------------------|-------------
id de la| uuid del obj-| expiracion de la accion   | uuid del        | nombre del objeto | datos extra
accion  | eto asignado |                           | actor asign-    | uv_owu.name(TEXT) | del objeto en
        |  a la accion |                           | ado a la accion |                   | JSON
```
    


Total de acciones/objetos hechos
---

### Intro

Acciones hechas: son aquellas acciones que sí cuentan con un registro en la tabla `results.actions`


### Tareas

- Vistas en SQL
    - [ ] uv_objects_with_users
    - [ ] uv_done_actions
- Validación de datos
    -  [ ] **Modelo de datos** `uv_done_actions`, `uv_objects_with_users` 
    
    #### `uv_done_actions`
    
    -  [ ] Parametros Default; start: lunes, end: termina domingo, actor_uuid= NULL, **intervalo**: `start <= data.actions.expire <= end`
        -  **output**:
            - [ ] los actions deben ser unicos
            - [ ] los actions devueltos existen en la tabla results.actions
    -  [ ] Parametros: start < end, actor_uuid=some-actor-uuid, **intervalo**: `start <= data.actions.expire <= end`
        -  **output**:
            - [ ] la lista de `objects` devueltos son un subconjunto propio de los `objetos` asignados al empleado filtrado
            - [ ] los actions deben ser unicos
    -  [ ] Parametros: start < end, actor_uuid=some-actor-uuid, el actor no tiene ningun object asignado. , **intervalo**: `start <= data.actions.expire <= end`
        -  **output**:
        -  [ ] debe devolver una lista vacia.
    -  [ ] Parametros: start < end, actor_uuid=some-actor-uuid, Filtra los objetos unicos, **intervalo**: `start <= data.actions.expire <= end`
        -  **output**:
            - [ ] la lista de `objects` devueltos son un subconjunto propio de los objetos asignados al empleado filtrado
    - **GraphQL**
        - [ ] Validar veracidad de los records devueltos por el SQL propuesto por hasura
        - [ ] Validar las agregaciones, resultado del SQL propuesto por hasura
        - [ ] Comprobacion del filtro por campo `extra:JSON`
            - [ ] extra->cadena
            - [ ] extra->canal
            - [ ] extra->formato
            - [ ] usar schema de object_types


- Implementación de consulta de graphql (Hasura)
    - Filtros: 
        - [ ] fecha de inicio
        - [ ] fecha de fin
        - [ ] usuario
        - [ ] extra
    - paginación:
        - [ ] total de acciones
        - [ ] página actual
        - [ ] total de páginas
        - [ ] obtener siguiente página
        - 
- Implementación en frontend
    - [ ] crear constante para gql
    - [ ] crear listado de objetos con filtro de status=done
    - [ ] conectar con indicador de hechas
    - [ ] mostrar datos con paginación


Componentes
---
#### uv_done_actions
Vista que nos entrega todos los `actions` hechas, salida:
``` 
id(INT) | object(UUID) | expire(TIMESTAMP WITH TZ) | actor(UUID)     | uv_owu.name(TEXT) | extra(JSONB) 
--------|--------------|---------------------------|-----------------|-------------------|-------------
id de la| uuid del obj-| expiracion de la accion   | uuid del        | nombre del objeto | datos extra
accion  | eto asignado |                           | actor asign-    | uv_owu.name(TEXT) | del objeto en
        |  a la accion |                           | ado a la accion |                   | JSON
```




Total de acciones/objetos vencidas
---

### Intro

Acciones vencidas: son las acciones que no tiene respuesta y que su fecha de expiración estan una semana antes de la fecha de inicio, por ejemplo si nuestra fecha de inicio es '2020-06-01' entoncens debemos consultar todas las acciones que estan dentro del rango de 2020-05-25 al 2020-06-01




### Tareas

- Vistas en SQL
    - [X] uv_objects_with_users
    - [X] uv_pending_actions
- Validación de datos
    -  [ ] **Modelo de datos** `uv_due_actions`, `uv_objects_with_users` 
    
    - **GraphQL**
        - [ ] Validar veracidad de los records devueltos por el SQL propuesto por hasura
        - [ ] Validar las agregaciones, resultado del SQL propuesto por hasura
        - [ ] Comprobacion del filtro por campo `extra:JSON`
            - [ ] extra->cadena
            - [ ] extra->canal
            - [ ] extra->formato
            - [ ] usar schema de object_types


- Implementación de consulta de graphql (Hasura)
    - Filtros: 
        - [ ] fecha de inicio = fecha de inicio - 8 días,
        - [ ] fecha de fin = fecha de inicio
        - [ ] usuario
        - [ ] extra
    - paginación
        - [ ] total de acciones
        - [ ] página actual
        - [ ] total de páginas
        - [ ] obtener siguiente página
        - 
- Implementación en frontend
    - [ ] crear cunsulta para gql
    - [ ] crear filtro por status=done 
    - [ ] conectar con indicador de hechas
    - [ ] mostrar datos con paginación


Componentes
---
#### uv_done_actions
Vista que nos entrega todos los `actions` hechas, salida:
``` 
id(INT) | object(UUID) | expire(TIMESTAMP WITH TZ) | actor(UUID)     | uv_owu.name(TEXT) | extra(JSONB) 
--------|--------------|---------------------------|-----------------|-------------------|-------------
id de la| uuid del obj-| expiracion de la accion   | uuid del        | nombre del objeto | datos extra
accion  | eto asignado |                           | actor asign-    | uv_owu.name(TEXT) | del objeto en
        |  a la accion |                           | ado a la accion |                   | JSON
```



Total de objetos sin actividad
---

### Intro
Son los objetos (clientes) que no tienen acciones asignadas en un perido de tiempo establecido (semana actual)


### Tareas

- Vistas en SQL
    - [X] uv_objects_with_users
    - [ ] uv_objects_with_no_actions
- Validación de datos
    -  [ ] **Modelo de datos** `uv_objects_with_no_actions`, `uv_objects_with_users` 
    -  
        #### `uv_objects_with_no_actions`

        -  [ ] Parametros Default: start: lunes, end: termina domingo, actor_uuid= NULL, **intervalo:** `start <= data.actions.expire <= end`
            -  **output**:
                - [ ] los objetos devueltos son unicos
                - [ ] los objetos devueltos son unicos no tienen data.action para ese rango de fecha.
        -  [ ] Parametros: start < end, actor_uuid=some-actor-uuid, **intervalo:** `start <= data.actions.expire <= end`
            -  **output**:
                - [ ] la lista de `objects` devueltos son un subconjunto propio de los `objetos` asignados al empleado filtrado
                - [ ] los objetos deben ser unicos
                - [ ] los objetos devueltos son unicos no tienen data.action para ese rango de fecha.
        -  [ ] Parametros: start < end, actor_uuid=some-actor-uuid, el actor no tiene ningun object asignado. `start <= data.actions.expire <= end`
            -  **output**:
            -  [ ] debe devolver una lista vacia.
    - **GraphQL**
        - [ ] Validar veracidad de los records devueltos por el SQL propuesto por hasura
        - [ ] Validar las agregaciones, resultado del SQL propuesto por hasura
        - [ ] Comprobacion del filtro por campo `extra:JSON`
            - [ ] extra->cadena
            - [ ] extra->canal
            - [ ] extra->formato
            - [ ] usar schema de object_types


- Implementación de consulta de graphql (Hasura)
    - filtrado: 
        - [ ] fecha de inicio,
        - [ ] fecha de fin
        - [ ] usuario
        - [ ] extra
    - paginación
        - [ ] total de acciones
        - [ ] página actual
        - [ ] total de páginas
        - [ ] obtener siguiente página
        - 
- Implementación en frontend
    - [ ] crear consulta para gql
    - [ ] crear filtro por status=sin actividad 
    - [ ] conectar con indicador sin actividad 
    - [ ] mostrar datos con paginación


Testing for `uv_objects_with_users`
---
```
-- the output shall be empty
SELECT * FROM (
  SELECT
    object,
    objs.id
  FROM data.uv_objects_with_users AS da_owu
  LEFT JOIN (
    SELECT DISTINCT ON(id) id FROM data.objects WHERE status = 1 AND tenant=2
  ) AS objs ON objs.id = da_owu.object
  WHERE tenant=2 AND actor IS NULL
) AS foo WHERE foo.object IS NULL OR foo.id IS NULL;
-- SHALL BE EMPTY
SELECT * FROM (
  SELECT
    object,
    objs.id,
    CASE WHEN object = objs.id THEN TRUE ELSE FALSE END AS m_match
  FROM data.uv_objects_with_users AS da_owu
  LEFT JOIN (
    SELECT DISTINCT ON(id) id FROM data.objects WHERE status = 1 AND tenant=2
  ) AS objs ON objs.id = da_owu.object
  WHERE tenant=2 AND actor IS NULL
) AS foo
WHERE foo.m_match IS FALSE;
-- COUNT SHALL MATCH
SELECT
  C1,
  C2,
  CASE WHEN C2=C1 THEN TRUE ELSE FALSE END
FROM (
  SELECT
  (SELECT COUNT(*) FROM data.uv_objects_with_users WHERE tenant=2 AND actor IS NULL ) as C1,
  (SELECT COUNT(*) FROM (SELECT DISTINCT ON(id) id FROM data.objects WHERE status = 1 AND tenant=2) AS tt) as C2
) AS dd;


------
-- Parametros Default; actor_uuid = some_unexisting_actor_uuid
-- output:
-- Devuelve una lista vacia o conteo = 0
SELECT
  COUNT(*)
FROM data.uv_objects_with_users AS da_owu
WHERE tenant=2 AND actor = '00000000-0000-0000-0000-000000000000';
-- Parametros Default; actor_uuid = some_unexisting_actor_uuid and tenant does not exists
-- output:
-- Devuelve una lista vacia o conteo = 0
SELECT
  COUNT(*)
FROM data.uv_objects_with_users AS da_owu
WHERE tenant=0 AND actor = '00000000-0000-0000-0000-000000000000';



-- Parametros Default; actor_uuid = some_existing_actor_uuid
-- output:
-- Devuelve la lista de TODOS los objects asignados a dicho actor.
-- the output of this validation query shall be empty
WITH my_users AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY id)  AS row_num
  FROM public.users
), max_users AS (
  SELECT max(row_num) FROM my_users
), random_user AS (
  SELECT id FROM my_users WHERE row_num = (
    SELECT floor(random() * ((SELECT * FROM max_users)-1) + 1)::int
  )
), actor_assignments AS (
  SELECT
    object, actor
  FROM data.objects_assignment WHERE actor = (SELECT id FROM random_user)
)
SELECT * FROM (
  SELECT
    CASE WHEN tt.da_owu_object = tt.object THEN TRUE ELSE FALSE END AS m_match
  FROM (
    SELECT
      ac_assi.object,
      ac_assi.actor,
      da_owu.actor AS da_owu_actor,
      da_owu.object AS da_owu_object
    FROM actor_assignments AS ac_assi
    LEFT JOIN data.uv_objects_with_users AS da_owu ON da_owu.actor = ac_assi.actor AND da_owu.object = ac_assi.object
  ) AS tt
) AS tt2 WHERE tt2.m_match = FALSE ;

--- using A discrete value instead of random shall be the same as using GraphQL

SELECT COUNT(*) FROM data.uv_objects_with_users WHERE actor = '291b6505-e988-47da-8f78-80bc3750aff4' AND tenant=2;


query GET_OBJECTS_WITH_USERS($_eq: uuid = "", $tenant: Int = 2) {
  data_uv_objects_with_users_aggregate(where: {actor: {_eq: $_eq}, tenant: {_eq: $tenant}}) {
    aggregate {
      count
    }
    nodes {
      actor
      extra
      name
      object
    }
  }
}


{
  "_eq": "291b6505-e988-47da-8f78-80bc3750aff4",
  "tenant": 2
}

```

Testing uv_pending_actions
---

```
----TESTING------uv_pending_actions---->>>>>>>>

-- Parametros Default; start: lunes, end: termina domingo, actor_uuid= NULL, intervalo: start <= data.actions.expire <= end
-- output:

-- los actions deben ser unicos
-- result shall be empty list
-- Shall be empty
SELECT * FROM (
  SELECT
    id,
    expire,
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY id) AS more_than_once
  FROM data.uv_pending_actions
  WHERE expire >= to_timestamp('2020-06-01T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND expire <= to_timestamp('2020-06-10T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND actor IS NULL
) AS tt WHERE tt.more_than_once > 1;
-- With a random User
WITH my_users AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY id)  AS row_num
  FROM public.users
), max_users AS (
  SELECT max(row_num) FROM my_users
), random_user AS (
  SELECT id FROM my_users WHERE row_num = (
    SELECT floor(random() * ((SELECT * FROM max_users)-1) + 1)::int
  )
)SELECT * FROM (
  SELECT
    id,
    expire,
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY id) AS more_than_once
  FROM data.uv_pending_actions
  WHERE expire >= to_timestamp('2020-06-01T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND expire <= to_timestamp('2020-06-10T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND actor = (SELECT id FROM random_user)
) AS tt WHERE tt.more_than_once > 1;
---->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.
-- los actions devueltos no existen en la tabla results.actions
-- list shall be EMPTY
SELECT * FROM results.actions WHERE action IN (
  SELECT
    id
  FROM data.uv_pending_actions
  WHERE expire >= to_timestamp('2020-06-01T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND expire <= to_timestamp('2020-06-10T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND actor IS NULL
);

-- With a random User
-- Shall be empty
WITH my_users AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY id)  AS row_num
  FROM public.users
), max_users AS (
  SELECT max(row_num) FROM my_users
), random_user AS (
  SELECT id FROM my_users WHERE row_num = (
    SELECT floor(random() * ((SELECT * FROM max_users)-1) + 1)::int
  )
)SELECT * FROM results.actions WHERE action IN (
  SELECT
    id
  FROM data.uv_pending_actions
  WHERE expire >= to_timestamp('2020-06-01T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND expire <= to_timestamp('2020-06-10T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND actor = (SELECT id FROM random_user)
);

---->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.........>>>>>>>>>
-- el campo expire de los data.actions devueltos estan dentro del rango de los parametros de start, end

WITH date_interval AS (
  SELECT
    TRUNC(EXTRACT(EPOCH FROM to_timestamp('2020-06-01T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')))::INTEGER AS start_datetime,
    TRUNC(EXTRACT(EPOCH FROM to_timestamp('2020-06-10T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')))::INTEGER AS end_datetime
)
SELECT
  *
FROM (
  SELECT
    id,
    CASE WHEN (TRUNC(EXTRACT(EPOCH FROM expire)) >= (SELECT start_datetime FROM date_interval) AND TRUNC(EXTRACT(EPOCH FROM expire)) <= (SELECT end_datetime FROM date_interval)) THEN TRUE ELSE FALSE END AS m_match
  FROM data.uv_pending_actions
  WHERE expire >= to_timestamp('2020-06-01T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND expire <= to_timestamp('2020-06-10T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND actor IS NULL
) AS tt WHERE tt.m_match = FALSE;

--  with a random user
-- Shall be empty
WITH date_interval AS (
  SELECT
    TRUNC(EXTRACT(EPOCH FROM to_timestamp('2020-06-01T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')))::INTEGER AS start_datetime,
    TRUNC(EXTRACT(EPOCH FROM to_timestamp('2020-06-10T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')))::INTEGER AS end_datetime
), my_users AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY id)  AS row_num
  FROM public.users
), max_users AS (
  SELECT max(row_num) FROM my_users
), random_user AS (
  SELECT id FROM my_users WHERE row_num = (
    SELECT floor(random() * ((SELECT * FROM max_users)-1) + 1)::int
  )
)
SELECT
  *
FROM (
  SELECT
    id,
    CASE WHEN (TRUNC(EXTRACT(EPOCH FROM expire)) >= (SELECT start_datetime FROM date_interval) AND TRUNC(EXTRACT(EPOCH FROM expire)) <= (SELECT end_datetime FROM date_interval)) THEN TRUE ELSE FALSE END AS m_match
  FROM data.uv_pending_actions
  WHERE expire >= to_timestamp('2020-06-01T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND expire <= to_timestamp('2020-06-10T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND actor = (SELECT id FROM random_user)
) AS tt WHERE tt.m_match = FALSE ;

-- el campo expire de los data.actions devueltos estan dentro del rango de los parametros de start, end



Parametros Default: start: lunes - 8 dias, end: lunes, actor_uuid= NULL, **intervalo**: `start <= data.actions.expire <= end`
-- For these test cases apply the same as before just update dates


----TESTING------uv_pending_actions---->>>>>>>>

-- Parametros: start < end, actor_uuid=some-actor-uuid, intervalo: start <= data.actions.expire <= end

-- output:
-- la lista de objects devueltos son un subconjunto propio de los objetos asignados al empleado filtrado
-- Test output shall return an empty list
WITH my_users AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY id)  AS row_num
  FROM public.users
), max_users AS (
  SELECT max(row_num) FROM my_users
), random_user AS (
  SELECT id FROM my_users WHERE row_num = (
    SELECT floor(random() * ((SELECT * FROM max_users)-1) + 1)::int
  )
), actor_assignments AS (
  SELECT
    object, actor
  FROM data.objects_assignment WHERE actor = (SELECT id FROM random_user)
)
SELECT
  *
FROM (
 SELECT
  ac_assi.object,
  ac_assi.actor,
  da_upa.actor AS da_upa_actor,
  da_upa.object AS da_upa_object
FROM actor_assignments AS ac_assi
LEFT JOIN data.uv_pending_actions AS da_upa ON da_upa.actor = ac_assi.actor AND da_upa.object = ac_assi.object
) AS tt WHERE actor IS NULL OR object IS NULL;

--->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.
--- los action son unicos
WITH my_users AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY id)  AS row_num
  FROM public.users
), max_users AS (
  SELECT max(row_num) FROM my_users
), random_user AS (
  SELECT id FROM my_users WHERE row_num = (
    SELECT floor(random() * ((SELECT * FROM max_users)-1) + 1)::int
  )
), actor_assignments AS (
  SELECT
    object, actor
  FROM data.objects_assignment WHERE actor = (SELECT id FROM random_user)
)
SELECT * FROM (
  SELECT
    id,
    expire,
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY id) AS more_than_once
  FROM data.uv_pending_actions
  WHERE expire >= to_timestamp('2020-05-25T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND expire <= to_timestamp('2020-06-01T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND actor = (SELECT id FROM random_user)
) AS tt WHERE tt.more_than_once > 1;


---->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.
-- los actions devueltos no existen en la tabla results.actions
-- list shall be EMPTY
WITH my_users AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY id)  AS row_num
  FROM public.users
), max_users AS (
  SELECT max(row_num) FROM my_users
), random_user AS (
  SELECT id FROM my_users WHERE row_num = (
    SELECT floor(random() * ((SELECT * FROM max_users)-1) + 1)::int
  )
)
SELECT * FROM results.actions WHERE action IN (
  SELECT
    id
  FROM data.uv_pending_actions
  WHERE expire >= to_timestamp('2020-05-25T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND expire <= to_timestamp('2020-06-01T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND actor = (SELECT id FROM random_user)
);

-- Parametros: start < end, actor_uuid=some-actor-uuid, el actor no tiene ningun object asignado,
-- intervalo: start <= data.actions.expire <= end
-- list shall be EMPTY
WITH la_moderna_id AS (
  SELECT id FROM public.tenants WHERE slug = 'lamoderna' LIMIT 1
), actor_w_no_assignments AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY id)  AS row_num
  FROM public.users WHERE id NOT IN (
    SELECT actor FROM data.objects_assignment WHERE tenant = (SELECT * FROM la_moderna_id)
  ) AND tenant_id = (SELECT * FROM la_moderna_id)
), max_users AS (
  SELECT max(row_num) FROM actor_w_no_assignments
), random_user AS (
  SELECT id FROM actor_w_no_assignments WHERE row_num = (
    SELECT floor(random() * ((SELECT * FROM max_users)) + 1)::int
  )
)SELECT * FROM data.uv_pending_actions
  WHERE expire >= to_timestamp('2020-05-25T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND expire <= to_timestamp('2020-06-01T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND actor = (SELECT id FROM random_user);
        
------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-- Parametros: start < end, actor_uuid=some-actor-uuid, Filtra los objetos unicos,
-- intervalo: start <= data.actions.expire <= end
-- test-output: EMPTY  list  
WITH la_moderna_id AS (
  SELECT id FROM public.tenants WHERE slug = 'lamoderna' LIMIT 1
), actor_w_assignments AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY id)  AS row_num
  FROM public.users WHERE id IN (
    SELECT actor FROM data.objects_assignment WHERE tenant = (SELECT * FROM la_moderna_id)
  ) AND tenant_id = (SELECT * FROM la_moderna_id)
), max_users AS (
  SELECT max(row_num) FROM actor_w_assignments
), random_user AS (
  SELECT id FROM actor_w_assignments WHERE row_num = (
    SELECT floor(random() * ((SELECT * FROM max_users)) + 1)::int
  )
), pending_objects AS (
  SELECT * FROM data.uv_pending_actions
  WHERE expire >= to_timestamp('2020-05-25T00:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND expire <= to_timestamp('2020-06-01T23:59:59.000', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND actor = (SELECT id FROM random_user)
)SELECT object, actor FROM pending_objects WHERE object NOT IN (SELECT object FROM data.objects_assignment WHERE actor=(SELECT id FROM random_user)) ;

```

### Consultando todos las actions pendientes con gql
```
--Query
query GET_PENDING_ACTIONS($where: data_uv_pending_actions_bool_exp) {
  objects: data_uv_pending_actions_aggregate(where: $where) {
    aggregate {
      count(distinct: true, columns: object)
    }
  }
  pendings: data_uv_pending_actions_aggregate(where: $where) {
    aggregate {
      count(distinct: true, columns: id)
    }
    nodes {
      id
      name
      object
      tenant
      actor
      expire
      extra
    }
  }
}

--Query Variables

{
  "where": {
	  "_and": {
      "expire": {"_gte": "2020-06-01", "_lte": "2020-06-30" },
      "actor": {"_eq": "291b6505-e988-47da-8f78-80bc3750aff4"},
    	"tenant": {"_eq": 2}
    }
  }
}

```

### Ejemplos

> Todas las acciones pendientes de Santiago Lopéz del 1 al 10 de junio de 2020 de la cadena:SORIANA y formato: SORIANA SUPER


```graphql=2
query GET_PENDING_ACTIONS($where: data_uv_pending_actions_bool_exp) {
  objects: data_uv_pending_actions_aggregate(where: $where) {
    aggregate {
      count(distinct: true, columns: object)
    }
  }
  pendings: data_uv_pending_actions_aggregate(where: $where) {
    aggregate {
      count(distinct: true, columns: id)
    }
    nodes {
      id
      name
      object
      tenant
      actor
      expire
      extra
    }
  }
}
```

Variables
```jsonld=1
{
  "where": {
    "_and": {
      "expire": {"_gte": "2020-06-01", "_lte": "2020-06-10" },
      "actor": {"_eq": "291b6505-e988-47da-8f78-80bc3750aff4"},
    	"tenant": {"_eq": 2}
    },
    "extra": {
      "_contains": {
        "chain": "SORIANA",
        "format": "SORIANA SUPER"
      }
    }
  }
}
```



###### tags: `indicadores` `mak` `doc` `gql` `testing`