Compare commits
34 Commits
d50cca2924
...
6.8
| Author | SHA1 | Date | |
|---|---|---|---|
| b7e06a3408 | |||
| 9096983ffd | |||
| 660ac06c1d | |||
| 7b0bafa05f | |||
| 4d88f9423d | |||
| e0f3846bb5 | |||
| ef8f45267f | |||
| 5cc0277db9 | |||
| 3f7b989781 | |||
| 6c31dfb64f | |||
| b1c3b21a9c | |||
| 99de45dd32 | |||
| 950b9350cc | |||
| 6f69709823 | |||
| cd0564c95f | |||
| 4a3d178a92 | |||
| 4826687b3b | |||
| bd62abb43f | |||
| 18d06374fe | |||
| d5ca112bff | |||
| d1ad40203b | |||
| 9c368809f9 | |||
| e40991de02 | |||
| b8ba775733 | |||
| 336a266578 | |||
| 22fb3736a7 | |||
| 5cc7ef011d | |||
| 72ae0cfa22 | |||
| 0b7d15f35b | |||
| 8a0aa29368 | |||
| f71e6f4671 | |||
| cf874db55f | |||
| e97e8fa99d | |||
| 5a2c5217a6 |
@@ -7,7 +7,7 @@
|
|||||||
[ ! -d "$SRC" ] && die "no se ubica ruta en SRC"
|
[ ! -d "$SRC" ] && die "no se ubica ruta en SRC"
|
||||||
|
|
||||||
# dependencias minimas
|
# dependencias minimas
|
||||||
pip3 install psycopg2 proteus inotify honcho
|
pip3 install psycopg2 proteus==6.8 inotify honcho
|
||||||
|
|
||||||
# instalar dependencias de tryton desde paquete
|
# instalar dependencias de tryton desde paquete
|
||||||
python3 setup.py install
|
python3 setup.py install
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#
|
|
||||||
# variables que puedo usar? https://woodpecker-ci.org/docs/0.15/usage/environment#built-in-environment-variables
|
# variables que puedo usar? https://woodpecker-ci.org/docs/0.15/usage/environment#built-in-environment-variables
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -33,7 +32,7 @@ steps:
|
|||||||
<p>${CI_COMMIT_AUTHOR}: <a href="${CI_BUILD_LINK}">Task ${CI_BUILD_NUMBER}</a> <font color="green"><b>TODO BIEN EN ${CI_REPO}</b></font></p>
|
<p>${CI_COMMIT_AUTHOR}: <a href="${CI_BUILD_LINK}">Task ${CI_BUILD_NUMBER}</a> <font color="green"><b>TODO BIEN EN ${CI_REPO}</b></font></p>
|
||||||
<pre><a href="${CI_COMMIT_LINK}">${CI_COMMIT_MESSAGE}</a></pre>
|
<pre><a href="${CI_COMMIT_LINK}">${CI_COMMIT_MESSAGE}</a></pre>
|
||||||
when:
|
when:
|
||||||
status: [ success ]
|
status: [success]
|
||||||
|
|
||||||
notify-failure:
|
notify-failure:
|
||||||
image: plugins/matrix
|
image: plugins/matrix
|
||||||
@@ -49,7 +48,7 @@ steps:
|
|||||||
<p>${CI_COMMIT_AUTHOR}: <a href="${CI_BUILD_LINK}">Task ${CI_BUILD_NUMBER}</a> <font color="red"><b>!!!TODO MAL EN ${CI_REPO} </b></font></p>
|
<p>${CI_COMMIT_AUTHOR}: <a href="${CI_BUILD_LINK}">Task ${CI_BUILD_NUMBER}</a> <font color="red"><b>!!!TODO MAL EN ${CI_REPO} </b></font></p>
|
||||||
<pre><a href="${CI_COMMIT_LINK}">${CI_COMMIT_MESSAGE}</a></pre>
|
<pre><a href="${CI_COMMIT_LINK}">${CI_COMMIT_MESSAGE}</a></pre>
|
||||||
when:
|
when:
|
||||||
status: [ failure ]
|
status: [failure]
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ FROM node as builder-node
|
|||||||
|
|
||||||
ENV SERIES 6.8
|
ENV SERIES 6.8
|
||||||
RUN npm install -g bower
|
RUN npm install -g bower
|
||||||
RUN curl https://downloads.tryton.org/${SERIES}/tryton-sao-last.tgz | tar zxf - -C /
|
RUN curl https://downloads.tryton.org/${SERIES}/tryton-sao-6.8.4.tgz | tar zxf - -C /
|
||||||
RUN cd /package && bower install --allow-root
|
RUN cd /package && bower install --allow-root
|
||||||
|
|
||||||
FROM python:3.9-bullseye
|
FROM python:3.9-bullseye
|
||||||
|
|||||||
70
__init__.py
70
__init__.py
@@ -1,9 +1,31 @@
|
|||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from . import prospect
|
|
||||||
from . import prospect_trace
|
# Prospect Core
|
||||||
from . import call
|
from .core.Prospect.models.prospect import Prospect
|
||||||
from . import pending_call
|
from .core.Prospect.models.contact_method import ContactMethod
|
||||||
from . import user
|
from .core.Prospect.wizards.assign_operator \
|
||||||
|
import AssignOperator, AssignOperatorStart
|
||||||
|
from .core.Prospect.wizards.reassign_prospect_by_prospect \
|
||||||
|
import ReasignProspectByProspect, ReassignProspectByProspectStart
|
||||||
|
from .core.Prospect.wizards.reassign_prospect_by_operator \
|
||||||
|
import ReassignProspectByOperator, ReassignProspectByOperatorStart
|
||||||
|
|
||||||
|
# Prospect Trace Core
|
||||||
|
from .core.ProspectTrace.wizards.make_call \
|
||||||
|
import MakeCall, MakeCallAsk, MakeCallAskTask, MakeCallStart
|
||||||
|
from .core.ProspectTrace.wizards.schedule_call \
|
||||||
|
import ScheduleCall, ScheduleCallStart
|
||||||
|
from .core.ProspectTrace.models.prospect_trace \
|
||||||
|
import ProspectTrace
|
||||||
|
|
||||||
|
# Call Core
|
||||||
|
from .core.Call.models.call import Call
|
||||||
|
from .core.Call.models.pending_call import PendingCall
|
||||||
|
from .core.Call.models.pending_task import PendingTask
|
||||||
|
|
||||||
|
# Role core
|
||||||
|
from .core.Role.models.user import User
|
||||||
|
|
||||||
from .locations import city
|
from .locations import city
|
||||||
from .locations import department
|
from .locations import department
|
||||||
|
|
||||||
@@ -12,29 +34,29 @@ __all__ = ['register']
|
|||||||
|
|
||||||
def register():
|
def register():
|
||||||
Pool.register(
|
Pool.register(
|
||||||
user.User,
|
User,
|
||||||
pending_call.PendingCall,
|
PendingCall,
|
||||||
pending_call.PendingTask,
|
Call,
|
||||||
call.Call,
|
PendingTask,
|
||||||
department.Department,
|
department.Department,
|
||||||
city.City,
|
city.City,
|
||||||
prospect.ContactMethod,
|
ContactMethod,
|
||||||
prospect.Prospect,
|
Prospect,
|
||||||
prospect_trace.ProspectTrace,
|
ProspectTrace,
|
||||||
prospect.AssignOperatorStart,
|
AssignOperatorStart,
|
||||||
prospect_trace.ScheduleCallStart,
|
ScheduleCallStart,
|
||||||
prospect_trace.MakeCallStart,
|
MakeCallStart,
|
||||||
prospect_trace.MakeCallAsk,
|
MakeCallAsk,
|
||||||
prospect_trace.MakeCallAskTask,
|
MakeCallAskTask,
|
||||||
prospect.ReassignProspectByOperatorStart,
|
ReassignProspectByOperatorStart,
|
||||||
prospect.ReassignProspectByProspectStart,
|
ReassignProspectByProspectStart,
|
||||||
module='sale_opportunity_management', type_='model')
|
module='sale_opportunity_management', type_='model')
|
||||||
Pool.register(
|
Pool.register(
|
||||||
prospect_trace.ScheduleCall,
|
ScheduleCall,
|
||||||
prospect.AssignOperator,
|
AssignOperator,
|
||||||
prospect_trace.MakeCall,
|
MakeCall,
|
||||||
prospect.ReassignProspectByOperator,
|
ReassignProspectByOperator,
|
||||||
prospect.ReasignProspectByProspect,
|
ReasignProspectByProspect,
|
||||||
module='sale_opportunity_management', type_='wizard')
|
module='sale_opportunity_management', type_='wizard')
|
||||||
Pool.register(
|
Pool.register(
|
||||||
module='sale_opportunity_management', type_='report')
|
module='sale_opportunity_management', type_='report')
|
||||||
|
|||||||
71
call.xml
71
call.xml
@@ -22,8 +22,9 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<record model="ir.action.act_window" id="act_call_tree">
|
<record model="ir.action.act_window" id="act_call_tree">
|
||||||
<field name="name">Calls</field>
|
<field name="name">Calls</field>
|
||||||
<field name="res_model">sale.call</field>
|
<field name="res_model">sale.call</field>
|
||||||
|
<field name="domain"
|
||||||
|
eval="[('operator_who_called', '=', Eval('_user'))]" pyson="1"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.ui.view" id="call_view_tree">
|
<record model="ir.ui.view" id="call_view_tree">
|
||||||
<field name="model">sale.call</field>
|
<field name="model">sale.call</field>
|
||||||
<field name="type">tree</field>
|
<field name="type">tree</field>
|
||||||
@@ -34,7 +35,6 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<field name="type">form</field>
|
<field name="type">form</field>
|
||||||
<field name="name">call_form</field>
|
<field name="name">call_form</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.action.act_window.view" id="act_call_tree_view1">
|
<record model="ir.action.act_window.view" id="act_call_tree_view1">
|
||||||
<field name="sequence" eval="10"/>
|
<field name="sequence" eval="10"/>
|
||||||
<field name="view" ref="call_view_tree"/>
|
<field name="view" ref="call_view_tree"/>
|
||||||
@@ -45,11 +45,6 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<field name="view" ref="call_view_form"/>
|
<field name="view" ref="call_view_form"/>
|
||||||
<field name="act_window" ref="act_call_tree"/>
|
<field name="act_window" ref="act_call_tree"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.ui.icon" id="call_icon">
|
|
||||||
<field name="name">tryton-phone</field>
|
|
||||||
<field name="path">icons/tryton-phone.svg</field>
|
|
||||||
</record>
|
|
||||||
<menuitem
|
<menuitem
|
||||||
name="Calls"
|
name="Calls"
|
||||||
sequence="10"
|
sequence="10"
|
||||||
@@ -66,7 +61,6 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<field name="menu" ref="menu_calls_tree"/>
|
<field name="menu" ref="menu_calls_tree"/>
|
||||||
<field name="group" ref="group_call"/>
|
<field name="group" ref="group_call"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.model.access" id="access_calls">
|
<record model="ir.model.access" id="access_calls">
|
||||||
<field name="model" search="[('model', '=', 'sale.call')]"/>
|
<field name="model" search="[('model', '=', 'sale.call')]"/>
|
||||||
<field name="perm_read" eval="False"/>
|
<field name="perm_read" eval="False"/>
|
||||||
@@ -74,7 +68,6 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<field name="perm_create" eval="False"/>
|
<field name="perm_create" eval="False"/>
|
||||||
<field name="perm_delete" eval="False"/>
|
<field name="perm_delete" eval="False"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.model.access" id="access_calls_calls">
|
<record model="ir.model.access" id="access_calls_calls">
|
||||||
<field name="model" search="[('model', '=', 'sale.call')]"/>
|
<field name="model" search="[('model', '=', 'sale.call')]"/>
|
||||||
<field name="group" ref="group_call"/>
|
<field name="group" ref="group_call"/>
|
||||||
@@ -83,5 +76,65 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<field name="perm_create" eval="True"/>
|
<field name="perm_create" eval="True"/>
|
||||||
<field name="perm_delete" eval="True"/>
|
<field name="perm_delete" eval="True"/>
|
||||||
</record>
|
</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>
|
||||||
|
<field name="domain"
|
||||||
|
eval="[If(Eval('context', {}).get('user_admin', None), (), ('prospect_trace.prospect_assigned_operator', '=', Eval('_user')))]"
|
||||||
|
pyson="1"/>
|
||||||
|
</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>
|
</data>
|
||||||
</tryton>
|
</tryton>
|
||||||
|
|||||||
0
core/Call/__init__.py
Normal file
0
core/Call/__init__.py
Normal file
@@ -1,10 +1,11 @@
|
|||||||
|
# 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.model import ModelSQL, ModelView, fields
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
from ....selections.interest import Interest
|
||||||
|
from ....selections.call_types import CallTypes
|
||||||
from .selections.interest import Interest
|
from ....selections.call_results import CallResults
|
||||||
from .selections.call_types import CallTypes
|
|
||||||
from .selections.call_results import CallResults
|
|
||||||
|
|
||||||
|
|
||||||
class Call(ModelSQL, ModelView):
|
class Call(ModelSQL, ModelView):
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
|
|
||||||
from trytond.model import ModelSQL, ModelView, fields
|
from trytond.model import ModelSQL, ModelView, fields
|
||||||
|
|
||||||
|
|
||||||
@@ -12,18 +13,3 @@ class PendingCall(ModelSQL, ModelView):
|
|||||||
def get_rec_name(self, name):
|
def get_rec_name(self, name):
|
||||||
if self.date:
|
if self.date:
|
||||||
return str(self.date)
|
return str(self.date)
|
||||||
|
|
||||||
|
|
||||||
class PendingTask(ModelSQL, ModelView):
|
|
||||||
'Tarea pendiente a un seguimiento de prospecto'
|
|
||||||
__name__ = "sale.pending_task"
|
|
||||||
|
|
||||||
description = fields.Text('Description', required=True)
|
|
||||||
done = fields.Boolean('Done')
|
|
||||||
prospect_trace = fields.Many2One(
|
|
||||||
'sale.prospect_trace', 'Prospect trace',
|
|
||||||
required=True, readonly=True)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def default_done(cls):
|
|
||||||
return False
|
|
||||||
47
core/Call/models/pending_task.py
Normal file
47
core/Call/models/pending_task.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# 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 Workflow, ModelSQL, ModelView, fields
|
||||||
|
from trytond.pyson import Eval
|
||||||
|
|
||||||
|
|
||||||
|
class PendingTask(Workflow, 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._transitions |= set((
|
||||||
|
('pending', 'done'),
|
||||||
|
))
|
||||||
|
cls._buttons.update({
|
||||||
|
'close_task': {
|
||||||
|
'invisible': ~Eval('state').in_(['pending']),
|
||||||
|
'depends':['state']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@ModelView.button
|
||||||
|
@Workflow.transition('done')
|
||||||
|
def close_task(cls, tasks):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default_state(cls):
|
||||||
|
return 'pending'
|
||||||
0
core/Prospect/__init__.py
Normal file
0
core/Prospect/__init__.py
Normal file
0
core/Prospect/models/__init__.py
Normal file
0
core/Prospect/models/__init__.py
Normal file
37
core/Prospect/models/contact_method.py
Normal file
37
core/Prospect/models/contact_method.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
class ContactMethod(ModelSQL, ModelView):
|
||||||
|
'Mecanismo de contacto'
|
||||||
|
__name__ = 'prospect.contact_method'
|
||||||
|
|
||||||
|
contact_type = fields.Selection([
|
||||||
|
('phone', 'Phone'),
|
||||||
|
('mobile', 'Mobile'),
|
||||||
|
('mail', 'Mail')
|
||||||
|
], 'Contact type', required=True)
|
||||||
|
|
||||||
|
value = fields.Char('Value', required=True)
|
||||||
|
name = fields.Char('Name')
|
||||||
|
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):
|
||||||
|
return 'mobile'
|
||||||
|
|
||||||
|
def get_rec_name(self, name):
|
||||||
|
fields = [self.name, self.job, self.value]
|
||||||
|
contact_rec_name = ''
|
||||||
|
|
||||||
|
for field in fields:
|
||||||
|
if field:
|
||||||
|
contact_rec_name += ' [' + str(field) + '] '
|
||||||
|
|
||||||
|
return contact_rec_name
|
||||||
80
core/Prospect/models/prospect.py
Normal file
80
core/Prospect/models/prospect.py
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# 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.pyson import Eval, If
|
||||||
|
from trytond.transaction import Transaction
|
||||||
|
from trytond.pool import Pool
|
||||||
|
from ....core.Prospect.wizards.assign_operator import GenericAssign
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
department = fields.Many2One('sale.department', 'Department')
|
||||||
|
city = fields.Many2One('sale.city', 'City',
|
||||||
|
domain=[If(Eval('department'),
|
||||||
|
('parent', '=', Eval('department')))])
|
||||||
|
|
||||||
|
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'
|
||||||
|
|
||||||
|
@fields.depends('prospect_trace', 'contact_methods')
|
||||||
|
def on_change_contact_methods(self):
|
||||||
|
for contact in self.contact_methods:
|
||||||
|
contact.prospect_trace = self.prospect_trace
|
||||||
|
|
||||||
|
@fields.depends('city', 'department')
|
||||||
|
def on_change_city(self):
|
||||||
|
if self.city:
|
||||||
|
self.department = self.city.parent
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls, values):
|
||||||
|
user_id = Transaction().user
|
||||||
|
records = super().create(values)
|
||||||
|
|
||||||
|
cls.try_assign_to_current_operator(records, user_id)
|
||||||
|
return records
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def try_assign_to_current_operator(cls, prospects, user_id):
|
||||||
|
User = Pool().get('res.user')
|
||||||
|
user, = User.search([('id', '=', user_id)])
|
||||||
|
|
||||||
|
if user.is_operator:
|
||||||
|
GenericAssign.assign_prospects_to_operator(prospects, user)
|
||||||
0
core/Prospect/wizards/__init__.py
Normal file
0
core/Prospect/wizards/__init__.py
Normal file
108
core/Prospect/wizards/assign_operator.py
Normal file
108
core/Prospect/wizards/assign_operator.py
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# 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.wizard import Wizard, StateView, Button, StateTransition
|
||||||
|
from trytond.model import ModelView, fields
|
||||||
|
from trytond.pyson import Eval
|
||||||
|
from trytond.pool import Pool
|
||||||
|
|
||||||
|
from ....core.ProspectTrace.models.prospect_trace import ProspectTrace
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
_prospects = self.start.prospects
|
||||||
|
_operator = self.start.operator
|
||||||
|
|
||||||
|
GenericAssign.assign_prospects_to_operator(_prospects, _operator)
|
||||||
|
|
||||||
|
return 'end'
|
||||||
|
|
||||||
|
|
||||||
|
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 GenericAssign():
|
||||||
|
@classmethod
|
||||||
|
def assign_prospects_to_operator(cls, prospects, operator):
|
||||||
|
for prospect in prospects:
|
||||||
|
prospect.assigned_operator = operator
|
||||||
|
prospect.state = 'assigned'
|
||||||
|
prospect.prospect_trace = cls._get_prosp_trace(prospect, operator)
|
||||||
|
prospect.save()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_prosp_trace(cls, prospect, operator):
|
||||||
|
ProspectTrace = Pool().get('sale.prospect_trace')
|
||||||
|
|
||||||
|
prospect_trace = ProspectTrace.search([('prospect', '=', prospect)])
|
||||||
|
|
||||||
|
if not prospect_trace:
|
||||||
|
created_trace = cls._create_base_prospect_trace(prospect, operator)
|
||||||
|
prospect_trace.append(created_trace)
|
||||||
|
|
||||||
|
prospect_trace, = prospect_trace
|
||||||
|
prospect_trace.prospect_assigned_operator = operator
|
||||||
|
prospect_trace.save()
|
||||||
|
return prospect_trace
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _create_base_prospect_trace(prospect, operator) -> ProspectTrace:
|
||||||
|
ProspectTrace = Pool().get('sale.prospect_trace')
|
||||||
|
|
||||||
|
prospect_trace = ProspectTrace(
|
||||||
|
prospect=prospect,
|
||||||
|
prospect_city=prospect.city,
|
||||||
|
prospect_business_unit=prospect.business_unit,
|
||||||
|
prospect_contacts=prospect.contact_methods
|
||||||
|
)
|
||||||
|
|
||||||
|
return prospect_trace
|
||||||
53
core/Prospect/wizards/reassign_prospect_by_operator.py
Normal file
53
core/Prospect/wizards/reassign_prospect_by_operator.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# 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.wizard import Wizard, StateView, Button, StateTransition
|
||||||
|
from trytond.model import ModelView, fields
|
||||||
|
from trytond.pool import Pool
|
||||||
|
|
||||||
|
from ....core.Prospect.wizards.assign_operator import GenericAssign
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
_prospects = self.start.prospects
|
||||||
|
_operator = self.start.new_operator
|
||||||
|
|
||||||
|
GenericAssign.assign_prospects_to_operator(_prospects, _operator)
|
||||||
|
|
||||||
|
return 'end'
|
||||||
40
core/Prospect/wizards/reassign_prospect_by_prospect.py
Normal file
40
core/Prospect/wizards/reassign_prospect_by_prospect.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# 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.wizard import Wizard, StateView, Button, StateTransition
|
||||||
|
from trytond.model import ModelView, fields
|
||||||
|
|
||||||
|
from ....core.Prospect.wizards.assign_operator import GenericAssign
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
_prospect = self.start.prospect
|
||||||
|
_operator = self.start.new_operator
|
||||||
|
|
||||||
|
GenericAssign.assign_prospects_to_operator([_prospect], _operator)
|
||||||
|
|
||||||
|
return 'end'
|
||||||
0
core/ProspectTrace/__init__.py
Normal file
0
core/ProspectTrace/__init__.py
Normal file
0
core/ProspectTrace/models/__init__.py
Normal file
0
core/ProspectTrace/models/__init__.py
Normal file
106
core/ProspectTrace/models/prospect_trace.py
Normal file
106
core/ProspectTrace/models/prospect_trace.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# 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.pyson import Eval
|
||||||
|
from ....selections.interest import Interest
|
||||||
|
|
||||||
|
|
||||||
|
class ProspectTrace(ModelSQL, ModelView):
|
||||||
|
'Seguimiento de un prospecto'
|
||||||
|
__name__ = 'sale.prospect_trace'
|
||||||
|
|
||||||
|
_states = {'readonly': True}
|
||||||
|
|
||||||
|
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',
|
||||||
|
states=_states)
|
||||||
|
|
||||||
|
state = fields.Selection([
|
||||||
|
('unassigned', 'Unassigned'),
|
||||||
|
('open', 'Open'),
|
||||||
|
('with_pending_calls', 'With pending calls'),
|
||||||
|
('closed', 'Closed')
|
||||||
|
], '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'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@ModelView.button_action(
|
||||||
|
'sale_opportunity_management.schedule_call_wizard')
|
||||||
|
def wizard_schedule(cls, prospect_traces):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@ModelView.button_action(
|
||||||
|
'sale_opportunity_management.make_call_wizard')
|
||||||
|
def wizard_make_call(cls, prospect_traces):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@ModelView.button
|
||||||
|
def close_trace(cls, prospect_traces):
|
||||||
|
for prospect_trace in prospect_traces:
|
||||||
|
prospect_trace.state = 'closed'
|
||||||
|
prospect_trace.save()
|
||||||
|
|
||||||
|
@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
|
||||||
@@ -1,141 +1,15 @@
|
|||||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
|
|
||||||
from trytond.wizard import Wizard, StateView, Button, StateTransition
|
from trytond.wizard import Wizard, StateView, Button, StateTransition
|
||||||
from trytond.model import ModelSQL, ModelView, fields
|
from trytond.model import ModelView, fields
|
||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from trytond.pyson import Eval
|
from trytond.pyson import Eval
|
||||||
from .selections.call_types import CallTypes
|
from ....selections.call_types import CallTypes
|
||||||
from .selections.interest import Interest
|
from ....selections.interest import Interest
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
class ProspectTrace(ModelSQL, ModelView):
|
|
||||||
'Seguimiento de un prospecto'
|
|
||||||
__name__ = 'sale.prospect_trace'
|
|
||||||
|
|
||||||
_states = {'readonly': True}
|
|
||||||
|
|
||||||
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',
|
|
||||||
states=_states)
|
|
||||||
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',
|
|
||||||
states=_states)
|
|
||||||
|
|
||||||
state = fields.Selection([
|
|
||||||
('unassigned', 'Unassigned'),
|
|
||||||
('open', 'Open'),
|
|
||||||
('with_pending_calls', 'With pending calls'),
|
|
||||||
('closed', 'Closed')
|
|
||||||
], 'State',
|
|
||||||
states=_states)
|
|
||||||
|
|
||||||
@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'
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@ModelView.button_action(
|
|
||||||
'sale_opportunity_management.schedule_call_wizard')
|
|
||||||
def wizard_schedule(cls, prospect_traces):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@ModelView.button_action(
|
|
||||||
'sale_opportunity_management.make_call_wizard')
|
|
||||||
def wizard_make_call(cls, prospect_traces):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@ModelView.button
|
|
||||||
def close_trace(cls, prospect_traces):
|
|
||||||
for prospect_trace in prospect_traces:
|
|
||||||
prospect_trace.state = 'closed'
|
|
||||||
prospect_trace.save()
|
|
||||||
|
|
||||||
@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
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
class MakeCallStart(ModelView):
|
||||||
'Inicio de creación de llamada a seguimiento de prospecto'
|
'Inicio de creación de llamada a seguimiento de prospecto'
|
||||||
__name__ = 'sale.prospect_trace.make_call.start'
|
__name__ = 'sale.prospect_trace.make_call.start'
|
||||||
40
core/ProspectTrace/wizards/schedule_call.py
Normal file
40
core/ProspectTrace/wizards/schedule_call.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# 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.wizard import Wizard, StateView, Button, StateTransition
|
||||||
|
from trytond.model import ModelView, fields
|
||||||
|
from trytond.pyson import Eval
|
||||||
|
from datetime import datetime
|
||||||
|
from ....core.ProspectTrace.wizards.make_call import MakeCall
|
||||||
|
|
||||||
|
|
||||||
|
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'
|
||||||
0
core/Role/__init__.py
Normal file
0
core/Role/__init__.py
Normal file
0
core/Role/models/__init__.py
Normal file
0
core/Role/models/__init__.py
Normal file
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
|
|
||||||
from trytond.model import fields
|
from trytond.model import fields
|
||||||
from trytond.pool import PoolMeta
|
from trytond.pool import PoolMeta
|
||||||
|
|
||||||
@@ -10,6 +10,7 @@ class User(metaclass=PoolMeta):
|
|||||||
__name__ = 'res.user'
|
__name__ = 'res.user'
|
||||||
|
|
||||||
user_admin = fields.Boolean('Is Admin')
|
user_admin = fields.Boolean('Is Admin')
|
||||||
|
is_operator = fields.Boolean('Is Operator')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __setup__(cls):
|
def __setup__(cls):
|
||||||
0
core/__init__.py
Normal file
0
core/__init__.py
Normal file
@@ -27,5 +27,9 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<field name="name">tryton-target</field>
|
<field name="name">tryton-target</field>
|
||||||
<field name="path">icons/tryton-target.svg</field>
|
<field name="path">icons/tryton-target.svg</field>
|
||||||
</record>
|
</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>
|
</data>
|
||||||
</tryton>
|
</tryton>
|
||||||
83
locale/es.po
83
locale/es.po
@@ -2,10 +2,6 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||||
|
|
||||||
msgctxt "field:res.user,user_admin:"
|
|
||||||
msgid "Is Admin"
|
|
||||||
msgstr "Es Administrador"
|
|
||||||
|
|
||||||
msgctxt "model:res.group,name:group_prospect"
|
msgctxt "model:res.group,name:group_prospect"
|
||||||
msgid "Prospects"
|
msgid "Prospects"
|
||||||
msgstr "Prospectos"
|
msgstr "Prospectos"
|
||||||
@@ -30,6 +26,14 @@ msgctxt "model:res.group,name:group_prospect_trace_admin"
|
|||||||
msgid "Traces Administrator"
|
msgid "Traces Administrator"
|
||||||
msgstr "Administración de Seguimientos"
|
msgstr "Administración de Seguimientos"
|
||||||
|
|
||||||
|
msgctxt "field:res.user,user_admin:"
|
||||||
|
msgid "Is Admin"
|
||||||
|
msgstr "Es Administrador"
|
||||||
|
|
||||||
|
msgctxt "field:res.user,is_operator:"
|
||||||
|
msgid "Is Operator"
|
||||||
|
msgstr "Es Operador"
|
||||||
|
|
||||||
msgctxt "field:sale.prospect_trace,prospect:"
|
msgctxt "field:sale.prospect_trace,prospect:"
|
||||||
msgid "Prospect"
|
msgid "Prospect"
|
||||||
msgstr "Prospecto"
|
msgstr "Prospecto"
|
||||||
@@ -76,7 +80,11 @@ msgstr "Unidad de negocio"
|
|||||||
|
|
||||||
msgctxt "view:sale.prospect:"
|
msgctxt "view:sale.prospect:"
|
||||||
msgid "Contact methods"
|
msgid "Contact methods"
|
||||||
msgstr "Metodos de contacto"
|
msgstr "Métodos de contacto"
|
||||||
|
|
||||||
|
msgctxt "view:sale.prospect:"
|
||||||
|
msgid "About prospect"
|
||||||
|
msgstr "Tipificación del prospecto"
|
||||||
|
|
||||||
msgctxt "field:sale.prospect,contact_methods:"
|
msgctxt "field:sale.prospect,contact_methods:"
|
||||||
msgid "Contact methods"
|
msgid "Contact methods"
|
||||||
@@ -102,6 +110,14 @@ msgctxt "field:sale.prospect,prospect_trace:"
|
|||||||
msgid "Prospect trace"
|
msgid "Prospect trace"
|
||||||
msgstr "Seguimiento de prospecto"
|
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:"
|
msgctxt "field:sale.call,date:"
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Fecha"
|
msgstr "Fecha"
|
||||||
@@ -226,6 +242,21 @@ msgctxt "field:sale.prospect_trace.make_call.ask,datetime:"
|
|||||||
msgid "Date time"
|
msgid "Date time"
|
||||||
msgstr "Fecha y hora"
|
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:"
|
msgctxt "selection:sale.prospect,business_unit:"
|
||||||
msgid "Brigade"
|
msgid "Brigade"
|
||||||
@@ -259,6 +290,10 @@ msgctxt "selection:prospect.contact_method,contact_type:"
|
|||||||
msgid "Mail"
|
msgid "Mail"
|
||||||
msgstr "Correo electrónico"
|
msgstr "Correo electrónico"
|
||||||
|
|
||||||
|
msgctxt "selection:sale.prospect,rating:"
|
||||||
|
msgid "None"
|
||||||
|
msgstr "Sin calificación"
|
||||||
|
|
||||||
msgctxt "selection:sale.prospect.assign.start,business_unit:"
|
msgctxt "selection:sale.prospect.assign.start,business_unit:"
|
||||||
msgid "Brigade"
|
msgid "Brigade"
|
||||||
msgstr "Brigada"
|
msgstr "Brigada"
|
||||||
@@ -387,6 +422,11 @@ msgctxt "selection:sale.call,call_business_unit:"
|
|||||||
msgid "Equipment"
|
msgid "Equipment"
|
||||||
msgstr "Equipos"
|
msgstr "Equipos"
|
||||||
|
|
||||||
|
msgctxt "selection:sale.prospect_trace.make_call.start,schedule_task:"
|
||||||
|
msgid "Yes"
|
||||||
|
msgstr "Si"
|
||||||
|
|
||||||
|
|
||||||
msgctxt "model:ir.ui.menu,name:menu_calls"
|
msgctxt "model:ir.ui.menu,name:menu_calls"
|
||||||
msgid "Calls"
|
msgid "Calls"
|
||||||
msgstr "Llamadas"
|
msgstr "Llamadas"
|
||||||
@@ -419,6 +459,10 @@ msgctxt "model:ir.ui.menu,name:menu_reassign_by_prospect_wizard"
|
|||||||
msgid "Reassign by prospect"
|
msgid "Reassign by prospect"
|
||||||
msgstr "Reasignar por prospecto"
|
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"
|
msgctxt "model:ir.model.button,string:schedule_call_wizard_button"
|
||||||
msgid "Schedule call"
|
msgid "Schedule call"
|
||||||
@@ -436,6 +480,10 @@ msgctxt "model:ir.model.button,string:reopen_trace_button"
|
|||||||
msgid "Reopen trace"
|
msgid "Reopen trace"
|
||||||
msgstr "Reabrir seguimiento"
|
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:"
|
msgctxt "wizard_button:sale.prospect_trace.make_call,start,end:"
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
@@ -451,7 +499,7 @@ msgstr "Cancelar"
|
|||||||
|
|
||||||
msgctxt "wizard_button:sale.prospect_trace.make_call,ask,schedule_call:"
|
msgctxt "wizard_button:sale.prospect_trace.make_call,ask,schedule_call:"
|
||||||
msgid "Schedule call"
|
msgid "Schedule call"
|
||||||
msgstr "Agendar"
|
msgstr "Agendar llamada"
|
||||||
|
|
||||||
msgctxt "wizard_button:sale.prospect_trace.schedule,start,end:"
|
msgctxt "wizard_button:sale.prospect_trace.schedule,start,end:"
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
@@ -459,7 +507,15 @@ msgstr "Cancelar"
|
|||||||
|
|
||||||
msgctxt "wizard_button:sale.prospect_trace.schedule,start,schedule:"
|
msgctxt "wizard_button:sale.prospect_trace.schedule,start,schedule:"
|
||||||
msgid "Schedule"
|
msgid "Schedule"
|
||||||
msgstr "Agendar"
|
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:"
|
msgctxt "wizard_button:sale.prospect.assign,start,end:"
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
@@ -513,6 +569,19 @@ msgctxt "model:ir.action.act_window.domain,name:act_prospect_domain_assigned"
|
|||||||
msgid "Assigned"
|
msgid "Assigned"
|
||||||
msgstr "Asignado"
|
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"
|
msgctxt "model:ir.action,name:schedule_call_wizard"
|
||||||
msgid "Schedule call"
|
msgid "Schedule call"
|
||||||
msgstr "Agendar llamada"
|
msgstr "Agendar llamada"
|
||||||
|
|||||||
251
prospect.py
251
prospect.py
@@ -1,251 +0,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.
|
|
||||||
from trytond.wizard import Wizard, StateView, Button, StateTransition
|
|
||||||
from trytond.model import ModelSQL, ModelView, fields
|
|
||||||
from trytond.pyson import Eval, If
|
|
||||||
from trytond.pool import Pool
|
|
||||||
|
|
||||||
|
|
||||||
class Prospect(ModelSQL, ModelView):
|
|
||||||
'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)
|
|
||||||
|
|
||||||
department = fields.Many2One('sale.department', 'Department')
|
|
||||||
city = fields.Many2One('sale.city', 'City',
|
|
||||||
domain=[If(Eval('department'),
|
|
||||||
('parent', '=', Eval('department')))])
|
|
||||||
|
|
||||||
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')
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def default_state(cls):
|
|
||||||
return 'unassigned'
|
|
||||||
|
|
||||||
@fields.depends('city', 'department')
|
|
||||||
def on_change_city(self):
|
|
||||||
if self.city:
|
|
||||||
self.department = self.city.parent
|
|
||||||
|
|
||||||
|
|
||||||
class ContactMethod(ModelSQL, ModelView):
|
|
||||||
'Mecanismo de contacto'
|
|
||||||
__name__ = 'prospect.contact_method'
|
|
||||||
|
|
||||||
contact_type = fields.Selection([
|
|
||||||
('phone', 'Phone'),
|
|
||||||
('mobile', 'Mobile'),
|
|
||||||
('mail', 'Mail')
|
|
||||||
], 'Contact type', required=True)
|
|
||||||
|
|
||||||
value = fields.Char('Value', required=True)
|
|
||||||
name = fields.Char('Name')
|
|
||||||
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):
|
|
||||||
return 'mobile'
|
|
||||||
|
|
||||||
def get_rec_name(self, name):
|
|
||||||
fields = [self.name, self.job, self.value]
|
|
||||||
contact_rec_name = ''
|
|
||||||
|
|
||||||
for field in fields:
|
|
||||||
if field:
|
|
||||||
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'
|
|
||||||
101
prospect.xml
101
prospect.xml
@@ -8,19 +8,22 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
</record>
|
</record>
|
||||||
<record model="res.group" id="group_prospect_admin">
|
<record model="res.group" id="group_prospect_admin">
|
||||||
<field name="name">Prospect Administrator</field>
|
<field name="name">Prospect Administrator</field>
|
||||||
<field name="parent" ref="group_prospect"/>
|
<field name="parent" ref="group_prospect" />
|
||||||
</record>
|
</record>
|
||||||
<record model="res.user-res.group" id="user_admin_group_prospect">
|
<record model="res.user-res.group" id="user_admin_group_prospect">
|
||||||
<field name="user" ref="res.user_admin"/>
|
<field name="user" ref="res.user_admin" />
|
||||||
<field name="group" ref="group_prospect"/>
|
<field name="group" ref="group_prospect" />
|
||||||
</record>
|
</record>
|
||||||
<record model="res.user-res.group" id="user_admin_group_prospect_admin">
|
<record model="res.user-res.group" id="user_admin_group_prospect_admin">
|
||||||
<field name="user" ref="res.user_admin"/>
|
<field name="user" ref="res.user_admin" />
|
||||||
<field name="group" ref="group_prospect_admin"/>
|
<field name="group" ref="group_prospect_admin" />
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.action.act_window" id="act_prospect_tree">
|
<record model="ir.action.act_window" id="act_prospect_tree">
|
||||||
<field name="name">Prospects</field>
|
<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>
|
<field name="res_model">sale.prospect</field>
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.ui.view" id="prospect_view_tree">
|
<record model="ir.ui.view" id="prospect_view_tree">
|
||||||
@@ -34,39 +37,39 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<field name="name">prospect_form</field>
|
<field name="name">prospect_form</field>
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.action.act_window.view" id="act_prospect_tree_view1">
|
<record model="ir.action.act_window.view" id="act_prospect_tree_view1">
|
||||||
<field name="sequence" eval="10"/>
|
<field name="sequence" eval="10" />
|
||||||
<field name="view" ref="prospect_view_tree"/>
|
<field name="view" ref="prospect_view_tree" />
|
||||||
<field name="act_window" ref="act_prospect_tree"/>
|
<field name="act_window" ref="act_prospect_tree" />
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.action.act_window.view" id="act_prospect_form_view1">
|
<record model="ir.action.act_window.view" id="act_prospect_form_view1">
|
||||||
<field name="sequence" eval="20"/>
|
<field name="sequence" eval="20" />
|
||||||
<field name="view" ref="prospect_view_form"/>
|
<field name="view" ref="prospect_view_form" />
|
||||||
<field name="act_window" ref="act_prospect_tree"/>
|
<field name="act_window" ref="act_prospect_tree" />
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.action.act_window.domain" id="act_prospect_domain_unassigned">
|
<record model="ir.action.act_window.domain" id="act_prospect_domain_unassigned">
|
||||||
<field name="name">Unassigned</field>
|
<field name="name">Unassigned</field>
|
||||||
<field name="sequence" eval="10"/>
|
<field name="sequence" eval="10" />
|
||||||
<field name="domain" eval="[('state', '=', 'unassigned')]" pyson="1"/>
|
<field name="domain" eval="[('state', '=', 'unassigned')]" pyson="1" />
|
||||||
<field name="count" eval="True"/>
|
<field name="count" eval="True" />
|
||||||
<field name="act_window" ref="act_prospect_tree"/>
|
<field name="act_window" ref="act_prospect_tree" />
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.action.act_window.domain" id="act_prospect_domain_assigned">
|
<record model="ir.action.act_window.domain" id="act_prospect_domain_assigned">
|
||||||
<field name="name">Assigned</field>
|
<field name="name">Assigned</field>
|
||||||
<field name="sequence" eval="10"/>
|
<field name="sequence" eval="10" />
|
||||||
<field name="domain" eval="[('state', '=', 'assigned')]" pyson="1"/>
|
<field name="domain" eval="[('state', '=', 'assigned')]" pyson="1" />
|
||||||
<field name="count" eval="True"/>
|
<field name="count" eval="True" />
|
||||||
<field name="act_window" ref="act_prospect_tree"/>
|
<field name="act_window" ref="act_prospect_tree" />
|
||||||
</record>
|
</record>
|
||||||
<menuitem
|
<menuitem
|
||||||
parent="menu_calls"
|
parent="menu_calls"
|
||||||
sequence="10"
|
sequence="10"
|
||||||
id="menu_prospects_tree"
|
id="menu_prospects_tree"
|
||||||
icon="tryton-party"
|
icon="tryton-party"
|
||||||
action="act_prospect_tree"/>
|
action="act_prospect_tree" />
|
||||||
|
|
||||||
<record model="ir.ui.menu-res.group" id="menu_prospects_group_prospect">
|
<record model="ir.ui.menu-res.group" id="menu_prospects_group_prospect">
|
||||||
<field name="menu" ref="menu_prospects_tree"/>
|
<field name="menu" ref="menu_prospects_tree" />
|
||||||
<field name="group" ref="group_prospect"/>
|
<field name="group" ref="group_prospect" />
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.action.act_window" id="act_contact_method_tree">
|
<record model="ir.action.act_window" id="act_contact_method_tree">
|
||||||
@@ -84,14 +87,14 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<field name="name">contact_method_form</field>
|
<field name="name">contact_method_form</field>
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.action.act_window.view" id="act_contact_method_tree_view1">
|
<record model="ir.action.act_window.view" id="act_contact_method_tree_view1">
|
||||||
<field name="sequence" eval="10"/>
|
<field name="sequence" eval="10" />
|
||||||
<field name="view" ref="contact_method_view_tree"/>
|
<field name="view" ref="contact_method_view_tree" />
|
||||||
<field name="act_window" ref="act_contact_method_tree"/>
|
<field name="act_window" ref="act_contact_method_tree" />
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.action.act_window.view" id="act_contact_method_form_view1">
|
<record model="ir.action.act_window.view" id="act_contact_method_form_view1">
|
||||||
<field name="sequence" eval="20"/>
|
<field name="sequence" eval="20" />
|
||||||
<field name="view" ref="contact_method_view_form"/>
|
<field name="view" ref="contact_method_view_form" />
|
||||||
<field name="act_window" ref="act_contact_method_tree"/>
|
<field name="act_window" ref="act_contact_method_tree" />
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.action.wizard" id="assign_operator_wizard">
|
<record model="ir.action.wizard" id="assign_operator_wizard">
|
||||||
@@ -106,17 +109,17 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<record model="ir.action.keyword" id="assign_operator_wizard_keyword">
|
<record model="ir.action.keyword" id="assign_operator_wizard_keyword">
|
||||||
<field name="keyword">form_action</field>
|
<field name="keyword">form_action</field>
|
||||||
<field name="model">sale.prospect, -1</field>
|
<field name="model">sale.prospect, -1</field>
|
||||||
<field name="action" ref="assign_operator_wizard"/>
|
<field name="action" ref="assign_operator_wizard" />
|
||||||
</record>
|
</record>
|
||||||
<menuitem
|
<menuitem
|
||||||
parent="menu_prospects_tree"
|
parent="menu_prospects_tree"
|
||||||
sequence="40"
|
sequence="40"
|
||||||
id="menu_prospects_assigned_wizard"
|
id="menu_prospects_assigned_wizard"
|
||||||
action="assign_operator_wizard"/>
|
action="assign_operator_wizard" />
|
||||||
|
|
||||||
<record model="ir.ui.menu-res.group" id="menu_prospect_assigned_group_prospect">
|
<record model="ir.ui.menu-res.group" id="menu_prospect_assigned_group_prospect">
|
||||||
<field name="menu" ref="menu_prospects_assigned_wizard"/>
|
<field name="menu" ref="menu_prospects_assigned_wizard" />
|
||||||
<field name="group" ref="group_prospect_admin"/>
|
<field name="group" ref="group_prospect_admin" />
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.action.wizard" id="reassign_by_operator_wizard">
|
<record model="ir.action.wizard" id="reassign_by_operator_wizard">
|
||||||
@@ -133,18 +136,18 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
parent="menu_prospects_tree"
|
parent="menu_prospects_tree"
|
||||||
sequence="50"
|
sequence="50"
|
||||||
id="menu_reassign"
|
id="menu_reassign"
|
||||||
icon='tryton-refresh'/>
|
icon='tryton-refresh' />
|
||||||
|
|
||||||
<record model="ir.ui.menu-res.group" id="menu_prospect_reassigned_group_prospect">
|
<record model="ir.ui.menu-res.group" id="menu_prospect_reassigned_group_prospect">
|
||||||
<field name="menu" ref="menu_reassign"/>
|
<field name="menu" ref="menu_reassign" />
|
||||||
<field name="group" ref="group_prospect_admin"/>
|
<field name="group" ref="group_prospect_admin" />
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem
|
<menuitem
|
||||||
parent="menu_reassign"
|
parent="menu_reassign"
|
||||||
sequence="10"
|
sequence="10"
|
||||||
id="menu_reassign_by_operator_wizard"
|
id="menu_reassign_by_operator_wizard"
|
||||||
action="reassign_by_operator_wizard"/>
|
action="reassign_by_operator_wizard" />
|
||||||
|
|
||||||
<record model="ir.action.wizard" id="reassign_by_prospect_wizard">
|
<record model="ir.action.wizard" id="reassign_by_prospect_wizard">
|
||||||
<field name="name">Reassign by prospect</field>
|
<field name="name">Reassign by prospect</field>
|
||||||
@@ -159,24 +162,24 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
parent="menu_reassign"
|
parent="menu_reassign"
|
||||||
sequence="20"
|
sequence="20"
|
||||||
id="menu_reassign_by_prospect_wizard"
|
id="menu_reassign_by_prospect_wizard"
|
||||||
action="reassign_by_prospect_wizard"/>
|
action="reassign_by_prospect_wizard" />
|
||||||
|
|
||||||
|
|
||||||
<record model="ir.model.access" id="access_sale">
|
<record model="ir.model.access" id="access_sale">
|
||||||
<field name="model" search="[('model', '=', 'sale.prospect')]"/>
|
<field name="model" search="[('model', '=', 'sale.prospect')]" />
|
||||||
<field name="perm_read" eval="False"/>
|
<field name="perm_read" eval="False" />
|
||||||
<field name="perm_write" eval="False"/>
|
<field name="perm_write" eval="False" />
|
||||||
<field name="perm_create" eval="False"/>
|
<field name="perm_create" eval="False" />
|
||||||
<field name="perm_delete" eval="False"/>
|
<field name="perm_delete" eval="False" />
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.model.access" id="access_sale_prospect">
|
<record model="ir.model.access" id="access_sale_prospect">
|
||||||
<field name="model" search="[('model', '=', 'sale.prospect')]"/>
|
<field name="model" search="[('model', '=', 'sale.prospect')]" />
|
||||||
<field name="group" ref="group_prospect"/>
|
<field name="group" ref="group_prospect" />
|
||||||
<field name="perm_read" eval="True"/>
|
<field name="perm_read" eval="True" />
|
||||||
<field name="perm_write" eval="True"/>
|
<field name="perm_write" eval="True" />
|
||||||
<field name="perm_create" eval="True"/>
|
<field name="perm_create" eval="True" />
|
||||||
<field name="perm_delete" eval="True"/>
|
<field name="perm_delete" eval="True" />
|
||||||
</record>
|
</record>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
</tryton>
|
</tryton>
|
||||||
35
tests/scenario_assign_prospect_to_me.rst
Normal file
35
tests/scenario_assign_prospect_to_me.rst
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
Importaciones::
|
||||||
|
|
||||||
|
>>> from proteus import Model, Wizard
|
||||||
|
>>> from trytond.transaction import Transaction
|
||||||
|
>>> from trytond.tests.tools import activate_modules, set_user
|
||||||
|
|
||||||
|
Activar módulos::
|
||||||
|
|
||||||
|
>>> config = activate_modules('sale_opportunity_management')
|
||||||
|
|
||||||
|
Crear operario::
|
||||||
|
>>> User = Model.get('res.user')
|
||||||
|
>>> operator, = User.find([('name', '=', 'Administrator')])
|
||||||
|
>>> operator.is_operator = True
|
||||||
|
>>> operator.save()
|
||||||
|
>>> set_user(operator.id)
|
||||||
|
|
||||||
|
Crear prospecto::
|
||||||
|
|
||||||
|
>>> Prospect = Model.get('sale.prospect')
|
||||||
|
>>> prospect = Prospect()
|
||||||
|
|
||||||
|
>>> prospect.name = 'Assignable To Me S.A.S'
|
||||||
|
>>> contact_method = prospect.contact_methods.new(value='123123123', name='Ricardo', job='Infraestructura')
|
||||||
|
>>> prospect.business_unit = 'brigade'
|
||||||
|
>>> prospect.save()
|
||||||
|
|
||||||
|
|
||||||
|
[ Se inició seguimiento, asignado al operador que lo creó ]
|
||||||
|
>>> ProspectTrace = Model.get('sale.prospect_trace')
|
||||||
|
>>> prospect_trace, = ProspectTrace.find([('prospect', '=', prospect)])
|
||||||
|
>>> assigned_operator_id = prospect_trace.prospect_assigned_operator.id
|
||||||
|
>>> assert operator.id == assigned_operator_id
|
||||||
|
>>> assert prospect.assigned_operator.id == assigned_operator_id
|
||||||
|
|
||||||
@@ -95,6 +95,10 @@ Crear tercer prospecto::
|
|||||||
>>> prospect3.business_unit = 'optics'
|
>>> prospect3.business_unit = 'optics'
|
||||||
>>> prospect3.save()
|
>>> prospect3.save()
|
||||||
|
|
||||||
|
Asignar tipificación a un prospecto
|
||||||
|
>>> prospect3.rating = '1'
|
||||||
|
>>> prospect3.comments = 'Calificación al cliente'
|
||||||
|
|
||||||
------------------------------------
|
------------------------------------
|
||||||
Asignación de prospectos a operarios
|
Asignación de prospectos a operarios
|
||||||
------------------------------------
|
------------------------------------
|
||||||
@@ -192,6 +196,11 @@ Verificar creación de seguimiento de prospecto::
|
|||||||
>>> prospect_trace.prospect_contacts
|
>>> 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)]
|
[proteus.Model.get('prospect.contact_method')(1), proteus.Model.get('prospect.contact_method')(2), proteus.Model.get('prospect.contact_method')(3)]
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
Crear llamadas a un seguimiento de prospecto::
|
Crear llamadas a un seguimiento de prospecto::
|
||||||
>>> make_call = Wizard('sale.prospect_trace.make_call', [prospect_trace])
|
>>> make_call = Wizard('sale.prospect_trace.make_call', [prospect_trace])
|
||||||
@@ -265,7 +274,7 @@ Crear una llamada agendada previamente::
|
|||||||
>>> prospect_trace.state
|
>>> prospect_trace.state
|
||||||
'open'
|
'open'
|
||||||
|
|
||||||
Hacer llamada y programar tarea
|
Hacer llamada y programar tarea::
|
||||||
>>> make_call = Wizard('sale.prospect_trace.make_call', [prospect_trace])
|
>>> 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.description = 'Prospect told me to send him an email'
|
||||||
>>> make_call.form.interest = '3'
|
>>> make_call.form.interest = '3'
|
||||||
@@ -282,6 +291,13 @@ Hacer llamada y programar tarea
|
|||||||
>>> task
|
>>> task
|
||||||
proteus.Model.get('sale.pending_task')(1)
|
proteus.Model.get('sale.pending_task')(1)
|
||||||
|
|
||||||
|
>>> task.state
|
||||||
|
'pending'
|
||||||
|
|
||||||
|
>>> task.click('close_task')
|
||||||
|
>>> task.state
|
||||||
|
'done'
|
||||||
|
|
||||||
Hacer llamada y cerrar venta (Seguimiento de prospecto)::
|
Hacer llamada y cerrar venta (Seguimiento de prospecto)::
|
||||||
>>> make_call = Wizard('sale.prospect_trace.make_call', [prospect_trace])
|
>>> make_call = Wizard('sale.prospect_trace.make_call', [prospect_trace])
|
||||||
>>> make_call.form.description = 'Closed sale'
|
>>> make_call.form.description = 'Closed sale'
|
||||||
@@ -349,8 +365,14 @@ Crear un usuario de rol administrador::
|
|||||||
>>> admin.user_admin == True
|
>>> admin.user_admin == True
|
||||||
True
|
True
|
||||||
|
|
||||||
|
Agregar un nuevo método de contacto desde prospecto
|
||||||
|
>>> contact_method = prospect1.contact_methods.new(value='0000000000', name='Nuevo', job='Puesto increíble')
|
||||||
|
>>> prospect1.save()
|
||||||
|
|
||||||
|
>>> prospect1.contact_methods[-1].value
|
||||||
|
'0000000000'
|
||||||
|
>>> prospect_trace.prospect_contacts[-1].value
|
||||||
|
'0000000000'
|
||||||
|
|
||||||
--------
|
--------
|
||||||
Reportes
|
Reportes
|
||||||
@@ -384,3 +406,4 @@ Reportes
|
|||||||
* Reporte de prospectos potenciales
|
* Reporte de prospectos potenciales
|
||||||
* llamadas con un nivel de interés alto
|
* llamadas con un nivel de interés alto
|
||||||
* Seguimiento de prospecto al que pertenecen las llamadas
|
* Seguimiento de prospecto al que pertenecen las llamadas
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,17 @@
|
|||||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||||
this repository contains the full copyright notices and license terms. -->
|
this repository contains the full copyright notices and license terms. -->
|
||||||
<form col="6">
|
<form col="6">
|
||||||
<label name="operator"/>
|
<label name="operator" />
|
||||||
<field name="operator"/>
|
<field name="operator" />
|
||||||
<label name="business_unit"/>
|
<label name="business_unit" />
|
||||||
<field name="business_unit"/>
|
<field name="business_unit" />
|
||||||
<label name="prospects_chunk"/>
|
<label name="prospects_chunk" />
|
||||||
<field name="prospects_chunk"/>
|
<field name="prospects_chunk" />
|
||||||
|
|
||||||
<notebook colspan="6">
|
<notebook colspan="6">
|
||||||
<page string="Prospects" id="prospects_to_assign" col="6">
|
<page string="Prospects" id="prospects_to_assign" col="6">
|
||||||
<group col="2" id="prospects">
|
<group col="2" id="prospects">
|
||||||
<field name="prospects"/>
|
<field name="prospects" />
|
||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
|
|||||||
12
view/pending_task_form.xml
Normal file
12
view/pending_task_form.xml
Normal 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>
|
||||||
8
view/pending_task_tree.xml
Normal file
8
view/pending_task_tree.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?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="prospect_trace" expand="1"/>
|
||||||
|
<field name="description" expand="1"/>
|
||||||
|
<button name="close_task"/>
|
||||||
|
</tree>
|
||||||
@@ -22,13 +22,24 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<page string="Contact methods" id="contact_methods">
|
<page string="Contact methods" id="contact_methods">
|
||||||
<field name="contact_methods" colspan="2"/>
|
<field name="contact_methods" colspan="2"/>
|
||||||
</page>
|
</page>
|
||||||
|
<page string="About prospect" id="contact_methods">
|
||||||
|
<label name="rating"/>
|
||||||
|
<field name="rating"/>
|
||||||
|
<newline/>
|
||||||
|
<label name="comments"/>
|
||||||
|
<field name="comments"/>
|
||||||
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
<newline/>
|
<newline/>
|
||||||
|
|
||||||
<group col="4" id="stated">
|
<group col="6" colspan="5" id="footer" yalign="0">
|
||||||
<label name="assigned_operator"/>
|
<label name="assigned_operator"/>
|
||||||
<field name="assigned_operator"/>
|
<field name="assigned_operator"/>
|
||||||
<label name="state"/>
|
<label name="state"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
|
<group col="-1" colspan="1" id="checkboxes">
|
||||||
|
<label name="active"/>
|
||||||
|
<field name="active" xexpand="0" width="25"/>
|
||||||
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<field name="department" expand="1"/>
|
<field name="department" expand="1"/>
|
||||||
<field name="city" expand="1"/>
|
<field name="city" expand="1"/>
|
||||||
<field name="assigned_operator" expand="1"/>
|
<field name="assigned_operator" expand="1"/>
|
||||||
|
<field name="rating" expand="1"/>
|
||||||
</tree>
|
</tree>
|
||||||
@@ -3,7 +3,9 @@
|
|||||||
this repository contains the full copyright notices and license terms. -->
|
this repository contains the full copyright notices and license terms. -->
|
||||||
<data>
|
<data>
|
||||||
<xpath expr="//field[@name='name']" position="after">
|
<xpath expr="//field[@name='name']" position="after">
|
||||||
<label name="user_admin"/>
|
<label name="user_admin" />
|
||||||
<field name="user_admin"/>
|
<field name="user_admin" />
|
||||||
|
<label name="is_operator" />
|
||||||
|
<field name="is_operator" />
|
||||||
</xpath>
|
</xpath>
|
||||||
</data>
|
</data>
|
||||||
Reference in New Issue
Block a user