Re-engineering
This commit is contained in:
parent
13398f774b
commit
827db71f79
21
__init__.py
21
__init__.py
|
@ -13,11 +13,12 @@ from . import party_validation
|
|||
from . import contract
|
||||
from . import ir
|
||||
from . import company
|
||||
from . import dash
|
||||
from . import commission
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
# exceptions.IncompletePartyValidation,
|
||||
survey.SurveyGroup,
|
||||
survey.SurveyTemplate,
|
||||
survey.SurveyTemplateLine,
|
||||
|
@ -33,26 +34,20 @@ def register():
|
|||
activity.Activity,
|
||||
opportunity.Opportunity,
|
||||
opportunity.CrmOpportunityLine,
|
||||
#opportunity.PartyValidationOpportunity,
|
||||
#opportunity.OpportunityTraceability,
|
||||
#opportunity.OpportunityKind,
|
||||
#opportunity.OpportunityKindConcept,
|
||||
opportunity.CrmOpportunityFollowUp,
|
||||
opportunity.OpportunityCancellReason,
|
||||
ir.Cron,
|
||||
# opportunity.PartyEvaluationConcept,
|
||||
# opportunity.PartyEvaluation,
|
||||
# party_validation.Validation,
|
||||
# party_validation.ValidationGroup,
|
||||
party_validation.ValidationTemplate,
|
||||
party_validation.ValidationTemplateAsk,
|
||||
party_validation.OpportunityValidation,
|
||||
party_validation.ValidationHistoryAsk,
|
||||
contract.Contract,
|
||||
company.Company,
|
||||
# opportunity.OpportunityEmployee,
|
||||
# opportunity.OpportunityEmployeeContext,
|
||||
# opportunity.OpportunityMonthly,
|
||||
# opportunity.OpportunityEmployeeMonthly,
|
||||
dash.DashApp,
|
||||
dash.AppCRMSales,
|
||||
dash.AppCRMService,
|
||||
dash.AppCRMMarketing,
|
||||
commission.Agent,
|
||||
module='crm', type_='model')
|
||||
Pool.register(
|
||||
customer_service.CustomerServiceReport,
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# 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.pool import PoolMeta
|
||||
from trytond.model import fields
|
||||
|
||||
|
||||
class Agent(metaclass=PoolMeta):
|
||||
__name__ = 'commission.agent'
|
||||
employee = fields.Many2One('company.employee', 'Employee',
|
||||
help="Associates the employee with the agent")
|
|
@ -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. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="agent_view_form">
|
||||
<field name="model">commission.agent</field>
|
||||
<field name="inherit" ref="commission.agent_view_form"/>
|
||||
<field name="name">agent_form</field>
|
||||
</record>
|
||||
|
||||
<!-- <record model="ir.ui.view" id="commission_agent_view_list">
|
||||
<field name="model">commission.agent</field>
|
||||
<field name="inherit" ref="commission.commission_agent_view_list"/>
|
||||
<field name="name">agent_list</field>
|
||||
</record> -->
|
||||
|
||||
</data>
|
||||
</tryton>
|
|
@ -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.
|
||||
|
||||
from trytond.model import ModelView, ModelSQL, fields
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pyson import Id
|
||||
|
@ -9,22 +10,19 @@ from trytond.pyson import Eval
|
|||
class Configuration(ModelSQL, ModelView):
|
||||
'CRM Configuration'
|
||||
__name__ = 'crm.configuration'
|
||||
|
||||
company = fields.Many2One('company.company', 'Company', required=True)
|
||||
customer_service_sequence = fields.Many2One('ir.sequence',
|
||||
'Customer Service Sequence', required=True,
|
||||
domain=[('sequence_type', '=',
|
||||
Id('crm', 'sequence_type_crm'))])
|
||||
domain=[('sequence_type', '=', Id('crm', 'sequence_type_crm'))])
|
||||
survey_sequence = fields.Many2One('ir.sequence',
|
||||
'Survey Sequence', required=True,
|
||||
domain=[('sequence_type', '=',
|
||||
Id('crm', 'sequence_type_survey_service'))])
|
||||
efficay_hour_limit = fields.Integer('Efficay Hour Limit',
|
||||
required=True)
|
||||
response_time_customer = fields.Integer('Response Time Customer',
|
||||
required=True, help="Limit in hours for response to customer")
|
||||
activity_sequence = fields.Many2One('ir.sequence',
|
||||
'Activity Sequence', required=True,
|
||||
domain=[('sequence_type', '=',
|
||||
Id('crm', 'sequence_type_activity'))])
|
||||
company = fields.Many2One('company.company', 'Company', required=True)
|
||||
domain=[('sequence_type', '=', Id('crm', 'sequence_type_activity'))])
|
||||
opportunity_sequence = fields.Many2One(
|
||||
'ir.sequence', "Opportunity Sequence", required=True,
|
||||
domain=[
|
||||
|
|
4
crm.xml
4
crm.xml
|
@ -30,7 +30,9 @@
|
|||
<field name="group" ref="group_crm"/>
|
||||
</record>
|
||||
|
||||
<menuitem name="Reports" parent="menu_crm" id="menu_reports" sequence="100" active="100"/>
|
||||
<menuitem name="Reports" parent="menu_crm" id="menu_reports"
|
||||
sequence="200"
|
||||
active="100"/>
|
||||
|
||||
</data>
|
||||
</tryton>
|
||||
|
|
|
@ -71,8 +71,9 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="domain"></field>
|
||||
<field name="act_window" ref="act_customer_service_form"/>
|
||||
</record>
|
||||
<menuitem parent="menu_crm" sequence="120"
|
||||
action="act_customer_service_form" id="menu_customer_service_form"/>
|
||||
<menuitem parent="menu_crm" sequence="40"
|
||||
action="act_customer_service_form"
|
||||
id="menu_customer_service_form"/>
|
||||
|
||||
<!-- Buttons -->
|
||||
<record model="ir.model.button" id="customer_service_cancel_button">
|
||||
|
|
|
@ -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.pool import PoolMeta
|
||||
from trytond.modules.dash.dash import DashAppBase
|
||||
|
||||
|
||||
class DashApp(metaclass=PoolMeta):
|
||||
__name__ = "dash.app"
|
||||
|
||||
@classmethod
|
||||
def _get_origin(cls):
|
||||
origins = super(DashApp, cls)._get_origin()
|
||||
origins.extend(
|
||||
[
|
||||
"dash.app.crm_sales",
|
||||
"dash.app.crm_service",
|
||||
"dash.app.crm_marketing",
|
||||
]
|
||||
)
|
||||
return origins
|
||||
|
||||
@classmethod
|
||||
def get_selection(cls):
|
||||
options = super(DashApp, cls).get_selection()
|
||||
options.extend(
|
||||
[
|
||||
("crm_sales", "CRM Sales"),
|
||||
("crm_service", "CRM Service"),
|
||||
("crm_marketing", "CRM Marketing"),
|
||||
]
|
||||
)
|
||||
return options
|
||||
|
||||
|
||||
class AppCRMSales(DashAppBase):
|
||||
"App CRM Sales"
|
||||
__name__ = "dash.app.crm_sales"
|
||||
|
||||
|
||||
class AppCRMService(DashAppBase):
|
||||
"App CRM Service"
|
||||
__name__ = "dash.app.crm_service"
|
||||
|
||||
|
||||
class AppCRMMarketing(DashAppBase):
|
||||
"App CRM Marketing"
|
||||
__name__ = "dash.app.crm_marketing"
|
|
@ -0,0 +1,89 @@
|
|||
<?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 noupdate="1">
|
||||
<record model="dash.app.crm_sales" id="dash_app_crm_sales">
|
||||
<field name="company">1</field>
|
||||
<field name="icon">th</field>
|
||||
<field name="kind">internal</field>
|
||||
</record>
|
||||
<record model="dash.app" id="app_crm_sales">
|
||||
<field name="name">CRM Sales</field>
|
||||
<field name="origin">dash.app.crm_sales,1</field>
|
||||
<field name="active">True</field>
|
||||
<field name="app_name">crm_sales</field>
|
||||
</record>
|
||||
|
||||
<record model="dash.app.crm_service" id="dash_app_crm_service">
|
||||
<field name="company">1</field>
|
||||
<field name="icon">key</field>
|
||||
<field name="kind">internal</field>
|
||||
</record>
|
||||
<record model="dash.app" id="app_crm_service">
|
||||
<field name="name">CRM Service</field>
|
||||
<field name="origin">dash.app.crm_service,1</field>
|
||||
<field name="active">True</field>
|
||||
<field name="app_name">crm_service</field>
|
||||
</record>
|
||||
|
||||
<record model="dash.app.crm_marketing" id="dash_app_crm_marketing">
|
||||
<field name="company">1</field>
|
||||
<field name="icon">key</field>
|
||||
<field name="kind">external</field>
|
||||
</record>
|
||||
<record model="dash.app" id="app_crm_marketing">
|
||||
<field name="name">CRM Marketing</field>
|
||||
<field name="origin">dash.app.crm_marketing,1</field>
|
||||
<field name="active">True</field>
|
||||
<field name="app_name">crm_marketing</field>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
<data>
|
||||
|
||||
<!-- <record model="dash.report" id="dash_report_checkin_today">
|
||||
<field name="name">Check-In Today</field>
|
||||
<field name="model">hotel.folio</field>
|
||||
<field name="type">card_info</field>
|
||||
<field name="method">report_check_in_today</field>
|
||||
</record>
|
||||
|
||||
<record model="dash.report" id="dash_report_checkout_today">
|
||||
<field name="name">Check-Out Today</field>
|
||||
<field name="model">hotel.folio</field>
|
||||
<field name="type">card_info</field>
|
||||
<field name="method">report_check_out_today</field>
|
||||
</record>
|
||||
|
||||
<record model="dash.report" id="dash_report_occupation_by_room">
|
||||
<field name="name">Occupation Today</field>
|
||||
<field name="model">hotel.folio</field>
|
||||
<field name="type">card_info</field>
|
||||
<field name="method">report_occupation_by_room</field>
|
||||
</record>
|
||||
|
||||
<record model="dash.report" id="dash_report_number_guests">
|
||||
<field name="name">Number Guests</field>
|
||||
<field name="model">hotel.folio</field>
|
||||
<field name="type">card_info</field>
|
||||
<field name="method">report_number_guests</field>
|
||||
</record>
|
||||
|
||||
<record model="dash.report" id="dash_report_current_occupancy_rate">
|
||||
<field name="name">Current Occupancy Rate</field>
|
||||
<field name="model">hotel.folio</field>
|
||||
<field name="type">card_info</field>
|
||||
<field name="method">report_current_occupancy_rate</field>
|
||||
</record>
|
||||
|
||||
<record model="dash.report" id="dash_report_month_occupancy_rate">
|
||||
<field name="name">Month Occupancy Rate</field>
|
||||
<field name="model">hotel.folio</field>
|
||||
<field name="type">line</field>
|
||||
<field name="method">report_month_occupancy_rate</field>
|
||||
</record> -->
|
||||
|
||||
</data>
|
||||
</tryton>
|
200
opportunity.py
200
opportunity.py
|
@ -25,7 +25,7 @@ from trytond.exceptions import UserError
|
|||
from .exceptions import IncompletePartyValidation, ChangeStateWarning
|
||||
from trytond.ir.attachment import AttachmentCopyMixin
|
||||
from trytond.ir.note import NoteCopyMixin
|
||||
from trytond.modules.company.model import employee_field, set_employee
|
||||
# from trytond.modules.company.model import employee_field, set_employee
|
||||
|
||||
|
||||
class Opportunity(
|
||||
|
@ -52,10 +52,9 @@ class Opportunity(
|
|||
|
||||
number = fields.Char('Number', readonly=True, required=True, select=True)
|
||||
reference = fields.Char('Reference', select=True,
|
||||
states={
|
||||
'readonly': Eval('state').in_(['converted', 'won', 'cancelled', 'lost'])
|
||||
})
|
||||
|
||||
states={
|
||||
'readonly': Eval('state').in_(['converted', 'won', 'cancelled', 'lost'])
|
||||
})
|
||||
# kind_opportunity = fields.Many2One('crm.opportunity_kind_concept', 'Opportunity Kind Concept', select=True,
|
||||
# states={
|
||||
# 'readonly': ~Eval('state').in_(['prospecting', 'quote_revision', 'review'])
|
||||
|
@ -71,6 +70,7 @@ class Opportunity(
|
|||
depends=['state', 'company'], required=True)
|
||||
contact = fields.Many2One(
|
||||
'party.contact_mechanism', "Contact",
|
||||
domain=[('party', '=', Eval('party'))],
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
},
|
||||
|
@ -100,9 +100,9 @@ class Opportunity(
|
|||
],
|
||||
depends=_depends_stop)
|
||||
currency = fields.Function(fields.Many2One('currency.currency',
|
||||
'Currency'), 'get_currency')
|
||||
'Currency'), 'get_currency')
|
||||
currency_digits = fields.Function(fields.Integer('Currency Digits'),
|
||||
'get_currency_digits')
|
||||
'get_currency_digits')
|
||||
amount = fields.Numeric('Amount', digits=(16, Eval('currency_digits', 2)),
|
||||
states={
|
||||
'readonly': ~Eval('state').in_(['won', 'lost']),
|
||||
|
@ -110,18 +110,9 @@ class Opportunity(
|
|||
}, depends=_depends_stop +
|
||||
['currency_digits'],
|
||||
help='Estimated revenue amount.')
|
||||
time_ammount = fields.Selection([
|
||||
('monthly', "Monthly"),
|
||||
('bimonthly', "Bimonthly"),
|
||||
('biannual', "Biannual"),
|
||||
('annual', "Annual")], "Time Ammount", select=True, sort=False,
|
||||
states={
|
||||
'readonly': Eval('state').in_(['won', 'lost'])
|
||||
})
|
||||
|
||||
payment_term = fields.Many2One('account.invoice.payment_term',
|
||||
'Payment Term')
|
||||
employee = fields.Many2One('company.employee', 'Employee',
|
||||
agent = fields.Many2One('commission.agent', 'Agent',
|
||||
states={
|
||||
'readonly': Eval('state').in_(['won', 'lost'])
|
||||
},
|
||||
|
@ -132,16 +123,22 @@ class Opportunity(
|
|||
end_date = fields.Date('End Date', select=True,
|
||||
states=_states_stop, depends=_depends_stop)
|
||||
description = fields.Char('Description',
|
||||
states={
|
||||
'readonly': Eval('state').in_(['won', 'lost']),
|
||||
# 'required': ~Eval('state').in_(['lead', 'lost', 'cancelled']),
|
||||
})
|
||||
states={
|
||||
'readonly': Eval('state').in_(['won', 'lost']),
|
||||
# 'required': ~Eval('state').in_(['lead', 'lost', 'cancelled']),
|
||||
})
|
||||
comment = fields.Text('Comment', states=_states_stop, depends=_depends_stop)
|
||||
lines = fields.One2Many('crm.opportunity.line', 'opportunity', 'Lines',
|
||||
states={
|
||||
'readonly': Eval('state').in_(['won', 'lost']),
|
||||
# 'required': ~Eval('state').in_(['lead', 'lost', 'cancelled']),
|
||||
})
|
||||
states={
|
||||
'readonly': Eval('state').in_(['won', 'lost']),
|
||||
# 'required': ~Eval('state').in_(['lead', 'lost', 'cancelled']),
|
||||
})
|
||||
follow_ups = fields.One2Many('crm.opportunity.follow_up',
|
||||
'opportunity', 'Follow-Ups',
|
||||
states={
|
||||
'readonly': Eval('state').in_(['won', 'lost']),
|
||||
# 'required': ~Eval('state').in_(['lead', 'lost', 'cancelled']),
|
||||
})
|
||||
conversion_probability = fields.Float('Conversion Probability',
|
||||
digits=(1, 4), required=True,
|
||||
domain=[
|
||||
|
@ -157,9 +154,8 @@ class Opportunity(
|
|||
}, depends=['state'])
|
||||
sales = fields.One2Many('sale.sale', 'origin', 'Sales')
|
||||
contracts = fields.One2Many('sale.contract', 'origin', 'Contracts')
|
||||
|
||||
converted_by = employee_field(
|
||||
"Converted By", states=['converted', 'won', 'lost'])
|
||||
# converted_by = employee_field(
|
||||
# "Converted By", states=['converted', 'won', 'lost'])
|
||||
# state = fields.Selection([
|
||||
# ('prospecting', "Prospecting"),
|
||||
# ('analysis', "Analysis"),
|
||||
|
@ -182,15 +178,13 @@ class Opportunity(
|
|||
('lost', 'Lost'),
|
||||
], "State", required=True, select=True,
|
||||
sort=False, readonly=True)
|
||||
|
||||
type = fields.Selection([
|
||||
('sale', 'Sale'),
|
||||
('contract', 'Contract'),
|
||||
], "Type", required=True, select=True,
|
||||
states={
|
||||
'readonly': Eval('state').in_(['won', 'lost'])
|
||||
})
|
||||
|
||||
], "Type", required=True, select=True,
|
||||
states={
|
||||
'readonly': Eval('state').in_(['won', 'lost'])
|
||||
})
|
||||
source = fields.Selection([
|
||||
('website', 'Website'),
|
||||
('phone', 'Phone'),
|
||||
|
@ -198,15 +192,13 @@ class Opportunity(
|
|||
('whatsapp', 'WhatsApp'),
|
||||
('salesman', 'Salesman'),
|
||||
('referred', 'Referred'),
|
||||
], "Source", required=True, select=True,
|
||||
states={
|
||||
'readonly': Eval('state').in_(['converted', 'won', 'lost'])
|
||||
})
|
||||
|
||||
total = fields.Function(fields.Float('Total'),
|
||||
'get_total_opportunity')
|
||||
], "Source", required=True, select=True,
|
||||
states={
|
||||
'readonly': Eval('state').in_(['converted', 'won', 'lost'])
|
||||
})
|
||||
total = fields.Function(fields.Float('Total'), 'get_total_opportunity')
|
||||
total_without_tax = fields.Function(fields.Float('Total'),
|
||||
'get_total_without_tax_opportunity')
|
||||
'get_total_without_tax_opportunity')
|
||||
# cancelled_reason = fields.Selection([
|
||||
# ('',''),
|
||||
# ('Sin acuerdo', "No se llego a un acuerdo"),
|
||||
|
@ -214,17 +206,16 @@ class Opportunity(
|
|||
# states={
|
||||
# 'invisible': ~Eval('state').in_(['analysis', 'review', 'quote_revision', 'cancelled', 'lost'])
|
||||
# }, depends=['state'])
|
||||
|
||||
# states={
|
||||
# 'readonly': ~Eval('state').in_(['prospecting', 'analysis'])
|
||||
# }
|
||||
|
||||
cancelled_reason = fields.Many2One('crm.opportunity_cancelled_reason', 'Cancelled Reason Concept', select=True,
|
||||
states={
|
||||
#'readonly': ~Eval('state').in_(['prospecting', 'quote_revision', 'review']),
|
||||
'invisible': ~Eval('state').in_(['won'])
|
||||
}, depends=['state'])
|
||||
|
||||
cancelled_reason = fields.Many2One(
|
||||
'crm.opportunity_cancelled_reason', 'Cancelled Reason Concept',
|
||||
select=True,
|
||||
states={
|
||||
#'readonly': ~Eval('state').in_(['prospecting', 'quote_revision', 'review']),
|
||||
'invisible': ~Eval('state').in_(['won'])
|
||||
}, depends=['state'])
|
||||
party_validations = fields.One2Many('crm.opportunity.validation',
|
||||
'opportunity', 'Party Validations')
|
||||
is_prospect = fields.Function(fields.Boolean('Is Prospect'), 'get_is_prospect')
|
||||
|
@ -239,7 +230,7 @@ class Opportunity(
|
|||
('opportunity', 'converted'),
|
||||
('opportunity', 'cancelled'),
|
||||
('cancelled', 'opportunity'),
|
||||
('cancelled', 'converted'),
|
||||
('cancelled', 'converted'),
|
||||
('converted', 'cancelled'),
|
||||
('converted', 'opportunity'),
|
||||
('converted', 'won'),
|
||||
|
@ -260,7 +251,6 @@ class Opportunity(
|
|||
},
|
||||
'lost': {
|
||||
'invisible': ~Eval('state').in_(['converted']),
|
||||
|
||||
},
|
||||
'cancelled': {
|
||||
'invisible': Eval('state').in_(['lead', 'won', 'lost', 'cancelled']),
|
||||
|
@ -289,8 +279,6 @@ class Opportunity(
|
|||
# res = False
|
||||
# return res
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def default_state():
|
||||
return 'lead'
|
||||
|
@ -308,10 +296,6 @@ class Opportunity(
|
|||
def default_company():
|
||||
return Transaction().context.get('company')
|
||||
|
||||
@staticmethod
|
||||
def default_employee():
|
||||
return Transaction().context.get('employee')
|
||||
|
||||
@classmethod
|
||||
def default_payment_term(cls):
|
||||
PaymentTerm = Pool().get('account.invoice.payment_term')
|
||||
|
@ -363,6 +347,7 @@ class Opportunity(
|
|||
default = default.copy()
|
||||
default.setdefault('number', None)
|
||||
default.setdefault('sales', None)
|
||||
default.setdefault('contracts', None)
|
||||
default.setdefault('converted_by')
|
||||
return super(CrmOpportunity, cls).copy(opportunities, default=default)
|
||||
|
||||
|
@ -396,7 +381,7 @@ class Opportunity(
|
|||
return {
|
||||
'description':self.description,
|
||||
'party':self.party,
|
||||
'salesman':self.employee,
|
||||
# 'salesman':self.employee,
|
||||
'payment_term':self.payment_term,
|
||||
'company':self.company,
|
||||
'currency':self.company.currency,
|
||||
|
@ -421,7 +406,7 @@ class Opportunity(
|
|||
contact=self.contact,
|
||||
payment_term=self.payment_term,
|
||||
company=self.company,
|
||||
salesman=self.employee,
|
||||
# salesman=self.employee,
|
||||
invoice_address=self.address,
|
||||
shipment_address=self.address,
|
||||
reference=self.reference,
|
||||
|
@ -539,22 +524,22 @@ class Opportunity(
|
|||
def quote_approbation(cls, records):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('quotation')
|
||||
@set_employee('converted_by')
|
||||
def quotation(cls, records):
|
||||
# Analyze if party validation is true in all lines
|
||||
cls.get_party_validation(records)
|
||||
# cls.procces_opportunity(records)
|
||||
history = []
|
||||
for record in records:
|
||||
value = {
|
||||
'opportunity':record.id,
|
||||
'create_date':date.today(),
|
||||
'action':'Cambio de estado a Cotización'
|
||||
}
|
||||
history.append(value)
|
||||
# @classmethod
|
||||
# @ModelView.button
|
||||
# @Workflow.transition('quotation')
|
||||
# @set_employee('converted_by')
|
||||
# def quotation(cls, records):
|
||||
# # Analyze if party validation is true in all lines
|
||||
# cls.get_party_validation(records)
|
||||
# # cls.procces_opportunity(records)
|
||||
# history = []
|
||||
# for record in records:
|
||||
# value = {
|
||||
# 'opportunity':record.id,
|
||||
# 'create_date':date.today(),
|
||||
# 'action':'Cambio de estado a Cotización'
|
||||
# }
|
||||
# history.append(value)
|
||||
|
||||
@property
|
||||
def is_forecast(self):
|
||||
|
@ -749,6 +734,16 @@ class OpportunityCancellReason(ModelSQL, ModelView):
|
|||
# validated_by = fields.Many2One('res.user', 'User')
|
||||
|
||||
|
||||
class CrmOpportunityFollowUp(sequence_ordered(), ModelSQL, ModelView):
|
||||
'CRM Opportunity FollowUp'
|
||||
__name__ = "crm.opportunity.follow_up"
|
||||
opportunity = fields.Many2One('crm.opportunity', 'Opportunity', required=True )
|
||||
follow_date = fields.Date('Follow Date')
|
||||
action = fields.Char('Action')
|
||||
notes = fields.Char('Notes')
|
||||
done_by = fields.Many2One('res.user', 'Done By')
|
||||
|
||||
|
||||
class CrmOpportunityLine(sequence_ordered(), ModelSQL, ModelView):
|
||||
'CRM Opportunity Line'
|
||||
__name__ = "crm.opportunity.line"
|
||||
|
@ -759,48 +754,47 @@ class CrmOpportunityLine(sequence_ordered(), ModelSQL, ModelView):
|
|||
}
|
||||
_depends = ['opportunity_state']
|
||||
|
||||
time_ammount = fields.Selection([
|
||||
('monthly', "Monthly"),
|
||||
('bimonthly', "Bimonthly"),
|
||||
('biannual', "Biannual"),
|
||||
('annual', "Annual")], "Time Ammount", select=True, sort=False,
|
||||
states={
|
||||
'readonly': Eval('state').in_(['won', 'lost'])
|
||||
})
|
||||
opportunity = fields.Many2One('crm.opportunity', 'Opportunity',
|
||||
ondelete='CASCADE', select=True, required=True,
|
||||
states={
|
||||
'readonly': _states['readonly'] & Bool(Eval('opportunity')),
|
||||
},
|
||||
depends=_depends)
|
||||
ondelete='CASCADE', select=True, required=True,
|
||||
states={
|
||||
'readonly': _states['readonly'] & Bool(Eval('opportunity')),
|
||||
},
|
||||
depends=_depends)
|
||||
opportunity_state = fields.Function(
|
||||
fields.Selection('get_opportunity_states', "Opportunity State"),
|
||||
'on_change_with_opportunity_state')
|
||||
product = fields.Many2One('product.product', 'Product', required=True,
|
||||
domain=[('salable', '=', True)], states=_states, depends=_depends)
|
||||
domain=[('salable', '=', True)], states=_states, depends=_depends)
|
||||
quantity = fields.Float('Quantity', required=True,
|
||||
digits=(16, Eval('unit_digits', 2)),
|
||||
states=_states, depends=['unit_digits'] + _depends)
|
||||
digits=(16, Eval('unit_digits', 2)),
|
||||
states=_states, depends=['unit_digits'] + _depends)
|
||||
unit = fields.Many2One('product.uom', 'Unit', required=True,
|
||||
states=_states, depends=_depends)
|
||||
|
||||
states=_states, depends=_depends)
|
||||
unit_digits = fields.Function(fields.Integer('Unit Digits'),
|
||||
'on_change_with_unit_digits')
|
||||
|
||||
tax = fields.Function(fields.Float('Tax Line'),
|
||||
'get_tax_line')
|
||||
|
||||
total_line = fields.Function(fields.Integer('Total Line'),
|
||||
'get_total_line')
|
||||
base_tax = fields.Function(fields.Float('Base Tax'),
|
||||
'get_base_tax')
|
||||
|
||||
tax = fields.Function(fields.Float('Tax Line'), 'get_tax_line')
|
||||
total_line = fields.Function(fields.Integer('Total Line'), 'get_total_line')
|
||||
base_tax = fields.Function(fields.Float('Base Tax'), 'get_base_tax')
|
||||
description = fields.Function(fields.Text('Description'),
|
||||
'on_change_with_description')
|
||||
|
||||
'on_change_with_description')
|
||||
unit_price = fields.Numeric('Unit Price', digits=(16, 2))
|
||||
|
||||
total_line_with_tax = fields.Function(fields.Integer('Total Line'),
|
||||
'get_total_line_with_tax')
|
||||
'get_total_line_with_tax')
|
||||
|
||||
del _states, _depends
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls.__access__.add('opportunity')
|
||||
# @classmethod
|
||||
# def __setup__(cls):
|
||||
# super().__setup__()
|
||||
# cls.__access__.add('opportunity')
|
||||
|
||||
@classmethod
|
||||
def get_opportunity_states(cls):
|
||||
|
|
|
@ -253,6 +253,17 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="name">opportunity_line_tree</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="crm_opportunity_follow_up_view_form">
|
||||
<field name="model">crm.opportunity.follow_up</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">opportunity_follow_up_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="crm_opportunity_follow_up_view_tree">
|
||||
<field name="model">crm.opportunity.follow_up</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">opportunity_follow_up_tree</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="crm_validation_template_view_form">
|
||||
<field name="model">crm.validation_template</field>
|
||||
<field name="type">form</field>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
[tryton]
|
||||
version=6.0.2
|
||||
version=6.0.3
|
||||
depends:
|
||||
party
|
||||
sale
|
||||
sale_contract
|
||||
company_department
|
||||
commission
|
||||
xml:
|
||||
crm.xml
|
||||
configuration.xml
|
||||
|
@ -18,3 +19,5 @@ xml:
|
|||
opportunity.xml
|
||||
message.xml
|
||||
company.xml
|
||||
commission.xml
|
||||
dash.xml
|
||||
|
|
|
@ -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="/form/field[@name='currency']" position="after">
|
||||
<label name="employee"/>
|
||||
<field name="employee"/>
|
||||
</xpath>
|
||||
</data>
|
|
@ -2,16 +2,16 @@
|
|||
<!-- 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="customer_service_sequence"/>
|
||||
<field name="customer_service_sequence"/>
|
||||
<label name="company"/>
|
||||
<field name="company"/>
|
||||
<label name="survey_sequence"/>
|
||||
<field name="survey_sequence"/>
|
||||
<label name="activity_sequence"/>
|
||||
<field name="activity_sequence"/>
|
||||
<label name="customer_service_sequence"/>
|
||||
<field name="customer_service_sequence"/>
|
||||
<label name="opportunity_sequence"/>
|
||||
<field name="opportunity_sequence"/>
|
||||
<label name="efficay_hour_limit"/>
|
||||
<field name="efficay_hour_limit"/>
|
||||
<label name="activity_sequence"/>
|
||||
<field name="activity_sequence"/>
|
||||
<label name="survey_sequence"/>
|
||||
<field name="survey_sequence"/>
|
||||
<label name="response_time_customer"/>
|
||||
<field name="response_time_customer"/>
|
||||
</form>
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
<!-- 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="customer_service_sequence"/>
|
||||
<field name="survey_sequence"/>
|
||||
<field name="activity_sequence"/>
|
||||
<field name="opportunity_sequence"/>
|
||||
<field name="company"/>
|
||||
<field name="company" expand="1"/>
|
||||
<field name="customer_service_sequence" expand="1"/>
|
||||
<field name="survey_sequence" expand="1"/>
|
||||
<field name="activity_sequence" expand="1"/>
|
||||
<field name="opportunity_sequence" expand="1"/>
|
||||
</tree>
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?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="follow_date"/>
|
||||
<field name="follow_date"/>
|
||||
<label name="action"/>
|
||||
<field name="action"/>
|
||||
<label name="done_by"/>
|
||||
<field name="done_by"/>
|
||||
<separator name="notes" colspan="4"/>
|
||||
<field name="notes" colspan="4"/>
|
||||
</form>
|
|
@ -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="follow_date" expand="1"/>
|
||||
<field name="action" expand="1"/>
|
||||
<field name="done_by" expand="1"/>
|
||||
</tree>
|
|
@ -8,25 +8,20 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="contact"/>
|
||||
<label name="number"/>
|
||||
<field name="number"/>
|
||||
|
||||
<label name="address"/>
|
||||
<field name="address"/>
|
||||
<!-- <label name="kind_opportunity"/>
|
||||
<field name="kind_opportunity"/> -->
|
||||
<label name="agent"/>
|
||||
<field name="agent"/>
|
||||
<label name="description"/>
|
||||
<field name="description"/>
|
||||
<label name="type"/>
|
||||
<field name="type"/>
|
||||
<!-- <newline/> -->
|
||||
<label name="source"/>
|
||||
<field name="source"/>
|
||||
<label name="reference"/>
|
||||
<field name="reference"/>
|
||||
|
||||
<label name="amount"/>
|
||||
<field name="amount" symbol="currency"/>
|
||||
<label name="time_ammount"/>
|
||||
<field name="time_ammount"/>
|
||||
<label name="conversion_probability"/>
|
||||
<group id="conversion_probability">
|
||||
<field name="conversion_probability" factor="100" xexpand="0"/>
|
||||
|
@ -36,22 +31,17 @@ this repository contains the full copyright notices and license terms. -->
|
|||
|
||||
<notebook colspan="6">
|
||||
<page string="Opportunity" id="opportunity">
|
||||
<label name="payment_term"/>
|
||||
<field name="payment_term"/>
|
||||
<label name="company"/>
|
||||
<field name="company"/>
|
||||
<newline/>
|
||||
<label name="employee"/>
|
||||
<field name="employee"/>
|
||||
<label name="converted_by"/>
|
||||
<field name="converted_by"/>
|
||||
<label name="start_date"/>
|
||||
<field name="start_date"/>
|
||||
<label name="end_date"/>
|
||||
<field name="end_date"/>
|
||||
<label name="payment_term"/>
|
||||
<field name="payment_term"/>
|
||||
|
||||
<label name="cancelled_reason"/>
|
||||
<field name="cancelled_reason"/>
|
||||
<field name="follow_ups" colspan="4"/>
|
||||
<separator name="comment" colspan="4"/>
|
||||
<field name="comment" colspan="4"/>
|
||||
</page>
|
||||
|
|
|
@ -14,7 +14,8 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="unit"/>
|
||||
<label name="unit_price"/>
|
||||
<field name="unit_price"/>
|
||||
<newline />
|
||||
<label name="description"/>
|
||||
<field name="description" colspan="6"/>
|
||||
<label name="time_ammount"/>
|
||||
<field name="time_ammount"/>
|
||||
<separator string="Description"/>
|
||||
<field name="description" colspan="4"/>
|
||||
</form>
|
||||
|
|
|
@ -6,7 +6,7 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="reference" expand="1"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="employee" expand="1"/>
|
||||
<field name="agent" expand="1"/>
|
||||
<field name="description" expand="1"/>
|
||||
<field name="party" expand="1"/>
|
||||
<field name="amount" symbol="currency"/>
|
||||
|
|
Loading…
Reference in New Issue