# Bugs Identificados
## Operador no se despliega en la lista de operadores para generar la carta porte
### Contexto
El dueño (o contacto administrativo) de la línea de transporte reporta que en la app móvil no aparece cierto operador para poder solicitar la carta porte.
### Diagnóstico
Hay 2 razones por las cuales el operador no aparecería en la lista de operador en la pantalla de generación de carta porte:
1. El usuario (operador) no existe.
2. El usuario (operador) no cumple con los requerimientos del embarcador.
### Solución
1. Revisar que el operador exista, siguiendo [estos pasos](https://hackmd.io/JoodTnDZTOu7rD5ZE0Mt6w#Agregar-operador-a-l%C3%ADnea-de-transporte).
2. Si el operador existe, revisar que el operador cumpla con los requerimientos del embarcador.
### Notas
* Desde el Sendengo Admin se pueden modificar la mayoría de los campos del operador.
* En caso de necesitar mayor nivel de detalle sobre los requerimientos con los que cuenta operador, se puede utilizar el siguiente query:
```
select * from users_driver where user_ptr_id=<ID del operador>;
```
### Recomendaciones
* Modificar la vista del Django Admin del operador ([ejemplo](https://sendengo.com/django-admin/companies/drivers/1545/change/)) para que desde ahí se puedan modificar los campos relevantes de un operador, y no directamente desde la base de datos.
## Agregar operador a línea de transporte
### Contexto
Cuando una línea de transporte quiere registrar un operador, el operador no se puede agregar correctamente.
Para agregar un operador (o un usuario de tipo embarcador o transportista a la plataforma, internamente se realizan los siguientes pasos:
1.) Crear el usuario (de tipo transportista, embarcador u operador).
2.) Crear la empresa (de tipo transporista o embarcador, y solo en caso de que no esté creada).
3.) Asociar al usuario con la empresa.
La plataforma puede crear correctamente al usuario y a la empresa, pero falla ocasionalmente al querer asociar al usuario con la empresa.
### Diagnóstico
Técnicamente hablando, la razón por la que la plataforma falla al realizar el paso 3.) mencionado anteriormente es por se atrasa la secuencia de la tabla `companies_companyteam`.
La tabla `companies_companyteam` contiene la asociación entre una empresa y sus usuarios. Al agregar un registro a esta tabla, especificamos un ID de empresa y un ID de usuario (entre otros valores que no tienen tanta importancia para efectos del diagnóstico). Por cada registro que se agrega, se agrega un identificados para esa asociación.
| ID (de Asociación) | ID Empresa | ID Usuario |
|--- | --- | --- |
|123 | 456 | 789
|124 | 654 | 987
|125 | 546 | 879
El ID de asociación es _secuencial_ y se genera automáticamente. Los IDs de empresa y usuario pueden ser cuales quieran (no tienen que seguir un orden en particular).
Al hacer una inserción, existe un apuntador (llamado una "secuencia") al último registro insertado en la base de datos (en este caso, al `125`) que se incremente automáticamente para insertar el siguiente registro. Dado que ese ID se genera automáticamente (es decir, nunca se tiene que especificar manualmente), este mecanismo es suficiente para encontrar el siguiente campo vacío para insertar un nuevo registro (en este caso, `126`).
El bug ocasiona que el apuntador (o la secuencia) se quede "atrasado", y que al querer incrementarlo para insertar un nuevo registro, el motor de la base de datos se encuentre con un ID existente.
En este caso, si la secuencia estaría apuntando a `124` y al querer crear un registro para una nueva asociación, ésta se incrementa a `125` e intenta hacer la inserción. Sin embargo, ya existe un registro con el ID `125` y por lo tanto, falla la inserción.
### Solución
Aún no sabemos qué ocasiona que la secuencia se atrase. Puede ser desde la forma en la que se crean los usuarios desde alguna parte de la plataforma (Admin, Onboarding, Carrier o Shipper), hasta un bug en PostgreSQL o Django. Aún no sabemos cómo curar la enfermedad, pero podemos curar el síntoma.
Para "curar el síntoma", tenemos que "resetear la secuencia" -- actualizar el apuntador para que apunte al último registro en la tabla de `companies_companyteam` y así tener certeza de que no habrá ninguna colisión al insertar el siguiente registro.
Para resetear la secuencia:
1. Seleccionar el valor máximo de ID en la tabla de `companies_company`.
```
SELECT MAX(id) FROM companies_companyteam;
```
2. Seleccionar el valor al que apunta la secuencia.
```
SELECT nextval('companies_companyteam_id_seq');
```
3. Asignar al valor de la secuencia el valor con el máximo ID de la tabla.
```
SELECT setval('companies_companyteam_id_seq', COALESCE((SELECT MAX(id)+1 FROM companies_companyteam), 1), false);
```
4. Hacer una insercion manual a la tabla de `companies_companyteam` para asociar al usuario con la empresa.
Para hacer una inserción en esta tabla se necesitan 2 datos: (1) ID de la empresa, (2) Email del usuario. En el caso más recurrente -- el de operadores -- el equipo reporta en el grupo de Incidencias técnicas el ID de la línea de transporte y el email del operador.
```
INSERT INTO companies_companyteam (id, created_at, updated_at, company_id, created_by_id, user_id)
VALUES (DEFAULT, NOW(), NOW(), <ID de la empresa>, NULL, (SELECT id FROM users_user WHERE email='<Email del usuario>'));
```
**Nota**: El query anterior realiza dos operaciones:
1. Obtiene el ID de un usuario a partir de su correo.
2. Agrega el registro a la tabla de `companies_companyteam`.
### Posibles soluciones a largo plazo
* Actualizar el motor de la base de datos a una versión más reciente de PostgreSQL.
* Migrar los datos a una nueva base de datos.
* Resetear la secuencia por medio de un query de SQL desde Django antes de hacer cualquier inserción a esta tabla.
* Modificar el modelo de Django de `CompanyTeam` team.
## Agregar usuarios internos (staff)
### Contexto
Nunca se desarrolló una funcionalidad para registrar usuarios de staff dentro del Admin. Por lo tanto, toda la alta, baja y modificaciones de usuarios se debe de realizar desde el Django Admin.
### Cómo resolverlo
#### Opción 1 - Crear usuario de staff desde el Django Admin
1. Entrar al [Django Admin](http://sendengo.com/django-admin) de de Sendengo.
2. En **Users** > **Staff**, dar click en [Agregar](https://sendengo.com/django-admin/users/admin/add/).
3. Completar el perfil del usuario.
Completar el perfil del usuario con los siguientes valores:
* **Contraseña**: Cualquier valor, se va a cambiar después.
* Checar el campo de **Es staff**.
* **Username**: Email de Sendengo del usuario.
* **User type**: Staff.
* **Email**: Email de Sendengo del usuario.
* **Phone**: Teléfono del usuario.
* **Phone extension**: 0 (o cualquier otro valor).
* **First name**: Nombre del usuario.
* **Last name**: Apellido del usuario.
* **Transitory name**: Nombre de display del usuario (el que se desplegará en el Admin de Sendengo -- usualmente es _Primer nombre_ + _Apellido_).
* **Changed email**: Correo de Sendengo del usuario.
* **Changed email expiration**: Cualquier fecha.
* **Changed email verification token**: Cualquier cadena de texto.
* **Rol**: Rol del usuario.
4. Obtener el ID del usuario.
Entrar al perfil del usuario recién creado (desde el Django Admin) y obtener su ID.
5. Restablecer la contraseña del usuario.
Entrar a `http://sendengo.com/admin/change/password/<ID del usuario>` (ejemplo: http://sendengo.com/admin/change/password/30000) y restablecer la contraseña.
#### Opción 2 - Inserciones directas en la base de datos (no-recomendada)
**Nota**: Esta opción no es recomendable y se deberá utilizar solo como último recurso.
1. Agregar el usuario a la tabla de `users`, para registrar al usuario.
```
INSERT INTO users_user (id, "password", last_login, is_superuser, is_staff, is_active, date_joined, username, user_type, email, phone, phone_extension, first_name, last_name, transitory_name, changed_email, changed_email_expiration, changed_email_verification_token)
VALUES (DEFAULT, 'password', NOW(), 'True', 'True', 'True', NOW(), '<Email del usuario>', 4, '<Email del usuario>', '<Teléfono del usuario>', NULL, '<Nombre del Usuario>', '<Apellido del Usuario>', '<Display Name del usuario>', NULL, NULL, NULL);
```
**Nota**: Este método crea un usuario con una contraseña temporal e insegura. Más adelante se creará la contraseña segura elegida por el usuario.
2. Consultar el ID del usuario recién creado.
```
SELECT id FROM users_user WHERE email='<Email del usuario>';
```
3. Agregar el usuario a la tabla de `staff`, para indicar que un usuario del staff de Sendengo.
```
INSERT INTO users_staff (user_ptr_id, rol, created_at, updated_at, profile_photo_id)
VALUES (<ID del usuario>, 1, NOW(), NOW(), NULL);
````
4. Restablecer la contraseña del usuario.
Entrar a `http://sendengo.com/admin/change/password/<ID del usuario>` (ejemplo: http://sendengo.com/admin/change/password/30000) y restablecer la contraseña.
### Recomendaciones
* Simplificar la interfaz del Django Admin para dar de alta usuario de staff. Los campos que no se necesitan son:
- Phone extension
- Changed email
- Changed email expiration
- Changed email verification token
* Para realizar este cambio, se deberá modificar el modelo de `user`.