merge from 8.0

This commit is contained in:
Christophe Matthieu 2014-07-09 09:43:02 +02:00
commit e26623da01
63 changed files with 589 additions and 571 deletions

View File

@ -98,7 +98,7 @@ class account_invoice(models.Model):
def _compute_reconciled(self):
self.reconciled = self.test_paid()
if not self.reconciled and self.state == 'paid':
self.signal_open_test()
self.signal_workflow('open_test')
@api.model
def _get_reference_type(self):

View File

@ -104,7 +104,7 @@ class account_fiscal_position(osv.osv):
# partner manually set fiscal position always win
if partner.property_account_position:
return part.property_account_position.id
return partner.property_account_position.id
# if no delivery use invocing
if delivery_id:

View File

@ -98,6 +98,24 @@ class account_invoice_report(osv.osv):
}
_order = 'date desc'
_depends = {
'account.invoice': [
'account_id', 'amount_total', 'commercial_partner_id', 'company_id',
'currency_id', 'date_due', 'date_invoice', 'fiscal_position',
'journal_id', 'partner_bank_id', 'partner_id', 'payment_term',
'period_id', 'residual', 'state', 'type', 'user_id',
],
'account.invoice.line': [
'account_id', 'invoice_id', 'price_subtotal', 'product_id',
'quantity', 'uos_id',
],
'product.product': ['product_tmpl_id'],
'product.template': ['categ_id'],
'product.uom': ['category_id', 'factor', 'name', 'uom_type'],
'res.currency.rate': ['currency_id', 'name'],
'res.partner': ['country_id'],
}
def _select(self):
select_str = """
SELECT sub.id, sub.date, sub.product_id, sub.partner_id, sub.country_id,

View File

@ -804,6 +804,12 @@ class account_analytic_account_summary_user(osv.osv):
'user': fields.many2one('res.users', 'User'),
}
_depends = {
'res.users': ['id'],
'account.analytic.line': ['account_id', 'journal_id', 'unit_amount', 'user_id'],
'account.analytic.journal': ['type'],
}
def init(self, cr):
openerp.tools.sql.drop_view_if_exists(cr, 'account_analytic_analysis_summary_user')
cr.execute('''CREATE OR REPLACE VIEW account_analytic_analysis_summary_user AS (
@ -837,6 +843,11 @@ class account_analytic_account_summary_month(osv.osv):
'month': fields.char('Month', size=32, readonly=True),
}
_depends = {
'account.analytic.line': ['account_id', 'date', 'journal_id', 'unit_amount'],
'account.analytic.journal': ['type'],
}
def init(self, cr):
openerp.tools.sql.drop_view_if_exists(cr, 'account_analytic_analysis_summary_month')
cr.execute('CREATE VIEW account_analytic_analysis_summary_month AS (' \

View File

@ -42,6 +42,14 @@ class account_followup_stat_by_partner(osv.osv):
'company_id': fields.many2one('res.company', 'Company', readonly=True),
}
_depends = {
'account.move.line': [
'account_id', 'company_id', 'credit', 'date', 'debit',
'followup_date', 'followup_line_id', 'partner_id', 'reconcile_id',
],
'account.account': ['active', 'type'],
}
def init(self, cr):
tools.drop_view_if_exists(cr, 'account_followup_stat_by_partner')
# Here we don't have other choice but to create a virtual ID based on the concatenation

View File

@ -24,6 +24,7 @@ import crm_segmentation
import crm_lead
import sales_team
import calendar_event
import ir_http
import crm_phonecall
import report
import wizard

View File

@ -19,13 +19,8 @@
#
##############################################################################
import calendar
from datetime import date, datetime
from dateutil import relativedelta
from openerp import tools
from openerp.osv import fields
from openerp.osv import osv
from openerp.osv import osv, fields
from openerp.http import request
AVAILABLE_PRIORITIES = [
('0', 'Very Low'),
@ -35,8 +30,10 @@ AVAILABLE_PRIORITIES = [
('4', 'Very High'),
]
class crm_case_channel(osv.osv):
_name = "crm.case.channel"
class crm_tracking_medium(osv.Model):
# OLD crm.case.channel
_name = "crm.tracking.medium"
_description = "Channels"
_order = 'name'
_columns = {
@ -47,6 +44,67 @@ class crm_case_channel(osv.osv):
'active': lambda *a: 1,
}
class crm_tracking_campaign(osv.Model):
# OLD crm.case.resource.type
_name = "crm.tracking.campaign"
_description = "Campaign"
_rec_name = "name"
_columns = {
'name': fields.char('Campaign Name', required=True, translate=True),
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
}
class crm_tracking_source(osv.Model):
_name = "crm.tracking.source"
_description = "Source"
_rec_name = "name"
_columns = {
'name': fields.char('Source Name', required=True, translate=True),
}
class crm_tracking_mixin(osv.AbstractModel):
"""Mixin class for objects which can be tracked by marketing. """
_name = 'crm.tracking.mixin'
_columns = {
'campaign_id': fields.many2one('crm.tracking.campaign', 'Campaign', # old domain ="['|',('section_id','=',section_id),('section_id','=',False)]"
help="This is a name that helps you keep track of your different campaign efforts Example: Fall_Drive, Christmas_Special"),
'source_id': fields.many2one('crm.tracking.source', 'Source', help="This is the source of the link Example: Search Engine, another domain, or name of email list"),
'medium_id': fields.many2one('crm.tracking.medium', 'Channel', help="This is the method of delivery. EX: Postcard, Email, or Banner Ad"),
}
def tracking_fields(self):
return [('utm_campaign', 'campaign_id'), ('utm_source', 'source_id'), ('utm_medium', 'medium_id')]
def tracking_get_values(self, cr, uid, vals, context=None):
for key, field in self.tracking_fields():
column = self._all_columns[field].column
value = vals.get(field) or (request and request.session.get(key)) # params.get sould be always in session by the dispatch from ir_http
if column._type in ['many2one'] and isinstance(value, basestring): # if we receive a string for a many2one, we search / create the id
if value:
Model = self.pool[column._obj]
rel_id = Model.name_search(cr, uid, value, context=context)
if not rel_id:
rel_id = Model.create(cr, uid, {'name': value}, context=context)
vals[field] = rel_id
# Here the code for other cases that many2one
else:
vals[field] = value
return vals
def _get_default_track(self, cr, uid, field, context=None):
return self.tracking_get_values(cr, uid, {}, context=context).get(field)
_defaults = {
'source_id': lambda self, cr, uid, ctx: self._get_default_track(cr, uid, 'source_id', ctx),
'campaign_id': lambda self, cr, uid, ctx: self._get_default_track(cr, uid, 'campaign_id', ctx),
'medium_id': lambda self, cr, uid, ctx: self._get_default_track(cr, uid, 'medium_id', ctx),
}
class crm_case_stage(osv.osv):
""" Model for case stages. This models the main stages of a document
management flow. Main CRM objects (leads, opportunities, project
@ -106,16 +164,6 @@ class crm_case_categ(osv.osv):
'object_id' : _find_object_id
}
class crm_case_resource_type(osv.osv):
""" Resource Type of case """
_name = "crm.case.resource.type"
_description = "Campaign"
_rec_name = "name"
_columns = {
'name': fields.char('Campaign Name', required=True, translate=True),
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
}
class crm_payment_mode(osv.osv):
""" Payment Mode for Fund """
_name = "crm.payment.mode"

View File

@ -13,18 +13,35 @@
<field name="state">open</field>
</record>
<record model="crm.case.channel" id="crm_case_channel_website">
<!-- Crm Source -->
<record model="crm.tracking.source" id="crm_source_search_engine">
<field name="name">Search engine</field>
</record>
<record model="crm.tracking.source" id="crm_source_mailing">
<field name="name">Mailing Partner</field>
</record>
<record model="crm.tracking.source" id="crm_source_newsletter">
<field name="name">Newsletter</field>
</record>
<!-- Crm Medium -->
<record model="crm.tracking.medium" id="crm_medium_website">
<field name="name">Website</field>
</record>
<record model="crm.case.channel" id="crm_case_channel_phone">
<record model="crm.tracking.medium" id="crm_medium_phone">
<field name="name">Phone</field>
</record>
<record model="crm.case.channel" id="crm_case_channel_direct">
<record model="crm.tracking.medium" id="crm_medium_direct">
<field name="name">Direct</field>
</record>
<record model="crm.case.channel" id="crm_case_channel_email">
<record model="crm.tracking.medium" id="crm_medium_email">
<field name="name">Email</field>
</record>
<record model="crm.tracking.medium" id="crm_medium_banner">
<field name="name">Banner Ad</field>
</record>
<record model="crm.case.section" id="sales_team.section_sales_department">
<field name="use_leads">True</field>

View File

@ -32,13 +32,14 @@ from openerp.tools.translate import _
CRM_LEAD_FIELDS_TO_MERGE = ['name',
'partner_id',
'channel_id',
'campaign_id',
'company_id',
'country_id',
'section_id',
'state_id',
'stage_id',
'type_id',
'medium_id',
'source_id',
'user_id',
'title',
'city',
@ -67,7 +68,7 @@ class crm_lead(format_address, osv.osv):
_name = "crm.lead"
_description = "Lead/Opportunity"
_order = "priority,date_action,id desc"
_inherit = ['mail.thread', 'ir.needaction_mixin']
_inherit = ['mail.thread', 'ir.needaction_mixin', 'crm.tracking.mixin']
_track = {
'stage_id': {
@ -214,9 +215,6 @@ class crm_lead(format_address, osv.osv):
'write_date': fields.datetime('Update Date', readonly=True),
'categ_ids': fields.many2many('crm.case.categ', 'crm_lead_category_rel', 'lead_id', 'category_id', 'Tags', \
domain="['|', ('section_id', '=', section_id), ('section_id', '=', False), ('object_id.model', '=', 'crm.lead')]", help="Classify and analyze your lead/opportunity categories like: Training, Service"),
'type_id': fields.many2one('crm.case.resource.type', 'Campaign', \
domain="['|',('section_id','=',section_id),('section_id','=',False)]", help="From which campaign (seminar, marketing campaign, mass mailing, ...) did this contact come from?"),
'channel_id': fields.many2one('crm.case.channel', 'Channel', help="Communication channel (mail, direct, phone, ...)"),
'contact_name': fields.char('Contact Name', size=64),
'partner_name': fields.char("Customer Name", size=64,help='The name of the future partner company that will be created while converting the lead into opportunity', select=1),
'opt_out': fields.boolean('Opt-Out', oldname='optout',

View File

@ -68,39 +68,6 @@
(4, ref('stage_lead7'))]"/>
</record>
<!-- Crm campain -->
<record model="crm.case.resource.type" id="type_lead1">
<field name="name">Telesales</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
</record>
<record model="crm.case.resource.type" id="type_lead2">
<field name="name">Email Campaign - Services</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
</record>
<record model="crm.case.resource.type" id="type_lead3">
<field name="name">Email Campaign - Products</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
</record>
<record model="crm.case.resource.type" id="type_lead4">
<field name="name">Twitter Ads</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
</record>
<record model="crm.case.resource.type" id="type_lead5">
<field name="name">Google Adwords</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
</record>
<record model="crm.case.resource.type" id="type_lead6">
<field name="name">Banner Ads</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
</record>
<record model="crm.case.resource.type" id="type_lead7">
<field name="name">Television</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
</record>
<record model="crm.case.resource.type" id="type_lead8">
<field name="name">Newsletter</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
</record>
<!-- crm categories -->
<record model="crm.case.categ" id="categ_oppor1">

View File

@ -16,9 +16,7 @@
<field name="city">Paris</field>
<field name="zip">93190</field>
<field name="phone">+33 1 25 54 45 69</field>
<field name="type_id" ref="type_lead2"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor6])]"/>
<field name="channel_id" ref="crm_case_channel_email"/>
<field name="priority">1</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
<field name="user_id" ref="base.user_root"/>
@ -51,9 +49,7 @@ Could you please send me the details ?</field>
<field name="function">Purchase Manager</field>
<field name="country_id" ref="base.fr"/>
<field name="city">Bordeaux</field>
<field name="type_id" ref="type_lead7"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor2])]"/>
<field name="channel_id" ref="crm_case_channel_website"/>
<field name="priority">1</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
<field name="user_id" ref="base.user_root"/>
@ -80,9 +76,7 @@ Could you please send me the details ?</field>
<field name="partner_id" ref=""/>
<field name="country_id" ref="base.us"/>
<field name="city">New-York</field>
<field name="type_id" ref="type_lead5"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor4])]"/>
<field name="channel_id" ref=""/>
<field name="priority">2</field>
<field name="section_id" ref="sales_team.crm_case_section_1"/>
<field name="user_id" ref="base.user_demo"/>
@ -101,9 +95,7 @@ Could you please send me the details ?</field>
<field name="partner_id" ref=""/>
<field name="country_id" ref="base.uk"/>
<field name="city">Drury</field>
<field name="type_id" ref="type_lead8"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor5])]"/>
<field name="channel_id" ref=""/>
<field name="priority">2</field>
<field name="section_id" ref="sales_team.crm_case_section_2"/>
<field name="user_id" ref="base.user_demo"/>
@ -126,9 +118,7 @@ Could you please send me the details ?</field>
<field name="city">Franklinville</field>
<field name="zip">NJ 08322</field>
<field name="phone">+1 813 494 5005</field>
<field name="type_id" ref="type_lead3"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor1])]"/>
<field name="channel_id" ref="crm_case_channel_website"/>
<field name="priority">2</field>
<field name="section_id" ref="sales_team.crm_case_section_1"/>
<field name="user_id" ref=""/>
@ -153,9 +143,7 @@ Contact: +1 813 494 5005</field>
<field name="function">Consultant</field>
<field name="country_id" ref="base.it"/>
<field name="city">Roma</field>
<field name="type_id" ref="type_lead3"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor3,categ_oppor4])]"/>
<field name="channel_id" ref=""/>
<field name="priority">2</field>
<field name="section_id" ref="sales_team.crm_case_section_2"/>
<field name="user_id" ref=""/>
@ -171,9 +159,7 @@ Contact: +1 813 494 5005</field>
<field name="function">Journalist</field>
<field name="country_id" ref="base.ua"/>
<field name="city">Kiev</field>
<field name="type_id" ref="type_lead8"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor4])]"/>
<field name="channel_id" ref=""/>
<field name="priority">0</field>
<field name="section_id" ref="sales_team.crm_case_section_2"/>
<field name="user_id" ref="base.user_root"/>
@ -190,9 +176,7 @@ Contact: +1 813 494 5005</field>
<field name="function">Sales</field>
<field name="country_id" ref="base.uk"/>
<field name="city">Cambridge</field>
<field name="type_id" ref="type_lead5"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor6,categ_oppor8])]"/>
<field name="channel_id" ref=""/>
<field name="priority">1</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
<field name="user_id" ref="base.user_root"/>
@ -209,9 +193,7 @@ Contact: +1 813 494 5005</field>
<field name="function">Sales</field>
<field name="country_id" ref="base.uk"/>
<field name="city">Oxford</field>
<field name="type_id" ref="type_lead3"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor7])]"/>
<field name="channel_id" ref="crm_case_channel_phone"/>
<field name="priority">2</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
<field name="user_id" ref="base.user_demo"/>
@ -227,9 +209,7 @@ Contact: +1 813 494 5005</field>
<field name="function">Medical illustrator</field>
<field name="country_id" ref="base.es"/>
<field name="city">Sevilla</field>
<field name="type_id" ref="type_lead8"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor1])]"/>
<field name="channel_id" ref="crm_case_channel_email"/>
<field name="priority">2</field>
<field name="section_id" ref="sales_team.crm_case_section_2"/>
<field name="user_id" ref="base.user_demo"/>
@ -250,9 +230,7 @@ Andrew</field>
<field name="partner_id" ref="base.res_partner_1"/>
<field name="function">Functional Consultant</field>
<field name="country_id" ref=""/>
<field name="type_id" ref="type_lead3"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor7])]"/>
<field name="channel_id" ref="crm_case_channel_direct"/>
<field name="priority">2</field>
<field name="section_id" ref="sales_team.crm_case_section_1"/>
<field name="user_id" ref=""/>
@ -268,9 +246,7 @@ Andrew</field>
<field name="partner_id" ref="base.res_partner_1"/>
<field name="country_id" ref="base.cn"/>
<field name="city">Shenzhen</field>
<field name="type_id" ref="type_lead3"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor1])]"/>
<field name="channel_id" ref="crm_case_channel_website"/>
<field name="priority">2</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
<field name="user_id" ref=""/>
@ -303,9 +279,7 @@ Andrew</field>
<field name="street">1 rue Rockfeller</field>
<field name="country_id" ref="base.at"/>
<field name="city">Melbourne</field>
<field name="type_id" ref="type_lead3"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor1])]"/>
<field name="channel_id" ref="crm_case_channel_email"/>
<field name="priority">1</field>
<field eval="time.strftime('%Y-%m-25')" name="date_deadline"/>
<field eval="time.strftime('%Y-%m-12')" name="date_action"/>
@ -328,9 +302,7 @@ Andrew</field>
<field name="country_id" ref="base.be"/>
<field name="city">Wavre</field>
<field name="zip">1300</field>
<field name="type_id" ref="type_lead3"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor2])]"/>
<field name="channel_id" ref="crm_case_channel_website"/>
<field name="priority">2</field>
<field eval="time.strftime('%Y-%m-23')" name="date_deadline"/>
<field eval="time.strftime('%Y-%m-10')" name="date_action"/>
@ -350,7 +322,6 @@ Andrew</field>
<field name="city">Wavre</field>
<field name="email_from">virginie@agrolait.com</field>
<field name="partner_id" ref="base.res_partner_2"/>
<field name="type_id" ref="type_lead8"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor1])]"/>
<field name="priority">1</field>
<field eval="time.strftime('%Y-%m-12')" name="date_deadline"/>
@ -377,7 +348,6 @@ Andrew</field>
<field name="country_id" ref="base.uk"/>
<field name="city">Liverpool</field>
<field name="zip">L25 4RL</field>
<field name="type_id" ref="type_lead5"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor5])]"/>
<field name="priority">2</field>
<field eval="time.strftime('%Y-%m-28')" name="date_deadline"/>
@ -401,9 +371,7 @@ Andrew</field>
<field name="street">Rue des Palais 51, bte 33</field>
<field name="country_id" ref="base.be"/>
<field name="city">Brussels</field>
<field name="type_id" ref="type_lead3"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor3,categ_oppor4])]"/>
<field name="channel_id" ref="crm_case_channel_website"/>
<field name="priority">1</field>
<field eval="time.strftime('%Y-%m-8')" name="date_deadline"/>
<field eval="time.strftime('%Y-%m-3')" name="date_action"/>
@ -429,7 +397,6 @@ Andrew</field>
<field name="street">3661 Station Street</field>
<field name="country_id" ref="base.uk"/>
<field name="partner_id" ref="base.res_partner_4"/>
<field name="type_id" ref="type_lead8"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor4,categ_oppor6])]"/>
<field name="priority">1</field>
<field eval="time.strftime('%Y-%m-13')" name="date_deadline"/>
@ -456,7 +423,6 @@ Andrew</field>
<field name="country_id" ref="base.uk"/>
<field name="city">Liverpool</field>
<field name="zip">L25 4RL</field>
<field name="type_id" ref="type_lead3"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor1])]"/>
<field name="priority">1</field>
<field eval="time.strftime('%Y-%m-10')" name="date_deadline"/>
@ -476,7 +442,6 @@ Andrew</field>
<field name="partner_name">Epic Technologies</field>
<field name="email_from">john.b@tech.info</field>
<field name="partner_id" ref="base.res_partner_5"/>
<field name="type_id" ref="type_lead3"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor4,categ_oppor8])]"/>
<field name="priority">2</field>
<field name="section_id" ref="sales_team.crm_case_section_1"/>
@ -489,9 +454,7 @@ Andrew</field>
<field name="name">“Resource Planning” project develpment</field>
<field eval="350" name="planned_revenue"/>
<field name="partner_id" ref="base.res_partner_7"/>
<field name="type_id" ref="type_lead2"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor7])]"/>
<field name="channel_id" ref="crm_case_channel_phone"/>
<field name="priority">2</field>
<field name="section_id" ref="sales_team.crm_case_section_2"/>
<field name="user_id" ref="base.user_root"/>
@ -507,9 +470,7 @@ Andrew</field>
<field name="contact_name">Benjamin Flores</field>
<field name="partner_name">Nebula Business</field>
<field name="partner_id" ref="base.res_partner_17"/>
<field name="type_id" ref="type_lead7"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor3])]"/>
<field name="channel_id" ref="crm_case_channel_email"/>
<field name="priority">1</field>
<field name="section_id" ref="sales_team.crm_case_section_2"/>
<field name="user_id" ref="base.user_root"/>
@ -522,9 +483,7 @@ Andrew</field>
<field eval="2000" name="planned_revenue"/>
<field eval="80.0" name="probability"/>
<field name="partner_id" ref="base.res_partner_18"/>
<field name="type_id" ref="type_lead5"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor3])]"/>
<field name="channel_id" ref="crm_case_channel_direct"/>
<field name="priority">0</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
<field name="user_id" ref="base.user_demo"/>
@ -540,9 +499,7 @@ Andrew</field>
<field name="email_from">info@mycompany.net</field>
<field name="country_id" ref="base.pe"/>
<field name="city">Lima</field>
<field name="type_id" ref="type_lead8"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor7])]"/>
<field name="channel_id" ref="crm_case_channel_website"/>
<field name="priority">0</field>
<field eval="time.strftime('%Y-%m-6')" name="date_deadline"/>
<field name="section_id" ref="sales_team.section_sales_department"/>
@ -564,7 +521,6 @@ Andrew</field>
<field name="country_id" ref="base.ar"/>
<field name="city">Buenos Aires</field>
<field name="zip">B7313</field>
<field name="type_id" ref="type_lead4"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor4])]"/>
<field name="priority">2</field>
<field name="title_action">Conf call with technical service</field>
@ -585,9 +541,7 @@ Andrew</field>
<field name="country_id" ref="base.be"/>
<field name="city">Wavre</field>
<field name="zip">1300</field>
<field name="type_id" ref="type_lead3"/>
<field name="categ_ids" eval="[(6, 0, [categ_oppor2])]"/>
<field name="channel_id" ref="crm_case_channel_website"/>
<field name="priority">2</field>
<field eval="time.strftime('%Y-%m-23')" name="date_deadline"/>
<field eval="time.strftime('%Y-%m-10')" name="date_action"/>

View File

@ -230,9 +230,9 @@
<field name="partner_id" invisible="1"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
<field name="probability" invisible="1"/>
<field name="type_id" invisible="1"/>
<field name="campaign_id" invisible="1"/>
<field name="referred" invisible="1"/>
<field name="channel_id" invisible="1"/>
<field name="medium_id" invisible="1"/>
<field name="message_unread" invisible="1"/>
</tree>
</field>
@ -513,8 +513,9 @@
<field name="country_id"/>
<field name="date_action"/>
<field name="title_action"/>
<field name="channel_id" invisible="1"/>
<field name="type_id" invisible="1"/>
<field name="medium_id" invisible="1"/>
<field name="campaign_id" invisible="1"/>
<field name="source_id" invisible="1"/>
<field name="stage_id"/>
<field name="planned_revenue" sum="Expected Revenues"/>
<field name="probability" avg="Avg. of Probability"/>

View File

@ -26,10 +26,10 @@
<menuitem id="base.next_id_64" name="Sales"
parent="base.menu_reporting" sequence="1"/>
<!-- crm.case.channel -->
<record id="crm_case_channel_view_tree" model="ir.ui.view">
<field name="name">crm.case.channel.tree</field>
<field name="model">crm.case.channel</field>
<!-- crm.tracking.medium -->
<record id="crm_tracking_medium_view_tree" model="ir.ui.view">
<field name="name">crm.tracking.medium.tree</field>
<field name="model">crm.tracking.medium</field>
<field name="arch" type="xml">
<tree string="Channels">
<field name="name"/>
@ -37,9 +37,9 @@
</tree>
</field>
</record>
<record id="crm_case_channel_view_form" model="ir.ui.view">
<field name="name">crm.case.channel.form</field>
<field name="model">crm.case.channel</field>
<record id="crm_tracking_medium_view_form" model="ir.ui.view">
<field name="name">crm.tracking.medium.form</field>
<field name="model">crm.tracking.medium</field>
<field name="arch" type="xml">
<form string="Channel">
<group>
@ -49,26 +49,66 @@
</form>
</field>
</record>
<record id="crm_case_channel_action" model="ir.actions.act_window">
<record id="crm_tracking_medium_action" model="ir.actions.act_window">
<field name="name">Channels</field>
<field name="res_model">crm.case.channel</field>
<field name="res_model">crm.tracking.medium</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to define a new channel.
</p><p>
Use channels to track the soure of your leads and opportunities. Channels
Use channels to track the type of source of your leads and opportunities. Channels
are mostly used in reporting to analyse sales performance
related to marketing efforts.
</p><p>
Some examples of channels: company website, phone call
campaign, reseller, etc.
campaign, reseller, banner, etc.
</p>
</field>
</record>
<menuitem action="crm_case_channel_action" id="menu_crm_case_channel" parent="base.menu_crm_config_lead" sequence="4" groups="base.group_no_one"/>
<!-- crm.tracking.source -->
<record id="crm_tracking_source_view_tree" model="ir.ui.view">
<field name="name">crm.tracking.source.tree</field>
<field name="model">crm.tracking.source</field>
<field name="arch" type="xml">
<tree string="Channels">
<field name="name"/>
</tree>
</field>
</record>
<record id="crm_tracking_source_view_form" model="ir.ui.view">
<field name="name">crm.tracking.source.form</field>
<field name="model">crm.tracking.source</field>
<field name="arch" type="xml">
<form string="Channel">
<group>
<field name="name"/>
</group>
</form>
</field>
</record>
<record id="crm_tracking_source_action" model="ir.actions.act_window">
<field name="name">Source</field>
<field name="res_model">crm.tracking.source</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to define a new source.
</p><p>
Use channels to track the source of your leads and opportunities. Channels
are mostly used in reporting to analyse sales performance
related to marketing efforts.
</p><p>
Some examples of channels: partner's website, google.com,
email list name, etc.
</p>
</field>
</record>
<menuitem action="crm_tracking_source_action" id="menu_crm_tracking_source" parent="base.menu_crm_config_lead" sequence="4" groups="base.group_no_one"/>
<!-- CRM Stage Tree View -->
@ -155,9 +195,9 @@
<!-- Resource Type of case Tree View -->
<record model="ir.ui.view" id="crm_case_resource_type_tree">
<field name="name">crm.case.resource.type.tree</field>
<field name="model">crm.case.resource.type</field>
<record model="ir.ui.view" id="crm_tracking_campaign_tree">
<field name="name">crm.tracking.campaign.tree</field>
<field name="model">crm.tracking.campaign</field>
<field name="arch" type="xml">
<tree string="Campaign">
<field name="name"/>
@ -168,9 +208,9 @@
<!-- Resource Type of case Form View -->
<record model="ir.ui.view" id="crm_case_resource_type_form">
<field name="name">crm.case.resource.type.form</field>
<field name="model">crm.case.resource.type</field>
<record model="ir.ui.view" id="crm_tracking_campaign_form">
<field name="name">crm.tracking.campaign.form</field>
<field name="model">crm.tracking.campaign</field>
<field name="arch" type="xml">
<form string="Campaign">
<group>
@ -183,15 +223,15 @@
<!-- Resource Type of case Action -->
<record id="crm_case_resource_type_act" model="ir.actions.act_window">
<record id="crm_tracking_campaign_act" model="ir.actions.act_window">
<field name="name">Campaigns</field>
<field name="res_model">crm.case.resource.type</field>
<field name="res_model">crm.tracking.campaign</field>
<field name="view_type">form</field>
<field name="view_id" ref="crm_case_resource_type_tree"/>
<field name="view_id" ref="crm_tracking_campaign_tree"/>
</record>
<menuitem action="crm_case_resource_type_act"
id="menu_crm_case_resource_type_act" sequence="4"
<menuitem action="crm_tracking_campaign_act"
id="menu_crm_tracking_campaign_act" sequence="4"
groups="base.group_no_one"
parent="base.menu_crm_config_lead"/>

13
addons/crm/ir_http.py Normal file
View File

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
from openerp.http import request
from openerp.osv import orm
class ir_http(orm.AbstractModel):
_inherit = 'ir.http'
def _dispatch(self):
for var, dummy in self.pool['crm.tracking.mixin'].tracking_fields():
if var in request.params and (var not in request.session or request.session[var] != request.params[var]):
request.session[var] = request.params[var]
return super(ir_http, self)._dispatch()

View File

@ -44,6 +44,7 @@ class crm_lead_report(osv.osv):
_auto = False
_description = "CRM Lead Analysis"
_rec_name = 'date_deadline'
_inherit = ["crm.tracking.mixin"]
_columns = {
'date_deadline': fields.date('Exp. Closing', readonly=True, help="Expected Closing"),
@ -58,10 +59,8 @@ class crm_lead_report(osv.osv):
'delay_expected': fields.float('Overpassed Deadline',digits=(16,2),readonly=True, group_operator="avg"),
'user_id':fields.many2one('res.users', 'User', readonly=True),
'section_id':fields.many2one('crm.case.section', 'Sales Team', readonly=True),
'country_id':fields.many2one('res.country', 'Country', readonly=True),
'section_id':fields.many2one('crm.case.section', 'Sales Team', readonly=True),
'channel_id':fields.many2one('crm.case.channel', 'Channel', readonly=True),
'type_id':fields.many2one('crm.case.resource.type', 'Campaign', readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True),
'probability': fields.float('Probability',digits=(16,2),readonly=True, group_operator="avg"),
'planned_revenue': fields.float('Planned Revenue',digits=(16,2),readonly=True),
@ -101,8 +100,9 @@ class crm_lead_report(osv.osv):
c.company_id,
c.priority,
c.section_id,
c.channel_id,
c.type_id,
c.campaign_id,
c.source_id,
c.medium_id,
c.partner_id,
c.country_id,
c.planned_revenue,

View File

@ -74,13 +74,15 @@
<group expand="0" string="Extended Filters">
<field name="partner_id" filter_domain="[('partner_id','child_of',self)]"/>
<field name="stage_id" domain="[('section_ids', '=', 'section_id')]" />
<field name="type_id"/>
<field name="channel_id"/>
<field name="campaign_id"/>
<field name="medium_id"/>
<field name="source_id"/>
<field name="company_id" groups="base.group_multi_company"/>
<separator orientation="vertical"/>
<field name="stage_id" widget="selection" domain="[('section_ids', '=', 'section_id')]" />
<field name="type_id" widget="selection"/>
<field name="channel_id" widget="selection"/>
<field name="campaign_id" widget="selection"/>
<field name="medium_id" widget="selection"/>
<field name="source_id" widget="selection"/>
<separator orientation="vertical"/>
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
<newline/>

View File

@ -3,8 +3,10 @@ access_crm_segmentation_user,crm.segmentation user,model_crm_segmentation,base.g
access_crm_segmentation_line_user,crm.segmentation.line user,model_crm_segmentation_line,base.group_sale_salesman,1,0,0,0
access_crm_segmentation,crm.segmentation,model_crm_segmentation,base.group_sale_manager,1,1,1,1
access_crm_segmentation_line,crm.segmentation.line,model_crm_segmentation_line,base.group_sale_manager,1,1,1,1
access_crm_case_channel_user,crm.case.channel user,model_crm_case_channel,base.group_sale_salesman,1,0,0,0
access_crm_case_channel_manager,crm.case.channel manager,model_crm_case_channel,base.group_sale_manager,1,1,1,1
access_crm_tracking_medium_user,crm.tracking.medium user,model_crm_tracking_medium,base.group_sale_salesman,1,0,0,0
access_crm_tracking_medium_manager,crm.tracking.medium manager,model_crm_tracking_medium,base.group_sale_manager,1,1,1,1
access_crm_tracking_source_user,crm.tracking.source user,model_crm_tracking_source,base.group_sale_salesman,1,0,0,0
access_crm_tracking_source_manager,crm.tracking.source manager,model_crm_tracking_source,base.group_sale_manager,1,1,1,1
access_crm_case_categ,crm.case.categ,model_crm_case_categ,base.group_sale_salesman,1,1,1,0
access_crm_lead_manager,crm.lead.manager,model_crm_lead,base.group_sale_manager,1,1,1,1
access_crm_phonecall_manager,crm.phonecall.manager,model_crm_phonecall,base.group_sale_manager,1,1,1,1
@ -13,8 +15,8 @@ access_crm_lead,crm.lead,model_crm_lead,base.group_sale_salesman,1,1,1,0
access_crm_phonecall,crm.phonecall,model_crm_phonecall,base.group_sale_salesman,1,1,1,0
access_crm_case_stage,crm.case.stage,model_crm_case_stage,,1,0,0,0
access_crm_case_stage_manager,crm.case.stage,model_crm_case_stage,base.group_sale_manager,1,1,1,1
access_crm_case_resource_type_user,crm_case_resource_type user,model_crm_case_resource_type,base.group_sale_salesman,1,1,1,0
access_crm_case_resource_type_manager,crm_case_resource_type manager,model_crm_case_resource_type,base.group_sale_manager,1,1,1,1
access_crm_tracking_campaign_user,crm_tracking_campaign user,model_crm_tracking_campaign,base.group_sale_salesman,1,1,1,0
access_crm_tracking_campaign_manager,crm_tracking_campaign manager,model_crm_tracking_campaign,base.group_sale_manager,1,1,1,1
access_crm_phonecall_report_user,crm.phonecall.report.user,model_crm_phonecall_report,base.group_sale_salesman,1,0,0,0
access_crm_phonecall_report_manager,crm.phonecall.report,model_crm_phonecall_report,base.group_sale_manager,1,1,1,1
access_res_partner_manager,res.partner.crm.manager,base.model_res_partner,base.group_sale_manager,1,0,0,0
@ -29,4 +31,4 @@ access_res_partner_bank_type_crm_user,res.partner.bank.type.crm.user,base.model_
access_crm_lead_partner_manager,crm.lead.partner.manager,model_crm_lead,base.group_partner_manager,1,0,0,0
access_crm_phonecall_partner_manager,crm.phonecall.partner.manager,model_crm_phonecall,base.group_partner_manager,1,1,1,1
access_crm_payment_mode_user,crm.payment.mode,model_crm_payment_mode,base.group_sale_salesman,1,0,0,0
access_crm_payment_mode,crm.payment.mode,model_crm_payment_mode,base.group_sale_manager,1,1,1,1
access_crm_payment_mode,crm.payment.mode,model_crm_payment_mode,base.group_sale_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
3 access_crm_segmentation_line_user crm.segmentation.line user model_crm_segmentation_line base.group_sale_salesman 1 0 0 0
4 access_crm_segmentation crm.segmentation model_crm_segmentation base.group_sale_manager 1 1 1 1
5 access_crm_segmentation_line crm.segmentation.line model_crm_segmentation_line base.group_sale_manager 1 1 1 1
6 access_crm_case_channel_user access_crm_tracking_medium_user crm.case.channel user crm.tracking.medium user model_crm_case_channel model_crm_tracking_medium base.group_sale_salesman 1 0 0 0
7 access_crm_case_channel_manager access_crm_tracking_medium_manager crm.case.channel manager crm.tracking.medium manager model_crm_case_channel model_crm_tracking_medium base.group_sale_manager 1 1 1 1
8 access_crm_tracking_source_user crm.tracking.source user model_crm_tracking_source base.group_sale_salesman 1 0 0 0
9 access_crm_tracking_source_manager crm.tracking.source manager model_crm_tracking_source base.group_sale_manager 1 1 1 1
10 access_crm_case_categ crm.case.categ model_crm_case_categ base.group_sale_salesman 1 1 1 0
11 access_crm_lead_manager crm.lead.manager model_crm_lead base.group_sale_manager 1 1 1 1
12 access_crm_phonecall_manager crm.phonecall.manager model_crm_phonecall base.group_sale_manager 1 1 1 1
15 access_crm_phonecall crm.phonecall model_crm_phonecall base.group_sale_salesman 1 1 1 0
16 access_crm_case_stage crm.case.stage model_crm_case_stage 1 0 0 0
17 access_crm_case_stage_manager crm.case.stage model_crm_case_stage base.group_sale_manager 1 1 1 1
18 access_crm_case_resource_type_user access_crm_tracking_campaign_user crm_case_resource_type user crm_tracking_campaign user model_crm_case_resource_type model_crm_tracking_campaign base.group_sale_salesman 1 1 1 0
19 access_crm_case_resource_type_manager access_crm_tracking_campaign_manager crm_case_resource_type manager crm_tracking_campaign manager model_crm_case_resource_type model_crm_tracking_campaign base.group_sale_manager 1 1 1 1
20 access_crm_phonecall_report_user crm.phonecall.report.user model_crm_phonecall_report base.group_sale_salesman 1 0 0 0
21 access_crm_phonecall_report_manager crm.phonecall.report model_crm_phonecall_report base.group_sale_manager 1 1 1 1
22 access_res_partner_manager res.partner.crm.manager base.model_res_partner base.group_sale_manager 1 0 0 0
31 access_crm_lead_partner_manager crm.lead.partner.manager model_crm_lead base.group_partner_manager 1 0 0 0
32 access_crm_phonecall_partner_manager crm.phonecall.partner.manager model_crm_phonecall base.group_partner_manager 1 1 1 1
33 access_crm_payment_mode_user crm.payment.mode model_crm_payment_mode base.group_sale_salesman 1 0 0 0
34 access_crm_payment_mode crm.payment.mode model_crm_payment_mode base.group_sale_manager 1 1 1 1

View File

@ -28,12 +28,12 @@
Case Category2
-->
<record model="crm.case.resource.type" id="type_claim1">
<record model="crm.tracking.campaign" id="claim_source1">
<field name="name">Corrective</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
</record>
<record model="crm.case.resource.type" id="type_claim2">
<record model="crm.tracking.campaign" id="claim_source2">
<field name="name">Preventive</field>
<field name="section_id" ref="sales_team.section_sales_department"/>
</record>

View File

@ -56,7 +56,7 @@ class crm_helpdesk(osv.osv):
'date': fields.datetime('Date'),
'ref': fields.reference('Reference', selection=openerp.addons.base.res.res_request.referencable_models),
'ref2': fields.reference('Reference 2', selection=openerp.addons.base.res.res_request.referencable_models),
'channel_id': fields.many2one('crm.case.channel', 'Channel', help="Communication channel."),
'channel_id': fields.many2one('crm.tracking.medium', 'Channel', help="Communication channel."),
'planned_revenue': fields.float('Planned Revenue'),
'planned_cost': fields.float('Planned Costs'),
'priority': fields.selection([('0','Low'), ('1','Normal'), ('2','High')], 'Priority'),

View File

@ -56,7 +56,7 @@ class crm_helpdesk_report(osv.osv):
'date_deadline': fields.date('Deadline', select=True),
'priority': fields.selection([('5', 'Lowest'), ('4', 'Low'), \
('3', 'Normal'), ('2', 'High'), ('1', 'Highest')], 'Priority'),
'channel_id': fields.many2one('crm.case.channel', 'Channel'),
'channel_id': fields.many2one('crm.tracking.medium', 'Channel'),
'categ_id': fields.many2one('crm.case.categ', 'Category', \
domain="[('section_id','=',section_id),\
('object_id.model', '=', 'crm.helpdesk')]"),

View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2014-Today OpenERP SA (<http://www.openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import mass_mailing

View File

@ -0,0 +1,18 @@
{
'name': 'Campaign in Mass Mailing',
'version': '1.0',
'summary': 'This module allow to specify a campaign, a source and a channel for a mass mailing campaign.',
'author': 'OpenERP SA',
'description': """
Mass Mailing with Crm Marketing
================================
Link module mass mailing with the marketing mixin from crm.
""",
'depends': ['crm', 'mass_mailing'],
'data': [
'mass_mailing.xml',
],
'installable': True,
'auto_install': True,
}

View File

@ -0,0 +1,6 @@
from openerp.osv import osv
class MassMailing(osv.Model):
_name = 'mail.mass_mailing'
_inherit = ['mail.mass_mailing', 'crm.tracking.mixin']

View File

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="view_tracking_mass_mailing_form">
<field name="name">mail.mass_mailing.inherit.form</field>
<field name="model">mail.mass_mailing</field>
<field name="inherit_id" ref="mass_mailing.view_mail_mass_mailing_form"/>
<field name="arch" type="xml">
<xpath expr="//notebook/page[@string='Options']" position="after">
<page string="Tracking">
<group>
<field name="campaign_id" />
<field name="medium_id" />
<field name="source_id" />
</group>
</page>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@ -12,9 +12,7 @@
<field name="function">Reseller</field>
<field name="country_id" ref="base.uk"/>
<field name="city">Edinburgh</field>
<field name="type_id" ref="crm.type_lead8"/>
<field name="categ_ids" eval="[(6, 0, [ref('crm.categ_oppor1')])]"/>
<field name="channel_id" ref="crm.crm_case_channel_email"/>
<field name="priority">2</field>
<field name="section_id" ref="sales_team.crm_case_section_2"/>
<field name="user_id" ref=""/>

View File

@ -15,9 +15,9 @@
<field name="email_from"/>
<field name="phone"/>
<field name="stage_id" invisible="1"/>
<field name="type_id" invisible="1"/>
<field name="campaign_id" invisible="1"/>
<field name="referred" invisible="1"/>
<field name="channel_id" invisible="1"/>
<field name="medium_id" invisible="1"/>
<field name="section_id" invisible="context.get('invisible_section', True)" groups="base.group_multi_salesteams"/>
<button string="I'm interested" name="case_interested" icon="gtk-index" type="object"/>
@ -80,8 +80,8 @@
<field name="country_id" invisible="context.get('invisible_country', True)" />
<field name="date_action"/>
<field name="title_action" />
<field name="channel_id" invisible="1"/>
<field name="type_id" invisible="1"/>
<field name="medium_id" invisible="1"/>
<field name="campaign_id" invisible="1"/>
<field name="planned_revenue" sum="Expected Revenues"/>
<field name="probability" widget="progressbar" avg="Avg. of Probability"/>
<field name="section_id" groups="base.group_multi_salesteams" invisible="context.get('invisible_section', True)" />
@ -140,8 +140,8 @@
</group>
<group col="2">
<separator string="Categorization" colspan="2"/>
<field name="type_id" readonly="1"/>
<field name="channel_id" readonly="1"/>
<field name="campaign_id" readonly="1"/>
<field name="medium_id" readonly="1"/>
</group>
</group>
<separator string="Details" />

View File

@ -35,7 +35,7 @@ import base64
from openerp import addons
from openerp.osv import fields, osv
from openerp import tools
from openerp import tools, api
from openerp.tools.translate import _
_logger = logging.getLogger(__name__)
@ -129,6 +129,7 @@ openerp_mailgate: "|/path/to/openerp-mailgate.py --host=localhost -u %(uid)d -p
self.write(cr, uid, ids , {'state':'draft'})
return True
@api.cr_uid_ids_context
def connect(self, cr, uid, server_id, context=None):
if isinstance(server_id, (list,tuple)):
server_id = server_id[0]

View File

@ -1,3 +1,3 @@
.oe_systray #oe_attendance_sign_in_out_icon {
font-color: white;
color: white;
}

View File

@ -59,6 +59,14 @@ class hr_evaluation_report(osv.Model):
}
_order = 'create_date desc'
_depends = {
'hr.evaluation.interview': ['evaluation_id', 'id', 'request_id'],
'hr_evaluation.evaluation': [
'create_date', 'date', 'date_close', 'employee_id', 'plan_id',
'rating', 'state',
],
}
def init(self, cr):
tools.drop_view_if_exists(cr, 'hr_evaluation_report')
cr.execute("""

View File

@ -532,6 +532,11 @@ class hr_timesheet_sheet_sheet_day(osv.osv):
'total_attendance': fields.float('Attendance', readonly=True),
'total_difference': fields.float('Difference', readonly=True),
}
_depends = {
'account.analytic.line': ['date', 'unit_amount'],
'hr.analytic.timesheet': ['line_id', 'sheet_id'],
'hr.attendance': ['action', 'name', 'sheet_id'],
}
def init(self, cr):
cr.execute("""create or replace view hr_timesheet_sheet_sheet_day as
@ -602,6 +607,12 @@ class hr_timesheet_sheet_sheet_account(osv.osv):
'invoice_rate': fields.many2one('hr_timesheet_invoice.factor', 'Invoice rate', readonly=True),
}
_depends = {
'account.analytic.line': ['account_id', 'date', 'to_invoice', 'unit_amount', 'user_id'],
'hr.analytic.timesheet': ['line_id'],
'hr_timesheet_sheet.sheet': ['date_from', 'date_to', 'user_id'],
}
def init(self, cr):
cr.execute("""create or replace view hr_timesheet_sheet_sheet_account as (
select

View File

@ -14,7 +14,6 @@
/* button */
.oe_systray #oe_topbar_imbutton_icon {
color: white;
margin-right: 10px;
}
.oe_topbar_item.oe_topbar_imbutton .oe_e {
position: relative;

View File

@ -12,8 +12,9 @@
<attribute name="groups"></attribute>
</xpath>
<xpath expr="//field[@name='company_id']" position="after">
<field name="type_id"/>
<field name="channel_id" widget="selection"/>
<field name="campaign_id" />
<field name="medium_id"/>
<field name="source_id" />
</xpath>
</field>
</record>
@ -25,8 +26,9 @@
<field name="arch" type="xml">
<xpath expr="//group[@name='mailings']" position="before">
<group string="Marketing">
<field name="type_id" />
<field name="channel_id" widget="selection"/>
<field name="campaign_id" />
<field name="medium_id" />
<field name="source_id" />
</group>
</xpath>
</field>

View File

@ -144,7 +144,6 @@ class MassMailingCampaign(osv.Model):
row['replied_ratio'] = 100.0 * row['replied'] / total
return results
_columns = {
'name': fields.char('Name', required=True),
'stage_id': fields.many2one('mail.mass_mailing.stage', 'Stage', required=True),
@ -326,7 +325,6 @@ class MassMailing(osv.Model):
row['replied_ratio'] = 100.0 * row['replied'] / total
return results
def _get_mailing_model(self, cr, uid, context=None):
res = []
for model_name in self.pool:

View File

@ -884,7 +884,7 @@ class mrp_production(osv.osv):
production = self.browse(cr, uid, production_id, context=context)
if not production.move_lines and production.state == 'ready':
# trigger workflow if not products to consume (eg: services)
self.signal_button_produce(cr, uid, [production_id])
self.signal_workflow(cr, uid, [production_id], 'button_produce')
produced_qty = self._get_produced_qty(cr, uid, production, context=context)
@ -944,7 +944,7 @@ class mrp_production(osv.osv):
stock_mov_obj.action_done(cr, uid, [extra_move_id], context=context)
self.message_post(cr, uid, production_id, body=_("%s produced") % self._description, context=context)
self.signal_button_produce_done(cr, uid, [production_id])
self.signal_workflow(cr, uid, [production_id], 'button_produce_done')
return True
def _costs_generate(self, cr, uid, production):

View File

@ -114,7 +114,7 @@ class procurement_order(osv.osv):
procurement.refresh()
self.production_order_create_note(cr, uid, procurement, context=context)
production_obj.action_compute(cr, uid, [produce_id], properties=[x.id for x in procurement.property_ids])
production_obj.signal_button_confirm(cr, uid, [produce_id])
production_obj.signal_workflow(cr, uid, [produce_id], 'button_confirm')
else:
res[procurement.id] = False
self.message_post(cr, uid, [procurement.id], body=_("No BoM exists for this product!"), context=context)

View File

@ -159,7 +159,7 @@ class StockMove(osv.osv):
'consumed_for': consumed_for}, context=context)
self.action_done(cr, uid, res, context=context)
production_ids = production_obj.search(cr, uid, [('move_lines', 'in', [move.id])])
production_obj.signal_button_produce(cr, uid, production_ids)
production_obj.signal_workflow(cr, uid, production_ids, 'button_produce')
for new_move in res:
if new_move != move.id:
#This move is not already there in move lines of production order
@ -181,7 +181,7 @@ class StockMove(osv.osv):
#If we are not scrapping our whole move, tracking and lot references must not be removed
production_ids = production_obj.search(cr, uid, [('move_lines', 'in', [move.id])])
for prod_id in production_ids:
production_obj.signal_button_produce(cr, uid, [prod_id])
production_obj.signal_workflow(cr, uid, [prod_id], 'button_produce')
for new_move in new_moves:
production_obj.write(cr, uid, production_ids, {'move_lines': [(4, new_move)]})
res.append(new_move)

View File

@ -497,7 +497,7 @@ class pos_session(osv.osv):
_('Error!'),
_("You cannot confirm all orders of this session, because they have not the 'paid' status"))
else:
pos_order_obj.signal_done(cr, uid, [order.id])
pos_order_obj.signal_workflow(cr, uid, [order.id], 'done')
return True
@ -581,14 +581,14 @@ class pos_order(osv.osv):
order_ids.append(order_id)
try:
self.signal_paid(cr, uid, [order_id])
self.signal_workflow(cr, uid, [order_id], 'paid')
except Exception as e:
_logger.error('Could not fully process the POS Order: %s', tools.ustr(e))
if to_invoice:
self.action_invoice(cr, uid, [order_id], context)
order_obj = self.browse(cr, uid, order_id, context)
self.pool['account.invoice'].signal_invoice_open(cr, uid, [order_obj.invoice_id.id])
self.pool['account.invoice'].signal_workflow(cr, uid, [order_obj.invoice_id.id], 'invoice_open')
return order_ids
@ -933,8 +933,8 @@ class pos_order(osv.osv):
inv_line['invoice_line_tax_id'] = [(6, 0, [x.id for x in line.product_id.taxes_id] )]
inv_line_ref.create(cr, uid, inv_line, context=context)
inv_ref.button_reset_taxes(cr, uid, [inv_id], context=context)
self.signal_invoice(cr, uid, [order.id])
inv_ref.signal_validate(cr, uid, [inv_id])
self.signal_workflow(cr, uid, [order.id], 'invoice')
inv_ref.signal_workflow(cr, uid, [inv_id], 'validate')
if not inv_ids: return {}

View File

@ -328,7 +328,7 @@ class purchase_order(osv.osv):
raise osv.except_osv(_('Invalid Action!'), _('In order to delete a purchase order, you must cancel it first.'))
# automatically sending subflow.delete upon deletion
self.signal_purchase_cancel(cr, uid, unlink_ids)
self.signal_workflow(cr, uid, unlink_ids, 'purchase_cancel')
return super(purchase_order, self).unlink(cr, uid, unlink_ids, context=context)
@ -519,7 +519,7 @@ class purchase_order(osv.osv):
This function prints the request for quotation and mark it as sent, so that we can see more easily the next step of the workflow
'''
assert len(ids) == 1, 'This option should only be used for a single id at a time'
self.signal_send_rfq(cr, uid, ids)
self.signal_workflow(cr, uid, ids, 'send_rfq')
return self.pool['report'].get_action(cr, uid, ids, 'purchase.report_purchasequotation', context=context)
def wkf_confirm_order(self, cr, uid, ids, context=None):
@ -680,19 +680,19 @@ class purchase_order(osv.osv):
_('Unable to cancel the purchase order %s.') % (purchase.name),
_('First cancel all receptions related to this purchase order.'))
self.pool.get('stock.picking') \
.signal_button_cancel(cr, uid, map(attrgetter('id'), purchase.picking_ids))
.signal_workflow(cr, uid, map(attrgetter('id'), purchase.picking_ids), 'button_cancel')
for inv in purchase.invoice_ids:
if inv and inv.state not in ('cancel', 'draft'):
raise osv.except_osv(
_('Unable to cancel this purchase order.'),
_('You must first cancel all invoices related to this purchase order.'))
self.pool.get('account.invoice') \
.signal_invoice_cancel(cr, uid, map(attrgetter('id'), purchase.invoice_ids))
.signal_workflow(cr, uid, map(attrgetter('id'), purchase.invoice_ids), 'invoice_cancel')
self.pool['purchase.order.line'].write(cr, uid, [l.id for l in purchase.order_line],
{'state': 'cancel'})
self.write(cr, uid, ids, {'state': 'cancel'})
self.set_order_line_status(cr, uid, ids, 'cancel', context=context)
self.signal_purchase_cancel(cr, uid, ids)
self.signal_workflow(cr, uid, ids, 'purchase_cancel')
return True
def _prepare_order_line_move(self, cr, uid, order, order_line, picking_id, group_id, context=None):
@ -933,7 +933,7 @@ class purchase_order(osv.osv):
# make triggers pointing to the old orders point to the new order
for old_id in old_ids:
self.redirect_workflow(cr, uid, [(old_id, neworder_id)])
self.signal_purchase_cancel(cr, uid, [old_id])
self.signal_workflow(cr, uid, [old_id], 'purchase_cancel')
return orders_info
@ -1370,7 +1370,7 @@ class mail_mail(osv.Model):
if mail_sent and mail.model == 'purchase.order':
obj = self.pool.get('purchase.order').browse(cr, uid, mail.res_id, context=context)
if obj.state == 'draft':
self.pool.get('purchase.order').signal_send_rfq(cr, uid, [mail.res_id])
self.pool.get('purchase.order').signal_workflow(cr, uid, [mail.res_id], 'send_rfq')
return super(mail_mail, self)._postprocess_sent_message(cr, uid, mail=mail, context=context, mail_sent=mail_sent)
@ -1423,7 +1423,7 @@ class mail_compose_message(osv.Model):
context = context or {}
if context.get('default_model') == 'purchase.order' and context.get('default_res_id'):
context = dict(context, mail_post_autofollow=True)
self.pool.get('purchase.order').signal_send_rfq(cr, uid, [context['default_res_id']])
self.pool.get('purchase.order').signal_workflow(cr, uid, [context['default_res_id']], 'send_rfq')
return super(mail_compose_message, self).send_mail(cr, uid, ids, context=context)

View File

@ -245,7 +245,7 @@ class purchase_requisition(osv.osv):
for quotation in tender.purchase_ids:
if (self.check_valid_quotation(cr, uid, quotation, context=context)):
#use workflow to set PO state to confirm
po.signal_purchase_confirm(cr, uid, [quotation.id])
po.signal_workflow(cr, uid, [quotation.id], 'purchase_confirm')
#get other confirmed lines per supplier
for po_line in tender.po_line_ids:
@ -268,13 +268,13 @@ class purchase_requisition(osv.osv):
vals = self._prepare_po_line_from_tender(cr, uid, tender, line, new_po, context=context)
poline.copy(cr, uid, line.id, default=vals, context=context)
#use workflow to set new PO state to confirm
po.signal_purchase_confirm(cr, uid, [new_po])
po.signal_workflow(cr, uid, [new_po], 'purchase_confirm')
#cancel other orders
self.cancel_unconfirmed_quotations(cr, uid, tender, context=context)
#set tender to state done
self.signal_done(cr, uid, [tender.id])
self.signal_workflow(cr, uid, [tender.id], 'done')
return True
def cancel_unconfirmed_quotations(self, cr, uid, tender, context=None):
@ -282,7 +282,7 @@ class purchase_requisition(osv.osv):
po = self.pool.get('purchase.order')
for quotation in tender.purchase_ids:
if quotation.state in ['draft', 'sent', 'bid']:
self.pool.get('purchase.order').signal_purchase_cancel(cr, uid, [quotation.id])
self.pool.get('purchase.order').signal_workflow(cr, uid, [quotation.id], 'purchase_cancel')
po.message_post(cr, uid, [quotation.id], body=_('Cancelled by the call for bids associated to this request for quotation.'), context=context)
return True

View File

@ -25,6 +25,9 @@ class account_invoice_report(osv.osv):
_columns = {
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
}
_depends = {
'account.invoice': ['section_id'],
}
def _select(self):
return super(account_invoice_report, self)._select() + ", sub.section_id as section_id"

View File

@ -60,7 +60,7 @@ class sale_make_invoice(osv.osv_memory):
for i in o.invoice_ids:
newinv.append(i.id)
# Dummy call to workflow, will not create another invoice but bind the new invoice to the subflow
order_obj.signal_manual_invoice(cr, uid, [o.id for o in orders if o.order_policy == 'manual'])
order_obj.signal_workflow(cr, uid, [o.id for o in orders if o.order_policy == 'manual'], 'manual_invoice')
result = mod_obj.get_object_reference(cr, uid, 'account', 'action_invoice_tree1')
id = result and result[1] or False
result = act_obj.read(cr, uid, [id], context=context)[0]

View File

@ -22,7 +22,8 @@
from openerp.osv import osv, fields
class sale_order(osv.osv):
_inherit = 'sale.order'
_name = "sale.order"
_inherit = ['sale.order', 'crm.tracking.mixin']
_columns = {
'categ_ids': fields.many2many('crm.case.categ', 'sale_order_category_rel', 'order_id', 'category_id', 'Tags', \
domain="['|', ('section_id', '=', section_id), ('section_id', '=', False), ('object_id.model', '=', 'crm.lead')]", context="{'object_name': 'crm.lead'}")

View File

@ -29,6 +29,12 @@
<field name="user_id" position="after">
<field name="categ_ids" widget="many2many_tags"/>
</field>
<field name="origin" position="after">
<field name="campaign_id" />
<field name="medium_id" />
<field name="source_id" />
</field>
</field>
</record>
</data>

View File

@ -159,7 +159,7 @@ class sale_order(osv.osv):
raise osv.except_osv(
_('Cannot cancel sales order!'),
_('You must first cancel all delivery order(s) attached to this sales order.'))
stock_obj.signal_button_cancel(cr, uid, [p.id for p in sale.picking_ids])
stock_obj.signal_workflow(cr, uid, [p.id for p in sale.picking_ids], 'button_cancel')
return super(sale_order, self).action_cancel(cr, uid, ids, context=context)
def action_wait(self, cr, uid, ids, context=None):
@ -356,7 +356,7 @@ class stock_move(osv.osv):
if move.procurement_id and move.procurement_id.sale_line_id:
sale_ids.append(move.procurement_id.sale_line_id.order_id.id)
if sale_ids:
self.pool.get('sale.order').signal_ship_except(cr, uid, sale_ids)
self.pool.get('sale.order').signal_workflow(cr, uid, sale_ids, 'ship_except')
return super(stock_move, self).action_cancel(cr, uid, ids, context=context)
def _create_invoice_line_from_vals(self, cr, uid, move, invoice_line_vals, context=None):

View File

@ -76,7 +76,7 @@
!python {model: sale.order}: |
invoice_ids = self.browse(cr, uid, ref("sale.sale_order_8")).invoice_ids
first_invoice_id = invoice_ids[0]
self.pool.get('account.invoice').signal_invoice_cancel(cr, uid, [first_invoice_id.id])
self.pool.get('account.invoice').signal_workflow(cr, uid, [first_invoice_id.id], 'invoice_cancel')
-
I check order status in "Invoice Exception" and related invoice is in cancel state.
-

View File

@ -190,7 +190,7 @@
so = self.browse(cr, uid, ref("sale_order_service"))
account_invoice_obj = self.pool.get('account.invoice')
for invoice in so.invoice_ids:
account_invoice_obj.signal_invoice_open(cr, uid, [invoice.id])
account_invoice_obj.signal_workflow(cr, uid, [invoice.id], 'invoice_open')
-
I pay the invoice
-

View File

@ -77,7 +77,7 @@ class make_procurement(osv.osv_memory):
'location_id': wh.lot_stock_id.id,
'company_id': wh.company_id.id,
})
procurement_obj.signal_button_confirm(cr, uid, [procure_id])
procurement_obj.signal_workflow(cr, uid, [procure_id], 'button_confirm')
id2 = data_obj._get_id(cr, uid, 'procurement', 'procurement_tree_view')
id3 = data_obj._get_id(cr, uid, 'procurement', 'procurement_form_view')

View File

@ -8,7 +8,6 @@
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "EntypoRegular";
src: url("/web/static/src/font/entypo-webfont.eot") format("eot");
@ -19,7 +18,6 @@
font-weight: normal;
font-style: normal;
}
#oe_main_menu_navbar {
min-height: 34px;
z-index: 1001;
@ -39,6 +37,39 @@
margin-bottom: 0px;
}
.oe_systray {
margin-right: 0px !important;
}
.oe_notification {
z-index: 1600;
}
.oe_webclient_timezone_notification a {
color: white;
text-decoration: underline;
}
.oe_webclient_timezone_notification p {
margin-top: 1em;
}
.oe_webclient_timezone_notification dt {
font-weight: bold;
}
.oe_timezone_systray span {
margin-top: 1px;
background-color: #f6cf3b;
}
.navbar .oe_topbar_name {
max-width: 150px;
display: inline-block;
height: 15px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.openerp {
padding: 0;
margin: 0;
@ -800,23 +831,6 @@
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
.openerp .oe_notification {
z-index: 1500;
}
.openerp .oe_webclient_timezone_notification a {
color: white;
text-decoration: underline;
}
.openerp .oe_webclient_timezone_notification p {
margin-top: 1em;
}
.openerp .oe_webclient_timezone_notification dt {
font-weight: bold;
}
.openerp .oe_timezone_systray span {
margin-top: 1px;
background-color: #f6cf3b;
}
.openerp .oe_dialog_warning {
width: 100%;
}
@ -847,133 +861,6 @@
.openerp .oe_content_full_screen .oe_topbar, .openerp .oe_content_full_screen .oe_leftbar {
display: none;
}
.openerp .navbar .oe_topbar_anonymous_login {
background-color: #dc5f59;
color: #eeeeee;
background-color: #be4343;
background-image: -webkit-gradient(linear, left top, left bottom, from(#fc8787), to(maroon));
background-image: -webkit-linear-gradient(top, #fc8787, maroon);
background-image: -moz-linear-gradient(top, #fc8787, maroon);
background-image: -ms-linear-gradient(top, #fc8787, maroon);
background-image: -o-linear-gradient(top, #fc8787, maroon);
background-image: linear-gradient(to bottom, #fc8787, #800000);
}
.openerp .navbar .oe_topbar_anonymous_login a {
display: block;
padding: 5px 10px 7px;
line-height: 20px;
height: 30px;
text-decoration: none;
color: white;
background: transparent;
-webkit-transition: all 0.2s ease-out;
-moz-transition: all 0.2s ease-out;
-ms-transition: all 0.2s ease-out;
-o-transition: all 0.2s ease-out;
transition: all 0.2s ease-out;
}
.openerp .navbar .oe_topbar_anonymous_login a:hover {
background: rgba(0, 0, 0, 0.1);
color: white;
text-shadow: 0px 0px 3px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) inset;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) inset;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) inset;
}
.openerp .navbar .oe_topbar_item {
display: block;
padding: 5px 10px 26px;
line-height: 20px;
height: 20px;
text-decoration: none;
color: #eeeeee;
vertical-align: top;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-webkit-transition: all 0.2s ease-out;
-moz-transition: all 0.2s ease-out;
-ms-transition: all 0.2s ease-out;
-o-transition: all 0.2s ease-out;
transition: all 0.2s ease-out;
}
.openerp .navbar .oe_topbar_item:hover {
background: rgba(0, 0, 0, 0.2);
text-shadow: black 0px 0px 3px;
color: white;
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4) inset;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4) inset;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4) inset;
}
.openerp .navbar .oe_topbar_avatar {
width: 24px;
height: 24px;
margin: -2px 2px 0 0;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
.openerp .navbar .oe_topbar_avatar {
vertical-align: top;
}
.openerp .navbar .oe_dropdown_arrow:after {
border-top: 4px solid white;
}
.openerp .navbar .dropdown_menu {
top: 32px;
background: #333333;
background: rgba(37, 37, 37, 0.9);
border-color: #999999;
border-color: rgba(0, 0, 0, 0.2);
border-style: solid;
border-width: 0 2px 1px;
-moz-border-radius: 0 0 6px 6px;
-webkit-border-radius: 0 0 6px 6px;
border-radius: 0 0 6px 6px;
-webkit-background-clip: padding-box;
-moz-background-clip: padding-box;
background-clip: padding-box;
}
.openerp .navbar .dropdown_menu li {
float: none;
padding: 3px 12px;
}
.openerp .navbar .dropdown_menu li a {
color: #eeeeee;
}
.openerp .navbar .dropdown_menu li:hover {
background-color: #212121;
background-image: -webkit-gradient(linear, left top, left bottom, from(#292929), to(#191919));
background-image: -webkit-linear-gradient(top, #292929, #191919);
background-image: -moz-linear-gradient(top, #292929, #191919);
background-image: -ms-linear-gradient(top, #292929, #191919);
background-image: -o-linear-gradient(top, #292929, #191919);
background-image: linear-gradient(to bottom, #292929, #191919);
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
}
.openerp .navbar .oe_topbar_name {
max-width: 150px;
display: inline-block;
height: 15px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.openerp .nav li a {
padding: 6px 8px 4px 8px;
}
.openerp .oe_user_menu {
float: right;
padding: 0;
margin: 0;
}
.openerp .oe_user_menu li {
list-style-type: none;
float: left;
}
.openerp .oe_user_menu .oe_dropdown_menu {
right: -1px;
}
.openerp .oe_leftbar {
display: none;
width: 220px;
@ -3114,7 +3001,6 @@
top: 0px;
}
}
.kitten-mode-activated {
background-size: cover;
background-attachment: fixed;

View File

@ -158,6 +158,37 @@ $sheet-padding: 16px
#oe_main_menu_navbar.navbar
margin-bottom: 0px
.oe_systray
margin-right: 0px !important
// Notifications {{{
.oe_notification
z-index: 1600
.oe_webclient_timezone_notification
a
color: white
text-decoration: underline
p
margin-top: 1em
dt
font-weight: bold
.oe_timezone_systray
span
margin-top: 1px
background-color: #f6cf3b
// }}}
// Top Menu {{{
.navbar
.oe_topbar_name
max-width: 150px
display: inline-block
height: 15px // Customize to manage caret when topbar_name is over sized.
text-overflow: ellipsis
white-space: nowrap
overflow: hidden // Customize to bring ellipsis when topbar_name is over sized.
// }}}
.openerp
// Global style {{{
padding: 0
@ -690,23 +721,6 @@ $sheet-padding: 16px
border-bottom-right-radius: 8px
border-bottom-left-radius: 8px
// }}}
// Notifications {{{
.oe_notification
z-index: 1500
.oe_webclient_timezone_notification
a
color: white
text-decoration: underline
p
margin-top: 1em
dt
font-weight: bold
.oe_timezone_systray
span
margin-top: 1px
background-color: #f6cf3b
// }}}
// CrashManager {{{
.oe_dialog_warning
width: 100%
@ -738,95 +752,6 @@ $sheet-padding: 16px
.oe_topbar, .oe_leftbar
display: none
// }}}
// Top Menu {{{
.navbar
.oe_topbar_anonymous_login
background-color: #dc5f59
color: #eeeeee
@include vertical-gradient(#FC8787, #800000)
a
display: block
padding: 5px 10px 7px
line-height: 20px
height: 30px
text-decoration: none
color: white
background: transparent
@include transition(all 0.2s ease-out)
a:hover
background: rgba(0,0,0,0.1)
color: white
text-shadow: 0px 0px 3px rgba(0,0,0,0.2)
@include box-shadow(0 1px 2px rgba(0,0,0,0.2) inset)
.oe_topbar_item
display: block
padding: 5px 10px 26px
line-height: 20px
height: 20px
text-decoration: none
color: #eee
vertical-align: top
text-shadow: 0 1px 1px rgba(0,0,0,0.2)
@include transition(all 0.2s ease-out)
&:hover
background: rgba(0,0,0,0.2)
text-shadow: black 0px 0px 3px
color: white
@include box-shadow(0 1px 2px rgba(0,0,0,0.4) inset)
.oe_topbar_avatar
width: 24px
height: 24px
margin: -2px 2px 0 0
@include radius(3px)
.oe_topbar_avatar
vertical-align: top
.oe_dropdown_arrow:after
border-top: 4px solid white
.dropdown_menu
top: 32px
background: #333
background: rgba(37,37,37,0.9)
border-color: #999
border-color: rgba(0, 0, 0, 0.2)
border-style: solid
border-width: 0 2px 1px
@include radius(0 0 6px 6px)
@include background-clip()
li
float: none
padding: 3px 12px
a
color: #eee
&:hover
@include vertical-gradient(#292929, #191919)
@include box-shadow(none)
.oe_topbar_name
max-width: 150px
display: inline-block
height: 15px // Customize to manage caret when topbar_name is over sized.
text-overflow: ellipsis
white-space: nowrap
overflow: hidden // Customize to bring ellipsis when topbar_name is over sized.
// oe menu is the list of the buttons on the left side of the bar.
// So why aren't the buttons oe_topbar_items ? This sad state of affairs
// is a leftover from an uncomplete refactoring when the left and top menu
// were merged. You are welcome to refactor and clean this up
.nav li a
padding: 6px 8px 4px 8px
.oe_user_menu
float: right
padding: 0
margin: 0
li
list-style-type: none
float: left
.oe_dropdown_menu
right: -1px
// }}}
// Webclient.leftbar {{{
.oe_leftbar
display: none

View File

@ -76,7 +76,7 @@ class ir_http(orm.AbstractModel):
if self.geo_ip_resolver and request.httprequest.remote_addr:
record = self.geo_ip_resolver.record_by_addr(request.httprequest.remote_addr) or {}
request.session['geoip'] = record
if request.website_enabled:
if func:
self._authenticate(func.routing['auth'])

View File

@ -62,7 +62,7 @@ class contactus(http.Controller):
return request.website.render("website.contactus", values)
try:
values['channel_id'] = request.registry['ir.model.data'].get_object_reference(request.cr, SUPERUSER_ID, 'crm', 'crm_case_channel_website')[1]
values['medium_id'] = request.registry['ir.model.data'].get_object_reference(request.cr, SUPERUSER_ID, 'crm', 'crm_tracking_medium_website')[1]
values['section_id'] = request.registry['ir.model.data'].xmlid_to_res_id(request.cr, SUPERUSER_ID, 'website.salesteam_website_sales')
except ValueError:
pass

View File

@ -65,7 +65,7 @@ class sale_quote(http.Controller):
if token != order.access_token:
return request.website.render('website.404')
attachments=sign and [('signature.png', sign.decode('base64'))] or []
order_obj.signal_order_confirm(request.cr, SUPERUSER_ID, [order_id], context=request.context)
order_obj.signal_workflow(request.cr, SUPERUSER_ID, [order_id], 'order_confirm', context=request.context)
message = _('Order signed by %s') % (signer,)
self.__message_post(message, order_id, type='comment', subtype='mt_comment', attachments=attachments)
return True

View File

@ -8,7 +8,7 @@ msgstr ""
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
"PO-Revision-Date: 2013-11-24 14:57+0000\n"
"Last-Translator: krnkris <Unknown>\n"
"Last-Translator: krnkris <krnkris@freemail.hu>\n"
"Language-Team: Hungarian <openerp-hungarian-team@lists.launchpad.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -103,7 +103,7 @@ msgstr "Indiai bérszámfejtés"
#: help:ir.cron,model:0
msgid ""
"Model name on which the method to be called is located, e.g. 'res.partner'."
msgstr "Modell név ahogyan az megnevezve megtalálható, p.l. 'res.partner'."
msgstr "Modell név elnevezése szerint megtalálható, p.l. 'res.partner'."
#. module: base
#: view:ir.module.module:0
@ -4000,7 +4000,7 @@ msgstr "Időszakos értékelések, Felbecsülések, Felmérések"
#: model:ir.actions.act_window,name:base.ir_property_form
#: model:ir.ui.menu,name:base.menu_ir_property_form_all
msgid "Configuration Parameters"
msgstr "Konfiguráció Paraméterek"
msgstr "Beállítási Paaraméterek"
#. module: base
#: constraint:ir.cron:0
@ -4171,9 +4171,9 @@ msgid ""
"separated list of valid field names (optionally followed by asc/desc for the "
"direction)"
msgstr ""
"Invalid \"order\" specified. A valid \"order\" specification is a comma-"
"separated list of valid field names (optionally followed by asc/desc for the "
"direction)"
"Érvénytelen \"megrendelés\" meghatározás. Az érvénnyes \"megrendelés\" egy vesszővel"
"elválasztott lista érvényes mező nevekkel (választhatóan növekvő/csökkenő sorrendbe "
"állítva)"
#. module: base
#: model:ir.model,name:base.model_ir_module_module_dependency
@ -4217,7 +4217,7 @@ msgstr ""
#. module: base
#: model:res.groups,name:base.group_survey_user
msgid "Survey / User"
msgstr "Felmérés / felhasználó"
msgstr "Felmérés / Felhasználó"
#. module: base
#: view:ir.module.module:0

View File

@ -848,9 +848,9 @@ class ir_actions_server(osv.osv):
def run_action_trigger(self, cr, uid, action, eval_context=None, context=None):
""" Trigger a workflow signal, depending on the use_relational_model:
- `base`: base_model_pool.signal_<TRIGGER_NAME>(cr, uid, context.get('active_id'))
- `base`: base_model_pool.signal_workflow(cr, uid, context.get('active_id'), <TRIGGER_NAME>)
- `relational`: find the related model and object, using the relational
field, then target_model_pool.signal_<TRIGGER_NAME>(cr, uid, target_id)
field, then target_model_pool.signal_workflow(cr, uid, target_id, <TRIGGER_NAME>)
"""
obj_pool = self.pool[action.model_id.model]
if action.use_relational_model == 'base':

View File

@ -177,8 +177,13 @@ class module(osv.osv):
element.set('src', "/%s/static/description/%s" % (module.name, element.get('src')))
res[module.id] = lxml.html.tostring(html)
else:
overrides = dict(embed_stylesheet=False, doctitle_xform=False, output_encoding='unicode')
output = publish_string(source=module.description, settings_overrides=overrides, writer=MyWriter())
overrides = {
'embed_stylesheet': False,
'doctitle_xform': False,
'output_encoding': 'unicode',
'xml_declaration': False,
}
output = publish_string(source=module.description or '', settings_overrides=overrides, writer=MyWriter())
res[module.id] = output
return res

View File

@ -756,7 +756,7 @@ class Environment(object):
"""
if not spec:
return
for env in list(self.all):
for env in list(iter(self.all)):
c = env.cache
for field, ids in spec:
if ids is None:
@ -769,7 +769,7 @@ class Environment(object):
def invalidate_all(self):
""" Clear the cache of all environments. """
for env in list(self.all):
for env in list(iter(self.all)):
env.cache.clear()
env.prefetch.clear()
env.computed.clear()

View File

@ -366,9 +366,17 @@ class Field(object):
else:
self._setup_regular(env)
# put invalidation/recomputation triggers on dependencies
# put invalidation/recomputation triggers on field dependencies
model = env[self.model_name]
for path in self.depends:
self._setup_dependency([], env[self.model_name], path.split('.'))
self._setup_dependency([], model, path.split('.'))
# put invalidation triggers on model dependencies
for dep_model_name, field_names in model._depends.iteritems():
dep_model = env[dep_model_name]
for field_name in field_names:
field = dep_model._fields[field_name]
field._triggers.add((self, None))
#
# Setup of related fields
@ -800,7 +808,7 @@ class Field(object):
# invalidate the fields that depend on self, and prepare recomputation
spec = [(self, records._ids)]
for field, path in self._triggers:
if field.store:
if path and field.store:
# don't move this line to function top, see log
env = records.env(user=SUPERUSER_ID, context={'active_test': False})
target = env[field.model_name].search([(path, 'in', records.ids)])
@ -824,10 +832,13 @@ class Field(object):
computed = target.browse(env.computed[field])
if path == 'id':
target = records - computed
elif path:
target = (target.browse(env.cache[field]) - computed).filtered(
lambda rec: rec._mapped_cache(path) & records
)
else:
for record in target.browse(env.cache[field]) - computed:
if record._mapped_cache(path) & records:
target += record
target = target.browse(env.cache[field]) - computed
if target:
spec.append((field, target._ids))
@ -1542,6 +1553,9 @@ class Id(Field):
store = True
readonly = True
def __init__(self, string=None, **kwargs):
super(Id, self).__init__(type='integer', string=string, **kwargs)
def to_column(self):
return fields.integer('ID')

View File

@ -1145,11 +1145,14 @@ class Root(object):
"""Root WSGI application for the OpenERP Web Client.
"""
def __init__(self):
self._loaded = False
@lazy_property
def session_store(self):
# Setup http sessions
path = openerp.tools.config.session_dir
_logger.debug('HTTP sessions stored in: %s', path)
self.session_store = werkzeug.contrib.sessions.FilesystemSessionStore(path, session_class=OpenERPSession)
self._loaded = False
return werkzeug.contrib.sessions.FilesystemSessionStore(path, session_class=OpenERPSession)
@lazy_property
def nodb_routing_map(self):

View File

@ -326,6 +326,10 @@ class BaseModel(object):
_log_create = False
_sql_constraints = []
# model dependencies, for models backed up by sql views:
# {model_name: field_names, ...}
_depends = {}
CONCURRENCY_CHECK_FIELD = '__last_update'
def log(self, cr, uid, id, message, secondary=False, context=None):
@ -585,6 +589,10 @@ class BaseModel(object):
inherits = dict(parent_class._inherits)
inherits.update(cls._inherits)
depends = dict(parent_class._depends)
for m, fs in cls._depends.iteritems():
depends.setdefault(m, []).extend(fs)
old_constraints = parent_class._constraints
new_constraints = cls._constraints
# filter out from old_constraints the ones overridden by a
@ -604,6 +612,7 @@ class BaseModel(object):
'_columns': columns,
'_defaults': defaults,
'_inherits': inherits,
'_depends': depends,
'_constraints': constraints,
'_sql_constraints': sql_constraints,
}
@ -617,6 +626,7 @@ class BaseModel(object):
'_columns': dict(cls._columns),
'_defaults': dict(cls._defaults),
'_inherits': dict(cls._inherits),
'_depends': dict(cls._depends),
'_constraints': list(cls._constraints),
'_sql_constraints': list(cls._sql_constraints),
'_original_module': original_module,
@ -629,76 +639,8 @@ class BaseModel(object):
if col._type == 'float':
cls._columns[key] = copy.copy(col)
# link the class to the registry, and update the registry
cls.pool = pool
# Note: we have to insert an instance into the registry now, because it
# can trigger some stuff on other models which expect this new instance
# (like method _inherits_reload_src())
# instantiate the model, and initialize it
model = object.__new__(cls)
cls._model = model # backward compatibility
pool.add(name, model)
# determine description, table, sequence and log_access
if not cls._description:
cls._description = cls._name
if not cls._table:
cls._table = cls._name.replace('.', '_')
if not cls._sequence:
cls._sequence = cls._table + '_id_seq'
if not hasattr(cls, '_log_access'):
# If _log_access is not specified, it is the same value as _auto.
cls._log_access = cls._auto
# Transience
if cls.is_transient():
cls._transient_check_count = 0
cls._transient_max_count = config.get('osv_memory_count_limit')
cls._transient_max_hours = config.get('osv_memory_age_limit')
assert cls._log_access, \
"TransientModels must have log_access turned on, " \
"in order to implement their access rights policy"
# retrieve new-style fields and duplicate them (to avoid clashes with
# inheritance between different models)
cls._fields = {}
for attr, field in getmembers(cls, Field.__instancecheck__):
if not field._origin:
cls._add_field(attr, field.copy())
# introduce magic fields
cls._add_magic_fields()
# register stuff about low-level function fields and custom fields
cls._init_function_fields(pool, cr)
cls._init_manual_fields(pool, cr)
# process _inherits
cls._inherits_check()
cls._inherits_reload()
# register constraints and onchange methods
cls._init_constraints_onchanges()
# check defaults
for k in cls._defaults:
assert k in cls._fields, \
"Model %s has a default for nonexiting field %s" % (cls._name, k)
# restart columns
for column in cls._columns.itervalues():
column.restart()
# validate rec_name
if cls._rec_name:
assert cls._rec_name in cls._fields, \
"Invalid rec_name %s for model %s" % (cls._rec_name, cls._name)
elif 'name' in cls._fields:
cls._rec_name = 'name'
# prepare ormcache, which must be shared by all instances of the model
cls._ormcache = {}
# complete the initialization of model
model.__init__(pool, cr)
return model
@ -818,8 +760,81 @@ class BaseModel(object):
return None
def __init__(self, pool, cr):
# this method no longer does anything; kept for backward compatibility
pass
""" Initialize a model and make it part of the given registry.
- copy the stored fields' functions in the registry,
- retrieve custom fields and add them in the model,
- ensure there is a many2one for each _inherits'd parent,
- update the children's _columns,
- give a chance to each field to initialize itself.
"""
cls = type(self)
# link the class to the registry, and update the registry
cls.pool = pool
cls._model = self # backward compatibility
pool.add(cls._name, self)
# determine description, table, sequence and log_access
if not cls._description:
cls._description = cls._name
if not cls._table:
cls._table = cls._name.replace('.', '_')
if not cls._sequence:
cls._sequence = cls._table + '_id_seq'
if not hasattr(cls, '_log_access'):
# If _log_access is not specified, it is the same value as _auto.
cls._log_access = cls._auto
# Transience
if cls.is_transient():
cls._transient_check_count = 0
cls._transient_max_count = config.get('osv_memory_count_limit')
cls._transient_max_hours = config.get('osv_memory_age_limit')
assert cls._log_access, \
"TransientModels must have log_access turned on, " \
"in order to implement their access rights policy"
# retrieve new-style fields and duplicate them (to avoid clashes with
# inheritance between different models)
cls._fields = {}
for attr, field in getmembers(cls, Field.__instancecheck__):
if not field._origin:
cls._add_field(attr, field.copy())
# introduce magic fields
cls._add_magic_fields()
# register stuff about low-level function fields and custom fields
cls._init_function_fields(pool, cr)
cls._init_manual_fields(pool, cr)
# process _inherits
cls._inherits_check()
cls._inherits_reload()
# register constraints and onchange methods
cls._init_constraints_onchanges()
# check defaults
for k in cls._defaults:
assert k in cls._fields, \
"Model %s has a default for nonexiting field %s" % (cls._name, k)
# restart columns
for column in cls._columns.itervalues():
column.restart()
# validate rec_name
if cls._rec_name:
assert cls._rec_name in cls._fields, \
"Invalid rec_name %s for model %s" % (cls._rec_name, cls._name)
elif 'name' in cls._fields:
cls._rec_name = 'name'
# prepare ormcache, which must be shared by all instances of the model
cls._ormcache = {}
def __export_xml_id(self):
""" Return a valid xml_id for the record `self`. """
@ -3013,7 +3028,7 @@ class BaseModel(object):
if not fields:
fields = filter(valid, self._fields)
else:
invalid_fields = list(set(filter(lambda name: not valid(name), fields)))
invalid_fields = set(filter(lambda name: not valid(name), fields))
if invalid_fields:
_logger.warning('Access Denied by ACLs for operation: %s, uid: %s, model: %s, fields: %s',
operation, user, self._name, ', '.join(invalid_fields))
@ -3281,7 +3296,7 @@ class BaseModel(object):
self._cr.execute(query, (self._name, tuple(self.ids)))
res = self._cr.dictfetchall()
uids = list(set(r[k] for r in res for k in ['write_uid', 'create_uid'] if r.get(k)))
uids = set(r[k] for r in res for k in ['write_uid', 'create_uid'] if r.get(k))
names = dict(self.env['res.users'].browse(uids).name_get())
for r in res:
@ -3504,7 +3519,7 @@ class BaseModel(object):
for order, obj_name, store_ids, fields in result_store:
if obj_name == self._name:
effective_store_ids = list(set(store_ids) - set(ids))
effective_store_ids = set(store_ids) - set(ids)
else:
effective_store_ids = store_ids
if effective_store_ids:
@ -4945,19 +4960,6 @@ class BaseModel(object):
""" stuff to do right after the registry is built """
pass
def __getattr__(self, name):
if name.startswith('signal_'):
# self.signal_XXX() sends signal XXX to the record's workflow
signal_name = name[7:]
assert signal_name
return (lambda *args, **kwargs:
self.signal_workflow(*args, signal=signal_name, **kwargs))
get = getattr(super(BaseModel, self), '__getattr__', None)
if get is None:
raise AttributeError("%r has no attribute %r" % (type(self).__name__, name))
return get(name)
def _patch_method(self, name, method):
""" Monkey-patch a method for all instances of this model. This replaces
the method called `name` by `method` in `self`'s class.
@ -5415,7 +5417,7 @@ class BaseModel(object):
""" If `field` must be recomputed on some record in `self`, return the
corresponding records that must be recomputed.
"""
for env in [self.env] + list(self.env.all):
for env in [self.env] + list(iter(self.env.all)):
if env.todo.get(field) and env.todo[field] & self:
return env.todo[field]
@ -5437,7 +5439,7 @@ class BaseModel(object):
""" Recompute stored function fields. The fields and records to
recompute have been determined by method :meth:`modified`.
"""
for env in list(self.env.all):
for env in list(iter(self.env.all)):
while env.todo:
field, recs = next(env.todo.iteritems())
# evaluate the fields to recompute, and save them to database

View File

@ -43,7 +43,7 @@ MANIFEST = '__openerp__.py'
_logger = logging.getLogger(__name__)
# addons path as a list
ad_paths = [tools.config.addons_data_dir]
ad_paths = []
hooked = False
# Modules already loaded
@ -89,6 +89,10 @@ def initialize_sys_path():
global ad_paths
global hooked
dd = tools.config.addons_data_dir
if dd not in ad_paths:
ad_paths.append(dd)
for ad in tools.config['addons_path'].split(','):
ad = os.path.abspath(tools.ustr(ad.strip()))
if ad not in ad_paths:

View File

@ -30,7 +30,7 @@ RELEASE_LEVELS_DISPLAY = {ALPHA: ALPHA,
# properly comparable using normal operarors, for example:
# (6,1,0,'beta',0) < (6,1,0,'candidate',1) < (6,1,0,'candidate',2)
# (6,1,0,'candidate',2) < (6,1,0,'final',0) < (6,1,2,'final',0)
version_info = (8, 0, 0, ALPHA, 1)
version_info = (8, 0, 0, RELEASE_CANDIDATE, 1)
version = '.'.join(map(str, version_info[:2])) + RELEASE_LEVELS_DISPLAY[version_info[3]] + str(version_info[4] or '')
series = serie = major_version = '.'.join(map(str, version_info[:2]))

View File

@ -61,7 +61,10 @@ def check_ssl():
DEFAULT_LOG_HANDLER = [':INFO']
def _get_default_datadir():
return appdirs.user_data_dir(appname='OpenERP', appauthor=release.author)
home = os.path.expanduser('~')
func = appdirs.user_data_dir if os.path.exists(home) else appdirs.site_data_dir
# No "version" kwarg as session and filestore paths are shared against series
return func(appname='Odoo', appauthor=release.author)
class configmanager(object):
def __init__(self, fname=None):
@ -649,7 +652,7 @@ class configmanager(object):
@property
def session_dir(self):
d = os.path.join(self['data_dir'], 'sessions', release.series)
d = os.path.join(self['data_dir'], 'sessions')
if not os.path.exists(d):
os.makedirs(d, 0700)
else: