122 Commits

Author SHA1 Message Date
fa850b69ef No-estable: Inicio reporte por operario
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-09-30 19:15:45 -05:00
e40991de02 feat: Se agregan dominios de vista de prospectos
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-22 10:39:10 -05:00
b8ba775733 chore(Tipificación del cliente): Se hacen traducciones
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-21 19:28:19 -05:00
336a266578 chore: Se hace visible rating en vista de arbol de prospectos
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-21 19:13:29 -05:00
22fb3736a7 chore(Agendación de tarea): Se agregan traducciones faltantes
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-21 19:08:24 -05:00
5cc7ef011d feat: Se agrega tipificación del cliente, closed #70
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-19 17:10:13 -05:00
72ae0cfa22 feat: Se hace posible agregar y modificar métodos de contactos desde seguimiento de prospectos, closed #72
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-19 15:56:21 -05:00
0b7d15f35b feat(Programación de tareas): Se agregan traducciones, #71
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-19 12:19:49 -05:00
8a0aa29368 feat: Se agregan estados a la vista de tareas pendientes, #71
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-19 11:57:29 -05:00
f71e6f4671 feat: Se implementa en las pruebas cierre de tarea pendientes
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-19 11:47:31 -05:00
cf874db55f chore(Task): se extrae clase a otro archivo, #71 2023-09-19 11:24:49 -05:00
e97e8fa99d chore: prueba error usuario gitea, #71
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-19 07:08:32 -05:00
5a2c5217a6 feat: Se agrega reporte de tareas pendientes, #71 2023-09-19 06:48:55 -05:00
d50cca2924 feat: Se implementa agendación de tarea en las vistas, #71
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-19 06:10:09 -05:00
c1be04d009 Merge branch '6.8' of https://gitea.onecluster.org/OneTeam/trytondo-sale_opportunity_management into 6.8
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-18 19:50:10 -05:00
214c6fc089 feat: Se implementa agendación de tarea en las pruebas, #71 2023-09-18 19:49:58 -05:00
a7bf0f2a38 Fix: Se añaden traducciones pendientes
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-12 19:29:24 -05:00
243f1123a8 Fix: se añade traduccion es administrador en usuarios
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-12 19:17:11 -05:00
faa8f35384 Fix: se añade traduccion pagina metodos de contacto
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-12 19:13:09 -05:00
78fcd0231d chore(Reasignación por prospecto): Solo se muestran los prospectos con un operario asignado, closed #68
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-10 14:07:13 -05:00
3ac393dd01 chore: Se corrige error en traducción
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-10 13:59:09 -05:00
abf0c05894 fix: Closed #65
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-09 18:14:16 -05:00
a73cd43582 prueba carpintero
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-05 18:22:37 -05:00
0ccb733dab chore: Se remueve código muerto
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-09-04 18:00:11 -05:00
649f610bb0 Fix: Se añade dominio en seguiemiento de prospectos por rol
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-04 17:42:24 -05:00
c32b4ce31c Fix: Se añade dominio en seguiemiento de prospectos por rol
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-09-04 17:39:20 -05:00
97bbcaed92 Fix: Se añade dominio en seguiemiento de prospectos por rol
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-09-04 17:33:37 -05:00
a1716141b0 Fix: Se añaden grupos de usuarios
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-04 13:43:20 -05:00
0c09498340 Fix: Se corrige errores de pruebas
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-04 09:53:01 -05:00
8e60272f91 Se añade grupos de usuarios
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-09-04 09:32:20 -05:00
4ec1d2e2cd feat: Se traducen encabezados de wizards, #63
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-02 11:26:22 -05:00
b36160c228 chore: Se remueve código muerto
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-02 11:04:50 -05:00
0460324ddf Chore: Se remueve página innecesaria
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-02 11:04:27 -05:00
33ac57175c feat: Se traducen dominios, #63
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-02 11:01:49 -05:00
732b9dbfb8 feat: Se traducen botones de wizards, #63
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-02 10:44:25 -05:00
01b5119f0b chore: Se agrega icono de reporte de llamadas
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-02 10:19:12 -05:00
eed86133f4 feat: Se agregan traducciones a selections, #63
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-31 18:56:13 -05:00
dd3cd79a1f fix: Se remueve traducción invalida
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-31 18:18:06 -05:00
766f3fbc0b feat: Gpt agrega traducciones a campos de modelos faltantes, #63
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-31 17:45:24 -05:00
2bd62e1b14 feat: Se agregan traducciones a campos de prospect, #63
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-31 17:26:07 -05:00
94321866eb feat: Se agregan traducciones a campos de prospect trace, #63
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-31 17:21:42 -05:00
f9bf0d3384 feat: Se agregan traducciones a botones, #63
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-31 17:13:30 -05:00
1bcc6e5294 chore: Se cambia enlace simbólico de documentación
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-30 21:31:00 -05:00
c9de0ab42e chore: Se cambian iconos
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-30 21:25:50 -05:00
d925fcf913 fix(Botón reabrir seguimiento): Se arreglan las evaluaciones de 'invisible'
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-30 21:19:29 -05:00
033f1aad43 feat(Prospect_Trace): Se agrega reanudación de seguimiento a las vistas, #64
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-30 19:13:28 -05:00
fd24a757fb feat: Se implementa reanudación de seguimiento en las pruebas, #64
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-30 19:00:31 -05:00
3d77cf9a98 chore: Se remueve código muerto, #64
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-30 18:31:42 -05:00
9efb29f1a1 feat(Prospect_Trace): Se agrega estado 'cerrado' las vistas, #64
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-30 18:30:11 -05:00
8c1ed18530 feat: Se implementa cierre de seguimiento en las pruebas, #64
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-30 18:04:27 -05:00
1a469a5106 feat: Se agregan traducciones (es) de menús
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-29 21:01:38 -05:00
fc70d7cb74 Fix: Se elimina campo currency_date de la vista
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-29 19:50:56 -05:00
ceb9f07aab feat: se añade dominio a campo para agendar proxima llamada
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-29 19:46:12 -05:00
bdcf78ad56 chore: En registros de llamadas se renombra 'operario asignado' por 'operario que llamó'
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-28 20:27:30 -05:00
79dd0454d6 chore(Calls): Se hace unidad de negocio de solo lectura
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-28 20:20:01 -05:00
a8c6ecaa79 feat: Se limita creación de llamadas desde otro lugar que no sea el asistente destinado a ello
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-28 20:18:28 -05:00
18413d9005 chore(Vista de prospectos): se cambia vista de menús por vista de pestañas, closed #62
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-28 20:13:16 -05:00
e0c47961bc chore: Se elimina código muerto
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-28 20:03:31 -05:00
22478c9e68 chore: se elimina código muerto
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-28 20:03:09 -05:00
8ec3e4b983 feat: Se inicia seguimiento automáticamente luego de asignar operario, closed #61
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-28 19:59:52 -05:00
543a52303c chore: Se remueve código duplicado
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-28 19:27:26 -05:00
70aa3f96d4 feat: Se agrega posible agendación de llamada en el flujo de crear una llamada, #58
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-27 20:52:42 -05:00
27d4ce8a77 feat: Se agregan vistas de reasignación de prospecto específico, #53
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-27 19:13:17 -05:00
2eb52e9dce feat: Se implementa reasignación de prospecto específico en las pruebas, #53
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-27 18:48:30 -05:00
ed07f5fcbc feat: Se hacen vistas a asistente de reasignación por operario, #53
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-27 11:39:33 -05:00
3d77056e6f feat: Se implementa en las pruebas asistene de reasignación por operario
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-27 11:13:43 -05:00
e260c70a11 Error: Solo se guarda nuevo operario en primer iteración
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-27 10:21:43 -05:00
416804983b chore: Se elimina código muerto
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-27 09:49:55 -05:00
0364110866 chore(scenario): Se usa registro de prospect_trace obtenido por el click de iniciar seguimiento
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-27 08:22:00 -05:00
27dcca74bc feat: Se crea botón para iniciar seguimiento de prospecto
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-26 20:38:40 -05:00
082d070643 chore: Se remueve menú innecesario
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-26 18:11:47 -05:00
1a1b262720 feat: Se hace posible filtrar llamadas por operario que realizó dicha llamada
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-26 17:59:08 -05:00
9067aa1446 chore: Se remueve código muerto y se da orden a las vistas, closed #54
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-26 17:35:59 -05:00
7c39fcc429 feat(ProspectTrace): Se agregan a la vista todos los contactos del prospecto 2023-08-26 16:36:32 -05:00
1ece8ae959 feat(ProspectTrace): Se agrega campo para todos los contactos del prospecto 2023-08-26 16:28:21 -05:00
05ae82839b feat: Se añade nuevo item en escala de interés, closed #57
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-24 15:18:21 -05:00
31fb4211e4 feat(AssignProspectsWizard): Se encuentran prospectos también por unidad de negocio, closed #55
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-24 15:01:39 -05:00
8fa5d20ea6 feat(Call): Se hace visible unidad de negocio, actualizandose junto con el seguimiento de prospecto, closed #56
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-24 14:11:05 -05:00
4ffb654814 feat(ProspectTrace): Se hace visible unidad de negocio, actualizandose al seleccionar prospecto, #56
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-24 13:16:21 -05:00
a33d43cb57 feat(Prospect): Se crea campo de unidad de negocio, #56
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-24 12:56:55 -05:00
3bb8ddbb2c chore: Se hace requerido prospect_trace en Call
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-22 19:03:07 -05:00
11a541a3eb chore: Se elimina código muerto
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-22 18:55:50 -05:00
06a7402f0c chore: Se da formato a formulario de asistente de creación de llamadas, closed #50
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-22 18:18:33 -05:00
f3f7493d6c chore: Se crea dominio en mecanismo de contacto, closed #48
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-22 18:11:19 -05:00
16508c5961 chore: Se agregan iconos personalizados, closed #51
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-22 17:56:02 -05:00
4449b57f60 chore: Se agregan iconos personalizados a ventana principal y wizard de creación de llamada
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-22 17:17:22 -05:00
9f8e0b96af feat: Se hace visible operario asignado desde la vista de árbol, closed #49
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-22 16:25:04 -05:00
229fa9044a chore: Se ajustan detalles en la documentación
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-22 16:14:45 -05:00
a8da18e2b6 feat: Se crea asistente para creación de llamadas a seguimiento, closed #39
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-21 12:48:25 -05:00
8d1d5d1553 fix: Se genera error cuando prospects_chunks es negativo
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-21 12:20:19 -05:00
36f074a519 Merge branch '6.8' of https://gitea.onecluster.org/OneTeam/trytondo-sale_opportunity_management into 6.8
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-21 11:59:46 -05:00
d330ac341a Se implementa wizard para crear llamadas a prospectos (en las pruebas), #39 2023-08-21 11:59:38 -05:00
1187dd6ecc Fix: Se da formato a la vista closed #46
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-21 10:18:43 -05:00
fd667a518b chore: Se hace que agendar llamada pendiente solo se pueda hacer desde el asistente
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-21 09:39:06 -05:00
b34a1e19af feat: Se crea asistente para agendar próxima llamada
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-21 09:27:48 -05:00
56550df81a Merge branch '6.8' of https://gitea.onecluster.org/OneTeam/trytondo-sale_opportunity_management into vistasWizardPendingCall 2023-08-21 09:08:53 -05:00
f0a5e30b38 feat(Wizard de asignación de prospectos): Se agrega campo para visualización de terceros encontrados según el chunk
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-21 09:05:48 -05:00
a63dd54089 Merge branch '6.8' of https://gitea.onecluster.org/OneTeam/trytondo-sale_opportunity_management into vistasWizardPendingCall
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-21 07:55:42 -05:00
3fc2db8543 chore: cambia pipeline por steps
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-08-20 23:04:46 +00:00
05ff4b8f8d Error registrando boton en ProspectTrace 2023-08-19 14:39:30 -05:00
881f34d582 feat: closed #44
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-19 13:01:00 -05:00
d7095e05bb chore: Se remueve código muerto
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-19 12:56:12 -05:00
c0db903ac8 Merge branch '6.8' of https://gitea.onecluster.org/OneTeam/trytondo-sale_opportunity_management into 6.8
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-19 12:45:33 -05:00
93c2f10040 Se implementa wizard para crear llamada pendiente en las pruebas, #35 2023-08-19 12:41:29 -05:00
590e604604 chore: usando imagen personalizada para plugin/matrix
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-18 20:41:09 -05:00
2c68c3bb53 chore: compatibilidad versión 1.0 woodpecker
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-18 20:34:34 -05:00
3c4e8f5a26 Feat: Se añade Wizard assign_operator_wizard a la vista
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-18 19:24:47 -05:00
51d58de12a Feat: se actualiza CONTRIBUIR.md
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-17 11:20:31 -05:00
1bb4af8f16 feat: Se añade wizard de asignación de operarios a la vista
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-16 20:49:00 -05:00
c3ad43d144 Merge branch '6.8' of https://gitea.onecluster.org/OneTeam/trytondo-sale_opportunity_management into 6.8
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-15 22:33:09 -05:00
bc4833b3cf feat: Se crea asistente para asignación de prospectos a operarios 2023-08-15 22:33:02 -05:00
1f52dcba26 chore: Se remueve código muerto 2023-08-15 16:35:44 -05:00
582c8adbd3 chore: se habilita nuevamente actualizador de cambios
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-14 21:44:04 -05:00
ca2d115e22 chore: se adiciona cliente sao 6.8
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
fixes #33
2023-08-14 21:15:53 -05:00
6d77af53ef feat: closed #36
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-14 20:32:49 -05:00
8ab3a97b3c feat: Se admite fecha y hora en llamada pendiente, closed #25
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-14 20:00:41 -05:00
0d1602fe1d chore: closed #21
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-14 19:48:46 -05:00
9b2c40d821 feat: Se hace visible agenda de llamadas en vista tree de prospect_trace, closed #31
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-13 21:05:57 -05:00
d7d5c95b29 chore: Se remueve código muerto luego de refactorizar
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-13 20:35:11 -05:00
1d38d797c5 fix: Un seguimiento a prospecto solo debe tener máximo una llamada agendada, closed #28
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-13 20:31:59 -05:00
452b97cdf9 feat: Se hace prospect_city de solo lectura
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-13 19:31:35 -05:00
87da50560a feat: Se añade vistas de estados
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-08-13 18:58:29 -05:00
52 changed files with 2040 additions and 318 deletions

View File

@@ -1 +1,2 @@
trytond: while true; do trytond -d ${DB_NAME} --dev -v -c $SCRIPT_DIR/trytond.cfg; done
monitor: python3 $SCRIPT_DIR/dev.py

View File

@@ -2,9 +2,12 @@
import sys
import os
import logging
import time
import inotify.adapters
logging.basicConfig(level=logging.INFO, stream=sys.stderr)
SRC = os.environ['SRC']
MODULE_NAME = os.environ['MODULE_NAME']
DB_NAME = os.environ['DB_NAME']
@@ -18,12 +21,17 @@ def _main():
for event in i.event_gen(yield_nones=False):
(_, type_names, path, filename) = event
(_, ext) = os.path.splitext(filename)
if 'IN_CLOSE_WRITE' not in type_names:
continue
if ext in ['.py', '.xml', '.cfg']:
if os.system("trytond-admin -d {} -u {}".format(DB_NAME, MODULE_NAME)) != 0:
print("fallo trytond-admin", file=sys.stderr)
logging.info("ACTUALIZADO TRYTOND POR CAMBIO DE ARCHIVO %s", filename)
for _ in range(0, 10):
if os.system("trytond-admin -d {} -u {}".format(DB_NAME, MODULE_NAME)) != 0:
time.sleep(2)
logging.error("fallo trytond-admin")
else:
logging.info("ACTUALIZADO TRYTOND POR CAMBIO DE ARCHIVO %s", filename)
break
if __name__ == '__main__':

View File

@@ -1,2 +1,3 @@
[web]
listen = 0.0.0.0:8000
root=/var/lib/trytond/www

View File

@@ -1,7 +1,7 @@
#
# variables que puedo usar? https://woodpecker-ci.org/docs/0.15/usage/environment#built-in-environment-variables
pipeline:
steps:
style:
image: python:3.9
commands:
@@ -20,7 +20,7 @@ pipeline:
- python3 -m unittest
notify-success:
image: plugins/matrix
image: gitea.onecluster.org/alnus/plugins/matrix:latest
settings:
home_server: https://matrix.org
roomid: "!oxZmsJwfvciTuLYIwg:matrix.org"

View File

@@ -18,12 +18,14 @@
1. iniciar entorno `rake init`
2. iterar con `rake tdd`
3. detener el entorno `rake down`
4. limpiar cache `git clean -xdf`
### entorno vivo de desarrollo
1. iniciar entorno `rake live:up`
2. conectar cliente tryton a `localhost:8000` usuario: `admin` y clave: `admin`
1. si desea ver la salida de trytond usar `rake live:tail`
1. o bien usar cliente web via `http://localhost:8000`
2. si desea ver la salida de trytond usar `rake live:tail`
3. detener entorno `rake live:down`
### consideraciones

View File

@@ -1,4 +1,16 @@
# TOMADO DE: https://hg.tryton.org/tryton-docker/file/tip/6.6/Dockerfile
FROM node as builder-node
ENV SERIES 6.8
RUN npm install -g bower
RUN curl https://downloads.tryton.org/${SERIES}/tryton-sao-last.tgz | tar zxf - -C /
RUN cd /package && bower install --allow-root
FROM python:3.9-bullseye
# trytond DB_CACHE requiere commandos `pg_dump` y `pg_restore`
RUN apt-get update && apt-get install -y postgresql-client
# TOMADO DE: https://hg.tryton.org/tryton-docker/file/tip/6.6/Dockerfile
COPY --from=builder-node /package /var/lib/trytond/www

View File

@@ -1 +1 @@
doc/index.rst
./tests/scenario_sale_opportunity_management.rst

View File

@@ -12,8 +12,8 @@ end
desc 'poblar entorno'
task :init => [:up] do
pecker = YAML.load_file(WOODPECKER_YML)
['tests', 'style'].each do |pipeline|
pecker.dig('pipeline', pipeline, 'commands').grep(/install/).each do |cmd|
['tests', 'style'].each do |steps|
pecker.dig('steps', steps, 'commands').grep(/install/).each do |cmd|
compose('exec', 'app.dev', cmd)
end
end

View File

@@ -3,6 +3,8 @@ from . import prospect
from . import prospect_trace
from . import call
from . import pending_call
from . import user
from . import print_report_by_operator
from .locations import city
from .locations import department
@@ -11,16 +13,31 @@ __all__ = ['register']
def register():
Pool.register(
user.User,
pending_call.PendingCall,
call.Call,
call.PendingTask,
department.Department,
city.City,
prospect.ContactMethod,
prospect.Prospect,
prospect_trace.ProspectTrace,
prospect.AssignOperatorStart,
prospect_trace.ScheduleCallStart,
prospect_trace.MakeCallStart,
prospect_trace.MakeCallAsk,
prospect_trace.MakeCallAskTask,
prospect.ReassignProspectByOperatorStart,
prospect.ReassignProspectByProspectStart,
print_report_by_operator.PrintReportByOperatorStart,
module='sale_opportunity_management', type_='model')
Pool.register(
prospect_trace.ScheduleCall,
prospect.AssignOperator,
prospect_trace.MakeCall,
prospect.ReassignProspectByOperator,
prospect.ReasignProspectByProspect,
print_report_by_operator.PrintReportByOperator,
module='sale_opportunity_management', type_='wizard')
Pool.register(
module='sale_opportunity_management', type_='report')

80
call.py
View File

@@ -1,7 +1,6 @@
from trytond.model import ModelSQL, ModelView, fields
from trytond.pyson import Eval
from datetime import date
from .selections.interest import Interest
from .selections.call_types import CallTypes
from .selections.call_results import CallResults
@@ -9,28 +8,81 @@ from .selections.call_results import CallResults
class Call(ModelSQL, ModelView):
'Llamada'
__name__ = 'sale.call'
_order_name = 'date'
_states = {'readonly': True}
date = fields.Date('Date')
date = fields.Date('Date', states=_states)
description = fields.Text('Description', strip=True)
prospect_trace = fields.Many2One('sale.prospect_trace', 'Prospect trace')
prospect_trace = fields.Many2One(
'sale.prospect_trace', 'Prospect trace', required=True, states=_states)
interest = fields.Selection(
Interest.get_interest_levels(), 'Interest', required=True)
call_type = fields.Selection(CallTypes.get_call_types(), 'Call type')
call_type = fields.Selection(
CallTypes.get_call_types(), 'Call type', states=_states)
call_result = fields.Selection(
CallResults.get_call_results(), 'Call result')
CallResults.get_call_results(),
'Call result', states=_states)
call_business_unit = fields.Selection(
[('brigade', 'Brigade'),
('optics', 'Optics'),
('equipment', 'Equipment')],
'Business unit', states=_states
)
operator_who_called = fields.Many2One(
'res.user', "Operator who called", states=_states)
@classmethod
def __setup__(cls):
super(Call, cls).__setup__()
cls._order = [
('date', 'DESC NULLS FIRST')
]
@classmethod
def default_date(cls):
return date.today()
@fields.depends('interest', 'call_result')
def on_change_interest(self):
if self.interest:
if self.interest == '0':
self.call_result = 'missed_call'
else:
self.call_result = 'answered_call'
class PendingTask(ModelSQL, ModelView):
'Tarea a realizar a un seguimiento de prospecto'
__name__ = "sale.pending_task"
description = fields.Text(
'Description', required=True,
states={
'readonly': Eval('state') == 'done'
})
state = fields.Selection(
[('pending', 'Pending'),
('done', 'Done')],
'State')
prospect_trace = fields.Many2One(
'sale.prospect_trace', 'Prospect trace',
required=True, readonly=True)
@classmethod
def __setup__(cls):
super(PendingTask, cls).__setup__()
cls._buttons.update({
'close_task': {
'invisible': Eval('state') == 'done'
}
})
@classmethod
@ModelView.button
def close_task(cls, tasks):
for task in tasks:
task.state = 'done'
task.save()
@classmethod
def default_state(cls):
return 'pending'

102
call.xml
View File

@@ -3,11 +3,26 @@
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<record model="res.group" id="group_call">
<field name="name">Calls</field>
</record>
<record model="res.group" id="group_call_admin">
<field name="name">Calls Administrator</field>
<field name="parent" ref="group_call"/>
</record>
<record model="res.user-res.group" id="user_admin_group_call">
<field name="user" ref="res.user_admin"/>
<field name="group" ref="group_call"/>
</record>
<record model="res.user-res.group" id="user_admin_group_call_admin">
<field name="user" ref="res.user_admin"/>
<field name="group" ref="group_call_admin"/>
</record>
<record model="ir.action.act_window" id="act_call_tree">
<field name="name">Calls</field>
<field name="res_model">sale.call</field>
</record>
<record model="ir.ui.view" id="call_view_tree">
<field name="model">sale.call</field>
<field name="type">tree</field>
@@ -18,7 +33,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="type">form</field>
<field name="name">call_form</field>
</record>
<record model="ir.action.act_window.view" id="act_call_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="call_view_tree"/>
@@ -29,15 +43,93 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="call_view_form"/>
<field name="act_window" ref="act_call_tree"/>
</record>
<menuitem
name="Calls"
sequence="10"
id="menu_calls"/>
id="menu_calls"
icon="tryton-phone"/>
<menuitem
parent="menu_calls"
sequence="30"
id="menu_calls_tree"
action="act_call_tree"/>
action="act_call_tree"
icon="tryton-graph"/>
<record model="ir.ui.menu-res.group" id="menu_call_group_call">
<field name="menu" ref="menu_calls_tree"/>
<field name="group" ref="group_call"/>
</record>
<record model="ir.model.access" id="access_calls">
<field name="model" search="[('model', '=', 'sale.call')]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_calls_calls">
<field name="model" search="[('model', '=', 'sale.call')]"/>
<field name="group" ref="group_call"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.action.act_window" id="act_pending_task_tree">
<field name="name">Pending tasks</field>
<field name="res_model">sale.pending_task</field>
</record>
<record model="ir.ui.view" id="pending_task_view_tree">
<field name="model">sale.pending_task</field>
<field name="type">tree</field>
<field name="name">pending_task_tree</field>
</record>
<record model="ir.ui.view" id="pending_task_view_form">
<field name="model">sale.pending_task</field>
<field name="type">form</field>
<field name="name">pending_task_form</field>
</record>
<record model="ir.action.act_window.view" id="act_pending_task_tree_view1">
<field name="sequence" eval="30"/>
<field name="view" ref="pending_task_view_tree"/>
<field name="act_window" ref="act_pending_task_tree"/>
</record>
<record model="ir.action.act_window.view" id="act_pending_task_form_view1">
<field name="sequence" eval="40"/>
<field name="view" ref="pending_task_view_form"/>
<field name="act_window" ref="act_pending_task_tree"/>
</record>
<record model="ir.action.act_window.domain" id="act_task_domain_pending">
<field name="name">Pending</field>
<field name="sequence" eval="10"/>
<field name="domain" eval="[('state', '=', 'pending')]" pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_pending_task_tree"/>
</record>
<record model="ir.action.act_window.domain" id="act_task_domain_done">
<field name="name">Done</field>
<field name="sequence" eval="20"/>
<field name="domain" eval="[('state', '=', 'done')]" pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_pending_task_tree"/>
</record>
<record model="ir.action.act_window.domain" id="act_task_domain_all">
<field name="name">All</field>
<field name="sequence" eval="9999"/>
<field name="domain"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_pending_task_tree"/>
</record>
<menuitem
parent="menu_calls"
sequence="60"
id="menu_pending_tasks"
action="act_pending_task_tree"
icon="tryton-graph"/>
<record model="ir.model.button" id="close_task_button">
<field name="name">close_task</field>
<field name="string">Close task</field>
<field name="model" search="[('model', '=', 'sale.pending_task')]"/>
</record>
</data>
</tryton>

35
icons.xml Normal file
View File

@@ -0,0 +1,35 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<record model="ir.ui.icon" id="party_icon">
<field name="name">tryton-party</field>
<field name="path">icons/tryton-party.svg</field>
</record>
<record model="ir.ui.icon" id="person_icon">
<field name="name">tryton-person</field>
<field name="path">icons/tryton-person.svg</field>
</record>
<record model="ir.ui.icon" id="unnasigned_icon">
<field name="name">tryton-person-negative</field>
<field name="path">icons/tryton-person-negative.svg</field>
</record>
<record model="ir.ui.icon" id="asigned_icon">
<field name="name">tryton-person-positive</field>
<field name="path">icons/tryton-person-positive.svg</field>
</record>
<record model="ir.ui.icon" id="tel_icon">
<field name="name">tryton-tel</field>
<field name="path">icons/tryton-tel.svg</field>
</record>
<record model="ir.ui.icon" id="target_icon">
<field name="name">tryton-target</field>
<field name="path">icons/tryton-target.svg</field>
</record>
<record model="ir.ui.icon" id="call_icon">
<field name="name">tryton-phone</field>
<field name="path">icons/tryton-phone.svg</field>
</record>
</data>
</tryton>

4
icons/tryton-party.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
<path d="M0 0h24v24H0z" fill="none"/>
</svg>

After

Width:  |  Height:  |  Size: 258 B

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>

After

Width:  |  Height:  |  Size: 1.3 KiB

7
icons/tryton-person.svg Normal file
View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>

After

Width:  |  Height:  |  Size: 1.1 KiB

12
icons/tryton-phone.svg Normal file
View File

@@ -0,0 +1,12 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier"> <path d="M15.5562 14.5477L15.1007 15.0272C15.1007 15.0272 14.0181 16.167 11.0631 13.0559C8.10812 9.94484 9.1907 8.80507 9.1907 8.80507L9.47752 8.50311C10.1841 7.75924 10.2507 6.56497 9.63424 5.6931L8.37326 3.90961C7.61028 2.8305 6.13596 2.68795 5.26145 3.60864L3.69185 5.26114C3.25823 5.71766 2.96765 6.30945 3.00289 6.96594C3.09304 8.64546 3.81071 12.259 7.81536 16.4752C12.0621 20.9462 16.0468 21.1239 17.6763 20.9631C18.1917 20.9122 18.6399 20.6343 19.0011 20.254L20.4217 18.7584C21.3806 17.7489 21.1102 16.0182 19.8833 15.312L17.9728 14.2123C17.1672 13.7486 16.1858 13.8848 15.5562 14.5477Z" fill="#267F82"/> <path d="M13.2595 1.87983C13.3257 1.47094 13.7122 1.19357 14.1211 1.25976C14.1464 1.26461 14.2279 1.27983 14.2705 1.28933C14.3559 1.30834 14.4749 1.33759 14.6233 1.38082C14.9201 1.46726 15.3347 1.60967 15.8323 1.8378C16.8286 2.29456 18.1544 3.09356 19.5302 4.46936C20.906 5.84516 21.705 7.17097 22.1617 8.16725C22.3899 8.66487 22.5323 9.07947 22.6187 9.37625C22.6619 9.52466 22.6912 9.64369 22.7102 9.72901C22.7197 9.77168 22.7267 9.80594 22.7315 9.83125L22.7373 9.86245C22.8034 10.2713 22.5286 10.6739 22.1197 10.7401C21.712 10.8061 21.3279 10.53 21.2601 10.1231C21.258 10.1121 21.2522 10.0828 21.2461 10.0551C21.2337 9.9997 21.2124 9.91188 21.1786 9.79572C21.1109 9.56339 20.9934 9.21806 20.7982 8.79238C20.4084 7.94207 19.7074 6.76789 18.4695 5.53002C17.2317 4.29216 16.0575 3.59117 15.2072 3.20134C14.7815 3.00618 14.4362 2.88865 14.2038 2.82097C14.0877 2.78714 13.9417 2.75363 13.8863 2.7413C13.4793 2.67347 13.1935 2.28755 13.2595 1.87983Z" fill="#267F82"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M13.4857 5.3293C13.5995 4.93102 14.0146 4.7004 14.4129 4.81419L14.2069 5.53534C14.4129 4.81419 14.4129 4.81419 14.4129 4.81419L14.4144 4.81461L14.4159 4.81505L14.4192 4.81602L14.427 4.81834L14.4468 4.8245C14.4618 4.82932 14.4807 4.8356 14.5031 4.84357C14.548 4.85951 14.6074 4.88217 14.6802 4.91337C14.8259 4.97581 15.0249 5.07223 15.2695 5.21694C15.7589 5.50662 16.4271 5.9878 17.2121 6.77277C17.9971 7.55775 18.4782 8.22593 18.7679 8.7154C18.9126 8.95991 19.009 9.15897 19.0715 9.30466C19.1027 9.37746 19.1254 9.43682 19.1413 9.48173C19.1493 9.50418 19.1555 9.52301 19.1604 9.53809L19.1665 9.55788L19.1688 9.56563L19.1698 9.56896L19.1702 9.5705C19.1702 9.5705 19.1707 9.57194 18.4495 9.77798L19.1707 9.57194C19.2845 9.97021 19.0538 10.3853 18.6556 10.4991C18.2607 10.6119 17.8492 10.3862 17.7313 9.99413L17.7276 9.98335C17.7223 9.96832 17.7113 9.93874 17.6928 9.89554C17.6558 9.8092 17.5887 9.66797 17.4771 9.47938C17.2541 9.10264 16.8514 8.53339 16.1514 7.83343C15.4515 7.13348 14.8822 6.73078 14.5055 6.50781C14.3169 6.39619 14.1757 6.32909 14.0893 6.29209C14.0461 6.27358 14.0165 6.26254 14.0015 6.25721L13.9907 6.25352C13.5987 6.13564 13.3729 5.72419 13.4857 5.3293Z" fill="#267F82"/> </g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

7
icons/tryton-target.svg Normal file
View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg fill="#267F82" width="800px" height="800px" viewBox="0 0 256 256" id="Flat" xmlns="http://www.w3.org/2000/svg" stroke="#267F82">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>

After

Width:  |  Height:  |  Size: 1.2 KiB

18
icons/tryton-tel.svg Normal file
View File

@@ -0,0 +1,18 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="#267F82">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier">
<path d="M50.19 20.6a3.33 3.33 0 0 0-4.62.8l-1.9 2.71a3.31 3.31 0 0 0 .8 4.61c5.41 3.81 1.59 9.22-.31 11.93S38.44 48.76 33 45a3.31 3.31 0 0 0-4.61.8l-1.91 2.7a3.31 3.31 0 0 0 .8 4.61C34.07 57.83 40 58 49.57 44.46s7.43-19.09.62-23.86z"/>
<rect x="8" y="8" width="6" height="6"/>
<rect x="20" y="8" width="6" height="6"/>
<rect x="32" y="8" width="6" height="6"/>

After

Width:  |  Height:  |  Size: 1.1 KiB

600
locale/es.po Normal file
View File

@@ -0,0 +1,600 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "model:res.group,name:group_prospect"
msgid "Prospects"
msgstr "Prospectos"
msgctxt "model:res.group,name:group_prospect_admin"
msgid "Prospect Administrator"
msgstr "Administración de Prospectos"
msgctxt "model:res.group,name:group_call"
msgid "Calls"
msgstr "Llamadas"
msgctxt "model:res.group,name:group_call_admin"
msgid "Calls Administrator"
msgstr "Administrador de Llamadas"
msgctxt "model:res.group,name:group_prospect_trace"
msgid "Prospect Traces"
msgstr "Seguimiento de Prospectos"
msgctxt "model:res.group,name:group_prospect_trace_admin"
msgid "Traces Administrator"
msgstr "Administración de Seguimientos"
msgctxt "field:res.user,user_admin:"
msgid "Is Admin"
msgstr "Es Administrador"
msgctxt "field:sale.prospect_trace,prospect:"
msgid "Prospect"
msgstr "Prospecto"
msgctxt "field:sale.prospect_trace,prospect_business_unit:"
msgid "Business unit"
msgstr "Unidad de negocio"
msgctxt "field:sale.prospect_trace,prospect_contacts:"
msgid "Prospect contacts"
msgstr "Métodos de contacto"
msgctxt "field:sale.prospect_trace,prospect_city:"
msgid "City"
msgstr "Ciudad"
msgctxt "field:sale.prospect_trace,prospect_assigned_operator:"
msgid "Assigned operator"
msgstr "Operario asignado"
msgctxt "field:sale.prospect_trace,calls:"
msgid "Calls"
msgstr "Llamadas"
msgctxt "field:sale.prospect_trace,pending_call:"
msgid "Pending call"
msgstr "LLamada pendiente"
msgctxt "field:sale.prospect_trace,current_interest:"
msgid "Current interest"
msgstr "Interés actual"
msgctxt "field:sale.prospect_trace,state:"
msgid "State"
msgstr "Estado"
msgctxt "field:sale.prospect,name:"
msgid "Name"
msgstr "Nombre"
msgctxt "field:sale.prospect,business_unit:"
msgid "Business unit"
msgstr "Unidad de negocio"
msgctxt "view:sale.prospect:"
msgid "Contact methods"
msgstr "Métodos de contacto"
msgctxt "view:sale.prospect:"
msgid "About prospect"
msgstr "Tipificación del prospecto"
msgctxt "field:sale.prospect,contact_methods:"
msgid "Contact methods"
msgstr "Métodos de contacto"
msgctxt "field:sale.prospect,department:"
msgid "Department"
msgstr "Departamento"
msgctxt "field:sale.prospect,city:"
msgid "City"
msgstr "Ciudad"
msgctxt "field:sale.prospect,assigned_operator:"
msgid "Assigned operator"
msgstr "Operario asignado"
msgctxt "field:sale.prospect,state:"
msgid "State"
msgstr "Estado"
msgctxt "field:sale.prospect,prospect_trace:"
msgid "Prospect trace"
msgstr "Seguimiento de prospecto"
msgctxt "field:sale.prospect,rating:"
msgid "Rating (1-5)"
msgstr "Calificación (1-5)"
msgctxt "field:sale.prospect,comments:"
msgid "Comments"
msgstr "Comentarios"
msgctxt "field:sale.call,date:"
msgid "Date"
msgstr "Fecha"
msgctxt "field:sale.call,description:"
msgid "Description"
msgstr "Descripción"
msgctxt "field:sale.call,prospect_trace:"
msgid "Prospect trace"
msgstr "Seguimiento de prospecto"
msgctxt "field:sale.call,interest:"
msgid "Interest"
msgstr "Interés"
msgctxt "field:sale.call,call_type:"
msgid "Call type"
msgstr "Tipo"
msgctxt "field:sale.call,call_result:"
msgid "Call result"
msgstr "Resultado"
msgctxt "field:sale.call,call_business_unit:"
msgid "Business unit"
msgstr "Unidad de negocio"
msgctxt "field:sale.call,operator_who_called:"
msgid "Operator who called"
msgstr "Llamado por"
msgctxt "field:sale.pending_call,date:"
msgid "Date"
msgstr "Fecha"
msgctxt "field:prospect.contact_method,contact_type:"
msgid "Contact type"
msgstr "Tipo de contacto"
msgctxt "field:prospect.contact_method,value:"
msgid "Value"
msgstr "Valor"
msgctxt "field:prospect.contact_method,name:"
msgid "Name"
msgstr "Nombre"
msgctxt "field:prospect.contact_method,job:"
msgid "Job"
msgstr "Cargo"
msgctxt "field:prospect.contact_method,prospect:"
msgid "Prospect"
msgstr "Prospecto"
msgctxt "field:prospect.contact_method,prospect_trace:"
msgid "Prospect Trace"
msgstr "Seguimiento de prospecto"
msgctxt "field:sale.prospect.assign.start,prospects_chunk:"
msgid "Prospects chunk"
msgstr "Cantidad de prospectos"
msgctxt "field:sale.prospect.assign.start,operator:"
msgid "Operator"
msgstr "Operador"
msgctxt "field:sale.prospect.assign.start,prospects:"
msgid "Prospects"
msgstr "Prospectos"
msgctxt "field:sale.prospect.assign.start,business_unit:"
msgid "Business unit"
msgstr "Unidad de negocio"
msgctxt "field:sale.prospect.reassign_by_operator.start,current_operator:"
msgid "Current operator"
msgstr "Operador actual"
msgctxt "field:sale.prospect.reassign_by_operator.start,new_operator:"
msgid "New operator"
msgstr "Nuevo operador"
msgctxt "field:sale.prospect.reassign_by_operator.start,prospects:"
msgid "Prospects"
msgstr "Prospectos"
msgctxt "field:sale.prospect.reassign_by_prospect.start,prospect:"
msgid "Prospect"
msgstr "Prospecto"
msgctxt "field:sale.prospect.reassign_by_prospect.start,new_operator:"
msgid "New operator"
msgstr "Nuevo operador"
msgctxt "field:sale.prospect_trace.schedule.start,currency_date:"
msgid "Currency Date"
msgstr "Fecha actual"
msgctxt "field:sale.prospect_trace.schedule.start,date_time:"
msgid "Date time"
msgstr "Fecha y hora"
msgctxt "field:sale.prospect_trace.make_call.start,description:"
msgid "Description"
msgstr "Descripción"
msgctxt "field:sale.prospect_trace.make_call.start,interest:"
msgid "Interest"
msgstr "Interés"
msgctxt "field:sale.prospect_trace.make_call.start,schedule_call:"
msgid "Schedule call?"
msgstr "¿Agendar llamada?"
msgctxt "field:sale.prospect_trace.make_call.ask,currency_date:"
msgid "Currency Date"
msgstr "Fecha actual"
msgctxt "field:sale.prospect_trace.make_call.ask,datetime:"
msgid "Date time"
msgstr "Fecha y hora"
msgctxt "field:sale.pending_task,description:"
msgid "Description"
msgstr "Descripción"
msgctxt "field:sale.pending_task,prospect_trace:"
msgid "Prospect trace"
msgstr "Seguimiento de prospecto"
msgctxt "field:sale.prospect_trace.make_call.start,schedule_task:"
msgid "Schedule task?"
msgstr "¿Agendar tarea?"
msgctxt "field:sale.prospect_trace.make_call.ask_task,task_description:"
msgid "Task description"
msgstr "Descripción de la tarea"
msgctxt "selection:sale.prospect,business_unit:"
msgid "Brigade"
msgstr "Brigada"
msgctxt "selection:sale.prospect,business_unit:"
msgid "Optics"
msgstr "Óptica"
msgctxt "selection:sale.prospect,business_unit:"
msgid "Equipment"
msgstr "Equipos"
msgctxt "selection:sale.prospect,state:"
msgid "Unsassigned"
msgstr "Sin asignar"
msgctxt "selection:sale.prospect,state:"
msgid "Assigned"
msgstr "Asignado"
msgctxt "selection:prospect.contact_method,contact_type:"
msgid "Phone"
msgstr "Teléfono fijo"
msgctxt "selection:prospect.contact_method,contact_type:"
msgid "Mobile"
msgstr "Celular"
msgctxt "selection:prospect.contact_method,contact_type:"
msgid "Mail"
msgstr "Correo electrónico"
msgctxt "selection:sale.prospect,rating:"
msgid "None"
msgstr "Sin calificación"
msgctxt "selection:sale.prospect.assign.start,business_unit:"
msgid "Brigade"
msgstr "Brigada"
msgctxt "selection:sale.prospect.assign.start,business_unit:"
msgid "Optics"
msgstr "Óptica"
msgctxt "selection:sale.prospect.assign.start,business_unit:"
msgid "Equipment"
msgstr "Equipos"
msgctxt "selection:sale.prospect_trace,prospect_business_unit:"
msgid "Brigade"
msgstr "Brigada"
msgctxt "selection:sale.prospect_trace,prospect_business_unit:"
msgid "Optics"
msgstr "Óptica"
msgctxt "selection:sale.prospect_trace,prospect_business_unit:"
msgid "Equipment"
msgstr "Equipos"
msgctxt "selection:sale.prospect_trace,current_interest:"
msgid "0 - Not answered"
msgstr "0 - No contestó"
msgctxt "selection:sale.prospect_trace,current_interest:"
msgid "1 - Complete disinterest"
msgstr "1 - Completo desinterés"
msgctxt "selection:sale.prospect_trace,current_interest:"
msgid "2 - Middle interest"
msgstr "2 - Interés intermedio"
msgctxt "selection:sale.prospect_trace,current_interest:"
msgid "3 - High interest"
msgstr "3 - Interés alto"
msgctxt "selection:sale.prospect_trace,current_interest:"
msgid "4 - Closed sale"
msgstr "4 - Venta cerrada"
msgctxt "selection:sale.prospect_trace,state:"
msgid "Open"
msgstr "Abierto"
msgctxt "selection:sale.prospect_trace,state:"
msgid "With pending calls"
msgstr "Con llamada pendiente"
msgctxt "selection:sale.prospect_trace,state:"
msgid "Closed"
msgstr "Cerrado"
msgctxt "selection:sale.prospect_trace.make_call.start,schedule_call:"
msgid "Yes"
msgstr "Si"
msgctxt "selection:sale.prospect_trace.make_call.start,interest:"
msgid "0 - Not answered"
msgstr "0 - No contestó"
msgctxt "selection:sale.prospect_trace.make_call.start,interest:"
msgid "1 - Complete disinterest"
msgstr "1 - Completo desinterés"
msgctxt "selection:sale.prospect_trace.make_call.start,interest:"
msgid "2 - Middle interest"
msgstr "2 - Interés intermedio"
msgctxt "selection:sale.prospect_trace.make_call.start,interest:"
msgid "3 - High interest"
msgstr "3 - Interés alto"
msgctxt "selection:sale.prospect_trace.make_call.start,interest:"
msgid "4 - Closed sale"
msgstr "4 - Venta cerrada"
msgctxt "selection:sale.call,interest:"
msgid "0 - Not answered"
msgstr "0 - No contestó"
msgctxt "selection:sale.call,interest:"
msgid "1 - Complete disinterest"
msgstr "1 - Completo desinterés"
msgctxt "selection:sale.call,interest:"
msgid "2 - Middle interest"
msgstr "2 - Interés intermedio"
msgctxt "selection:sale.call,interest:"
msgid "3 - High interest"
msgstr "3 - Interés alto"
msgctxt "selection:sale.call,interest:"
msgid "4 - Closed sale"
msgstr "4 - Venta cerrada"
msgctxt "selection:sale.call,call_type:"
msgid "First call"
msgstr "Primera llamada"
msgctxt "selection:sale.call,call_type:"
msgid "Follow up call"
msgstr "LLamada de seguimiento"
msgctxt "selection:sale.call,call_result:"
msgid "Missed call"
msgstr "Llamada perdida"
msgctxt "selection:sale.call,call_result:"
msgid "Answered call"
msgstr "LLamada contestada"
msgctxt "selection:sale.call,call_business_unit:"
msgid "Brigade"
msgstr "Brigada"
msgctxt "selection:sale.call,call_business_unit:"
msgid "Optics"
msgstr "Óptica"
msgctxt "selection:sale.call,call_business_unit:"
msgid "Equipment"
msgstr "Equipos"
msgctxt "selection:sale.prospect_trace.make_call.start,schedule_task:"
msgid "Yes"
msgstr "Si"
msgctxt "model:ir.ui.menu,name:menu_calls"
msgid "Calls"
msgstr "Llamadas"
msgctxt "model:ir.ui.menu,name:menu_calls_tree"
msgid "Calls"
msgstr "Llamadas"
msgctxt "model:ir.ui.menu,name:menu_prospect_trace_tree"
msgid "Prospect Traces"
msgstr "Seguimiento de Prospectos"
msgctxt "model:ir.ui.menu,name:menu_prospects_tree"
msgid "Prospects"
msgstr "Prospectos"
msgctxt "model:ir.ui.menu,name:menu_prospects_assigned_wizard"
msgid "Assign Operator"
msgstr "Asignar Operador"
msgctxt "model:ir.ui.menu,name:menu_reassign"
msgid "Reassign"
msgstr "Reasignar"
msgctxt "model:ir.ui.menu,name:menu_reassign_by_operator_wizard"
msgid "Reassign by operator"
msgstr "Reasignar por operador"
msgctxt "model:ir.ui.menu,name:menu_reassign_by_prospect_wizard"
msgid "Reassign by prospect"
msgstr "Reasignar por prospecto"
msgctxt "model:ir.ui.menu,name:menu_pending_tasks"
msgid "Pending tasks"
msgstr "Tareas pendientes"
msgctxt "model:ir.model.button,string:schedule_call_wizard_button"
msgid "Schedule call"
msgstr "Agendar llamada"
msgctxt "model:ir.model.button,string:make_call_wizard_button"
msgid "Make call"
msgstr "Hacer llamada"
msgctxt "model:ir.model.button,string:close_trace_button"
msgid "Close trace"
msgstr "Cerrar seguimiento"
msgctxt "model:ir.model.button,string:reopen_trace_button"
msgid "Reopen trace"
msgstr "Reabrir seguimiento"
msgctxt "model:ir.model.button,string:close_task_button"
msgid "Close task"
msgstr "Cerrar tarea"
msgctxt "wizard_button:sale.prospect_trace.make_call,start,end:"
msgid "Cancel"
msgstr "Cancelar"
msgctxt "wizard_button:sale.prospect_trace.make_call,start,make_call:"
msgid "Make call"
msgstr "Hacer llamada"
msgctxt "wizard_button:sale.prospect_trace.make_call,ask,end:"
msgid "Cancel"
msgstr "Cancelar"
msgctxt "wizard_button:sale.prospect_trace.make_call,ask,schedule_call:"
msgid "Schedule call"
msgstr "Agendar llamada"
msgctxt "wizard_button:sale.prospect_trace.schedule,start,end:"
msgid "Cancel"
msgstr "Cancelar"
msgctxt "wizard_button:sale.prospect_trace.schedule,start,schedule:"
msgid "Schedule"
msgstr "Agendar llamada"
msgctxt "wizard_button:sale.prospect_trace.make_call,ask_task,end:"
msgid "Cancel"
msgstr "Cancelar"
msgctxt "wizard_button:sale.prospect_trace.make_call,ask_task,schedule_task:"
msgid "Schedule task"
msgstr "Agendar tarea"
msgctxt "wizard_button:sale.prospect.assign,start,end:"
msgid "Cancel"
msgstr "Cancelar"
msgctxt "wizard_button:sale.prospect.assign,start,assign:"
msgid "Assign"
msgstr "Asignar"
msgctxt "wizard_button:sale.prospect.reassign_by_operator,start,end:"
msgid "Cancel"
msgstr "Cancelar"
msgctxt "wizard_button:sale.prospect.reassign_by_operator,start,reassign_by_operator:"
msgid "Reassign"
msgstr "Reasignar"
msgctxt "wizard_button:sale.prospect.reassign_by_prospect,start,end:"
msgid "Cancel"
msgstr "Cancelar"
msgctxt "wizard_button:sale.prospect.reassign_by_prospect,start,reassign_by_prospect:"
msgid "Reassign"
msgstr "Reasignar"
msgctxt "model:ir.action.act_window.domain,name:act_prospect_trace_domain_open"
msgid "Open"
msgstr "Abierto"
msgctxt "model:ir.action.act_window.domain,name:act_prospect_trace_domain_with_pending_calls"
msgid "With pending calls"
msgstr "Con llamada pendiente"
msgctxt "model:ir.action.act_window.domain,name:act_prospect_trace_domain_with_pending_calls"
msgid "With pending calls"
msgstr "Con llamada pendiente"
msgctxt "model:ir.action.act_window.domain,name:act_prospect_trace_domain_closed"
msgid "Closed"
msgstr "Cerrado"
msgctxt "model:ir.action.act_window.domain,name:act_prospect_trace_domain_all"
msgid "All"
msgstr "Todo"
msgctxt "model:ir.action.act_window.domain,name:act_prospect_domain_unassigned"
msgid "Unassigned"
msgstr "Sin asignar"
msgctxt "model:ir.action.act_window.domain,name:act_prospect_domain_assigned"
msgid "Assigned"
msgstr "Asignado"
msgctxt "model:ir.action.act_window.domain,name:act_task_domain_pending"
msgid "Pending"
msgstr "Pendiente"
msgctxt "model:ir.action.act_window.domain,name:act_task_domain_done"
msgid "Done"
msgstr "Completado"
msgctxt "model:ir.action.act_window.domain,name:act_task_domain_all"
msgid "All"
msgstr "Todo"
msgctxt "model:ir.action,name:schedule_call_wizard"
msgid "Schedule call"
msgstr "Agendar llamada"
msgctxt "model:ir.action,name:make_call_wizard"
msgid "Make call"
msgstr "Hacer llamada"
msgctxt "model:ir.action,name:assign_operator_wizard"
msgid "Assign Operator"
msgstr "Asignar operador"
msgctxt "model:ir.action,name:reassign_by_operator_wizard"
msgid "Reassign by operator"
msgstr "Reasignar por operador"
msgctxt "model:ir.action,name:reassign_by_prospect_wizard"
msgid "Reassign by prospect"
msgstr "Reasignar por prospecto"

View File

@@ -7,5 +7,8 @@ class PendingCall(ModelSQL, ModelView):
'Llamada pendiente a un prospecto'
__name__ = "sale.pending_call"
date = fields.Date('Date', required=True)
prospect_trace = fields.Many2One('sale.prospect_trace', 'Prospect trace')
date = fields.DateTime('Date', required=True)
def get_rec_name(self, name):
if self.date:
return str(self.date)

View File

@@ -1,43 +0,0 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<record model="ir.action.act_window" id="act_pending_call_tree">
<field name="name">Pending calls</field>
<field name="res_model">sale.pending_call</field>
</record>
<record model="ir.ui.view" id="pending_call_view_tree">
<field name="model">sale.pending_call</field>
<field name="type">tree</field>
<field name="name">pending_call_tree</field>
</record>
<record model="ir.ui.view" id="pending_call_view_form">
<field name="model">sale.pending_call</field>
<field name="type">form</field>
<field name="name">pending_call_form</field>
</record>
<record model="ir.action.act_window.view" id="act_pending_call_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="pending_call_view_tree"/>
<field name="act_window" ref="act_pending_call_tree"/>
</record>
<record model="ir.action.act_window.view" id="act_pending_call_form_view1">
<field name="sequence" eval="20"/>
<field name="view" ref="pending_call_view_form"/>
<field name="act_window" ref="act_pending_call_tree"/>
</record>
<!-- <menuitem
name="Calls"
sequence="10"
id="menu_calls"/> -->
<menuitem
parent="menu_calls"
sequence="40"
id="menu_pending_calls_tree"
action="act_pending_call_tree"/>
</data>
</tryton>

View File

@@ -0,0 +1,24 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
# from trytond.model import ModelSQL, ModelView, fields
from trytond.wizard import Wizard, StateView, Button # , StateReport
from trytond.model import fields, ModelView
class PrintReportByOperatorStart(ModelView):
'Vista inicial de reporte por operario'
__name__ = 'sale.print_report_by_operator.start'
start_date = fields.Date('Start date')
end_date = fields.Date('End date')
class PrintReportByOperator(Wizard):
'Generar reporte por operario'
__name__ = 'sale.print_report_by_operator'
start = StateView(
'sale.print_report_by_operator.start',
'sale_opportunity_management.print_report_by_operator_start_view_form',
[Button("Cancel", "end", "tryton-cancel"),
Button("Print Report", "print_report", "tryton-ok", default=True)])

View File

@@ -0,0 +1,16 @@
<!-- <?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<record model="ir.action.wizard" id="print_report_by_operator_wizard">
<field name="name">Print report by operator</field>
<field name="wiz_name">sale.print_report_by_operator</field>
</record>
<record model="ir.ui.view" id="print_report_by_operator_start_view_form">
<field name="model">sale.print_report_by_operator.start</field>
<field name="type">form</field>
<field name="name">print_report_by_operator_start_form</field>
</record>
<data>
<tryton/> -->

View File

@@ -1,16 +1,25 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
from trytond.wizard import Wizard, StateView, Button, StateTransition
from trytond.model import ModelSQL, ModelView, fields, DeactivableMixin
from trytond.pyson import Eval, If
from trytond.pool import Pool
class Prospect(ModelSQL, ModelView):
class Prospect(ModelSQL, ModelView, DeactivableMixin):
'Prospecto'
__name__ = 'sale.prospect'
_rec_name = 'name'
name = fields.Char('Name', required=True)
business_unit = fields.Selection(
[('brigade', 'Brigade'),
('optics', 'Optics'),
('equipment', 'Equipment')],
'Business unit', required=True
)
contact_methods = fields.One2Many(
'prospect.contact_method',
'prospect', 'Contact methods', required=True)
@@ -20,12 +29,24 @@ class Prospect(ModelSQL, ModelView):
domain=[If(Eval('department'),
('parent', '=', Eval('department')))])
assigned_operator = fields.Many2One('res.user', "Assigned operator")
assigned_operator = fields.Many2One(
'res.user', "Assigned operator", readonly=True)
state = fields.Selection([
('unassigned', 'Unsassigned'),
('assigned', 'Assigned')], "State", readonly=True)
prospect_trace = fields.Many2One('sale.prospect_trace', 'Prospect trace')
rating = fields.Selection(
[(None, None),
('1', '1'),
('2', '2'),
('3', '3'),
('4', '4'),
('5', '5')], 'Rating (1-5)')
comments = fields.Text('Comments')
@classmethod
def default_state(cls):
return 'unassigned'
@@ -35,13 +56,6 @@ class Prospect(ModelSQL, ModelView):
if self.city:
self.department = self.city.parent
@fields.depends('assigned_operator', 'state')
def on_change_assigned_operator(self):
if self.assigned_operator:
self.state = 'assigned'
else:
self.state = 'unassigned'
class ContactMethod(ModelSQL, ModelView):
'Mecanismo de contacto'
@@ -55,9 +69,11 @@ class ContactMethod(ModelSQL, ModelView):
value = fields.Char('Value', required=True)
name = fields.Char('Name')
job = fields.Char('job')
job = fields.Char('Job')
prospect = fields.Many2One('sale.prospect', 'Prospect', required=True)
prospect_trace = fields.Many2One(
'sale.prospect_trace', 'Prospect Trace', required=False)
@classmethod
def default_contact_type(cls):
@@ -72,3 +88,173 @@ class ContactMethod(ModelSQL, ModelView):
contact_rec_name += ' [' + str(field) + '] '
return contact_rec_name
class AssignOperatorStart(ModelView):
'Inicio de asignación de operador'
__name__ = 'sale.prospect.assign.start'
prospects_chunk = fields.Integer(
'Prospects chunk', required=True,
states={
'readonly': ~Eval('business_unit', False)})
operator = fields.Many2One('res.user', 'Operator', required=True)
prospects = fields.One2Many(
'sale.prospect', None, 'Prospects', readonly=True)
business_unit = fields.Selection(
[('brigade', 'Brigade'),
('optics', 'Optics'),
('equipment', 'Equipment')],
'Business unit',
states={
'readonly': Eval('prospects_chunk', False)}
)
@classmethod
def default_prospects_chunk(cls):
return 0
@fields.depends('prospects_chunk', 'prospects', 'business_unit')
def on_change_prospects_chunk(self):
pool = Pool()
Prospect = pool.get('sale.prospect')
if self.prospects_chunk >= 1:
self.prospects = []
self.prospects = Prospect.search(
[('state', '=', 'unassigned'),
('business_unit', '=', self.business_unit)],
limit=self.prospects_chunk)
class AssignOperator(Wizard):
'Asignar operador a prospecto'
__name__ = 'sale.prospect.assign'
start = StateView(
'sale.prospect.assign.start',
'sale_opportunity_management.assign_start_view_form', [
Button("Cancel", 'end', 'tryton-cancel'),
Button("Assign", 'assign', 'tryton-ok', default=True)])
assign = StateTransition()
def transition_assign(self):
pool = Pool()
ProspectTrace = pool.get('sale.prospect_trace')
for prospect in self.start.prospects:
prospect.assigned_operator = self.start.operator
prospect.state = 'assigned'
prospect.save()
prospect_trace = ProspectTrace(
prospect=prospect,
prospect_city=prospect.city,
prospect_business_unit=prospect.business_unit,
prospect_assigned_operator=prospect.assigned_operator,
prospect_contacts=prospect.contact_methods
)
prospect_trace.save()
prospect.prospect_trace = prospect_trace
prospect.save()
return 'end'
class ReassignProspectByOperatorStart(ModelView):
'Inicio de reasignación de prospecto por operario'
__name__ = 'sale.prospect.reassign_by_operator.start'
current_operator = fields.Many2One(
'res.user', "Current operator", required=True)
new_operator = fields.Many2One(
'res.user', "New operator", required=True)
prospects = fields.One2Many(
'sale.prospect', None, 'Prospects', readonly=True)
@fields.depends('current_operator', 'prospects')
def on_change_current_operator(self):
pool = Pool()
Prospect = pool.get('sale.prospect')
self.prospects = []
self.prospects = Prospect.search(
[('state', '=', 'assigned'),
('assigned_operator', '=', self.current_operator)])
class ReassignProspectByOperator(Wizard):
'Reasignar todos los prospectos de un operario, a otro operario'
__name__ = 'sale.prospect.reassign_by_operator'
start = StateView(
'sale.prospect.reassign_by_operator.start',
'sale_opportunity_management.reassign_by_operator_start_view_form',
[Button("Cancel", 'end', 'tryton-cancel'),
Button("Reassign", 'reassign_by_operator', 'tryton-ok', default=True)
])
reassign_by_operator = StateTransition()
def transition_reassign_by_operator(self):
pool = Pool()
ProspectTrace = pool.get('sale.prospect_trace')
for prospect in self.start.prospects:
prospect.assigned_operator = self.start.new_operator
if prospect.prospect_trace:
prospect_trace, = ProspectTrace.search(
[('prospect', '=', prospect)])
prospect_trace.prospect_assigned_operator =\
self.start.new_operator
prospect_trace.save()
prospect.save()
return 'end'
class ReassignProspectByProspectStart(ModelView):
'Inicio de reasignación de un prospecto en específico'
__name__ = 'sale.prospect.reassign_by_prospect.start'
prospect = fields.Many2One(
'sale.prospect', 'Prospect', required=True,
domain=[('assigned_operator', '!=', None)])
new_operator = fields.Many2One('res.user', "New operator", required=True)
class ReasignProspectByProspect(Wizard):
'Reasignar un prospecto en específico a un nuevo operario'
__name__ = 'sale.prospect.reassign_by_prospect'
start = StateView(
'sale.prospect.reassign_by_prospect.start',
'sale_opportunity_management.reassign_by_prospect_start_view_form',
[Button("Cancel", 'end', 'tryton-cancel'),
Button("Reassign", 'reassign_by_prospect', 'tryton-ok', default=True)
])
reassign_by_prospect = StateTransition()
def transition_reassign_by_prospect(self):
pool = Pool()
ProspectTrace = pool.get('sale.prospect_trace')
self.start.prospect.assigned_operator = self.start.new_operator
if self.start.prospect.prospect_trace:
prospect_trace, = ProspectTrace.search(
[('prospect', '=', self.start.prospect)])
prospect_trace.prospect_assigned_operator =\
self.start.new_operator
prospect_trace.save()
self.start.prospect.save()
return 'end'

View File

@@ -3,11 +3,29 @@
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<record model="ir.action.act_window" id="act_prospect_tree">
<field name="name">Prospects</field>
<field name="res_model">sale.prospect</field>
<record model="res.group" id="group_prospect">
<field name="name">Prospects</field>
</record>
<record model="res.group" id="group_prospect_admin">
<field name="name">Prospect Administrator</field>
<field name="parent" ref="group_prospect"/>
</record>
<record model="res.user-res.group" id="user_admin_group_prospect">
<field name="user" ref="res.user_admin"/>
<field name="group" ref="group_prospect"/>
</record>
<record model="res.user-res.group" id="user_admin_group_prospect_admin">
<field name="user" ref="res.user_admin"/>
<field name="group" ref="group_prospect_admin"/>
</record>
<record model="ir.action.act_window" id="act_prospect_tree">
<field name="name">Prospects</field>
<field name="domain"
eval="[If(Eval('context', {}).get('user_admin', None), (), ('assigned_operator', '=', Eval('_user')))]"
pyson="1"/>
<field name="res_model">sale.prospect</field>
</record>
<record model="ir.ui.view" id="prospect_view_tree">
<field name="model">sale.prospect</field>
<field name="type">tree</field>
@@ -18,7 +36,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="type">form</field>
<field name="name">prospect_form</field>
</record>
<record model="ir.action.act_window.view" id="act_prospect_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="prospect_view_tree"/>
@@ -29,86 +46,36 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="prospect_view_form"/>
<field name="act_window" ref="act_prospect_tree"/>
</record>
<record model="ir.action.act_window.domain" id="act_prospect_domain_unassigned">
<field name="name">Unassigned</field>
<field name="sequence" eval="10"/>
<field name="domain" eval="[('state', '=', 'unassigned')]" pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_prospect_tree"/>
</record>
<record model="ir.action.act_window.domain" id="act_prospect_domain_assigned">
<field name="name">Assigned</field>
<field name="sequence" eval="10"/>
<field name="domain" eval="[('state', '=', 'assigned')]" pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_prospect_tree"/>
</record>
<menuitem
parent="menu_calls"
sequence="10"
id="menu_prospects_tree"
icon="tryton-party"
action="act_prospect_tree"/>
<record model="ir.action.act_window" id="act_prospect_unassigned_tree">
<field name="name">Unassigned</field>
<field name="res_model">sale.prospect</field>
<field name="domain" eval="[('state', '=', 'unassigned')]" pyson="1"/>
<record model="ir.ui.menu-res.group" id="menu_prospects_group_prospect">
<field name="menu" ref="menu_prospects_tree"/>
<field name="group" ref="group_prospect"/>
</record>
<record model="ir.ui.view" id="prospect_unassigned_view_tree">
<field name="model">sale.prospect</field>
<field name="type">tree</field>
<field name="name">prospect_tree</field>
</record>
<record model="ir.ui.view" id="prospect_unassigned_view_form">
<field name="model">sale.prospect</field>
<field name="type">form</field>
<field name="name">prospect_form</field>
</record>
<record model="ir.action.act_window.view" id="act_prospect_unassigned_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="prospect_unassigned_view_tree"/>
<field name="act_window" ref="act_prospect_unassigned_tree"/>
</record>
<record model="ir.action.act_window.view" id="act_prospect_unassigned_form_view1">
<field name="sequence" eval="20"/>
<field name="view" ref="prospect_view_form"/>
<field name="act_window" ref="act_prospect_unassigned_tree"/>
</record>
<menuitem
parent="menu_prospects_tree"
sequence="10"
id="menu_prospects_unassigned_tree"
action="act_prospect_unassigned_tree"/>
<record model="ir.action.act_window" id="act_prospect_assigned_tree">
<field name="name">Assigned</field>
<field name="res_model">sale.prospect</field>
<field name="domain" eval="[('state', '=', 'assigned')]" pyson="1"/>
</record>
<record model="ir.ui.view" id="prospect_assigned_view_tree">
<field name="model">sale.prospect</field>
<field name="type">tree</field>
<field name="name">prospect_tree</field>
</record>
<record model="ir.ui.view" id="prospect_assigned_view_form">
<field name="model">sale.prospect</field>
<field name="type">form</field>
<field name="name">prospect_form</field>
</record>
<record model="ir.action.act_window.view" id="act_prospect_assigned_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="prospect_assigned_view_tree"/>
<field name="act_window" ref="act_prospect_assigned_tree"/>
</record>
<record model="ir.action.act_window.view" id="act_prospect_assigned_form_view1">
<field name="sequence" eval="20"/>
<field name="view" ref="prospect_view_form"/>
<field name="act_window" ref="act_prospect_assigned_tree"/>
</record>
<menuitem
parent="menu_prospects_tree"
sequence="10"
id="menu_prospects_assigned_tree"
action="act_prospect_assigned_tree"/>
<record model="ir.action.act_window" id="act_contact_method_tree">
<field name="name">Contact method</field>
<field name="res_model">prospect.contact_method</field>
</record>
<record model="ir.ui.view" id="contact_method_view_tree">
<field name="model">prospect.contact_method</field>
<field name="type">tree</field>
@@ -119,7 +86,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="type">form</field>
<field name="name">contact_method_form</field>
</record>
<record model="ir.action.act_window.view" id="act_contact_method_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="contact_method_view_tree"/>
@@ -130,5 +96,90 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="contact_method_view_form"/>
<field name="act_window" ref="act_contact_method_tree"/>
</record>
</data>
<record model="ir.action.wizard" id="assign_operator_wizard">
<field name="name">Assign Operator</field>
<field name="wiz_name">sale.prospect.assign</field>
</record>
<record model="ir.ui.view" id="assign_start_view_form">
<field name="model">sale.prospect.assign.start</field>
<field name="type">form</field>
<field name="name">assign_start_form</field>
</record>
<record model="ir.action.keyword" id="assign_operator_wizard_keyword">
<field name="keyword">form_action</field>
<field name="model">sale.prospect, -1</field>
<field name="action" ref="assign_operator_wizard"/>
</record>
<menuitem
parent="menu_prospects_tree"
sequence="40"
id="menu_prospects_assigned_wizard"
action="assign_operator_wizard"/>
<record model="ir.ui.menu-res.group" id="menu_prospect_assigned_group_prospect">
<field name="menu" ref="menu_prospects_assigned_wizard"/>
<field name="group" ref="group_prospect_admin"/>
</record>
<record model="ir.action.wizard" id="reassign_by_operator_wizard">
<field name="name">Reassign by operator</field>
<field name="wiz_name">sale.prospect.reassign_by_operator</field>
</record>
<record model="ir.ui.view" id="reassign_by_operator_start_view_form">
<field name="model">sale.prospect.reassign_by_operator.start</field>
<field name="type">form</field>
<field name="name">reassign_by_operator_form</field>
</record>
<menuitem
name="Reassign"
parent="menu_prospects_tree"
sequence="50"
id="menu_reassign"
icon='tryton-refresh'/>
<record model="ir.ui.menu-res.group" id="menu_prospect_reassigned_group_prospect">
<field name="menu" ref="menu_reassign"/>
<field name="group" ref="group_prospect_admin"/>
</record>
<menuitem
parent="menu_reassign"
sequence="10"
id="menu_reassign_by_operator_wizard"
action="reassign_by_operator_wizard"/>
<record model="ir.action.wizard" id="reassign_by_prospect_wizard">
<field name="name">Reassign by prospect</field>
<field name="wiz_name">sale.prospect.reassign_by_prospect</field>
</record>
<record model="ir.ui.view" id="reassign_by_prospect_start_view_form">
<field name="model">sale.prospect.reassign_by_prospect.start</field>
<field name="type">form</field>
<field name="name">reassign_by_prospect_form</field>
</record>
<menuitem
parent="menu_reassign"
sequence="20"
id="menu_reassign_by_prospect_wizard"
action="reassign_by_prospect_wizard"/>
<record model="ir.model.access" id="access_sale">
<field name="model" search="[('model', '=', 'sale.prospect')]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_sale_prospect">
<field name="model" search="[('model', '=', 'sale.prospect')]"/>
<field name="group" ref="group_prospect"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
</data>
</tryton>

View File

@@ -1,92 +1,278 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields, DeactivableMixin
from trytond.wizard import Wizard, StateView, Button, StateTransition
from trytond.model import ModelSQL, ModelView, fields
from trytond.pool import Pool
from trytond.pyson import Eval
from .selections.call_types import CallTypes
from .selections.interest import Interest
from datetime import datetime
class ProspectTrace(DeactivableMixin, ModelSQL, ModelView):
class ProspectTrace(ModelSQL, ModelView):
'Seguimiento de un prospecto'
__name__ = 'sale.prospect_trace'
prospect = fields.Many2One('sale.prospect', 'Prospect', required=True)
prospect_contact = fields.Many2One(
'prospect.contact_method', 'Contact method')
prospect_city = fields.Many2One('sale.city', 'City')
_states = {'readonly': True}
calls = fields.One2Many('sale.call', 'prospect_trace', 'Calls')
pending_calls = fields.One2Many(
'sale.pending_call', 'prospect_trace', 'Pending calls')
prospect = fields.Many2One(
'sale.prospect', 'Prospect', required=True, states=_states)
prospect_business_unit = fields.Selection(
[('brigade', 'Brigade'),
('optics', 'Optics'),
('equipment', 'Equipment')],
'Business unit', states=_states
)
prospect_contacts = fields.One2Many(
'prospect.contact_method', 'prospect_trace',
'Prospect contacts', required=True)
prospect_city = fields.Many2One('sale.city', 'City',
states=_states)
prospect_assigned_operator = fields.Many2One(
'res.user', "Assigned operator", states=_states)
calls = fields.One2Many(
'sale.call', 'prospect_trace', 'Calls', states=_states)
pending_call = fields.Many2One(
'sale.pending_call', 'Pending call', states=_states)
current_interest = fields.Selection(
Interest.get_interest_levels(), 'Current interest')
Interest.get_interest_levels(), 'Current interest',
states=_states)
state = fields.Selection([
('unassigned', 'Unassigned'),
('open', 'Open'),
('with_pending_calls', 'With pending calls'),
('closed', 'Closed')
], 'State')
], 'State',
states=_states)
@fields.depends('prospect_contacts', 'prospect')
def on_change_prospect_contacts(self):
for contact in self.prospect_contacts:
contact.prospect = self.prospect
@classmethod
def __setup__(cls):
super(ProspectTrace, cls).__setup__()
cls._buttons.update({
'wizard_schedule': {
'invisible': Eval('state') == 'with_pending_calls',
},
'wizard_make_call': {},
'close_trace': {
'invisible': Eval('state') == 'closed',
'depends': ['state']
},
'reopen_trace': {
'invisible': (Eval('state') == 'open')
| (Eval('state') == 'with_pending_calls'),
'depends': ['state']
}
})
@classmethod
def default_state(cls):
return 'open'
@fields.depends('calls', 'pending_calls', 'current_interest')
def on_change_calls(self):
if not self.calls:
return
@classmethod
@ModelView.button_action(
'sale_opportunity_management.schedule_call_wizard')
def wizard_schedule(cls, prospect_traces):
pass
last_call = self.calls[-1]
self.current_interest = last_call.interest
@classmethod
@ModelView.button_action(
'sale_opportunity_management.make_call_wizard')
def wizard_make_call(cls, prospect_traces):
pass
already_exist_a_call = len(self.calls) > 1
if already_exist_a_call:
followup_call_type = CallTypes.get_call_types()[1][0]
last_call.call_type = followup_call_type
else:
first_call_type = CallTypes.get_call_types()[0][0]
last_call.call_type = first_call_type
@classmethod
@ModelView.button
def close_trace(cls, prospect_traces):
for prospect_trace in prospect_traces:
prospect_trace.state = 'closed'
prospect_trace.save()
there_is_a_pending_call = len(self.pending_calls) >= 1
if there_is_a_pending_call:
self.pending_calls = None
self.state = 'open'
@fields.depends('pending_calls', 'state')
def on_change_pending_calls(self):
if len(self.pending_calls) >= 1:
self.state = 'with_pending_calls'
@fields.depends('prospect')
def on_change_prospect(self):
if not self.prospect:
return
self.prospect_city = self.prospect.city
mobile_contact = self._get_prospect_mobile_contact()
if mobile_contact:
self.prospect_contact = mobile_contact
@classmethod
@ModelView.button
def reopen_trace(cls, prospect_traces):
for prospect_trace in prospect_traces:
prospect_trace.state = 'open'
prospect_trace.save()
def get_rec_name(self, name):
if self.prospect:
return '[' + str(self.id) + '] ' + self.prospect.name
def _get_current_interest(self, name):
if self.calls:
return self.calls[-1].interest
def _get_prospect_mobile_contact(self):
class ScheduleCallStart(ModelView):
'Inicio agendar llamada a seguimiento de prospecto'
__name__ = 'sale.prospect_trace.schedule.start'
currency_date = fields.DateTime('Currency Date', readonly=True)
date_time = fields.DateTime('Date time', domain=[
('date_time', '>=', Eval('currency_date'))])
@classmethod
def default_currency_date(cls):
date = datetime.now()
return date
class ScheduleCall(Wizard):
'Agendar llamada a seguimiento de prospecto'
__name__ = 'sale.prospect_trace.schedule'
start = StateView(
'sale.prospect_trace.schedule.start',
'sale_opportunity_management.schedule_start_view_form', [
Button("Cancel", 'end', 'tryton-cancel'),
Button("Schedule", 'schedule', 'tryton-ok', default=True)])
schedule = StateTransition()
def transition_schedule(self):
MakeCall.create_schedule_call(self.start.date_time, self.record)
return 'end'
class MakeCallStart(ModelView):
'Inicio de creación de llamada a seguimiento de prospecto'
__name__ = 'sale.prospect_trace.make_call.start'
description = fields.Text('Description')
interest = fields.Selection(
Interest.get_interest_levels(), 'Interest', required=True)
schedule_call = fields.Selection(
[('yes', 'Yes'),
('no', 'No')], 'Schedule call?', required=True)
schedule_task = fields.Selection(
[('yes', 'Yes'),
('no', 'No')], 'Schedule task?', required=True)
class MakeCallAsk(ModelView):
'Posible agendación de llamada luego de hacer llamada actual'
__name__ = 'sale.prospect_trace.make_call.ask'
currency_date = fields.DateTime('Currency Date', readonly=True)
datetime = fields.DateTime('Date time', domain=[
('datetime', '>=', Eval('currency_date'))])
@classmethod
def default_currency_date(cls):
date = datetime.now()
return date
class MakeCallAskTask(ModelView):
'Posible agendación de tarea luego de hacer llamada actual'
__name__ = 'sale.prospect_trace.make_call.ask_task'
task_description = fields.Text('Task description')
class MakeCall(Wizard):
'Crear llamada a un seguimiento de prospecto'
__name__ = 'sale.prospect_trace.make_call'
start = StateView(
'sale.prospect_trace.make_call.start',
'sale_opportunity_management.make_call_start_view_form', [
Button("Cancel", 'end', 'tryton-cancel'),
Button("Make call", 'make_call', 'tryton-ok', default=True)])
make_call = StateTransition()
ask = StateView(
'sale.prospect_trace.make_call.ask',
'sale_opportunity_management.make_call_ask_view_form', [
Button("Cancel", 'end', 'tryton-cancel'),
Button(
"Schedule call", 'schedule_call', 'tryton-ok', default=True)])
schedule_call = StateTransition()
ask_task = StateView(
'sale.prospect_trace.make_call.ask_task',
'sale_opportunity_management.make_call_ask_task_view_form', [
Button("Cancel", 'end', 'tryton-cancel'),
Button("Schedule task", 'schedule_task', 'tryton-ok', default=True)
]
)
schedule_task = StateTransition()
def transition_make_call(self):
prospect_trace = self.record
pool = Pool()
ContactMethod = pool.get('prospect.contact_method')
Call = pool.get('sale.call')
call = Call()
call.description = self.start.description
call.interest = self.start.interest
call.prospect_trace = self.record
call.call_business_unit = self.record.prospect_business_unit
call.operator_who_called = self.record.prospect_assigned_operator
contact_mobile = ContactMethod.search(
[('prospect', '=', self.prospect.id),
('contact_type', '=', 'mobile')],
limit=1)
if call.interest == '0':
call.call_result = 'missed_call'
else:
call.call_result = 'answered_call'
already_exist_a_call = len(prospect_trace.calls) >= 1
if already_exist_a_call:
followup_call_type = CallTypes.get_call_types()[1][0]
call.call_type = followup_call_type
else:
first_call_type = CallTypes.get_call_types()[0][0]
call.call_type = first_call_type
call.save()
if contact_mobile:
return contact_mobile[0]
prospect_trace.current_interest = call.interest
if prospect_trace.pending_call:
prospect_trace.pending_call = None
prospect_trace.state = 'open'
prospect_trace.calls += (call,)
prospect_trace.save()
if self.start.schedule_call == 'yes':
return 'ask'
if self.start.schedule_task == 'yes':
return 'ask_task'
return 'end'
def transition_schedule_task(self):
self.create_schedule_task(self.ask_task.task_description, self.record)
return 'end'
def transition_schedule_call(self):
self.create_schedule_call(self.ask.datetime, self.record)
if (self.start.schedule_call and self.start.schedule_task) == 'yes':
return 'ask_task'
return 'end'
@classmethod
def create_schedule_task(cls, description, prospect_trace):
pool = Pool()
Task = pool.get('sale.pending_task')
task = Task()
task.description = description
task.prospect_trace = prospect_trace
task.save()
@classmethod
def create_schedule_call(cls, datetime, prospect_trace):
pool = Pool()
PendingCall = pool.get('sale.pending_call')
pending_call = PendingCall()
pending_call.date = datetime
pending_call.save()
prospect_trace.pending_call = pending_call
prospect_trace.state = 'with_pending_calls'
prospect_trace.save()

View File

@@ -3,6 +3,22 @@
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<record model="res.group" id="group_prospect_trace">
<field name="name">Prospect Traces</field>
</record>
<record model="res.group" id="group_prospect_trace_admin">
<field name="name">Traces Administrator</field>
<field name="parent" ref="group_prospect_trace"/>
</record>
<record model="res.user-res.group" id="user_admin_group_prospect_trace">
<field name="user" ref="res.user_admin"/>
<field name="group" ref="group_prospect_trace"/>
</record>
<record model="res.user-res.group" id="user_admin_group_prospect_traces_admin">
<field name="user" ref="res.user_admin"/>
<field name="group" ref="group_prospect_trace_admin"/>
</record>
<record model="ir.ui.view" id="prospect_trace_view_tree">
<field name="model">sale.prospect_trace</field>
<field name="type">tree</field>
@@ -15,6 +31,9 @@ this repository contains the full copyright notices and license terms. -->
</record>
<record model="ir.action.act_window" id="act_prospect_trace_tree">
<field name="name">Prospect Traces</field>
<field name="domain"
eval="[If(Eval('context', {}).get('user_admin', None), (), ('prospect_assigned_operator', '=', Eval('_user')))]"
pyson="1"/>
<field name="res_model">sale.prospect_trace</field>
</record>
<record model="ir.action.act_window.view" id="act_prospect_trace_tree_view1">
@@ -36,11 +55,18 @@ this repository contains the full copyright notices and license terms. -->
</record>
<record model="ir.action.act_window.domain" id="act_prospect_trace_domain_with_pending_calls">
<field name="name">With pending calls</field>
<field name="sequence" eval="10"/>
<field name="sequence" eval="20"/>
<field name="domain" eval="[('state', '=', 'with_pending_calls')]" pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_prospect_trace_tree"/>
</record>
<record model="ir.action.act_window.domain" id="act_prospect_trace_domain_closed">
<field name="name">Closed</field>
<field name="sequence" eval="30"/>
<field name="domain" eval="[('state', '=', 'closed')]" pyson="1"/>
<field name="count" eval="True"/>
<field name="act_window" ref="act_prospect_trace_tree"/>
</record>
<record model="ir.action.act_window.domain" id="act_prospect_trace_domain_all">
<field name="name">All</field>
<field name="sequence" eval="9999"/>
@@ -48,11 +74,85 @@ this repository contains the full copyright notices and license terms. -->
<field name="count" eval="True"/>
<field name="act_window" ref="act_prospect_trace_tree"/>
</record>
<menuitem
parent="menu_calls"
sequence="20"
id="menu_prospect_trace_tree"
icon="tryton-target"
action="act_prospect_trace_tree"/>
<record model="ir.ui.menu-res.group" id="menu_prospect_trace_group_prospect_trace">
<field name="menu" ref="menu_prospect_trace_tree"/>
<field name="group" ref="group_prospect_trace"/>
</record>
<record model="ir.model.access" id="access_prospect_trace">
<field name="model" search="[('model', '=', 'sale.prospect_trace')]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_prospect_trace_trace">
<field name="model" search="[('model', '=', 'sale.prospect_trace')]"/>
<field name="group" ref="group_prospect_trace"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.action.wizard" id="schedule_call_wizard">
<field name="name">Schedule call</field>
<field name="wiz_name">sale.prospect_trace.schedule</field>
</record>
<record model="ir.ui.view" id="schedule_start_view_form">
<field name="model">sale.prospect_trace.schedule.start</field>
<field name="type">form</field>
<field name="name">schedule_start_form</field>
</record>
<record model="ir.model.button" id="schedule_call_wizard_button">
<field name="name">wizard_schedule</field>
<field name="string">Schedule call</field>
<field name="model" search="[('model', '=', 'sale.prospect_trace')]"/>
</record>
<record model="ir.action.wizard" id="make_call_wizard">
<field name="name">Make call</field>
<field name="wiz_name">sale.prospect_trace.make_call</field>
</record>
<record model="ir.ui.view" id="make_call_start_view_form">
<field name="model">sale.prospect_trace.make_call.start</field>
<field name="type">form</field>
<field name="name">make_call_start_form</field>
</record>
<record model="ir.ui.view" id="make_call_ask_view_form">
<field name="model">sale.prospect_trace.make_call.ask</field>
<field name="type">form</field>
<field name="name">make_call_ask_form</field>
</record>
<record model="ir.ui.view" id="make_call_ask_task_view_form">
<field name="model">sale.prospect_trace.make_call.ask_task</field>
<field name="type">form</field>
<field name="name">make_call_ask_task_form</field>
</record>
<record model="ir.model.button" id="make_call_wizard_button">
<field name="name">wizard_make_call</field>
<field name="string">Make call</field>
<field name="model" search="[('model', '=', 'sale.prospect_trace')]"/>
</record>
<record model="ir.model.button" id="close_trace_button">
<field name="name">close_trace</field>
<field name="string">Close trace</field>
<field name="model" search="[('model', '=', 'sale.prospect_trace')]"/>
</record>
<record model="ir.model.button" id="reopen_trace_button">
<field name="name">reopen_trace</field>
<field name="string">Reopen trace</field>
<field name="model" search="[('model', '=', 'sale.prospect_trace')]"/>
</record>
</data>
</tryton>

View File

@@ -6,7 +6,8 @@ class Interest():
('0', '0 - Not answered'),
('1', '1 - Complete disinterest'),
('2', '2 - Middle interest'),
('3', '3 - High interest')
('3', '3 - High interest'),
('4', '4 - Closed sale')
]
return interest_levels

View File

@@ -7,7 +7,7 @@ Imports::
>>> from proteus import Model, Wizard
>>> from trytond.tests.tools import activate_modules
>>> from datetime import date, timedelta
>>> from datetime import date, timedelta, datetime
>>> import xml.etree.ElementTree as ET
Activate modules::
@@ -42,71 +42,97 @@ El administrador deberá poder registrar los contactos de diferentes prospectos,
Crear prospecto::
>>> Prospect = Model.get('sale.prospect')
>>> prospect = Prospect()
>>> prospect.name = 'guchito S.A.S'
>>> contact_method = prospect.contact_methods.new(value='31223425234', name='Roberto', job='Gerente R.H')
>>> contact_method = prospect.contact_methods.new(contact_type='mobile', value='12345678910', name='Pancracia', job='Asistente administrativo')
>>> contact_method = prospect.contact_methods.new(contact_type='mail', value='peralto@guchitos.org', name='Peralto', job='Administrador')
.. >>> Department = Model.get('sale.department')
.. >>> cundinamarca, = Department.find([('code', '=', 'CO-25')])
.. >>> prospect.department = cundinamarca
>>> prospect1 = Prospect()
>>> prospect1.name = 'guchito S.A.S'
>>> contact_method = prospect1.contact_methods.new(value='31223425234', name='Roberto', job='Gerente R.H')
>>> contact_method = prospect1.contact_methods.new(contact_type='mobile', value='12345678910', name='Pancracia', job='Asistente administrativo')
>>> contact_method = prospect1.contact_methods.new(contact_type='mail', value='peralto@guchitos.org', name='Peralto', job='Administrador')
>>> City = Model.get('sale.city')
>>> medellin, = City.find([('code', '=', 'CO-05001')])
>>> prospect.city = medellin
>>> prospect.save()
>>> prospect1.city = medellin
>>> prospect1.business_unit = 'brigade'
>>> prospect1.save()
Verificar estado final de creación de prospecto::
>>> prospect.contact_methods
>>> prospect1.contact_methods
[proteus.Model.get('prospect.contact_method')(1), proteus.Model.get('prospect.contact_method')(2), proteus.Model.get('prospect.contact_method')(3)]
>>> prospect.contact_methods[0].contact_type
>>> prospect1.contact_methods[0].contact_type
'mobile'
>>> prospect.contact_methods[0].job
>>> prospect1.contact_methods[0].job
'Gerente R.H'
>>> prospect.contact_methods[2].name
>>> prospect1.contact_methods[2].name
'Peralto'
>>> prospect.contact_methods[2].value
>>> prospect1.contact_methods[2].value
'peralto@guchitos.org'
>>> prospect.city.code
>>> prospect1.city.code
'CO-05001'
>>> prospect.department.code
>>> prospect1.department.code
'CO-05'
>>> prospect.state
>>> prospect1.business_unit
'brigade'
>>> prospect1.state
'unassigned'
Asignar operario a un prospecto::
>>> User = Model.get('res.user')
>>> user, = User.find([('name', '=', 'Administrator')])
>>> prospect.assigned_operator = user
Crear segundo prospecto::
>>> prospect2 = Prospect()
>>> prospect.assigned_operator.name
'Administrator'
>>> prospect.state
'assigned'
>>> prospect2.name = 'Modernitus S.A.S'
>>> contact_method = prospect2.contact_methods.new(value='3122390987', name='Pepe', job='Jefe de ventas')
Remover operario asignado de un prospecto::
>>> prospect.assigned_operator = None
>>> prospect.state
'unassigned'
>>> City = Model.get('sale.city')
>>> bogota, = City.find([('code', '=', 'CO-11001')])
>>> prospect2.city = bogota
>>> prospect2.business_unit = 'brigade'
>>> prospect2.save()
Crear tercer prospecto::
>>> prospect3 = Prospect()
>>> prospect3.name = 'Vision S.A.S'
>>> contact_method = prospect3.contact_methods.new(value='3122324287', name='Alfredo', job='Administrador')
>>> prospect3.business_unit = 'optics'
>>> prospect3.save()
Asignar tipificación a un prospecto
>>> prospect3.rating = '1'
>>> prospect3.comments = 'Calificación al cliente'
------------------------------------
Asignación de prospectos a operarios
------------------------------------
**Como administrador, quiero poder asignar diferentes seguimientos de prospectos a diferentes operarios, para dividir el trabajo de una manera efectiva y que cada operario tenga sus propias llamadas y que no se mezcle con las de los demás**
TODO
Asignar prospectos a un operario::
>>> User = Model.get('res.user')
>>> user, = User.find([('name', '=', 'Administrator')])
>>> assign = Wizard('sale.prospect.assign', [prospect1, prospect2, prospect3])
>>> assign.form.business_unit = 'brigade'
>>> assign.form.prospects_chunk = 3
>>> assign.form.operator = user
>>> assign.form.prospects
[proteus.Model.get('sale.prospect')(1), proteus.Model.get('sale.prospect')(2)]
>>> assign.execute('assign')
>>> prospect1.assigned_operator.name
'Administrator'
>>> prospect1.state
'assigned'
>>> prospect2.assigned_operator.name
'Administrator'
>>> prospect2.state
'assigned'
-----------------------
Seguimiento de llamadas
-----------------------
**Como operador quiero poder crear un seguimiento de prospecto para luego hacer una llamada**
**Como operador quiero registrar una llamada para luego generar reportes**
**Como operador quiero programar una llamada para luego obtener un reporte de trabajo pendiente**
["Crear Campo para registro de la fecha de la llamada"]
@@ -155,38 +181,64 @@ Seguimiento de prospecto 2
* Seguimiento de prospecto al que pertence
Crear seguimiento de prospecto::
Verificar creación de seguimiento de prospecto::
>>> ProspectTrace = Model.get('sale.prospect_trace')
>>> prospect_trace = ProspectTrace()
>>> prospect_trace.prospect = prospect
>>> prospect_trace.save()
>>> prospect_trace, = ProspectTrace.find([('prospect', '=', prospect1)])
>>> prospect_trace.prospect.name
'guchito S.A.S'
>>> prospect_trace.prospect_business_unit
'brigade'
>>> prospect_trace.prospect_city.name
'Medellín'
>>> prospect_trace.prospect_contact.value
'31223425234'
>>> prospect_trace.prospect_contact.contact_type
'mobile'
>>> prospect_trace.prospect_contact.job
'Gerente R.H'
>>> prospect_trace.prospect_assigned_operator.name
'Administrator'
>>> prospect_trace.prospect_contacts
[proteus.Model.get('prospect.contact_method')(1), proteus.Model.get('prospect.contact_method')(2), proteus.Model.get('prospect.contact_method')(3)]
Crear llamadas a un seguimiento de prospecto desde el seguimiento de prospecto::
>>> call1 = prospect_trace.calls.new(description='First call', interest='0')
>>> call2 = prospect_trace.calls.new(description='Second call', interest='1')
>>> call3 = prospect_trace.calls.new(description='Third call', interest='3')
>>> prospect_trace.save()
Agregar un método de contacto desde el seguimiento de prospecto::
>>> contact_method_ = prospect_trace.prospect_contacts.new(value='31231231212', name='Carlos', job='Supervisor')
>>> contact_method_.prospect
proteus.Model.get('sale.prospect')(1)
Verificar estado final del seguimiento del prospecto y sus llamadas
Crear llamadas a un seguimiento de prospecto::
>>> make_call = Wizard('sale.prospect_trace.make_call', [prospect_trace])
>>> make_call.form.description = 'First call to the prospect'
>>> make_call.form.interest = '0'
>>> make_call.form.schedule_call = 'no'
>>> make_call.execute('make_call')
>>> make_call.state
'end'
>>> make_call = Wizard('sale.prospect_trace.make_call', [prospect_trace])
>>> make_call.form.description = 'Second call to the prospect'
>>> make_call.form.interest = '1'
>>> make_call.form.schedule_call = 'no'
>>> make_call.execute('make_call')
>>> make_call.state
'end'
>>> make_call = Wizard('sale.prospect_trace.make_call', [prospect_trace])
>>> make_call.form.description = 'Third call to the prospect'
>>> make_call.form.interest = '3'
>>> make_call.form.schedule_call = 'yes'
>>> make_call.execute('make_call')
>>> make_call.form.datetime = datetime(2023, 8, 14, 15, 30, 30)
>>> make_call.execute('schedule_call')
Verificar estado final del seguimiento del prospecto y sus llamadas::
>>> prospect_trace.calls[0].call_result
'missed_call'
>>> prospect_trace.calls[0].call_type
'first_call'
>>> prospect_trace.calls[0].date == date.today()
True
>>> prospect_trace.calls[0].call_business_unit
'brigade'
>>> prospect_trace.calls[0].operator_who_called.name
'Administrator'
>>> prospect_trace.calls[1].call_result
'answered_call'
>>> prospect_trace.calls[1].call_type
@@ -194,46 +246,143 @@ Verificar estado final del seguimiento del prospecto y sus llamadas
>>> prospect_trace.calls
[proteus.Model.get('sale.call')(1), proteus.Model.get('sale.call')(2), proteus.Model.get('sale.call')(3)]
>>> prospect_trace.pending_call.date
datetime.datetime(2023, 8, 14, 15, 30, 30)
>>> prospect_trace.current_interest
'3'
>>> prospect_trace.state
'open'
'with_pending_calls'
Programar una próxima llamada pendiente al seguimiento de prospecto::
>>> pending_call4 = prospect_trace.pending_calls.new(date = date.today() + timedelta(days=7))
>>> prospect_trace.save()
>>> prospect_trace.pending_calls
[proteus.Model.get('sale.pending_call')(1)]
>>> schedule = Wizard('sale.prospect_trace.schedule', [prospect_trace])
>>> schedule.form.date_time = datetime(2023, 8, 14, 15, 30, 30)
>>> schedule.execute('schedule')
>>> prospect_trace.pending_call.date
datetime.datetime(2023, 8, 14, 15, 30, 30)
>>> prospect_trace.state
'with_pending_calls'
Crear una llamada agendada previamente:
>>> call4 = prospect_trace.calls.new(description='fourth call', interest='3')
Crear una llamada agendada previamente::
>>> make_call = Wizard('sale.prospect_trace.make_call', [prospect_trace])
>>> make_call.form.description = 'Fourth call to the prospect'
>>> make_call.form.interest = '2'
>>> make_call.execute('make_call')
>>> prospect_trace.pending_call
>>> prospect_trace.pending_calls
[]
>>> prospect_trace.state
'open'
Cuando se asigna prospecto sin método de contacto mobile, el contacto en el seguimiento es vacío::
>>> prospect2 = Prospect()
>>> prospect2.name = 'Sin celulares S.A.S'
>>> contact_method = prospect2.contact_methods.new(contact_type='mail', value='felpucio@sincelulares.org', name='felpucio', job='Supervisor')
>>> prospect2.save()
Hacer llamada y programar tarea::
>>> make_call = Wizard('sale.prospect_trace.make_call', [prospect_trace])
>>> make_call.form.description = 'Prospect told me to send him an email'
>>> make_call.form.interest = '3'
>>> make_call.form.schedule_call = 'yes'
>>> make_call.form.schedule_task = 'yes'
>>> make_call.execute('make_call')
>>> make_call.form.datetime = datetime(2023, 8, 14, 15, 30, 30)
>>> make_call.execute('schedule_call')
>>> make_call.form.task_description = 'I have to send a mail to prospect offering him this services...'
>>> make_call.execute('schedule_task')
>>> prospect_trace2 = ProspectTrace()
>>> prospect_trace2.prospect = prospect2
>>> Task = Model.get('sale.pending_task')
>>> task, = Task.find([('description', '=', 'I have to send a mail to prospect offering him this services...')])
>>> task
proteus.Model.get('sale.pending_task')(1)
>>> prospect_trace2.save()
>>> task.state
'pending'
>>> task.click('close_task')
>>> task.state
'done'
Hacer llamada y cerrar venta (Seguimiento de prospecto)::
>>> make_call = Wizard('sale.prospect_trace.make_call', [prospect_trace])
>>> make_call.form.description = 'Closed sale'
>>> make_call.form.interest = '4'
>>> make_call.execute('make_call')
>>> prospect_trace.click('close_trace')
>>> prospect_trace.state
'closed'
Reabrir seguimiento a prospecto una vez cerrado::
>>> prospect_trace.click('reopen_trace')
>>> prospect_trace.state
'open'
Reasignar prospectos por operador::
>>> operator2 = User();
>>> operator2.name = 'Operatus'
>>> operator2.login = 'login'
>>> operator2.save()
>>> reassign_by_operator = Wizard('sale.prospect.reassign_by_operator', [])
>>> reassign_by_operator.form.current_operator = user
>>> reassign_by_operator.form.prospects
[proteus.Model.get('sale.prospect')(1), proteus.Model.get('sale.prospect')(2)]
>>> reassign_by_operator.form.new_operator = operator2
>>> reassign_by_operator.execute('reassign_by_operator')
>>> prospect1.reload()
>>> prospect1.assigned_operator.name
'Operatus'
>>> prospect2.reload()
>>> prospect2.assigned_operator.name
'Operatus'
>>> prospect_trace.reload()
>>> prospect_trace.prospect_assigned_operator.name
'Operatus'
.. Las llamadas deben conservar el operador que las hizo
>>> prospect_trace.calls[0].operator_who_called.name
'Administrator'
Reasignar prospectos por prospecto::
>>> reassign_by_prospect = Wizard('sale.prospect.reassign_by_prospect', [])
>>> reassign_by_prospect.form.prospect = prospect1
>>> reassign_by_prospect.form.new_operator = user
>>> reassign_by_prospect.execute('reassign_by_prospect')
>>> prospect1.reload()
>>> prospect1.assigned_operator.name
'Administrator'
>>> prospect_trace.reload()
>>> prospect_trace.prospect_assigned_operator.name
'Administrator'
>>> prospect_trace.calls[0].operator_who_called.name
'Administrator'
Crear un usuario de rol administrador::
>>> User = Model.get('res.user')
>>> admin = User(name="Administrator", login="administrator", user_admin=True)
>>> admin.save()
>>> admin.user_admin == True
True
.. Generar reporte por operario y consolidado::
.. >>> PrintReportByOperator = Model.get('sale.print_report_by_operato`r', type='wizard')
.. >>> session_id, _, _ = PrintReportByOperator.create()
.. >>> print_report_by_operator = Wizard('sale.print_report_by_operator', [])
.. >>> print_report_by_operator.form.start_date = date.today()
.. >>> print_report_by_operator.form.end_date = date.today()
.. >>> print_report_by_operator.execute('print_report')
--------
Reportes
--------
["Crear un reporte en el que evidencie por operario y consolidado"]
["Cantidad de llamadas realizadas en un período de tiempo"]
["Crear un reporte para verificar cantidad de llamadas por realizar"]
["Crear reporte para identificación de clientes potenciales (Cliente que en la llamada fueron marcados con un nivel alto)"]
@@ -243,7 +392,7 @@ Reportes
* Observaciones
* Operario
* Reporte de seguimientos a prospectos (Análisis de prospectos):
* Reporte de seguimiento a prospecto (Análisis de prospecto):
* Interés durante distintas etapas del seguimiento
@@ -257,3 +406,4 @@ Reportes
* Reporte de prospectos potenciales
* llamadas con un nivel de interés alto
* Seguimiento de prospecto al que pertenecen las llamadas

View File

@@ -24,6 +24,12 @@ class RequiredValuesTestCase(ModuleTestCase):
Prospect = pool.get('sale.prospect')
self.assertTrue(Prospect.name.required)
@with_transaction()
def test_bussiness_unit_en_Prospect_es_obligatorio(self):
pool = Pool()
Prospect = pool.get('sale.prospect')
self.assertTrue(Prospect.business_unit.required)
@with_transaction()
def test_value_en_ContactMethod_es_obligatorio(self):
pool = Pool()

View File

@@ -4,9 +4,10 @@ depends:
ir
res
xml:
icons.xml
user.xml
call.xml
prospect_trace.xml
prospect.xml
pending_call.xml
./locations/departments.xml
./locations/cities.xml

17
user.py Normal file
View File

@@ -0,0 +1,17 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import fields
from trytond.pool import PoolMeta
class User(metaclass=PoolMeta):
"User"
__name__ = 'res.user'
user_admin = fields.Boolean('Is Admin')
@classmethod
def __setup__(cls):
super(User, cls).__setup__()
cls._context_fields.insert(0, 'user_admin')

12
user.xml Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<record model="ir.ui.view" id="user_view_form" >
<field name="name">user_form</field>
<field name="inherit" ref="res.user_view_form"/>
<field name="model">res.user</field>
</record>
</data>
</tryton>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form col="6">
<label name="operator"/>
<field name="operator"/>
<label name="business_unit"/>
<field name="business_unit"/>
<label name="prospects_chunk"/>
<field name="prospects_chunk"/>
<notebook colspan="6">
<page string="Prospects" id="prospects_to_assign" col="6">
<group col="2" id="prospects">
<field name="prospects"/>
</group>
</page>
</notebook>
</form>

View File

@@ -18,4 +18,6 @@ this repository contains the full copyright notices and license terms. -->
<label name="call_result"/>
<field name="call_result"/>
<label name="call_business_unit"/>
<field name="call_business_unit"/>
</form>

View File

@@ -8,4 +8,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="call_result" expand="1"/>
<field name="prospect_trace" expand="1"/>
<field name="description" expand="1"/>
<field name="call_business_unit" expand="1"/>
<field name="operator_who_called" expand="1"/>
</tree>

View File

@@ -4,7 +4,6 @@ this repository contains the full copyright notices and license terms. -->
<tree editable="1">
<field name="contact_type" expand="1"/>
<field name="value" expand="1"/>
<field name="prospect" expand="1"/>
<field name="name" expand="1"/>
<field name="job" expand="1"/>
</tree>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<label name="datetime"/>
<field name="datetime"/>
</form>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<label name="task_description"/>
<field name="task_description"/>
</form>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<group col="6" id="description">
<label name="description"/>
<field name="description"/>
</group>
<newline/>
<group col="6" id="call_data">
<label name="interest"/>
<field name="interest" colspan="1"/>
<label name="schedule_call"/>
<field name="schedule_call" colspan="1"/>
<label name="schedule_task"/>
<field name="schedule_task" colspan="1"/>
</group>
</form>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<group col="6" id="content">
<label name="prospect_trace"/>
<field name="prospect_trace"/>
<newline/>
<label name="description"/>
<field name="description"/>
</group>
</form>

View File

@@ -2,6 +2,7 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree>
<field name="date" expand="1"/>
<field name="prospect_trace" expand="1"/>
<field name="description" expand="1"/>
<button name="close_task"/>
</tree>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree>
<field name="start_date" expand="1"/>
<field name="end_date" expand="1"/>
</tree>

View File

@@ -6,6 +6,9 @@ this repository contains the full copyright notices and license terms. -->
<label name="name"/>
<field name="name"/>
<label name="business_unit"/>
<field name="business_unit"/>
<newline/>
<label name="department"/>
<field name="department"/>
@@ -19,6 +22,24 @@ this repository contains the full copyright notices and license terms. -->
<page string="Contact methods" id="contact_methods">
<field name="contact_methods" colspan="2"/>
</page>
<page string="About prospect" id="contact_methods">
<label name="rating"/>
<field name="rating"/>
<newline/>
<label name="comments"/>
<field name="comments"/>
</page>
</notebook>
<newline/>
<group col="6" colspan="5" id="footer" yalign="0">
<label name="assigned_operator"/>
<field name="assigned_operator"/>
<label name="state"/>
<field name="state"/>
<group col="-1" colspan="1" id="checkboxes">
<label name="active"/>
<field name="active" xexpand="0" width="25"/>
</group>
</group>
</form>

View File

@@ -5,8 +5,8 @@ this repository contains the full copyright notices and license terms. -->
<group col="6" colspan="5" id="header" yalign="0">
<label name="prospect"/>
<field name="prospect"/>
<label name="prospect_contact"/>
<field name="prospect_contact"/>
<label name="prospect_business_unit"/>
<field name="prospect_business_unit"/>
<label name="prospect_city"/>
<field name="prospect_city"/>
</group>
@@ -14,18 +14,25 @@ this repository contains the full copyright notices and license terms. -->
<group col="6" colspan="5" id="trace_data" yalign="0">
<label name="current_interest"/>
<field name="current_interest"/>
<label name="active"/>
<field name="active" xexpand="0" width="25"/>
</group>
<field name="calls" colspan="6"/>
<newline/>
<group col="-1" colspan="6" id="buttons">
<button name="wizard_make_call" icon="tryton-tel"/>
<button name="wizard_schedule" icon="tryton-calendar"/>
</group>
<newline/>
<notebook colspan="6">
<page string="Calls - Oldest to Newest" id="calls">
<field name="calls" colspan="2"/>
</page>
</notebook>
<field name="pending_calls" colspan="6"/>
<field name="prospect_contacts" colspan="6"/>
<label name="pending_call"/>
<field name="pending_call"/>
<label name="state"/>
<field name="state"/>
<group col="-1" colspan="6" id="footer_buttons">
<button name="close_trace" icon="tryton-archive"/>
<button name="reopen_trace" icon="tryton-unarchive"/>
</group>
</form>

View File

@@ -3,9 +3,10 @@
this repository contains the full copyright notices and license terms. -->
<tree>
<field name="prospect" expand="1"/>
<field name="prospect_contact" expand="1"/>
<field name="prospect_business_unit" expand="1"/>
<field name="prospect_city" expand="1"/>
<field name="current_interest" expand="1"/>
<field name="calls" expand="1"/>
<field name="pending_calls" expand="1"/>
<field name="pending_call" expand="1"/>
<field name="prospect_assigned_operator" expand="1"/>
</tree>

View File

@@ -3,7 +3,9 @@
this repository contains the full copyright notices and license terms. -->
<tree>
<field name="name" expand="1"/>
<field name="business_unit" expand="1"/>
<field name="department" expand="1"/>
<field name="city" expand="1"/>
<field name="contact_methods" expand="1"/>
<field name="assigned_operator" expand="1"/>
<field name="rating" expand="1"/>
</tree>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<label name="current_operator"/>
<field name="current_operator"/>
<label name="new_operator"/>
<field name="new_operator"/>
<field name="prospects" colspan="6"/>
</form>

View File

@@ -2,9 +2,8 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<label name="date"/>
<field name="date"/>
<label name="prospect_trace"/>
<field name="prospect_trace"/>
<label name="prospect"/>
<field name="prospect"/>
<label name="new_operator"/>
<field name="new_operator"/>
</form>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<label name="date_time"/>
<field name="date_time"/>
</form>

9
view/user_form.xml Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="//field[@name='name']" position="after">
<label name="user_admin"/>
<field name="user_admin"/>
</xpath>
</data>