[MERGE]: Merge with latest trunk-addons

bzr revid: rpa@tinyerp.com-20120703062351-tazpsjb7a3usajvf
This commit is contained in:
Rucha (Open ERP) 2012-07-03 11:53:51 +05:30
commit 9e6f918bbe
76 changed files with 1966 additions and 893 deletions

View File

@ -13,8 +13,7 @@
<attribute name="string">Continue</attribute> <attribute name="string">Continue</attribute>
</button> </button>
<separator string="title" position="replace"> <separator string="title" position="replace">
<group string="Select an Accounting Setup"> <group>
<label colspan="2" string="This will automatically configure your taxes and accounts."/>
<field name="charts"/> <field name="charts"/>
</group> </group>
<group string="Configure your Fiscal Year" groups="account.group_account_user"> <group string="Configure your Fiscal Year" groups="account.group_account_user">

View File

@ -157,33 +157,39 @@
<field name="state" widget="statusbar" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/> <field name="state" widget="statusbar" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/>
</header> </header>
<sheet string="Supplier Invoice"> <sheet string="Supplier Invoice">
<group> <div class="oe_title">
<group> <h1>
<field string="Supplier" name="partner_id" <label string="Draft Invoice" attrs="{'invisible': [('state', '&lt;&gt;', 'draft')]}"/>
<label for="number" class="oe_edit_only" attrs="{'invisible': [('state', '=', 'draft')]}"/>
<field name="number" class="oe_inline" attrs="{'invisible': [('state', '=', 'draft')]}"/>
</h1>
<h2>
<label for="origin" string="Concerns" class="oe_inline"/>
<field name="origin" placeholder="PO0025" class="oe_inline"/>
<label string=" from " attrs="{'invisible': [('origin', '=', False)]}" class='oe_inline'/>
<field string="Supplier" name="partner_id" class="oe_inline"
on_change="onchange_partner_id(type,partner_id,date_invoice,payment_term, partner_bank_id,company_id)" on_change="onchange_partner_id(type,partner_id,date_invoice,payment_term, partner_bank_id,company_id)"
context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}" context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}"
domain="[('supplier', '=', True)]"/> domain="[('supplier', '=', True)]"/>
<field name="fiscal_position" widget="selection"/> </h2>
</div>
<group>
<group>
<field name="date_invoice"/>
<field name="date_due"/>
<field name="type" invisible="1"/>
<field name="period_id" domain="[('state', '=', 'draft')]" groups="account.group_account_user" widget="selection"/>
</group> </group>
<group> <group>
<field name="number"/> <field name="fiscal_position" widget="selection"/>
<field name="date_invoice"/>
<field name="period_id" domain="[('state', '=', 'draft')]"
groups="account.group_account_user" widget="selection"/>
<field name="journal_id" on_change="onchange_journal_id(journal_id)" widget="selection"
groups="account.group_account_user"/>
<field domain="[('company_id', '=', company_id), ('type', '=', 'payable')]"
name="account_id" groups="account.group_account_user"/>
<field name="currency_id"/> <field name="currency_id"/>
<field name="type" invisible="1"/> <field domain="[('company_id', '=', company_id), ('type', '=', 'payable')]" name="account_id" groups="account.group_account_user" invisible="1"/>
</group> </group>
<group> <group>
<label for="reference"/> <label for="reference"/>
<div> <div>
<field name="reference_type"/>
<field name="reference" placeholder="Payment Reference"/> <field name="reference" placeholder="Payment Reference"/>
</div> </div>
<field name="date_due"/>
</group> </group>
</group> </group>
<notebook> <notebook>
@ -196,10 +202,11 @@
<field domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id), ('parent_id', '!=', False)]" name="account_analytic_id" groups="analytic.group_analytic_accounting"/> <field domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id), ('parent_id', '!=', False)]" name="account_analytic_id" groups="analytic.group_analytic_accounting"/>
<field name="quantity"/> <field name="quantity"/>
<field name="price_unit"/> <field name="price_unit"/>
<!-- Removed if subtotal is set -->
<field name="price_subtotal"/> <field name="price_subtotal"/>
<field invisible="True" name="name"/> <field domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '&lt;&gt;', 'view')]" name="account_id" on_change="onchange_account_id(product_id,parent.partner_id,parent.type,parent.fiscal_position,account_id)" invisible="1"/>
<field invisible="True" name="uos_id"/> <!-- Removed if subtotal is set -->
<field name="name" invisible="1"/>
<field name="uos_id" invisible="1"/>
</tree> </tree>
</field> </field>
<group> <group>
@ -232,16 +239,17 @@
<field name="comment"/> <field name="comment"/>
</page> </page>
<page string="Other Info"> <page string="Other Info">
<group col="4"> <group>
<group>
<field domain="[('partner_id', '=', partner_id)]" name="partner_bank_id" on_change="onchange_partner_bank(partner_bank_id)"/> <field domain="[('partner_id', '=', partner_id)]" name="partner_bank_id" on_change="onchange_partner_bank(partner_bank_id)"/>
<field name="company_id" on_change="onchange_company_id(company_id,partner_id,type,invoice_line,currency_id)" widget="selection" groups="base.group_multi_company"/>
<newline/>
<field name="payment_term" widget="selection"/> <field name="payment_term" widget="selection"/>
<field name="name"/> </group>
<newline/> <group>
<field name="origin" placeholder="PO0025"/>
<field name="user_id"/> <field name="user_id"/>
<field name="name" invisible="1"/>
<field name="move_id" groups="account.group_account_user"/> <field name="move_id" groups="account.group_account_user"/>
<field name="company_id" on_change="onchange_company_id(company_id,partner_id,type,invoice_line,currency_id)" widget="selection" groups="base.group_multi_company"/>
</group>
</group> </group>
</page> </page>
<page string="Payments"> <page string="Payments">

View File

@ -2357,12 +2357,11 @@
<group string="res_config_contents" position="replace"> <group string="res_config_contents" position="replace">
<field name="only_one_chart_template" invisible="1"/> <field name="only_one_chart_template" invisible="1"/>
<field name="complete_tax_set" invisible="1"/> <field name="complete_tax_set" invisible="1"/>
<p>This will automatically configure your chart of accounts, bank accounts, taxes and journals according to the selected template.</p>
<div groups="base.group_multi_company"> <div groups="base.group_multi_company">
<label for="company_id"/> <label for="company_id"/>
<field name="company_id" widget="selection"/> <!-- we assume that this wizard will be run only by administrators and as this field may cause problem if hidden (because of the default company of the user removed from the selection because already configured), we simply choosed to remove the group "multi company" of it --> <field name="company_id" widget="selection"/> <!-- we assume that this wizard will be run only by administrators and as this field may cause problem if hidden (because of the default company of the user removed from the selection because already configured), we simply choosed to remove the group "multi company" of it -->
</div> </div>
<group string="Set Your Accounting Options"> <group>
<div attrs="{'invisible': [('only_one_chart_template','=',True)]}"> <div attrs="{'invisible': [('only_one_chart_template','=',True)]}">
<label for="chart_template_id"/> <label for="chart_template_id"/>
<field name="chart_template_id" widget="selection" on_change="onchange_chart_template_id(chart_template_id)" domain="[('visible','=', True)]"/> <field name="chart_template_id" widget="selection" on_change="onchange_chart_template_id(chart_template_id)" domain="[('visible','=', True)]"/>

View File

@ -51,12 +51,12 @@
<field name="type">form</field> <field name="type">form</field>
<field name="inherit_id" ref="product.product_category_form_view"/> <field name="inherit_id" ref="product.product_category_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form position="inside"> <data>
<group string="Accounting Properties"> <xpath expr="/form/sheet//group[@name='account_property']" position="inside">
<field name="property_account_income_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/> <field name="property_account_income_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="property_account_expense_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/> <field name="property_account_expense_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
</group> </xpath>
</form> </data>
</field> </field>
</record> </record>

View File

@ -34,12 +34,11 @@
<field name="type">form</field> <field name="type">form</field>
<field name="inherit_id" ref="product.product_category_form_view"/> <field name="inherit_id" ref="product.product_category_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form position="inside"> <data>
<group> <xpath expr="/form/sheet//group[@name='account_property']" position="inside">
<separator string="Accounting Property" colspan="2"/>
<field name="property_account_creditor_price_difference_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/> <field name="property_account_creditor_price_difference_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
</group> </xpath>
</form> </data>
</field> </field>
</record> </record>

View File

@ -45,10 +45,10 @@
</group> </group>
</group> </group>
<group> <group>
<group string="Delegrated From"> <group string="Delegated From">
<field name="parent_ids" readonly="1" nolabel="1" /> <field name="parent_ids" readonly="1" nolabel="1" />
</group> </group>
<group string="Delegrated To" > <group string="Delegated To" >
<field name="child_ids" readonly="1" nolabel="1" /> <field name="child_ids" readonly="1" nolabel="1" />
</group> </group>
</group> </group>

View File

@ -7,13 +7,36 @@
<field name="model">caldav.browse</field> <field name="model">caldav.browse</field>
<field name="type">form</field> <field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Browse Caldav" > <form string="Browse Caldav" version="7.0">
<group colspan="4" width="700" height="500"> <header>
<separator string="Browse Caldav" colspan="4"/> <button special="cancel" string="_Close" icon="gtk-close"/>
<field name="url" colspan="4" /> </header>
<separator string="Description" colspan="4"/> <sheet>
<field name="description" colspan="4" nolabel="1"/> <group>
</group> <separator string="Browse Caldav" colspan="4"/>
<field name="url" colspan="2" />
<separator string="Help" colspan="4"/>
<group colspan="4"><div>
1. Webdav server that provides remote access to calendar<br/>
2. Synchronisation of calendar using WebDAV<br/>
3. Customize calendar event and todo attribute with any of OpenERP model<br/>
4. Provides iCal Import/Export functionality
<br/></div></group>
<group colspan="4"><div>
To access Calendars using CalDAV clients, point them to:
http://<i>HOSTNAME</i>:<i>PORT</i>/webdav/<i>DATABASE_NAME</i>/calendars/users/<i>USERNAME</i>/c</div></group>
<group colspan="4"><div>
To access OpenERP Calendar using WebCal to remote site use the URL like:
http://<i>HOSTNAME</i>:<i>PORT</i>/webdav/<i>DATABASE_NAME</i>/Calendars/<i>CALENDAR_NAME</i>.ics</div></group>
<group colspan="4"><div>
<i>
HOSTNAME: Host on which OpenERP server(With webdav) is running<br/>
PORT : Port on which OpenERP server is running (By Default : 8069)<br/>
DATABASE_NAME: Name of database on which OpenERP Calendar is created</i>
</div></group>
</group>
</sheet>
</form> </form>
</field> </field>
</record> </record>
@ -29,12 +52,11 @@
or or
<button string="Cancel" class="oe_link" special="cancel"/> <button string="Cancel" class="oe_link" special="cancel"/>
</header> </header>
<label string="Configure your openerp hostname. For example : " colspan="4"></label> <sheet>
<newline/> <group>
<label string="database.my.openerp.com or companyserver.com" colspan="4"/> <field name="host_name" colspan="2" width="250" placeholder="For example : database.my.openerp.com or companyserver.com"/>
<newline/> </group>
<separator colspan="4"/> </sheet>
<field name="host_name" colspan="4" width="250" />
</form> </form>
</field> </field>
</record> </record>
@ -50,11 +72,14 @@
or or
<button string="Cancel" class="oe_link" special="cancel"/> <button string="Cancel" class="oe_link" special="cancel"/>
</header> </header>
<separator string="" colspan="4"/> <sheet>
<field name="service" colspan="4" width="250" readonly="1"/> <group>
<field name="collection" colspan="4" width="250" invisible="1" /> <field name="service" readonly="1"/>
<field name="calendar" colspan="4" width="250" domain="[('collection_id','=', collection)]" readonly="1"/> <field name="collection" invisible="1" />
<field name="device" colspan="4" width="250" /> <field name="calendar" domain="[('collection_id','=', collection)]" readonly="1"/>
<field name="device"/>
</group>
</sheet>
</form> </form>
</field> </field>
</record> </record>

View File

@ -273,14 +273,6 @@ class crm_lead(base_stage, osv.osv):
'color': 0, 'color': 0,
} }
def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, [])
for obj in self.browse(cr, uid, ids, context=context):
# salesman must perform an action when in draft mode
if obj.state == 'draft' and obj.user_id:
result[obj.id] = [obj.user_id.id]
return result
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
obj_id = super(crm_lead, self).create(cr, uid, vals, context) obj_id = super(crm_lead, self).create(cr, uid, vals, context)
self.create_send_note(cr, uid, [obj_id], context=context) self.create_send_note(cr, uid, [obj_id], context=context)
@ -770,64 +762,6 @@ class crm_lead(base_stage, osv.osv):
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
} }
def message_new(self, cr, uid, msg, custom_values=None, context=None):
"""Automatically calls when new email message arrives"""
res_id = super(crm_lead, self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
subject = msg.get('subject') or _("No Subject")
body = msg.get('body_text')
msg_from = msg.get('from')
priority = msg.get('priority')
vals = {
'name': subject,
'email_from': msg_from,
'email_cc': msg.get('cc'),
'description': body,
'user_id': False,
}
if priority:
vals['priority'] = priority
vals.update(self.message_partner_by_email(cr, uid, msg.get('from', False)))
self.write(cr, uid, [res_id], vals, context)
return res_id
def message_update(self, cr, uid, ids, msg, vals=None, default_act='pending', context=None):
if isinstance(ids, (str, int, long)):
ids = [ids]
if vals == None:
vals = {}
super(crm_lead, self).message_update(cr, uid, ids, msg, context=context)
if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
vals['priority'] = msg.get('priority')
maps = {
'cost':'planned_cost',
'revenue': 'planned_revenue',
'probability':'probability'
}
vls = {}
for line in msg['body_text'].split('\n'):
line = line.strip()
res = tools.misc.command_re.match(line)
if res and maps.get(res.group(1).lower()):
key = maps.get(res.group(1).lower())
vls[key] = res.group(2).lower()
vals.update(vls)
# Unfortunately the API is based on lists
# but we want to update the state based on the
# previous state, so we have to loop:
for case in self.browse(cr, uid, ids, context=context):
values = dict(vals)
if case.state in CRM_LEAD_PENDING_STATES:
#re-open
values.update(state=crm.AVAILABLE_STATES[1][0])
if not case.date_open:
values['date_open'] = time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
res = self.write(cr, uid, [case.id], values, context=context)
return res
def action_makeMeeting(self, cr, uid, ids, context=None): def action_makeMeeting(self, cr, uid, ids, context=None):
""" """
This opens Meeting's calendar view to schedule meeting on current Opportunity This opens Meeting's calendar view to schedule meeting on current Opportunity
@ -882,19 +816,66 @@ class crm_lead(base_stage, osv.osv):
if stage.on_change: if stage.on_change:
vals['probability'] = stage.probability vals['probability'] = stage.probability
return super(crm_lead,self).write(cr, uid, ids, vals, context) return super(crm_lead,self).write(cr, uid, ids, vals, context)
# ----------------------------------------
# Mail Gateway
# ----------------------------------------
def message_new(self, cr, uid, msg, custom_values=None, context=None):
""" Overrides mail_thread message_new that is called by the mailgateway
through message_process.
This override updates the document according to the email.
"""
if custom_values is None: custom_values = {}
custom_values.update({
'name': msg.get('subject') or _("No Subject"),
'description': msg.get('body_text'),
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
'user_id': False,
})
if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
custom_values['priority'] = msg.get('priority')
custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from', False), context=context))
return super(crm_lead, self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
""" Overrides mail_thread message_update that is called by the mailgateway
through message_process.
This method updates the document according to the email.
"""
if isinstance(ids, (str, int, long)):
ids = [ids]
if update_vals is None: update_vals = {}
if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
vals['priority'] = msg.get('priority')
maps = {
'cost':'planned_cost',
'revenue': 'planned_revenue',
'probability':'probability',
}
for line in msg.get('body_text', '').split('\n'):
line = line.strip()
res = tools.misc.command_re.match(line)
if res and maps.get(res.group(1).lower()):
key = maps.get(res.group(1).lower())
vals[key] = res.group(2).lower()
return super(crm_lead, self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context)
# ---------------------------------------- # ----------------------------------------
# OpenChatter methods and notifications # OpenChatter methods and notifications
# ---------------------------------------- # ----------------------------------------
def message_get_subscribers(self, cr, uid, ids, context=None): def message_get_subscribers(self, cr, uid, ids, context=None):
sub_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context) """ Override to add the salesman. """
# add salesman to the subscribers user_ids = super(crm_lead, self).message_get_subscribers(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if obj.user_id: if obj.user_id and not obj.user_id.id in user_ids:
sub_ids.append(obj.user_id.id) user_ids.append(obj.user_id.id)
return self.pool.get('res.users').read(cr, uid, sub_ids, context=context) return user_ids
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
""" Override of the (void) default notification method. """ """ Override of the (void) default notification method. """
stage_name = self.pool.get('crm.case.stage').name_get(cr, uid, [stage_id], context=context)[0][1] stage_name = self.pool.get('crm.case.stage').name_get(cr, uid, [stage_id], context=context)[0][1]

View File

@ -1,7 +1,10 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<openerp> <openerp>
<data> <data noupdate="1">
<!-- Demo Leads --> <!--
Demo Leads
-->
<record id="crm_case_itisatelesalescampaign0" model="crm.lead"> <record id="crm_case_itisatelesalescampaign0" model="crm.lead">
<field name="type_id" ref="crm.type_lead1"/> <field name="type_id" ref="crm.type_lead1"/>
<field eval="'3'" name="priority"/> <field eval="'3'" name="priority"/>
@ -21,7 +24,6 @@
<field eval="'Plan to Attend a Training'" name="name"/> <field eval="'Plan to Attend a Training'" name="name"/>
<field eval="'0033 769 703-274'" name="phone"/> <field eval="'0033 769 703-274'" name="phone"/>
</record> </record>
<record id="crm_case_electonicgoodsdealer0" model="crm.lead"> <record id="crm_case_electonicgoodsdealer0" model="crm.lead">
<field name="type_id" ref="crm.type_lead7"/> <field name="type_id" ref="crm.type_lead7"/>
<field eval="'4'" name="priority"/> <field eval="'4'" name="priority"/>
@ -76,7 +78,6 @@
<field eval="'(514) 698-4118'" name="phone"/> <field eval="'(514) 698-4118'" name="phone"/>
<field eval="'hmc@thgascompany.com'" name="email_from"/> <field eval="'hmc@thgascompany.com'" name="email_from"/>
</record> </record>
<record id="crm_case_itdeveloper0" model="crm.lead"> <record id="crm_case_itdeveloper0" model="crm.lead">
<field name="type_id" ref="crm.type_lead4"/> <field name="type_id" ref="crm.type_lead4"/>
<field eval="'3'" name="priority"/> <field eval="'3'" name="priority"/>
@ -96,7 +97,6 @@
<field eval="'(855) 924-4364'" name="phone"/> <field eval="'(855) 924-4364'" name="phone"/>
<field eval="'helle@stonageit.be'" name="email_from"/> <field eval="'helle@stonageit.be'" name="email_from"/>
</record> </record>
<record id="crm_case_mgroperations0" model="crm.lead"> <record id="crm_case_mgroperations0" model="crm.lead">
<field eval="1" name="active"/> <field eval="1" name="active"/>
<field name="type_id" ref="crm.type_lead3"/> <field name="type_id" ref="crm.type_lead3"/>
@ -209,10 +209,21 @@
<!-- Call Function to Cancel the leads (set as Dead) --> <!-- Call Function to Cancel the leads (set as Dead) -->
<function model="crm.lead" name="case_cancel" <function model="crm.lead" name="case_cancel"
eval="[ref('crm_case_company_partnership0'), ref('crm_case_vpoperations0'), ref('crm_case_developingwebapplications0'), ref('crm_case_webvisitor0')], {'install_mode': True}" eval="[ ref('crm_case_company_partnership0'), ref('crm_case_vpoperations0'),
ref('crm_case_developingwebapplications0'), ref('crm_case_webvisitor0')],
{'install_mode': True}"
/>
<!-- Call Function to set the leads as Unread -->
<function model="crm.lead" name="message_mark_as_unread"
eval="[ ref('crm_case_itisatelesalescampaign0'), ref('crm_case_electonicgoodsdealer0'),
ref('crm_case_itdeveloper0'), ref('crm_case_employee0')], {}"
/> />
<!-- Demo Opportunities -->
<!--
Demo Opportunities
-->
<record id="crm_case_construstazunits0" model="crm.lead"> <record id="crm_case_construstazunits0" model="crm.lead">
<field eval="60" name="probability"/> <field eval="60" name="probability"/>
<field eval="1" name="active"/> <field eval="1" name="active"/>
@ -398,7 +409,7 @@
<field name="section_id" ref="crm.section_sales_department"/> <field name="section_id" ref="crm.section_sales_department"/>
<field name="categ_id" ref="crm.categ_oppor5"/> <field name="categ_id" ref="crm.categ_oppor5"/>
<field name="stage_id" ref="crm.stage_lead5"/> <field name="stage_id" ref="crm.stage_lead5"/>
<field eval="'Need new design for my website'" name="name"/> <field eval="'Need a new design for my website'" name="name"/>
<field eval="time.strftime('%Y-05-01')" name="date_action"/> <field eval="time.strftime('%Y-05-01')" name="date_action"/>
<field eval="time.strftime('%Y-06-30')" name="date_deadline"/> <field eval="time.strftime('%Y-06-30')" name="date_deadline"/>
<field eval="'info@opensides.be'" name="email_from"/> <field eval="'info@opensides.be'" name="email_from"/>
@ -469,7 +480,7 @@
<field name="section_id" ref="crm.section_sales_department"/> <field name="section_id" ref="crm.section_sales_department"/>
<field name="categ_id" ref="crm.categ_oppor1"/> <field name="categ_id" ref="crm.categ_oppor1"/>
<field name="stage_id" ref="crm.stage_lead4"/> <field name="stage_id" ref="crm.stage_lead4"/>
<field eval="'Need customize the solution'" name="name"/> <field eval="'Need to customize the solution'" name="name"/>
<field eval="'Conf call with technical service'" name="title_action"/> <field eval="'Conf call with technical service'" name="title_action"/>
<field name="partner_name">Thymbra</field> <field name="partner_name">Thymbra</field>
<field name="street">Palermo, Capital Federal</field> <field name="street">Palermo, Capital Federal</field>
@ -522,5 +533,12 @@
<field name="stage_id" ref="crm.stage_lead1"/> <field name="stage_id" ref="crm.stage_lead1"/>
<field eval="'Need more info about your pc2'" name="name"/> <field eval="'Need more info about your pc2'" name="name"/>
</record> </record>
<!-- Call Function to set the opportunities as Unread -->
<function model="crm.lead" name="message_mark_as_unread"
eval="[ ref('crm_case_rdroundfundingunits25'), ref('crm_case_unifliege'),
ref('crm_case_ericdubois4'), ref('crm_case_abcfuelcounits0')], {}"
/>
</data> </data>
</openerp> </openerp>

View File

@ -2,6 +2,43 @@
<openerp> <openerp>
<data> <data>
<!-- Read/Unread actions -->
<record id="actions_server_crm_lead_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_crm_lead"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_crm_lead_unread" model="ir.values">
<field name="name">action_crm_lead_unread</field>
<field name="action_id" ref="actions_server_crm_lead_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_crm_lead_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_crm_lead" />
<field name="model">crm.lead</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_crm_lead_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_crm_lead"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_crm_lead_read" model="ir.values">
<field name="name">action_crm_lead_read</field>
<field name="action_id" ref="actions_server_crm_lead_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_crm_lead_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_crm_lead" />
<field name="model">crm.lead</field>
<field name="key2">client_action_multi</field>
</record>
<!-- <!--
CRM CASE STAGE CRM CASE STAGE
--> -->
@ -172,9 +209,9 @@
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_bottom"> <footer>
<field name="message_ids" widget="ThreadView"/> <field name="message_ids" widget="ThreadView"/>
</div> </footer>
</form> </form>
</field> </field>
</record> </record>
@ -185,8 +222,7 @@
<field name="model">crm.lead</field> <field name="model">crm.lead</field>
<field name="type">tree</field> <field name="type">tree</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Leads" fonts="bold:needaction_pending==True" colors="blue:state=='pending';grey:state in ('cancel', 'done')"> <tree string="Leads" fonts="bold:needaction_pending==True" colors="grey:state in ('cancel', 'done')">
<field name="needaction_pending" invisible="1"/>
<field name="date_deadline" invisible="1"/> <field name="date_deadline" invisible="1"/>
<field name="create_date" groups="base.group_no_one"/> <field name="create_date" groups="base.group_no_one"/>
<field name="name"/> <field name="name"/>
@ -202,6 +238,7 @@
<field name="referred" invisible="1"/> <field name="referred" invisible="1"/>
<field name="channel_id" invisible="1"/> <field name="channel_id" invisible="1"/>
<field name="subjects" invisible="1"/> <field name="subjects" invisible="1"/>
<field name="needaction_pending" invisible="1"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -235,6 +272,8 @@
<field name="user_email"/> <field name="user_email"/>
<field name="user_id"/> <field name="user_id"/>
<field name="partner_address_email"/> <field name="partner_address_email"/>
<field name="message_summary"/>
<field name="needaction_pending"/>
<templates> <templates>
<t t-name="lead_details"> <t t-name="lead_details">
<ul class="oe_kanban_tooltip"> <ul class="oe_kanban_tooltip">
@ -288,6 +327,8 @@
<img t-att-src="kanban_image('res.users', 'avatar', record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/> <img t-att-src="kanban_image('res.users', 'avatar', record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div> </div>
<div class="oe_kanban_footer_left"> <div class="oe_kanban_footer_left">
<t t-if="record.needaction_pending.raw_value"><span class="oe_kanban_mail_new">New</span></t>
<t t-raw="record.message_summary.raw_value"/>
</div> </div>
</div> </div>
<div class="oe_clear"></div> <div class="oe_clear"></div>
@ -313,6 +354,10 @@
<field name="type">search</field> <field name="type">search</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Search Leads"> <search string="Search Leads">
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<field name="name" string="Lead / Customer" filter_domain="['|','|',('partner_name','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/> <field name="name" string="Lead / Customer" filter_domain="['|','|',('partner_name','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/>
<!-- subjects is not set as store=True so, it is placed outside filter_domain--> <!-- subjects is not set as store=True so, it is placed outside filter_domain-->
<field name="subjects"/> <field name="subjects"/>
@ -327,10 +372,6 @@
string="Open" string="Open"
name="open" name="open"
domain="[('state','=','open')]"/> domain="[('state','=','open')]"/>
<filter icon="terp-gtk-media-pause"
string="Pending"
name="pending"
domain="[('state','=','pending')]"/>
<filter string="Unassigned Leads" <filter string="Unassigned Leads"
icon="terp-personal-" icon="terp-personal-"
domain="[('user_id','=', False)]" domain="[('user_id','=', False)]"
@ -424,7 +465,6 @@
<div class="oe_title"> <div class="oe_title">
<label for="name" class="oe_edit_only"/> <label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1> <h1><field name="name"/></h1>
<label for="planned_revenue" class="oe_edit_only"/> <label for="planned_revenue" class="oe_edit_only"/>
<h2> <h2>
<field name="planned_revenue" class="oe_inline"/> <field name="planned_revenue" class="oe_inline"/>
@ -535,8 +575,7 @@
<field name="model">crm.lead</field> <field name="model">crm.lead</field>
<field name="type">tree</field> <field name="type">tree</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Opportunities" fonts="bold:needaction_pending==True" colors="blue:state=='pending' and not(date_deadline and (date_deadline &lt; current_date));gray:state in ('cancel', 'done');red:date_deadline and (date_deadline &lt; current_date)"> <tree string="Opportunities" fonts="bold:needaction_pending==True" colors="gray:state in ('cancel', 'done');red:date_deadline and (date_deadline &lt; current_date)">
<field name="needaction_pending" invisible="1"/>
<field name="date_deadline" invisible="1"/> <field name="date_deadline" invisible="1"/>
<field name="create_date" groups="base.group_no_one"/> <field name="create_date" groups="base.group_no_one"/>
<field name="name" string="Opportunity"/> <field name="name" string="Opportunity"/>
@ -555,6 +594,7 @@
<field name="priority" invisible="1"/> <field name="priority" invisible="1"/>
<field name="categ_id" invisible="1"/> <field name="categ_id" invisible="1"/>
<field name="state" groups="base.group_no_one"/> <field name="state" groups="base.group_no_one"/>
<field name="needaction_pending" invisible="1"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -567,21 +607,21 @@
<field name="type">search</field> <field name="type">search</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Search Opportunities"> <search string="Search Opportunities">
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<field name="name" string="Opportunity / Customer" <field name="name" string="Opportunity / Customer"
filter_domain="['|','|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self),('name', 'ilike', self)]"/> filter_domain="['|','|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self),('name', 'ilike', self)]"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>
<filter icon="terp-check" <filter icon="terp-check"
string="New" help="New Opportunities" string="New" help="New Opportunities"
name="new" name="new"
domain="[('state','=','draft')]"/> domain="[('state','=','draft')]"/>
<filter icon="terp-camera_test" <filter icon="terp-camera_test"
string="Open" help="Open Opportunities" string="Open" help="Open Opportunities"
name="open" name="open"
domain="[('state','=','open')]"/> domain="[('state','=','open')]"/>
<filter icon="terp-gtk-media-pause"
string="Pending" help="Pending Opportunities"
name="pending"
domain="[('state','=','pending')]"/>
<filter string="Unassigned Opportunities" <filter string="Unassigned Opportunities"
icon="terp-personal-" icon="terp-personal-"
domain="[('user_id','=', False)]" domain="[('user_id','=', False)]"

View File

@ -76,13 +76,6 @@ class crm_meeting(base_state, osv.Model):
self.create_send_note(cr, uid, [obj_id], context=context) self.create_send_note(cr, uid, [obj_id], context=context)
return obj_id return obj_id
def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, [])
for obj in self.browse(cr, uid, ids, context=context):
if (obj.state == 'draft' and obj.user_id):
result[obj.id] = [obj.user_id.id]
return result
def case_open(self, cr, uid, ids, context=None): def case_open(self, cr, uid, ids, context=None):
""" Confirms meeting """ """ Confirms meeting """
res = super(crm_meeting, self).case_open(cr, uid, ids, context) res = super(crm_meeting, self).case_open(cr, uid, ids, context)

View File

@ -2,6 +2,43 @@
<openerp> <openerp>
<data> <data>
<!-- Read/Unread actions -->
<record id="actions_server_crm_meeting_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_crm_meeting"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_crm_meeting_unread" model="ir.values">
<field name="name">action_crm_meeting_unread</field>
<field name="action_id" ref="actions_server_crm_meeting_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_crm_meeting_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_crm_meeting" />
<field name="model">crm.meeting</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_crm_meeting_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_crm_meeting"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_crm_meeting_read" model="ir.values">
<field name="name">action_crm_meeting_read</field>
<field name="action_id" ref="actions_server_crm_meeting_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_crm_meeting_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_crm_meeting" />
<field name="model">crm.meeting</field>
<field name="key2">client_action_multi</field>
</record>
<!-- CRM Meetings Categories Form View --> <!-- CRM Meetings Categories Form View -->
<record id="crm_meeting_categ_action" model="ir.actions.act_window"> <record id="crm_meeting_categ_action" model="ir.actions.act_window">
@ -47,24 +84,26 @@
<h1> <h1>
<field name="name"/> <field name="name"/>
</h1> </h1>
<h2>
At <field name="location" class="oe_inline" />
</h2>
</div> </div>
<h2> <group>
<label for="duration" string="Duration" /> <h2>
<field name="duration" widget="float_time" <label for="date" string="Starting at"/>
on_change="onchange_dates(date,duration,False,allday)" <field name="date" required="1" class="oe_inline"/>
class="oe_inline"/> from <label string="in" class="oe_inline" attrs="{'invisible': [('location', '=', False)]}"/> <field name="location" placeholder="Specify the location here" class="oe_inline"/>
<field name="date" </h2>
string="Start Date" </group>
required="1" <group>
class="oe_edit_only oe_inline"/> to <h2>
<field name="date_deadline" <label for="duration" string="Duration" />
string="End Date" required="1" <field name="duration" widget="float_time"
on_change="onchange_dates(date,False,date_deadline)" on_change="onchange_dates(date,duration,False,allday)"
class="oe_inline"/> class="oe_inline"/> (
</h2> <field name="date_deadline"
string="End Date" required="1"
on_change="onchange_dates(date,False,date_deadline)"
class="oe_inline"/> )
</h2>
</group>
<group colspan="4" col="4"> <group colspan="4" col="4">
<group colspan="2"> <group colspan="2">
<field name="user_id" /> <field name="user_id" />
@ -234,7 +273,6 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Meetings" fonts="bold:needaction_pending==True" <tree string="Meetings" fonts="bold:needaction_pending==True"
colors="red:state=='open';black:state in ('draft', 'cancel','done','pending')"> colors="red:state=='open';black:state in ('draft', 'cancel','done','pending')">
<field name="needaction_pending" invisible="1"/>
<field name="name" string="Subject" /> <field name="name" string="Subject" />
<field name="user_id"/> <field name="user_id"/>
<field name="date"/> <field name="date"/>
@ -243,6 +281,7 @@
<field name="partner_id" string="Partner" /> <field name="partner_id" string="Partner" />
<field name="location" /> <field name="location" />
<field name="categ_id"/> <field name="categ_id"/>
<field name="needaction_pending" invisible="1"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -284,6 +323,11 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Search Meetings"> <search string="Search Meetings">
<group> <group>
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<separator orientation="vertical"/>
<field name="name" string="Meeting / Partner" <field name="name" string="Meeting / Partner"
filter_domain="['|',('name','ilike',self),('partner_id','ilike', self)]"/> filter_domain="['|',('name','ilike',self),('partner_id','ilike', self)]"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>

View File

@ -288,14 +288,6 @@ class crm_phonecall(base_state, osv.osv):
# ---------------------------------------- # ----------------------------------------
# OpenChatter # OpenChatter
# ---------------------------------------- # ----------------------------------------
def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids)
for obj in self.browse(cr, uid, ids, context=context):
result[obj.id] = []
if (obj.state == 'draft' and obj.user_id):
result[obj.id] = [obj.user_id.id]
return result
def case_get_note_msg_prefix(self, cr, uid, id, context=None): def case_get_note_msg_prefix(self, cr, uid, id, context=None):
return 'Phonecall' return 'Phonecall'

View File

@ -2,8 +2,44 @@
<openerp> <openerp>
<data> <data>
<!-- Phonecall Categories Form View --> <!-- Read/Unread actions -->
<record id="actions_server_crm_phonecall_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_crm_phonecall"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_crm_phonecall_unread" model="ir.values">
<field name="name">action_crm_phonecall_unread</field>
<field name="action_id" ref="actions_server_crm_phonecall_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_crm_phonecall_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_crm_phonecall" />
<field name="model">crm.phonecall</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_crm_phonecall_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_crm_phonecall"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_crm_phonecall_read" model="ir.values">
<field name="name">action_crm_phonecall_read</field>
<field name="action_id" ref="actions_server_crm_phonecall_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_crm_phonecall_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_crm_phonecall" />
<field name="model">crm.phonecall</field>
<field name="key2">client_action_multi</field>
</record>
<!-- Phonecall Categories Form View -->
<record id="crm_phonecall_categ_action" model="ir.actions.act_window"> <record id="crm_phonecall_categ_action" model="ir.actions.act_window">
<field name="name">Phonecall Categories</field> <field name="name">Phonecall Categories</field>
<field name="res_model">crm.case.categ</field> <field name="res_model">crm.case.categ</field>
@ -34,6 +70,7 @@
<field name="categ_id" invisible="1"/> <field name="categ_id" invisible="1"/>
<field name="create_date" invisible="1"/> <field name="create_date" invisible="1"/>
<field name="opportunity_id" invisible="1"/> <field name="opportunity_id" invisible="1"/>
<field name="needaction_pending" invisible="1"/>
<button string="Convert to Opportunity" <button string="Convert to Opportunity"
name="%(phonecall2opportunity_act)d" name="%(phonecall2opportunity_act)d"
states="open,pending" states="open,pending"
@ -123,7 +160,6 @@
<field name="type">tree</field> <field name="type">tree</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Phone Calls" fonts="bold:needaction_pending==True" editable="top"> <tree string="Phone Calls" fonts="bold:needaction_pending==True" editable="top">
<field name="needaction_pending" invisible="1"/>
<field name="date"/> <field name="date"/>
<field name="name"/> <field name="name"/>
<field name="partner_id" <field name="partner_id"
@ -138,6 +174,7 @@
<field name="state" invisible="1"/> <field name="state" invisible="1"/>
<field name="create_date" invisible="1"/> <field name="create_date" invisible="1"/>
<field name="opportunity_id" invisible="1"/> <field name="opportunity_id" invisible="1"/>
<field name="needaction_pending" invisible="1"/>
<button string="Schedule Other Call" <button string="Schedule Other Call"
icon="terp-call-start" icon="terp-call-start"
name="%(phonecall_to_phonecall_act)d" name="%(phonecall_to_phonecall_act)d"
@ -154,7 +191,7 @@
</field> </field>
</record> </record>
<!-- Phonecalls Calendar View --> <!-- Phonecalls Calendar View -->
<record model="ir.ui.view" id="crm_case_phone_calendar_view"> <record model="ir.ui.view" id="crm_case_phone_calendar_view">
<field name="name">CRM - Phone Calls Calendar</field> <field name="name">CRM - Phone Calls Calendar</field>
@ -169,14 +206,18 @@
</field> </field>
</record> </record>
<!-- Phonecalls Search View --> <!-- Phonecalls Search View -->
<record id="view_crm_case_phonecalls_filter" model="ir.ui.view"> <record id="view_crm_case_phonecalls_filter" model="ir.ui.view">
<field name="name">CRM - Phone Calls Search</field> <field name="name">CRM - Phone Calls Search</field>
<field name="model">crm.phonecall</field> <field name="model">crm.phonecall</field>
<field name="type">search</field> <field name="type">search</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Search Phonecalls"> <search string="Search Phonecalls">
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<separator orientation="vertical"/>
<field name="name" string="Phonecalls"/> <field name="name" string="Phonecalls"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>
<field name="date"/> <field name="date"/>

View File

@ -81,11 +81,16 @@
<notebook colspan="4"> <notebook colspan="4">
<page string="Sales Team"> <page string="Sales Team">
<group col="4"> <group col="4">
<field name="reply_to"/> <group>
<field name="allow_unlink"/> <field name="reply_to"/>
<field name="change_responsible"/> </group>
<field name="member_ids"/> <group>
<field name="change_responsible"/>
<field name="allow_unlink"/>
</group>
</group> </group>
<separator string="Team Members"/>
<field name="member_ids"/>
</page> </page>
<page string="Stages"> <page string="Stages">
<separator string="Select Stages for this Sales Team"/> <separator string="Select Stages for this Sales Team"/>

View File

@ -99,10 +99,9 @@
context="{'default_partner_id': [active_id], 'default_duration': 4.0}"/> context="{'default_partner_id': [active_id], 'default_duration': 4.0}"/>
<button type="action" string="Schedule a Call" <button type="action" string="Schedule a Call"
name="%(crm.crm_case_categ_phone_create_partner)d" name="%(crm.crm_case_categ_phone_create_partner)d"
context="{'search_default_partner_id': [active_id], 'default_duration': 1.0}" /> context="{'search_default_partner_id': [active_id], 'default_duration': 1.0, 'default_partner_id': active_id}" />
<button type="action" string="Opportunities" <button type="action" string="Opportunities"
context="{'search_default_partner_id': [active_id]}" name="%(crm.crm_case_category_act_oppor11)d" context="{'search_default_partner_id': [active_id]}"/>
name="%(crm.action_view_crm_partner2opportunity)d" />
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@ -17,15 +17,12 @@
<button string="Cancel" class="oe_link" special="cancel" /> <button string="Cancel" class="oe_link" special="cancel" />
</header> </header>
<group col="4"> <group col="4">
<separator string="Schedule/Log a Call" colspan="4"/>
<field name="action"/> <field name="action"/>
<separator string="Call Details" colspan="4"/>
<field name="name"/> <field name="name"/>
<field name="date" string="Planned Date" attrs="{'invisible': [('action','=','log')]}"/> <field name="date" string="Planned Date" attrs="{'invisible': [('action','=','log')]}"/>
<field name="partner_id" readonly="True"/> <field name="partner_id" readonly="True"/>
<field name="user_id" /> <field name="user_id" />
<field name="section_id"/> <field name="section_id"/>
<field name="categ_id" string="Type" widget="selection" domain="[('object_id.model', '=', 'crm.phonecall')]"/>
</group> </group>
</form> </form>
</field> </field>

View File

@ -2,7 +2,7 @@
<openerp> <openerp>
<data> <data>
<record id="action_caldav_browse" model="ir.actions.act_window"> <record id="action_caldav_browse" model="ir.actions.act_window">
<field name="name">Caldav Browse</field> <field name="name">Synchronize Your Meetings</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
<field name="res_model">user.preference</field> <field name="res_model">user.preference</field>
<field name="view_id" ref="caldav.host_prefernce_form"/> <field name="view_id" ref="caldav.host_prefernce_form"/>

View File

@ -183,59 +183,53 @@ class crm_claim(base_stage, osv.osv):
} }
address = self.pool.get('res.partner').browse(cr, uid, part) address = self.pool.get('res.partner').browse(cr, uid, part)
return {'value': {'email_from': address.email, 'partner_phone': address.phone}} return {'value': {'email_from': address.email, 'partner_phone': address.phone}}
def message_new(self, cr, uid, msg, custom_values=None, context=None):
"""Automatically called when new email message arrives"""
res_id = super(crm_claim,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
subject = msg.get('subject')
body = msg.get('body_text')
msg_from = msg.get('from')
priority = msg.get('priority')
vals = {
'name': subject,
'email_from': msg_from,
'email_cc': msg.get('cc'),
'description': body,
'user_id': False,
}
if priority:
vals['priority'] = priority
vals.update(self.message_partner_by_email(cr, uid, msg.get('from', False)))
self.write(cr, uid, [res_id], vals, context=context)
return res_id
def message_update(self, cr, uid, ids, msg, vals={}, default_act='pending', context=None): # -------------------------------------------------------
# Mail gateway
# -------------------------------------------------------
def message_new(self, cr, uid, msg, custom_values=None, context=None):
""" Overrides mail_thread message_new that is called by the mailgateway
through message_process.
This override updates the document according to the email.
"""
if custom_values is None: custom_values = {}
custom_values.update({
'name': msg.get('subject') or _("No Subject"),
'description': msg.get('body_text'),
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
})
if msg.get('priority'):
custom_values['priority'] = msg.get('priority')
custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from'), context=context))
return super(crm_claim,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
""" Overrides mail_thread message_update that is called by the mailgateway
through message_process.
This method updates the document according to the email.
"""
if isinstance(ids, (str, int, long)): if isinstance(ids, (str, int, long)):
ids = [ids] ids = [ids]
if update_vals is None: update_vals = {}
res_id = super(crm_claim,self).message_update(cr, uid, ids, msg, context=context)
if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES): if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
vals['priority'] = msg.get('priority') update_vals['priority'] = msg.get('priority')
maps = { maps = {
'cost':'planned_cost', 'cost':'planned_cost',
'revenue': 'planned_revenue', 'revenue': 'planned_revenue',
'probability':'probability' 'probability':'probability'
} }
vls = {}
for line in msg['body_text'].split('\n'): for line in msg['body_text'].split('\n'):
line = line.strip() line = line.strip()
res = tools.misc.command_re.match(line) res = tools.misc.command_re.match(line)
if res and maps.get(res.group(1).lower()): if res and maps.get(res.group(1).lower()):
key = maps.get(res.group(1).lower()) key = maps.get(res.group(1).lower())
vls[key] = res.group(2).lower() update_vals[key] = res.group(2).lower()
vals.update(vls)
# Unfortunately the API is based on lists return super(crm_claim,self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context)
# but we want to update the state based on the
# previous state, so we have to loop:
for case in self.browse(cr, uid, ids, context=context):
values = dict(vals)
if case.state in CRM_CLAIM_PENDING_STATES:
values.update(state=crm.AVAILABLE_STATES[1][0]) #re-open
res = self.write(cr, uid, [case.id], values, context=context)
return res
# --------------------------------------------------- # ---------------------------------------------------
# OpenChatter methods and notifications # OpenChatter methods and notifications

View File

@ -127,21 +127,26 @@ class crm_fundraising(base_stage, osv.osv):
self.create_send_note(cr, uid, [obj_id], context=context) self.create_send_note(cr, uid, [obj_id], context=context)
return obj_id return obj_id
# -------------------------------------------------------
# Mail gateway
# -------------------------------------------------------
def message_new(self, cr, uid, msg, custom_values=None, context=None): def message_new(self, cr, uid, msg, custom_values=None, context=None):
"""Automatically called when new email message arrives""" """ Overrides mail_thread message_new that is called by the mailgateway
res_id = super(crm_fundraising,self).message_new(cr, uid, msg, custom_values=custom_values, context=context) through message_process.
vals = { This override also updates the document according to the email.
'name': msg.get('subject'), """
if custom_values is None: custom_values = {}
custom_values.update({
'name': msg.get('subject') or _("No Subject"),
'description': msg.get('body_text'),
'email_from': msg.get('from'), 'email_from': msg.get('from'),
'email_cc': msg.get('cc'), 'email_cc': msg.get('cc'),
'description': msg.get('body_text'), })
} if msg.get('priority'):
priority = msg.get('priority') custom_values['priority'] = priority
if priority: custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from'), context=context))
vals['priority'] = priority return super(crm_fundraising,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
vals.update(self.message_partner_by_email(cr, uid, msg.get('from')))
self.write(cr, uid, [res_id], vals, context=context)
return res_id
# --------------------------------------------------- # ---------------------------------------------------
# OpenChatter methods and notifications # OpenChatter methods and notifications

View File

@ -72,38 +72,48 @@
<field name="state" widget="statusbar" nolabel="1" statusbar_visible="draft,open,done" statusbar_colors='{"pending":"blue"}'/> <field name="state" widget="statusbar" nolabel="1" statusbar_visible="draft,open,done" statusbar_colors='{"pending":"blue"}'/>
</header> </header>
<sheet string="Funds Form"> <sheet string="Funds Form">
<group col="4"> <label for="name" class="oe_edit_only"/>
<field name="name" string="Name"/> <h1>
<field name="section_id" colspan="1" widget="selection"/> <field name="name"/>
<field name="user_id" string="Responsible"/> </h1>
<field name="date"/> <label for="categ_id" class="oe_edit_only"/>
<field name="categ_id" widget="selection" domain="[('object_id.model', '=', 'crm.fundraising')]"/> <h2>
<field name="type_id" string="Payment Mode" widget="selection"/> <field name="categ_id" widget="selection" domain="[('object_id.model', '=', 'crm.fundraising')]" class="oe_inline"/>
</h2>
<group>
<group>
<field name="user_id" string="Responsible"/>
<field name="section_id" colspan="1" widget="selection"/>
</group>
<group>
<field name="date"/>
<field name="type_id" string="Payment Mode" widget="selection"/>
<field name="priority" string="Priority"/>
</group>
</group> </group>
<notebook> <notebook>
<page string="Funds"> <page string="Funds">
<group> <group>
<group string="Communication"> <group>
<field name="partner_id" <field name="partner_id"
on_change="onchange_partner_id(partner_id, email_from)" on_change="onchange_partner_id(partner_id, email_from)"
/> />
<field name="email_from"/> <field name="email_from"/>
</group> </group>
<group string="Estimates"> <group>
<field name="planned_cost"/> <field name="planned_cost"/>
<field name="planned_revenue"/> <field name="planned_revenue"/>
<field name="probability"/> <field name="probability"/>
</group> </group>
</group> </group>
<separator colspan="4" string="Notes"/> <separator colspan="4" string="Notes"/>
<field name="description"/> <field name="description" placeholder="Add a note..."/>
</page> </page>
<page string="Extra Info"> <page string="Extra Info">
<group> <group>
<group string="Misc"> <group string="Misc">
<field name="active"/> <field name="active"/>
<field name="id"/> <field name="id"/>
<field name="priority" string="Priority"/>
</group> </group>
<group groups="base.group_no_one" string="Dates"> <group groups="base.group_no_one" string="Dates">
<field name="create_date"/> <field name="create_date"/>

View File

@ -95,55 +95,51 @@ class crm_helpdesk(base_state, osv.osv):
self.create_send_note(cr, uid, [obj_id], context=context) self.create_send_note(cr, uid, [obj_id], context=context)
return obj_id return obj_id
def message_new(self, cr, uid, msg_dict, custom_values=None, context=None): # -------------------------------------------------------
"""Automatically called when new email message arrives""" # Mail gateway
res_id = super(crm_helpdesk,self).message_new(cr, uid, msg_dict, custom_values=custom_values, context=context) # -------------------------------------------------------
subject = msg_dict.get('subject') or _("No Subject")
body = msg_dict.get('body_text')
msg_from = msg_dict.get('from')
vals = {
'name': subject,
'email_from': msg_from,
'email_cc': msg_dict.get('cc'),
'description': body,
'user_id': False,
}
vals.update(self.message_partner_by_email(cr, uid, msg_from))
self.write(cr, uid, [res_id], vals, context)
return res_id
def message_update(self, cr, uid, ids, msg, vals={}, default_act='pending', context=None): def message_new(self, cr, uid, msg, custom_values=None, context=None):
""" Overrides mail_thread message_new that is called by the mailgateway
through message_process.
This override updates the document according to the email.
"""
if custom_values is None: custom_values = {}
custom_values.update({
'name': msg.get('subject') or _("No Subject"),
'description': msg.get('body_text'),
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
'user_id': False,
})
custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from'), context=context))
return super(crm_helpdesk,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
""" Overrides mail_thread message_update that is called by the mailgateway
through message_process.
This method updates the document according to the email.
"""
if isinstance(ids, (str, int, long)): if isinstance(ids, (str, int, long)):
ids = [ids] ids = [ids]
if update_vals is None: update_vals = {}
super(crm_helpdesk,self).message_update(cr, uid, ids, msg, context=context)
if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES): if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
vals['priority'] = msg.get('priority') update_vals['priority'] = msg.get('priority')
maps = { maps = {
'cost':'planned_cost', 'cost':'planned_cost',
'revenue': 'planned_revenue', 'revenue': 'planned_revenue',
'probability':'probability' 'probability':'probability'
} }
vls = {}
for line in msg['body_text'].split('\n'): for line in msg['body_text'].split('\n'):
line = line.strip() line = line.strip()
res = tools.misc.command_re.match(line) res = tools.misc.command_re.match(line)
if res and maps.get(res.group(1).lower()): if res and maps.get(res.group(1).lower()):
key = maps.get(res.group(1).lower()) key = maps.get(res.group(1).lower())
vls[key] = res.group(2).lower() update_vals[key] = res.group(2).lower()
vals.update(vls)
# Unfortunately the API is based on lists return super(crm_helpdesk,self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context)
# but we want to update the state based on the
# previous state, so we have to loop:
for case in self.browse(cr, uid, ids, context=context):
values = dict(vals)
if case.state in CRM_HELPDESK_STATES:
values.update(state=crm.AVAILABLE_STATES[1][0]) #re-open
res = self.write(cr, uid, [case.id], values, context=context)
return res
# ****************************** # ******************************
# OpenChatter # OpenChatter

View File

@ -271,13 +271,6 @@ class event_event(osv.osv):
# OpenChatter methods and notifications # OpenChatter methods and notifications
# ---------------------------------------- # ----------------------------------------
def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, [])
for obj in self.browse(cr, uid, ids, context=context):
if obj.state == 'draft' and obj.user_id:
result[obj.id] = [obj.user_id.id]
return result
def create_send_note(self, cr, uid, ids, context=None): def create_send_note(self, cr, uid, ids, context=None):
message = _("Event has been <b>created</b>.") message = _("Event has been <b>created</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context) self.message_append_note(cr, uid, ids, body=message, context=context)
@ -451,13 +444,6 @@ class event_registration(osv.osv):
# OpenChatter methods and notifications # OpenChatter methods and notifications
# ---------------------------------------- # ----------------------------------------
def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, [])
for obj in self.browse(cr, uid, ids, context=context):
if obj.state == 'draft' and obj.user_id:
result[obj.id] = [obj.user_id.id]
return result
def create_send_note(self, cr, uid, ids, context=None): def create_send_note(self, cr, uid, ids, context=None):
message = _("Registration has been <b>created</b>.") message = _("Registration has been <b>created</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context) self.message_append_note(cr, uid, ids, body=message, context=context)

View File

@ -47,6 +47,43 @@
<!-- Events Organisation/CONFIGURATION/EVENTS --> <!-- Events Organisation/CONFIGURATION/EVENTS -->
<!-- Event Read/Unread actions -->
<record id="actions_server_event_event_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_event_event"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_event_event_unread" model="ir.values">
<field name="name">action_event_event_unread</field>
<field name="action_id" ref="actions_server_event_event_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_event_event_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_event_event" />
<field name="model">event.event</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_event_event_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_event_event"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_event_event_read" model="ir.values">
<field name="name">action_event_event_read</field>
<field name="action_id" ref="actions_server_event_event_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_event_event_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_event_event" />
<field name="model">event.event</field>
<field name="key2">client_action_multi</field>
</record>
<record model="ir.ui.view" id="view_event_form"> <record model="ir.ui.view" id="view_event_form">
<field name="name">Events</field> <field name="name">Events</field>
<field name="model">event.event</field> <field name="model">event.event</field>
@ -144,7 +181,7 @@
<field name="model">event.event</field> <field name="model">event.event</field>
<field name="type">tree</field> <field name="type">tree</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Events" colors="red:(register_min and register_min&gt;register_current) or (register_max and register_max&lt;register_current);grey:state=='cancel'"> <tree string="Events" fonts="bold:needaction_pending==True" colors="red:(register_min and register_min&gt;register_current) or (register_max and register_max&lt;register_current);grey:state=='cancel'">
<field name="name" string="Name"/> <field name="name" string="Name"/>
<field name="type"/> <field name="type"/>
<field name="date_begin"/> <field name="date_begin"/>
@ -155,6 +192,7 @@
<field name="main_speaker_id" groups="base.extended"/> <field name="main_speaker_id" groups="base.extended"/>
<field name="user_id"/> <field name="user_id"/>
<field name="state"/> <field name="state"/>
<field name="needaction_pending" invisible="1"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -264,6 +302,11 @@
<field name="type">search</field> <field name="type">search</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Events"> <search string="Events">
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<separator orientation="vertical"/>
<group> <group>
<field name="name" string="Events"/> <field name="name" string="Events"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>
@ -330,12 +373,49 @@
<!-- EVENTS/REGISTRATIONS/EVENTS --> <!-- EVENTS/REGISTRATIONS/EVENTS -->
<!-- Registration Read/Unread actions -->
<record id="actions_server_event_registration_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_event_registration"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_event_registration_unread" model="ir.values">
<field name="name">action_event_registration_unread</field>
<field name="action_id" ref="actions_server_event_registration_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_event_registration_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_event_registration" />
<field name="model">event.registration</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_event_registration_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_event_registration"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_event_registration_read" model="ir.values">
<field name="name">action_event_registration_read</field>
<field name="action_id" ref="actions_server_event_registration_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_event_registration_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_event_registration" />
<field name="model">event.registration</field>
<field name="key2">client_action_multi</field>
</record>
<record model="ir.ui.view" id="view_event_registration_tree"> <record model="ir.ui.view" id="view_event_registration_tree">
<field name="name">event.registration.tree</field> <field name="name">event.registration.tree</field>
<field name="model">event.registration</field> <field name="model">event.registration</field>
<field name="type">tree</field> <field name="type">tree</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Registration" > <tree string="Registration" fonts="bold:needaction_pending==True">
<field name="create_date"/> <field name="create_date"/>
<field name="partner_id"/> <field name="partner_id"/>
<field name="name"/> <field name="name"/>
@ -345,6 +425,7 @@
<field name="user_id"/> <field name="user_id"/>
<field name="origin"/> <field name="origin"/>
<field name="state"/> <field name="state"/>
<field name="needaction_pending" invisible="1"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -449,6 +530,11 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Event Registration"> <search string="Event Registration">
<group> <group>
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<separator orientation="vertical"/>
<field name="name" string="Participant" <field name="name" string="Participant"
filter_domain="['|','|','|',('name','ilike',self),('partner_id','ilike',self),('email','ilike',self),('origin','ilike',self)]"/> filter_domain="['|','|','|',('name','ilike',self),('partner_id','ilike',self),('email','ilike',self),('origin','ilike',self)]"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>

View File

@ -151,7 +151,7 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS
connection = server.connect() connection = server.connect()
server.write({'state':'done'}) server.write({'state':'done'})
except Exception, e: except Exception, e:
logger.exception("Failed to connect to %s server %s", server.type, server.name) _logger.exception("Failed to connect to %s server %s", server.type, server.name)
raise osv.except_osv(_("Connection test failed!"), _("Here is what we got instead:\n %s") % tools.ustr(e)) raise osv.except_osv(_("Connection test failed!"), _("Here is what we got instead:\n %s") % tools.ustr(e))
finally: finally:
try: try:
@ -177,7 +177,7 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS
mail_thread = self.pool.get('mail.thread') mail_thread = self.pool.get('mail.thread')
action_pool = self.pool.get('ir.actions.server') action_pool = self.pool.get('ir.actions.server')
for server in self.browse(cr, uid, ids, context=context): for server in self.browse(cr, uid, ids, context=context):
logger.info('start checking for new emails on %s server %s', server.type, server.name) _logger.info('start checking for new emails on %s server %s', server.type, server.name)
context.update({'fetchmail_server_id': server.id, 'server_type': server.type}) context.update({'fetchmail_server_id': server.id, 'server_type': server.type})
count = 0 count = 0
imap_server = False imap_server = False
@ -198,9 +198,9 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS
imap_server.store(num, '+FLAGS', '\\Seen') imap_server.store(num, '+FLAGS', '\\Seen')
cr.commit() cr.commit()
count += 1 count += 1
logger.info("fetched/processed %s email(s) on %s server %s", count, server.type, server.name) _logger.info("fetched/processed %s email(s) on %s server %s", count, server.type, server.name)
except Exception, e: except Exception, e:
logger.exception("Failed to fetch mail from %s server %s", server.type, server.name) _logger.exception("Failed to fetch mail from %s server %s", server.type, server.name)
finally: finally:
if imap_server: if imap_server:
imap_server.close() imap_server.close()
@ -222,9 +222,9 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS
action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id]}) action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id]})
pop_server.dele(num) pop_server.dele(num)
cr.commit() cr.commit()
logger.info("fetched/processed %s email(s) on %s server %s", numMsgs, server.type, server.name) _logger.info("fetched/processed %s email(s) on %s server %s", numMsgs, server.type, server.name)
except Exception, e: except Exception, e:
logger.exception("Failed to fetch mail from %s server %s", server.type, server.name) _logger.exception("Failed to fetch mail from %s server %s", server.type, server.name)
finally: finally:
if pop_server: if pop_server:
pop_server.quit() pop_server.quit()

View File

@ -359,7 +359,7 @@ class hr_holidays(osv.osv):
# ----------------------------- # -----------------------------
def get_needaction_user_ids(self, cr, uid, ids, context=None): def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, []) result = super(hr_holidays, self).get_needaction_user_ids(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if obj.state == 'confirm' and obj.employee_id.parent_id: if obj.state == 'confirm' and obj.employee_id.parent_id:
result[obj.id] = [obj.employee_id.parent_id.user_id.id] result[obj.id] = [obj.employee_id.parent_id.user_id.id]
@ -371,14 +371,16 @@ class hr_holidays(osv.osv):
hr_manager_group = self.pool.get('res.groups').read(cr, uid, [obj_id], ['users'], context=context)[0] hr_manager_group = self.pool.get('res.groups').read(cr, uid, [obj_id], ['users'], context=context)[0]
result[obj.id] = hr_manager_group['users'] result[obj.id] = hr_manager_group['users']
return result return result
def message_get_subscribers(self, cr, uid, ids, context=None): def message_get_subscribers(self, cr, uid, ids, context=None):
sub_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context); """ Override to add employee and its manager. """
# add the employee and its manager if specified to the subscribed users user_ids = super(hr_holidays, self).message_get_subscribers(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if obj.employee_id.parent_id: if obj.user_id and not obj.user_id.id in user_ids:
sub_ids.append(obj.employee_id.parent_id.user_id.id) user_ids.append(obj.user_id.id)
return self.pool.get('res.users').read(cr, uid, sub_ids, context=context) if obj.employee_id.parent_id and not obj.employee_id.parent_id.user_id.id in user_ids:
user_ids.append(obj.employee_id.parent_id.user_id.id)
return user_ids
def create_notificate(self, cr, uid, ids, context=None): def create_notificate(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):

View File

@ -1,6 +1,43 @@
<openerp> <openerp>
<data> <data>
<!-- Hr holidays Read/Unread actions -->
<record id="actions_server_holidays_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_hr_holidays"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_holidays_unread" model="ir.values">
<field name="name">action_holidays_unread</field>
<field name="action_id" ref="actions_server_holidays_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_holidays_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_hr_holidays" />
<field name="model">hr.holidays</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_holidays_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_hr_holidays"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_holidays_read" model="ir.values">
<field name="name">action_holidays_read</field>
<field name="action_id" ref="actions_server_holidays_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_holidays_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_hr_holidays" />
<field name="model">hr.holidays</field>
<field name="key2">client_action_multi</field>
</record>
<record id="view_hr_holidays_filter" model="ir.ui.view"> <record id="view_hr_holidays_filter" model="ir.ui.view">
<field name="name">hr.holidays.filter</field> <field name="name">hr.holidays.filter</field>
<field name="model">hr.holidays</field> <field name="model">hr.holidays</field>
@ -10,6 +47,11 @@
<group> <group>
<field name="date_from"/> <field name="date_from"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<separator orientation="vertical"/>
<filter string="My Leaves" icon="terp-personal" name="my_leaves" domain="[('employee_id.user_id','=', uid)]" help="My Leaves"/> <filter string="My Leaves" icon="terp-personal" name="my_leaves" domain="[('employee_id.user_id','=', uid)]" help="My Leaves"/>
<filter string="My Department Leaves" icon="terp-personal+" help="My Department Leaves" domain="[('department_id.manager_id','=',uid)]"/> <filter string="My Department Leaves" icon="terp-personal+" help="My Department Leaves" domain="[('department_id.manager_id','=',uid)]"/>
<filter icon="terp-check" domain="[('state','=','draft')]" string="To Confirm"/> <filter icon="terp-check" domain="[('state','=','draft')]" string="To Confirm"/>

View File

@ -357,54 +357,53 @@ class hr_applicant(base_stage, osv.Model):
return value return value
def message_new(self, cr, uid, msg, custom_values=None, context=None): def message_new(self, cr, uid, msg, custom_values=None, context=None):
"""Automatically called when new email message arrives""" """ Overrides mail_thread message_new that is called by the mailgateway
res_id = super(hr_applicant,self).message_new(cr, uid, msg, custom_values=custom_values, context=context) through message_process.
subject = msg.get('subject') or _("No Subject") This override updates the document according to the email.
body = msg.get('body_text') """
msg_from = msg.get('from') if custom_values is None: custom_values = {}
priority = msg.get('priority') custom_values.update({
vals = { 'name': msg.get('subject') or _("No Subject"),
'name': subject, 'description': msg.get('body_text'),
'email_from': msg_from, 'email_from': msg.get('from'),
'email_cc': msg.get('cc'), 'email_cc': msg.get('cc'),
'description': body,
'user_id': False, 'user_id': False,
} })
if priority: if msg.get('priority'):
vals['priority'] = priority custom_values['priority'] = msg.get('priority')
vals.update(self.message_partner_by_email(cr, uid, msg.get('from', False))) custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from', False), context=context))
self.write(cr, uid, [res_id], vals, context) return super(hr_applicant,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
return res_id
def message_update(self, cr, uid, ids, msg, vals=None, default_act='pending', context=None): def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
""" Override mail_thread message_update that is called by the mailgateway
through message_process.
This method updates the document according to the email.
"""
if isinstance(ids, (str, int, long)): if isinstance(ids, (str, int, long)):
ids = [ids] ids = [ids]
if vals is None: if update_vals is None: vals = {}
vals = {}
msg_from = msg['from'] update_vals.update({
vals.update({ 'description': msg.get('body'),
'description': msg['body_text'] 'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
}) })
if msg.get('priority', False): if msg.get('priority'):
vals['priority'] = msg.get('priority') update_vals['priority'] = msg.get('priority')
maps = { maps = {
'cost':'planned_cost', 'cost': 'planned_cost',
'revenue': 'planned_revenue', 'revenue': 'planned_revenue',
'probability':'probability' 'probability': 'probability',
} }
vls = { } for line in msg.get('body_text', '').split('\n'):
for line in msg['body_text'].split('\n'):
line = line.strip() line = line.strip()
res = tools.misc.command_re.match(line) res = tools.misc.command_re.match(line)
if res and maps.get(res.group(1).lower(), False): if res and maps.get(res.group(1).lower(), False):
key = maps.get(res.group(1).lower()) key = maps.get(res.group(1).lower())
vls[key] = res.group(2).lower() update_vals[key] = res.group(2).lower()
vals.update(vls) return super(hr_applicant, self).message_update(cr, uids, ids, update_vals=update_vals, context=context)
res = self.write(cr, uid, ids, vals, context=context)
self.message_append_dict(cr, uid, ids, msg, context=context)
return res
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
obj_id = super(hr_applicant, self).create(cr, uid, vals, context=context) obj_id = super(hr_applicant, self).create(cr, uid, vals, context=context)
@ -493,20 +492,14 @@ class hr_applicant(base_stage, osv.Model):
# ------------------------------------------------------- # -------------------------------------------------------
# OpenChatter methods and notifications # OpenChatter methods and notifications
# ------------------------------------------------------- # -------------------------------------------------------
def message_get_subscribers(self, cr, uid, ids, context=None):
sub_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context);
for obj in self.browse(cr, uid, ids, context=context):
if obj.user_id:
sub_ids.append(obj.user_id.id)
return self.pool.get('res.users').read(cr, uid, sub_ids, context=context)
def get_needaction_user_ids(self, cr, uid, ids, context=None): def message_get_subscribers(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, []) """ Override to add responsible user. """
user_ids = super(hr_applicant, self).message_get_subscribers(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if obj.state == 'draft' and obj.user_id: if obj.user_id and not obj.user_id.id in user_ids:
result[obj.id] = [obj.user_id.id] user_ids.append(obj.user_id.id)
return result return user_ids
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
""" Override of the (void) default notification method. """ """ Override of the (void) default notification method. """

View File

@ -45,6 +45,43 @@
# Jobs # Jobs
# ------------------------------------------------------ # ------------------------------------------------------
<!-- Applicant Read/Unread actions -->
<record id="actions_server_applicant_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_hr_applicant"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_applicant_unread" model="ir.values">
<field name="name">action_project_unread</field>
<field name="action_id" ref="actions_server_applicant_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_applicant_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_hr_applicant" />
<field name="model">hr.applicant</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_applicant_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_hr_applicant"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_applicant_read" model="ir.values">
<field name="name">action_project_read</field>
<field name="action_id" ref="actions_server_applicant_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_applicant_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_hr_applicant" />
<field name="model">hr.applicant</field>
<field name="key2">client_action_multi</field>
</record>
<record model="ir.ui.view" id="crm_case_tree_view_job"> <record model="ir.ui.view" id="crm_case_tree_view_job">
<field name="name">Applicants</field> <field name="name">Applicants</field>
<field name="model">hr.applicant</field> <field name="model">hr.applicant</field>
@ -192,6 +229,12 @@
<field name="type">search</field> <field name="type">search</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Search Jobs"> <search string="Search Jobs">
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<separator orientation="vertical"/>
<filter icon="terp-document-new" string="New" name="filter_new"/>
<field name="partner_name" filter_domain="['|','|',('name','ilike',self),('partner_name','ilike',self),('email_from','ilike',self)]" string="Subject / Applicant"/> <field name="partner_name" filter_domain="['|','|',('name','ilike',self),('partner_name','ilike',self),('email_from','ilike',self)]" string="Subject / Applicant"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>
<filter icon="terp-document-new" string="New" <filter icon="terp-document-new" string="New"

View File

@ -949,7 +949,7 @@ class import_sugarcrm(osv.osv):
'user' : fields.boolean('User', help="Check this box to import sugarCRM Users into OpenERP users, warning if a user with the same login exist in OpenERP, user information will be erase by sugarCRM user information", readonly=True), 'user' : fields.boolean('User', help="Check this box to import sugarCRM Users into OpenERP users, warning if a user with the same login exist in OpenERP, user information will be erase by sugarCRM user information", readonly=True),
'opportunity': fields.boolean('Leads & Opp', help="Check this box to import sugarCRM Leads and Opportunities into OpenERP Leads and Opportunities"), 'opportunity': fields.boolean('Leads & Opp', help="Check this box to import sugarCRM Leads and Opportunities into OpenERP Leads and Opportunities"),
'contact': fields.boolean('Contacts', help="Check this box to import sugarCRM Contacts into OpenERP addresses"), 'contact': fields.boolean('Contacts', help="Check this box to import sugarCRM Contacts into OpenERP addresses"),
'account': fields.boolean('Accounts', help="Check this box to import sugarCRM Accounts into OpenERP partners"), 'account': fields.boolean('Partner/Account', help="Check this box to import sugarCRM Accounts into OpenERP partners"),
'employee': fields.boolean('Employee', help="Check this box to import sugarCRM Employees into OpenERP employees"), 'employee': fields.boolean('Employee', help="Check this box to import sugarCRM Employees into OpenERP employees"),
'meeting': fields.boolean('Meetings', help="Check this box to import sugarCRM Meetings and Tasks into OpenERP meetings"), 'meeting': fields.boolean('Meetings', help="Check this box to import sugarCRM Meetings and Tasks into OpenERP meetings"),
'call': fields.boolean('Calls', help="Check this box to import sugarCRM Calls into OpenERP calls"), 'call': fields.boolean('Calls', help="Check this box to import sugarCRM Calls into OpenERP calls"),

View File

@ -9,76 +9,58 @@
<field name="type">form</field> <field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Import Data From SugarCRM" version="7.0"> <form string="Import Data From SugarCRM" version="7.0">
<header> <header>
<button name="import_from_scheduler_all" string="_Schedule Recurrent Imports" type="object" class="oe_highlight" /> <button name="import_all" string="_Import"
or type="object" class="oe_highlight"/>
<button name="import_all" string="_Import" type="object" class="oe_highlight" /> <button name="import_from_scheduler_all" string="_Schedule Recurrent Imports"
or type="object" class="oe_highlight" />
<button string="Cancel" class="oe_link" special="cancel" /> <button special="cancel" string="_Cancel" class="oe_link"/>
</header> </header>
<group col="8" > <sheet>
<group colspan="2" col="2" width="200"> <group col="8" >
<label colspan="2" string="Import your data from SugarCRM :"/> <group colspan="5">
<label colspan="2" string="" /> <separator string="Login Information" colspan="4"/>
<label colspan="2" string="Use the SugarSoap API URL (read tooltip) and a full access SugarCRM login."/> <field name="url" colspan="2" widget="url"/>
<label colspan="2" string="" /> <field name="username" colspan="2"/>
<label colspan="2" string="Choose data you want to import. Click 'Import' to get data manually or 'Schedule Reccurent Imports' to get recurrently and automatically data."/> <field name="password" password="True" colspan="2"/>
<label colspan="2" string="" />
<label colspan="2" string="If you make recurrent or ponctual import, data already in OpenERP will be updated by SugarCRM data."/>
<label colspan="2" string="" />
<label colspan="2" string="Do not forget the email address to be notified of the success of the import."/>
<label colspan="2" />
<label colspan="2" string="Online documentation:"/>
<label colspan="2" string="(Coming Soon)"/>
<label colspan="2" string=""/>
</group>
<separator string="" orientation="vertical" colspan="1" rowspan="24" />
<group colspan="5">
<separator string="Login Information" colspan="4"/>
<field name="url" colspan="4" widget="url"/>
<field name="username" colspan="4"/>
<field name="password" password="True" colspan="4"/>
<group colspan="4"> <group colspan="4">
<group colspan="1" col="2"> <separator string="Data to Import" colspan="4"/>
<separator string="Address Book" colspan="2"/> <group colspan="1" col="2">
<field name="user" /> <field name="user" />
<field name= "account" /> <field name= "account" />
<field name= "contact" /> <field name= "contact" />
</group> </group>
<group colspan="1" col="2"> <group colspan="1" col="2">
<separator string="CRM" colspan="2"/> <field name="opportunity" />
<field name="opportunity" /> <field name= "call" />
<field name= "call" /> <field name= "meeting" />
<field name= "meeting" /> <field name= "claim" />
<field name= "claim" /> </group>
</group> <group colspan="1" col="2">
<group colspan="1" col="2"> <field name= "project" />
<separator string="Project" colspan="2"/> <field name= "project_task" />
<field name= "project" /> <field name= "bug"/>
<field name= "project_task" /> </group>
<field name= "bug"/> <group colspan="1" col="2">
</group> <field name="employee" />
<group colspan="1" col="2"> <field name="email_history"/>
<separator string="HR" colspan="2"/> <field name= "document" />
<field name="employee" /> </group>
<separator string="Document" colspan="2"/> </group>
<field name="email_history"/>
<field name= "document" /> <group colspan="4">
<separator string="Email Notification When Import is Finished" colspan="2"/>
<field name="email_from" widget="email" string="Email Address to Notify" colspan="2"/>
</group>
<group colspan="4" groups="base.group_no_one">
<separator string="Multi Instance Management" colspan="4"/>
<field name="instance_name" colspan="2"/>
</group> </group>
</group> </group>
<group colspan="4">
<separator string="Email Notification When Import is Finished" colspan="4"/>
<field name="email_from" widget="email" string="Email Address to Notify" colspan="4"/>
</group> </group>
</sheet>
<group colspan="4" groups="base.group_no_one">
<separator string="Multi Instance Management" colspan="4"/>
<field name="instance_name" colspan="4"/>
</group>
</group>
</group>
</form> </form>
</field> </field>
</record> </record>

View File

@ -23,6 +23,7 @@ import mail_message
import mail_thread import mail_thread
import mail_group import mail_group
import mail_subscription import mail_subscription
import ir_needaction
import res_users import res_users
import res_partner import res_partner
import report import report

View File

@ -86,6 +86,7 @@ The main features are:
'static/src/css/mail_group.css', 'static/src/css/mail_group.css',
], ],
'js': [ 'js': [
'static/lib/jquery.expander/jquery.expander.js',
'static/src/js/mail.js', 'static/src/js/mail.js',
], ],
'qweb': [ 'qweb': [

View File

@ -10,3 +10,4 @@ Mail Module documentation topics
mail_openchatter_howto mail_openchatter_howto
mail_needaction_howto mail_needaction_howto
mail_partner mail_partner
mail_state

View File

@ -0,0 +1,28 @@
.. _mail_state:
message_state
=============
``message_state`` is a boolean field that states whether the document
has unread messages. In previous versions, some documents were going
back to ``pending`` state when receiving an email through the mail
gateway. Now the state related to messages differs from the state or
stage of the document itself.
message_state and need action mechanism
+++++++++++++++++++++++++++++++++++++++
The ``mail`` module introduces a default behavior for the need_action
mechanism [REF].
::
def get_needaction_user_ids(self, cr, uid, ids, context=None):
""" Returns the user_ids that have to perform an action
:return: dict { record_id: [user_ids], }
"""
result = super(ir_needaction_mixin, self).get_needaction_user_ids(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context):
if obj.message_state == False and obj.user_id:
result[obj.id].append(obj.user_id.id)
return result

View File

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2012-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/>
#
##############################################################################
from osv import osv
class ir_needaction_mixin(osv.Model):
""" Update of ir.needaction_mixin class
- override the get_needaction_user_ids method to define the default
mail gateway need_action: when the object is unread, the object
responsible has an action to perform.
"""
_name = 'ir.needaction_mixin'
_inherit = ['ir.needaction_mixin']
def get_needaction_user_ids(self, cr, uid, ids, context=None):
""" Returns the user_ids that have to perform an action. It the
document mail state is unread (False), return object.user_id.id
as need_action uid.
:return: dict { record_id: [user_ids], }
"""
result = super(ir_needaction_mixin, self).get_needaction_user_ids(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context):
if obj.message_state == False and obj.user_id:
result[obj.id].append(obj.user_id.id)
return result
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -87,7 +87,7 @@ class mail_group(osv.osv):
result = dict.fromkeys(ids) result = dict.fromkeys(ids)
for id in ids: for id in ids:
result[id] = {} result[id] = {}
result[id]['member_ids'] = self.message_get_subscribers_ids(cr, uid, [id], context=context) result[id]['member_ids'] = self.message_get_subscribers(cr, uid, [id], context=context)
result[id]['member_count'] = len(result[id]['member_ids']) result[id]['member_count'] = len(result[id]['member_ids'])
result[id]['is_subscriber'] = uid in result[id]['member_ids'] result[id]['is_subscriber'] = uid in result[id]['member_ids']
return result return result

View File

@ -51,28 +51,30 @@
<field name="priority" eval="10"/> <field name="priority" eval="10"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Group Form" version="7.0"> <form string="Group Form" version="7.0">
<div style="padding: 8px"> <sheet class="openerp_mail_group_sheet">
<div class="oe_right"> <group colspan="4" col="8">
<field name="photo" widget='image' on_change="onchange_photo(photo)"/> <group colspan="1" col="2">
</div> <field name="photo" widget='image' nolabel="1" on_change="onchange_photo(photo)"/>
<div class="oe_title"> </group>
<div class="oe_edit_only"> <group colspan="7" col="6">
<label for="name"/> <div class="oe_edit_only">
</div> <label for="name"/>
<h1><field name="name"/></h1> </div>
<div class="oe_edit_only"> <h2><field name="name" colspan="4"/></h2>
<label for="responsible_id"/> <newline/>
</div> <group colspan="4" col="4">
<field name="responsible_id" class="oe_inline"/> <field name="description" colspan="4" nolabel="1"/>
<div class="oe_edit_only"> </group>
<label for="public"/> <group colspan="2" col="2" class="oe_edit_only">
<field name="public" class="oe_inline"/> <field name="responsible_id" colspan="2"/>
</div> <field name="public" colspan="2"/>
<field name="description" colspan="4" nolabel="1"/> </group>
</div> </group>
</div> </group>
<footer> </sheet>
<field name="message_ids" colspan="4" widget="ThreadView" options='{"thread_level": 1}'/> <footer class="openerp_mail_group_footer">
<field name="message_ids" widget="ThreadView"
options='{"thread_level": 1}'/>
</footer> </footer>
</form> </form>
</field> </field>

View File

@ -96,11 +96,24 @@ class mail_message_common(osv.osv_memory):
continue continue
result[message.id] = self.pool.get(message.model).name_get(cr, uid, [message.res_id], context=context)[0][1] result[message.id] = self.pool.get(message.model).name_get(cr, uid, [message.res_id], context=context)[0][1]
return result return result
def name_get(self, cr, uid, ids, context=None):
res = []
for message in self.browse(cr, uid, ids, context=context):
name = ''
if message.subject:
name = '%s: ' % (message.subject)
if message.body_text:
name = '%s%s ' % (name, message.body_text[0:20])
if message.date:
name = '%s(%s)' % (name, message.date)
res.append((message.id, name))
return res
_name = 'mail.message.common' _name = 'mail.message.common'
_rec_name = 'subject' _rec_name = 'subject'
_columns = { _columns = {
'subject': fields.char('Subject', size=512, required=True), 'subject': fields.char('Subject', size=512),
'model': fields.char('Related Document Model', size=128, select=1), 'model': fields.char('Related Document Model', size=128, select=1),
'res_id': fields.integer('Related Document ID', select=1), 'res_id': fields.integer('Related Document ID', select=1),
'record_name': fields.function(get_record_name, type='string', string='Message Record Name', 'record_name': fields.function(get_record_name, type='string', string='Message Record Name',

View File

@ -34,7 +34,7 @@ import xmlrpclib
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class mail_thread(osv.osv): class mail_thread(osv.Model):
'''Mixin model, meant to be inherited by any model that needs to '''Mixin model, meant to be inherited by any model that needs to
act as a discussion topic on which messages can be attached. act as a discussion topic on which messages can be attached.
Public methods are prefixed with ``message_`` in order to avoid Public methods are prefixed with ``message_`` in order to avoid
@ -62,10 +62,15 @@ class mail_thread(osv.osv):
_name = 'mail.thread' _name = 'mail.thread'
_description = 'Email Thread' _description = 'Email Thread'
def _get_message_ids(self, cr, uid, ids, name, arg, context=None): def _get_message_ids(self, cr, uid, ids, name, args, context=None):
res = {} res = {}
for id in ids: for id in ids:
res[id] = self.message_load_ids(cr, uid, [id], context=context) message_ids = self.message_load_ids(cr, uid, [id], context=context)
subscriber_ids = self.message_get_subscribers(cr, uid, [id], context=context)
res[id] = {
'message_ids': message_ids,
'message_summary': "<span>Msg: %d</span> . <span>Fol: %d</span>" % (len(message_ids), len(subscriber_ids)),
}
return res return res
def _search_message_ids(self, cr, uid, obj, name, args, context=None): def _search_message_ids(self, cr, uid, obj, name, args, context=None):
@ -73,10 +78,23 @@ class mail_thread(osv.osv):
msg_ids = msg_obj.search(cr, uid, ['&', ('res_id', 'in', args[0][2]), ('model', '=', self._name)], context=context) msg_ids = msg_obj.search(cr, uid, ['&', ('res_id', 'in', args[0][2]), ('model', '=', self._name)], context=context)
return [('id', 'in', msg_ids)] return [('id', 'in', msg_ids)]
# OpenChatter: message_ids is a dummy field that should not be used
_columns = { _columns = {
'message_ids': fields.function(_get_message_ids, method=True, fnct_search=_search_message_ids, 'message_ids': fields.function(_get_message_ids, method=True,
type='one2many', obj='mail.message', string='Temp messages', _fields_id = 'res_id'), fnct_search=_search_message_ids,
type='one2many', obj='mail.message', _fields_id = 'res_id',
string='Temp messages', multi="_get_message_ids",
help="Functional field holding messages related to the current document."),
'message_state': fields.boolean('Read',
help="When checked, new messages require your attention."),
'message_summary': fields.function(_get_message_ids, method=True,
type='text', string='Summary', multi="_get_message_ids",
help="Holds the Chatter summary (number of messages, ...). "\
"This summary is directly in html format in order to "\
"be inserted in kanban views."),
}
_defaults = {
'message_state': True,
} }
#------------------------------------------------------ #------------------------------------------------------
@ -84,10 +102,11 @@ class mail_thread(osv.osv):
#------------------------------------------------------ #------------------------------------------------------
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
"""Automatically subscribe the creator""" """Automatically subscribe the creator """
thread_id = super(mail_thread, self).create(cr, uid, vals, context=context); thread_id = super(mail_thread, self).create(cr, uid, vals, context=context)
self.message_subscribe(cr, uid, [thread_id], [uid], context=context) if thread_id:
return thread_id; self.message_subscribe(cr, uid, [thread_id], [uid], context=context)
return thread_id
def write(self, cr, uid, ids, vals, context=None): def write(self, cr, uid, ids, vals, context=None):
"""Automatically subscribe the writer""" """Automatically subscribe the writer"""
@ -106,8 +125,6 @@ class mail_thread(osv.osv):
a foreign key with a 'cascade' ondelete attribute. a foreign key with a 'cascade' ondelete attribute.
Notifications will be deleted with messages Notifications will be deleted with messages
""" """
if context is None:
context = {}
subscr_obj = self.pool.get('mail.subscription') subscr_obj = self.pool.get('mail.subscription')
msg_obj = self.pool.get('mail.message') msg_obj = self.pool.get('mail.message')
# delete subscriptions # delete subscriptions
@ -120,17 +137,18 @@ class mail_thread(osv.osv):
return super(mail_thread, self).unlink(cr, uid, ids, context=context) return super(mail_thread, self).unlink(cr, uid, ids, context=context)
#------------------------------------------------------ #------------------------------------------------------
# Generic message api # mail.message wrappers and tools
#------------------------------------------------------ #------------------------------------------------------
def message_create(self, cr, uid, thread_id, vals, context=None): def message_create(self, cr, uid, thread_id, vals, context=None):
"""OpenSocial: wrapper of mail.message create method """ OpenChatter: wrapper of mail.message create method
- creates the mail.message - creates the mail.message
- automatically subscribe the message writer - automatically subscribe the message writer
- push the message to subscribed users - push the message to subscribed users
""" """
if context is None: if context is None:
context = {} context = {}
message_obj = self.pool.get('mail.message') message_obj = self.pool.get('mail.message')
subscription_obj = self.pool.get('mail.subscription') subscription_obj = self.pool.get('mail.subscription')
notification_obj = self.pool.get('mail.notification') notification_obj = self.pool.get('mail.notification')
@ -167,7 +185,10 @@ class mail_thread(osv.osv):
# create message # create message
msg_id = message_obj.create(cr, uid, vals, context=context) msg_id = message_obj.create(cr, uid, vals, context=context)
# Set as unread if writer is not the document responsible
self.message_create_set_unread(cr, uid, [thread_id], context=context)
# special: if install mode, do not push demo data # special: if install mode, do not push demo data
if context.get('install_mode', False): if context.get('install_mode', False):
return True return True
@ -186,7 +207,7 @@ class mail_thread(osv.osv):
body = new_msg_vals.get('body_html', '') if new_msg_vals.get('subtype', 'plain') == 'html' else new_msg_vals.get('body_text', '') body = new_msg_vals.get('body_html', '') if new_msg_vals.get('subtype', 'plain') == 'html' else new_msg_vals.get('body_text', '')
for thread_id in thread_ids: for thread_id in thread_ids:
# add subscribers # add subscribers
notif_user_ids += [user['id'] for user in self.message_get_subscribers(cr, uid, [thread_id], context=context)] notif_user_ids += self.message_get_subscribers(cr, uid, [thread_id], context=context)
# add users requested via parsing message (@login) # add users requested via parsing message (@login)
notif_user_ids += self.message_parse_users(cr, uid, [thread_id], body, context=context) notif_user_ids += self.message_parse_users(cr, uid, [thread_id], body, context=context)
# add users requested to perform an action (need_action mechanism) # add users requested to perform an action (need_action mechanism)
@ -214,6 +235,10 @@ class mail_thread(osv.osv):
user_ids = self.pool.get('res.users').search(cr, uid, [('login', 'in', login_lst)], context=context) user_ids = self.pool.get('res.users').search(cr, uid, [('login', 'in', login_lst)], context=context)
return user_ids return user_ids
#------------------------------------------------------
# Generic message api
#------------------------------------------------------
def message_capable_models(self, cr, uid, context=None): def message_capable_models(self, cr, uid, context=None):
ret_dict = {} ret_dict = {}
for model_name in self.pool.obj_list(): for model_name in self.pool.obj_list():
@ -376,7 +401,6 @@ class mail_thread(osv.osv):
original = msg_dict.get('original'), original = msg_dict.get('original'),
context = context) context = context)
# Message loading
def _message_add_ancestor_ids(self, cr, uid, ids, child_ids, root_ids, context=None): def _message_add_ancestor_ids(self, cr, uid, ids, child_ids, root_ids, context=None):
""" Given message child_ids """ Given message child_ids
Find their ancestors until root ids""" Find their ancestors until root ids"""
@ -420,6 +444,9 @@ class mail_thread(osv.osv):
msg_ids = self.message_load_ids(cr, uid, ids, limit, offset, domain, ascent, root_ids, context=context) msg_ids = self.message_load_ids(cr, uid, ids, limit, offset, domain, ascent, root_ids, context=context)
msgs = self.pool.get('mail.message').read(cr, uid, msg_ids, [], context=context) msgs = self.pool.get('mail.message').read(cr, uid, msg_ids, [], context=context)
# Set as read
self.message_check_and_set_read(cr, uid, ids, context=context)
""" Retrieve all attachments names """ """ Retrieve all attachments names """
map_id_to_name = {} map_id_to_name = {}
@ -474,7 +501,7 @@ class mail_thread(osv.osv):
return msgs return msgs
#------------------------------------------------------ #------------------------------------------------------
# Email specific # Mail gateway
#------------------------------------------------------ #------------------------------------------------------
# message_process will call either message_new or message_update. # message_process will call either message_new or message_update.
@ -549,7 +576,7 @@ class mail_thread(osv.osv):
if res_id: if res_id:
res_id = res_id.group(1) res_id = res_id.group(1)
if res_id: if res_id:
res_id = int(res_id) res_id = res_id
if model_pool.exists(cr, uid, res_id): if model_pool.exists(cr, uid, res_id):
if hasattr(model_pool, 'message_update'): if hasattr(model_pool, 'message_update'):
model_pool.message_update(cr, uid, [res_id], msg, {}, context=context) model_pool.message_update(cr, uid, [res_id], msg, {}, context=context)
@ -558,7 +585,7 @@ class mail_thread(osv.osv):
res_id = False res_id = False
if not res_id: if not res_id:
res_id = create_record(msg) res_id = create_record(msg)
#To forward the email to other followers # To forward the email to other followers
self.message_forward(cr, uid, model, [res_id], msg_txt, context=context) self.message_forward(cr, uid, model, [res_id], msg_txt, context=context)
return res_id return res_id
@ -594,29 +621,34 @@ class mail_thread(osv.osv):
fields = model_pool.fields_get(cr, uid, context=context) fields = model_pool.fields_get(cr, uid, context=context)
data = model_pool.default_get(cr, uid, fields, context=context) data = model_pool.default_get(cr, uid, fields, context=context)
if 'name' in fields and not data.get('name'): if 'name' in fields and not data.get('name'):
data['name'] = msg_dict.get('from','') data['name'] = msg_dict.get('from', '')
if custom_values and isinstance(custom_values, dict): if custom_values and isinstance(custom_values, dict):
data.update(custom_values) data.update(custom_values)
res_id = model_pool.create(cr, uid, data, context=context) res_id = model_pool.create(cr, uid, data, context=context)
self.message_append_dict(cr, uid, [res_id], msg_dict, context=context) self.message_append_dict(cr, uid, [res_id], msg_dict, context=context)
return res_id return res_id
def message_update(self, cr, uid, ids, msg_dict, vals={}, default_act=None, context=None): def message_update(self, cr, uid, ids, msg_dict, update_vals=None, context=None):
"""Called by ``message_process`` when a new message is received """ Called by ``message_process`` when a new message is received
for an existing thread. The default behavior is to create a for an existing thread. The default behavior is to create a
new mail.message in the given thread (by calling new mail.message in the given thread (by calling
``message_append_dict``) ``message_append_dict``)
Additional behavior may be implemented by overriding this Additional behavior may be implemented by overriding this
method. method.
:param dict msg_dict: a map containing the email details and :param dict msg_dict: a map containing the email details and
attachments. See ``message_process`` and attachments. See ``message_process`` and
``mail.message.parse()`` for details. ``mail.message.parse()`` for details.
:param dict context: if a ``thread_model`` value is present :param dict vals: a dict containing values to update records
given their ids; if the dict is None or is
void, no write operation is performed.
:param dict context: if a ``thread_model`` value is present
in the context, its value will be used in the context, its value will be used
to determine the model of the thread to to determine the model of the thread to
update (instead of the current model). update (instead of the current model).
""" """
if update_vals:
self.write(cr, uid, ids, update_vals, context=context)
return self.message_append_dict(cr, uid, ids, msg_dict, context=context) return self.message_append_dict(cr, uid, ids, msg_dict, context=context)
def message_thread_followers(self, cr, uid, ids, context=None): def message_thread_followers(self, cr, uid, ids, context=None):
@ -746,13 +778,8 @@ class mail_thread(osv.osv):
self.message_append_note(cr, uid, [id], 'res.log', message, context=context) self.message_append_note(cr, uid, [id], 'res.log', message, context=context)
def message_append_note(self, cr, uid, ids, subject=None, body=None, parent_id=False, type='notification', subtype='html', context=None): def message_append_note(self, cr, uid, ids, subject=None, body=None, parent_id=False, type='notification', subtype='html', context=None):
if subject is None: if type in ['notification', 'reply']:
if type == 'notification': subject = None
subject = _('System notification')
elif type == 'comment' and not parent_id:
subject = _('Comment')
elif type == 'comment' and parent_id:
subject = _('Reply')
if subtype == 'html': if subtype == 'html':
body_html = body body_html = body
body_text = body body_text = body
@ -765,51 +792,77 @@ class mail_thread(osv.osv):
# Subscription mechanism # Subscription mechanism
#------------------------------------------------------ #------------------------------------------------------
def message_get_subscribers_ids(self, cr, uid, ids, context=None): def message_get_subscribers(self, cr, uid, ids, context=None):
""" Returns the current document followers. Basically this method
checks in mail.subscription for entries with matching res_model,
res_id.
:param get_ids: if set to True, return the ids of users; if set
to False, returns the result of a read in res.users
"""
subscr_obj = self.pool.get('mail.subscription') subscr_obj = self.pool.get('mail.subscription')
subscr_ids = subscr_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) subscr_ids = subscr_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context)
subs = subscr_obj.read(cr, uid, subscr_ids, context=context) return [sub['user_id'][0] for sub in subscr_obj.read(cr, uid, subscr_ids, ['user_id'], context=context)]
return [sub['user_id'][0] for sub in subs]
def message_get_subscribers(self, cr, uid, ids, context=None): def message_read_subscribers(self, cr, uid, ids, fields=['id', 'name', 'avatar'], context=None):
user_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context) """ Returns the current document followers as a read result. Used
users = self.pool.get('res.users').read(cr, uid, user_ids, fields=['id', 'name', 'avatar'], context=context) mainly for Chatter having only one method to call to have
return users details about users.
"""
user_ids = self.message_get_subscribers(cr, uid, ids, context=context)
return self.pool.get('res.users').read(cr, uid, user_ids, fields=fields, context=context)
def message_is_subscriber(self, cr, uid, ids, user_id = None, context=None): def message_is_subscriber(self, cr, uid, ids, user_id = None, context=None):
users = self.message_get_subscribers(cr, uid, ids, context=context) """ Check if uid or user_id (if set) is a subscriber to the current
document.
:param user_id: if set, check is done on user_id; if not set
check is done on uid
"""
sub_user_id = uid if user_id is None else user_id sub_user_id = uid if user_id is None else user_id
if sub_user_id in [user['id'] for user in users]: if sub_user_id in self.message_get_subscribers(cr, uid, ids, context=context):
return True return True
return False return False
def message_subscribe(self, cr, uid, ids, user_ids = None, context=None): def message_subscribe(self, cr, uid, ids, user_ids = None, context=None):
""" Subscribe the user (or user_ids) to the current document.
:param user_ids: a list of user_ids; if not set, subscribe
uid instead
"""
subscription_obj = self.pool.get('mail.subscription') subscription_obj = self.pool.get('mail.subscription')
to_subscribe_uids = [uid] if user_ids is None else user_ids to_subscribe_uids = [uid] if user_ids is None else user_ids
create_ids = [] create_ids = []
for id in ids: for id in ids:
already_subscribed_user_ids = self.message_get_subscribers(cr, uid, [id], context=context)
for user_id in to_subscribe_uids: for user_id in to_subscribe_uids:
if self.message_is_subscriber(cr, uid, [id], user_id=user_id, context=context): continue if user_id in already_subscribed_user_ids: continue
create_ids.append(subscription_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context)) create_ids.append(subscription_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context))
return create_ids return create_ids
def message_unsubscribe(self, cr, uid, ids, user_ids = None, context=None): def message_unsubscribe(self, cr, uid, ids, user_ids = None, context=None):
if not user_ids and not uid in self.message_get_subscribers_ids(cr, uid, ids, context=context): """ Unsubscribe the user (or user_ids) from the current document.
:param user_ids: a list of user_ids; if not set, subscribe
uid instead
"""
# Trying to unsubscribe somebody not in subscribers: returns False
# if special management is needed; allows to know that an automatically
# subscribed user tries to unsubscribe and allows to warn him
mail_thread_model = self.pool.get('mail.thread')
if not user_ids and not uid in mail_thread_model.message_get_subscribers(cr, uid, ids, context=context):
return False return False
subscription_obj = self.pool.get('mail.subscription') subscription_obj = self.pool.get('mail.subscription')
to_unsubscribe_uids = [uid] if user_ids is None else user_ids to_unsubscribe_uids = [uid] if user_ids is None else user_ids
to_delete_sub_ids = subscription_obj.search(cr, uid, to_delete_sub_ids = subscription_obj.search(cr, uid,
['&', '&', ('res_model', '=', self._name), ('res_id', 'in', ids), ('user_id', 'in', to_unsubscribe_uids)], context=context) ['&', '&', ('res_model', '=', self._name), ('res_id', 'in', ids), ('user_id', 'in', to_unsubscribe_uids)], context=context)
subscription_obj.unlink(cr, uid, to_delete_sub_ids, context=context) return subscription_obj.unlink(cr, uid, to_delete_sub_ids, context=context)
return True
#------------------------------------------------------ #------------------------------------------------------
# Notification API # Notification API
#------------------------------------------------------ #------------------------------------------------------
def message_remove_pushed_notifications(self, cr, uid, ids, msg_ids, remove_childs=True, context=None): def message_remove_pushed_notifications(self, cr, uid, ids, msg_ids, remove_childs=True, context=None):
if context is None:
context = {}
notif_obj = self.pool.get('mail.notification') notif_obj = self.pool.get('mail.notification')
msg_obj = self.pool.get('mail.message') msg_obj = self.pool.get('mail.message')
if remove_childs: if remove_childs:
@ -819,4 +872,37 @@ class mail_thread(osv.osv):
to_del_notif_ids = notif_obj.search(cr, uid, ['&', ('user_id', '=', uid), ('message_id', 'in', notif_msg_ids)], context=context) to_del_notif_ids = notif_obj.search(cr, uid, ['&', ('user_id', '=', uid), ('message_id', 'in', notif_msg_ids)], context=context)
return notif_obj.unlink(cr, uid, to_del_notif_ids, context=context) return notif_obj.unlink(cr, uid, to_del_notif_ids, context=context)
#------------------------------------------------------
# Thread_state
#------------------------------------------------------
def message_create_set_unread(self, cr, uid, ids, context=None):
""" When creating a new message, set as unread if uid is not the
object responsible. """
for obj in self.browse(cr, uid, ids, context=context):
if obj.message_state and hasattr(obj, 'user_id') and (not obj.user_id or obj.user_id.id != uid):
self.message_mark_as_unread(cr, uid, [obj.id], context=context)
def message_check_and_set_unread(self, cr, uid, ids, context=None):
""" Set unread if uid is the object responsible or if the object has
no responsible. """
for obj in self.browse(cr, uid, ids, context=context):
if obj.message_state and hasattr(obj, 'user_id') and (not obj.user_id or obj.user_id.id == uid):
self.message_mark_as_unread(cr, uid, [obj.id], context=context)
def message_mark_as_unread(self, cr, uid, ids, context=None):
""" Set as unread. """
return self.write(cr, uid, ids, {'message_state': False}, context=context)
def message_check_and_set_read(self, cr, uid, ids, context=None):
""" Set read if uid is the object responsible. """
for obj in self.browse(cr, uid, ids, context=context):
if not obj.message_state and hasattr(obj, 'user_id') and obj.user_id and obj.user_id.id == uid:
self.message_mark_as_read(cr, uid, [obj.id], context=context)
def message_mark_as_read(self, cr, uid, ids, context=None):
""" Set as read. """
return self.write(cr, uid, ids, {'message_state': True}, context=context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,385 @@
/*!
* jQuery Expander Plugin v1.4.2
*
* Date: Fri Mar 16 14:29:56 2012 EDT
* Requires: jQuery v1.3+
*
* Copyright 2011, Karl Swedberg
* Dual licensed under the MIT and GPL licenses (just like jQuery):
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*
*
*
*/
(function($) {
$.expander = {
version: '1.4.2',
defaults: {
// the number of characters at which the contents will be sliced into two parts.
slicePoint: 100,
// whether to keep the last word of the summary whole (true) or let it slice in the middle of a word (false)
preserveWords: true,
// a threshold of sorts for whether to initially hide/collapse part of the element's contents.
// If after slicing the contents in two there are fewer words in the second part than
// the value set by widow, we won't bother hiding/collapsing anything.
widow: 4,
// text displayed in a link instead of the hidden part of the element.
// clicking this will expand/show the hidden/collapsed text
expandText: 'read more',
expandPrefix: '&hellip; ',
expandAfterSummary: false,
// class names for summary element and detail element
summaryClass: 'summary',
detailClass: 'details',
// class names for <span> around "read-more" link and "read-less" link
moreClass: 'read-more',
lessClass: 'read-less',
// number of milliseconds after text has been expanded at which to collapse the text again.
// when 0, no auto-collapsing
collapseTimer: 0,
// effects for expanding and collapsing
expandEffect: 'fadeIn',
expandSpeed: 250,
collapseEffect: 'fadeOut',
collapseSpeed: 200,
// allow the user to re-collapse the expanded text.
userCollapse: true,
// text to use for the link to re-collapse the text
userCollapseText: 'read less',
userCollapsePrefix: ' ',
// all callback functions have the this keyword mapped to the element in the jQuery set when .expander() is called
onSlice: null, // function() {}
beforeExpand: null, // function() {},
afterExpand: null, // function() {},
onCollapse: null // function(byUser) {}
}
};
$.fn.expander = function(options) {
var meth = 'init';
if (typeof options == 'string') {
meth = options;
options = {};
}
var opts = $.extend({}, $.expander.defaults, options),
rSelfClose = /^<(?:area|br|col|embed|hr|img|input|link|meta|param).*>$/i,
rAmpWordEnd = opts.wordEnd || /(&(?:[^;]+;)?|[a-zA-Z\u00C0-\u0100]+)$/,
rOpenCloseTag = /<\/?(\w+)[^>]*>/g,
rOpenTag = /<(\w+)[^>]*>/g,
rCloseTag = /<\/(\w+)>/g,
rLastCloseTag = /(<\/[^>]+>)\s*$/,
rTagPlus = /^<[^>]+>.?/,
delayedCollapse;
var methods = {
init: function() {
this.each(function() {
var i, l, tmp, newChar, summTagless, summOpens, summCloses,
lastCloseTag, detailText, detailTagless,
$thisDetails, $readMore,
openTagsForDetails = [],
closeTagsForsummaryText = [],
defined = {},
thisEl = this,
$this = $(this),
$summEl = $([]),
o = $.meta ? $.extend({}, opts, $this.data()) : opts,
hasDetails = !!$this.find('.' + o.detailClass).length,
hasBlocks = !!$this.find('*').filter(function() {
var display = $(this).css('display');
return (/^block|table|list/).test(display);
}).length,
el = hasBlocks ? 'div' : 'span',
detailSelector = el + '.' + o.detailClass,
moreSelector = 'span.' + o.moreClass,
expandSpeed = o.expandSpeed || 0,
allHtml = $.trim( $this.html() ),
allText = $.trim( $this.text() ),
summaryText = allHtml.slice(0, o.slicePoint);
// bail out if we've already set up the expander on this element
if ( $.data(this, 'expander') ) {
return;
}
$.data(this, 'expander', true);
// determine which callback functions are defined
$.each(['onSlice','beforeExpand', 'afterExpand', 'onCollapse'], function(index, val) {
defined[val] = $.isFunction(o[val]);
});
// back up if we're in the middle of a tag or word
summaryText = backup(summaryText);
// summary text sans tags length
summTagless = summaryText.replace(rOpenCloseTag, '').length;
// add more characters to the summary, one for each character in the tags
while (summTagless < o.slicePoint) {
newChar = allHtml.charAt(summaryText.length);
if (newChar == '<') {
newChar = allHtml.slice(summaryText.length).match(rTagPlus)[0];
}
summaryText += newChar;
summTagless++;
}
summaryText = backup(summaryText, o.preserveWords);
// separate open tags from close tags and clean up the lists
summOpens = summaryText.match(rOpenTag) || [];
summCloses = summaryText.match(rCloseTag) || [];
// filter out self-closing tags
tmp = [];
$.each(summOpens, function(index, val) {
if ( !rSelfClose.test(val) ) {
tmp.push(val);
}
});
summOpens = tmp;
// strip close tags to just the tag name
l = summCloses.length;
for (i = 0; i < l; i++) {
summCloses[i] = summCloses[i].replace(rCloseTag, '$1');
}
// tags that start in summary and end in detail need:
// a). close tag at end of summary
// b). open tag at beginning of detail
$.each(summOpens, function(index, val) {
var thisTagName = val.replace(rOpenTag, '$1');
var closePosition = $.inArray(thisTagName, summCloses);
if (closePosition === -1) {
openTagsForDetails.push(val);
closeTagsForsummaryText.push('</' + thisTagName + '>');
} else {
summCloses.splice(closePosition, 1);
}
});
// reverse the order of the close tags for the summary so they line up right
closeTagsForsummaryText.reverse();
// create necessary summary and detail elements if they don't already exist
if ( !hasDetails ) {
// end script if there is no detail text or if detail has fewer words than widow option
detailText = allHtml.slice(summaryText.length);
detailTagless = $.trim( detailText.replace(rOpenCloseTag, '') );
if ( detailTagless === '' || detailTagless.split(/\s+/).length < o.widow ) {
return;
}
// otherwise, continue...
lastCloseTag = closeTagsForsummaryText.pop() || '';
summaryText += closeTagsForsummaryText.join('');
detailText = openTagsForDetails.join('') + detailText;
} else {
// assume that even if there are details, we still need readMore/readLess/summary elements
// (we already bailed out earlier when readMore el was found)
// but we need to create els differently
// remove the detail from the rest of the content
detailText = $this.find(detailSelector).remove().html();
// The summary is what's left
summaryText = $this.html();
// allHtml is the summary and detail combined (this is needed when content has block-level elements)
allHtml = summaryText + detailText;
lastCloseTag = '';
}
o.moreLabel = $this.find(moreSelector).length ? '' : buildMoreLabel(o);
if (hasBlocks) {
detailText = allHtml;
}
summaryText += lastCloseTag;
// onSlice callback
o.summary = summaryText;
o.details = detailText;
o.lastCloseTag = lastCloseTag;
if (defined.onSlice) {
// user can choose to return a modified options object
// one last chance for user to change the options. sneaky, huh?
// but could be tricky so use at your own risk.
tmp = o.onSlice.call(thisEl, o);
// so, if the returned value from the onSlice function is an object with a details property, we'll use that!
o = tmp && tmp.details ? tmp : o;
}
// build the html with summary and detail and use it to replace old contents
var html = buildHTML(o, hasBlocks);
$this.html( html );
// set up details and summary for expanding/collapsing
$thisDetails = $this.find(detailSelector);
$readMore = $this.find(moreSelector);
$thisDetails.hide();
$readMore.find('a').unbind('click.expander').bind('click.expander', expand);
$summEl = $this.find('div.' + o.summaryClass);
if ( o.userCollapse && !$this.find('span.' + o.lessClass).length ) {
$this
.find(detailSelector)
.append('<span class="' + o.lessClass + '">' + o.userCollapsePrefix + '<a href="#">' + o.userCollapseText + '</a></span>');
}
$this
.find('span.' + o.lessClass + ' a')
.unbind('click.expander')
.bind('click.expander', function(event) {
event.preventDefault();
clearTimeout(delayedCollapse);
var $detailsCollapsed = $(this).closest(detailSelector);
reCollapse(o, $detailsCollapsed);
if (defined.onCollapse) {
o.onCollapse.call(thisEl, true);
}
});
function expand(event) {
event.preventDefault();
$readMore.hide();
$summEl.hide();
if (defined.beforeExpand) {
o.beforeExpand.call(thisEl);
}
$thisDetails.stop(false, true)[o.expandEffect](expandSpeed, function() {
$thisDetails.css({zoom: ''});
if (defined.afterExpand) {o.afterExpand.call(thisEl);}
delayCollapse(o, $thisDetails, thisEl);
});
}
}); // this.each
},
destroy: function() {
if ( !this.data('expander') ) {
return;
}
this.removeData('expander');
this.each(function() {
var $this = $(this),
o = $.meta ? $.extend({}, opts, $this.data()) : opts,
details = $this.find('.' + o.detailClass).contents();
$this.find('.' + o.moreClass).remove();
$this.find('.' + o.summaryClass).remove();
$this.find('.' + o.detailClass).after(details).remove();
$this.find('.' + o.lessClass).remove();
});
}
};
// run the methods (almost always "init")
if ( methods[meth] ) {
methods[ meth ].call(this);
}
// utility functions
function buildHTML(o, blocks) {
var el = 'span',
summary = o.summary;
if ( blocks ) {
el = 'div';
// if summary ends with a close tag, tuck the moreLabel inside it
if ( rLastCloseTag.test(summary) && !o.expandAfterSummary) {
summary = summary.replace(rLastCloseTag, o.moreLabel + '$1');
} else {
// otherwise (e.g. if ends with self-closing tag) just add moreLabel after summary
// fixes #19
summary += o.moreLabel;
}
// and wrap it in a div
summary = '<div class="' + o.summaryClass + '">' + summary + '</div>';
} else {
summary += o.moreLabel;
}
return [
summary,
'<',
el + ' class="' + o.detailClass + '"',
'>',
o.details,
'</' + el + '>'
].join('');
}
function buildMoreLabel(o) {
var ret = '<span class="' + o.moreClass + '">' + o.expandPrefix;
ret += '<a href="#">' + o.expandText + '</a></span>';
return ret;
}
function backup(txt, preserveWords) {
if ( txt.lastIndexOf('<') > txt.lastIndexOf('>') ) {
txt = txt.slice( 0, txt.lastIndexOf('<') );
}
if (preserveWords) {
txt = txt.replace(rAmpWordEnd,'');
}
return $.trim(txt);
}
function reCollapse(o, el) {
el.stop(true, true)[o.collapseEffect](o.collapseSpeed, function() {
var prevMore = el.prev('span.' + o.moreClass).show();
if (!prevMore.length) {
el.parent().children('div.' + o.summaryClass).show()
.find('span.' + o.moreClass).show();
}
});
}
function delayCollapse(option, $collapseEl, thisEl) {
if (option.collapseTimer) {
delayedCollapse = setTimeout(function() {
reCollapse(option, $collapseEl);
if ( $.isFunction(option.onCollapse) ) {
option.onCollapse.call(thisEl, false);
}
}, option.collapseTimer);
}
}
return this;
};
// plugin defaults
$.fn.expander.defaults = $.expander.defaults;
})(jQuery);

View File

@ -314,8 +314,8 @@
text-align: justify; text-align: justify;
} }
.openerp .oe_mail_msg_tail { .openerp .oe_mail_msg_body span.oe_mail_msg_tail {
display: none; display: inline;
} }
/* Read more/less link */ /* Read more/less link */

View File

@ -1,3 +1,40 @@
/* ------------------------------ */
/* Group Form */
/* ------------------------------ */
/* Resize sheet width */
.openerp .oe_form_sheetbg.openerp_mail_group_sheet {
min-height: 0px;
max-height: none;
}
.openerp .oe_form_sheetbg.openerp_mail_group_sheet .oe_form_sheet {
min-height: 0px;
max-height: none;
padding: 0px 18px;
max-width: 80%;
}
/* Resize footer width */
.openerp .oe_form footer.openerp_mail_group_footer {
max-width: 80%;
}
/* Resize group logo */
.openerp .oe_form_sheetbg.openerp_mail_group_sheet .oe_form_field_image > img {
max-width: 100px;
max-height: 100px;
}
/* Resize group description */
.openerp .oe_form_sheetbg.openerp_mail_group_sheet .oe_form_field_text > textarea {
height: 40px;
}
/* ------------------------------ */
/* Group Kanban */
/* ------------------------------ */
.oe_group_vignette { .oe_group_vignette {
padding: 8px 0; padding: 8px 0;
min-height: 100px; min-height: 100px;
@ -71,9 +108,3 @@
.oe_group_details li { .oe_group_details li {
margin: 2px 0; margin: 2px 0;
} }
.oe_group_description {
}
.oe_kanban_record div.true {
}

View File

@ -302,17 +302,20 @@ openerp.mail = function(session) {
record.body = this.do_clean_text(record.body); record.body = this.do_clean_text(record.body);
record.body = this.do_replace_internal_links(record.body); record.body = this.do_replace_internal_links(record.body);
// split for see more
var split = this.do_truncate_string(record.body, this.params.msg_more_limit);
record.body_head = split[0];
record.body_tail = split[1];
// format date according to the user timezone // format date according to the user timezone
record.date = session.web.format_value(record.date, {type:"datetime"}); record.date = session.web.format_value(record.date, {type:"datetime"});
var rendered = session.web.qweb.render('mail.Thread.message', {'record': record, 'thread': this, 'params': this.params, 'display': this.display}); var rendered = session.web.qweb.render('mail.Thread.message', {'record': record, 'thread': this, 'params': this.params, 'display': this.display});
$( rendered).appendTo(this.$element.children('div.oe_mail_thread_display:first')); $(rendered).appendTo(this.$element.children('div.oe_mail_thread_display:first'));
// expand feature
this.$element.find('div.oe_mail_msg_body:last').expander({
slicePoint: this.params.msg_more_limit,
expandText: 'see more',
userCollapseText: 'see less',
detailClass: 'oe_mail_msg_tail',
moreClass: 'oe_mail_expand',
lesClass: 'oe_mail_reduce',
});
}, },
/** /**
@ -447,20 +450,6 @@ openerp.mail = function(session) {
return this.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || ''); return this.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || '');
}, },
/**
* @param {String} string to truncate
* @param {Number} max number of chars to display
* @returns {String} truncated string
*/
do_truncate_string: function(string, max_length) {
// multiply by 1.2: prevent truncating an just too little long string
if (string.length <= (max_length * 1.2)) {
return [string, ""];
} else {
return [string.slice(0, max_length), string.slice(max_length)];
}
},
/** Removes html tags, except b, em, br */ /** Removes html tags, except b, em, br */
do_clean_text: function (string) { do_clean_text: function (string) {
var html = $('<div/>').text(string.replace(/\s+/g, ' ')).html().replace(new RegExp('&lt;(/)?(b|em|br|br /)\\s*&gt;', 'gi'), '<$1$2>'); var html = $('<div/>').text(string.replace(/\s+/g, ' ')).html().replace(new RegExp('&lt;(/)?(b|em|br|br /)\\s*&gt;', 'gi'), '<$1$2>');
@ -565,7 +554,7 @@ openerp.mail = function(session) {
}, },
fetch_subscribers: function () { fetch_subscribers: function () {
return this.ds.call('message_get_subscribers', [[this.view.datarecord.id]]).then(this.proxy('display_subscribers')); return this.ds.call('message_read_subscribers', [[this.view.datarecord.id]]).then(this.proxy('display_subscribers'));
}, },
display_subscribers: function (records) { display_subscribers: function (records) {

View File

@ -91,10 +91,7 @@
</div> </div>
<div class="oe_mail_msg_body"> <div class="oe_mail_msg_body">
<a href="#" data-res-model='res.users' t-attf-data-res-id='{record.user_id[0]}' class="oe_mail_internal_link"><t t-raw="record.user_id[1]"/></a> <a href="#" data-res-model='res.users' t-attf-data-res-id='{record.user_id[0]}' class="oe_mail_internal_link"><t t-raw="record.user_id[1]"/></a>
<t t-raw="record.body_head"/> <t t-raw="record.body"/>
<t t-if="record.body_tail"><a href="#" class="oe_mail_msg_more">... See more</a>
<span class="oe_mail_msg_tail"><t t-raw="record.body_tail"/></span>
</t>
</div> </div>
<ul class="oe_mail_msg_footer"> <ul class="oe_mail_msg_footer">
<li><span t-att-title="record.date"><t t-raw="record.timerelative"/></span></li> <li><span t-att-title="record.date"><t t-raw="record.timerelative"/></span></li>

View File

@ -12,18 +12,18 @@
or or
<button string="Cancel" class="oe_link" special="cancel" /> <button string="Cancel" class="oe_link" special="cancel" />
</header> </header>
<group col="6" colspan="4"> <group>
<field name="model" invisible="1"/> <field name="model" invisible="1"/>
<field name="res_id" invisible="1"/> <field name="res_id" invisible="1"/>
<field name='filter_id' invisible="context.get('active_model',False)"/> <field name='filter_id' invisible="context.get('active_model',False)"/>
<field name="email_from" colspan="4" required="1"/> <field name="email_from" required="1"/>
<field name="email_to" colspan="4" required="1"/> <field name="email_to" required="1"/>
<field name="email_cc" colspan="4"/> <field name="email_cc"/>
<field name="email_bcc" colspan="4"/> <field name="email_bcc"/>
<field name="reply_to" colspan="4"/> <field name="reply_to"/>
<field name="subject" colspan="4" widget="char" size="512"/> <field name="subject" widget="char" size="512"/>
<field name="references" invisible="1"/> <field name="references"/>
<field name="message_id" invisible="1"/> <field name="message_id"/>
</group> </group>
<notebook colspan="4"> <notebook colspan="4">
<page string="Body"> <page string="Body">

View File

@ -141,7 +141,7 @@ class membership_line(osv.osv):
_name = 'membership.membership_line' _name = 'membership.membership_line'
_columns = { _columns = {
'partner': fields.many2one('res.partner', 'Partner', ondelete='cascade', select=1), 'partner': fields.many2one('res.partner', 'Partner', ondelete='cascade', select=1),
'membership_id': fields.many2one('product.product', string="Membership Product", required=True), 'membership_id': fields.many2one('product.product', string="Membership", required=True),
'date_from': fields.date('From', readonly=True), 'date_from': fields.date('From', readonly=True),
'date_to': fields.date('To', readonly=True), 'date_to': fields.date('To', readonly=True),
'date_cancel': fields.date('Cancel date'), 'date_cancel': fields.date('Cancel date'),

View File

@ -241,8 +241,11 @@
<group> <group>
<group> <group>
<field name="free_member"/> <field name="free_member"/>
<field colspan="4" name="membership_state"/> <label for="membership_state"/>
<button name="%(action_membership_invoice_view)d" type="action" string="Join Membership" attrs="{'readonly':[('free_member','=',True)]}" icon="gtk-apply"/> <div>
<field name="membership_state" class="oe_inline"/>
<button name="%(action_membership_invoice_view)d" type="action" string="Join Membership" attrs="{'readonly':[('free_member','=',True)]}" class="oe_inline oe_right"/>
</div>
</group> </group>
<group> <group>
<field name="associate_member" attrs="{'readonly':[('membership_state','!=', 'none')]}"/> <field name="associate_member" attrs="{'readonly':[('membership_state','!=', 'none')]}"/>
@ -254,7 +257,7 @@
<field name="member_lines" nolabel="1" colspan="4" readonly="1"> <field name="member_lines" nolabel="1" colspan="4" readonly="1">
<tree string="Memberships"> <tree string="Memberships">
<field name="date"/> <field name="date"/>
<field name="membership_id" string="Membership"/> <field name="membership_id"/>
<field name="member_price"/> <field name="member_price"/>
<field name="account_invoice_id"/> <field name="account_invoice_id"/>
<field name="state"/> <field name="state"/>

View File

@ -1033,20 +1033,14 @@ class mrp_production(osv.osv):
# --------------------------------------------------- # ---------------------------------------------------
# OpenChatter methods and notifications # OpenChatter methods and notifications
# --------------------------------------------------- # ---------------------------------------------------
def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, [])
for obj in self.browse(cr, uid, ids, context=context):
if obj.state == 'draft' and obj.user_id:
result[obj.id] = [obj.user_id.id]
return result
def message_get_subscribers(self, cr, uid, ids, context=None): def message_get_subscribers(self, cr, uid, ids, context=None):
sub_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context); """ Override to add responsible user. """
user_ids = super(mrp_production, self).message_get_subscribers(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if obj.user_id: if obj.user_id and not obj.user_id.id in user_ids:
sub_ids.append(obj.user_id.id) user_ids.append(obj.user_id.id)
return self.pool.get('res.users').read(cr, uid, sub_ids, context=context) return user_ids
def create_send_note(self, cr, uid, ids, context=None): def create_send_note(self, cr, uid, ids, context=None):
self.message_append_note(cr, uid, ids, body=_("Manufacturing order has been <b>created</b>."), context=context) self.message_append_note(cr, uid, ids, body=_("Manufacturing order has been <b>created</b>."), context=context)

View File

@ -28,7 +28,7 @@ UID_ROOT = 1
SHARED_DOCS_MENU = "Documents" SHARED_DOCS_MENU = "Documents"
SHARED_DOCS_CHILD_MENU = "Shared Documents" SHARED_DOCS_CHILD_MENU = "Shared Documents"
class share_wizard_portal(osv.osv_memory): class share_wizard_portal(osv.TransientModel):
"""Inherited share wizard to automatically create appropriate """Inherited share wizard to automatically create appropriate
menus in the selected portal upon sharing with a portal group.""" menus in the selected portal upon sharing with a portal group."""
_inherit = "share.wizard" _inherit = "share.wizard"

View File

@ -8,7 +8,7 @@
<field name="type">form</field> <field name="type">form</field>
<field name="inherit_id" ref="share.share_step1_form"/> <field name="inherit_id" ref="share.share_step1_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="/form/field[@name='user_type']" position="attributes"> <xpath expr="//field[@name='user_type']" position="attributes">
<attribute name='invisible'>0</attribute> <attribute name='invisible'>0</attribute>
<attribute name='colspan'>4</attribute> <attribute name='colspan'>4</attribute>
</xpath> </xpath>
@ -40,11 +40,11 @@
<xpath expr="//field[@name='result_line_ids']//field[@name='login']" position="after"> <xpath expr="//field[@name='result_line_ids']//field[@name='login']" position="after">
<field name="share_url" groups="portal.group_portal_manager"/> <field name="share_url" groups="portal.group_portal_manager"/>
</xpath> </xpath>
<xpath expr="//field[@name='result_line_ids']//field[@name='login']" position="after">
<field name="share_url" colspan="4" groups="portal.group_portal_manager"/>
</xpath>
<xpath expr="//field[@name='result_line_ids']" position="after"> <xpath expr="//field[@name='result_line_ids']" position="after">
<field colspan="4" name="share_root_url" groups="portal.group_portal_manager"/> <newline/>
<group string="Details">
<field name="share_root_url" groups="portal.group_portal_manager"/>
</group>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@ -312,12 +312,26 @@
<field name="type">form</field> <field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Product Categories" version="7.0"> <form string="Product Categories" version="7.0">
<group col="4"> <sheet>
<field name="name"/> <div class="oe_title">
<field name="parent_id"/> <h1>
<field name="sequence" invisible="1"/> <label for="name" class="oe_edit_only"/>
<field name="type"/> <field name="name"/>
</group> </h1>
</div>
<group>
<group>
<field name="type"/>
</group>
<group>
<field name="parent_id"/>
</group>
</group>
<group name="basic">
<group name="account_property" string="Account Properties"/>
<group name="account_stock_property" string="Account Stock Properties"/>
</group>
</sheet>
</form> </form>
</field> </field>
</record> </record>
@ -409,12 +423,12 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Units of Measure" version="7.0"> <form string="Units of Measure" version="7.0">
<group> <group>
<group string="Unit of Measure Properties"> <group>
<field name="name"/> <field name="name"/>
<field name="category_id"/> <field name="category_id"/>
<field name="active"/> <field name="active"/>
</group> </group>
<group string="Ratio &amp; Precision"> <group>
<field name="uom_type" on_change="onchange_type(uom_type)"/> <field name="uom_type" on_change="onchange_type(uom_type)"/>
<field name="rounding"/> <field name="rounding"/>
<field name="factor" attrs="{'invisible':[('uom_type','!=','smaller')]}"/> <field name="factor" attrs="{'invisible':[('uom_type','!=','smaller')]}"/>

View File

@ -10,19 +10,19 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<notebook position="inside"> <notebook position="inside">
<page string="Manufacturer"> <page string="Manufacturer">
<separator string="Manufacturer" colspan="4" /> <group string="Manufacturer">
<field name="manufacturer" /> <field name="manufacturer" />
<newline/> <field name="manufacturer_pname"/>
<field name="manufacturer_pname"/> <field name="manufacturer_pref"/>
<field name="manufacturer_pref"/> </group>
<group string="Attributes">
<separator string="Attributes" colspan="4"/> <field name="attribute_ids" colspan="4" nolabel="1">
<field name="attribute_ids" colspan="4" nolabel="1"> <tree string="Product Attributes" editable="bottom">
<tree string="Product Attributes" editable="bottom"> <field name="name"/>
<field name="name"/> <field name="value"/>
<field name="value"/> </tree>
</tree> </field>
</field> </group>
</page> </page>
</notebook> </notebook>
</field> </field>

View File

@ -480,21 +480,14 @@ def Project():
# ------------------------------------------------ # ------------------------------------------------
# OpenChatter methods and notifications # OpenChatter methods and notifications
# ------------------------------------------------ # ------------------------------------------------
def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids)
for obj in self.browse(cr, uid, ids, context=context):
result[obj.id] = []
if obj.state == 'draft' and obj.user_id:
result[obj.id] = [obj.user_id.id]
return result
def message_get_subscribers(self, cr, uid, ids, context=None): def message_get_subscribers(self, cr, uid, ids, context=None):
sub_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context); """ Override to add responsible user. """
user_ids = super(project, self).message_get_subscribers(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if obj.user_id: if obj.user_id and not obj.user_id.id in user_ids:
sub_ids.append(obj.user_id.id) user_ids.append(obj.user_id.id)
return self.pool.get('res.users').read(cr, uid, sub_ids, context=context) return user_ids
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
obj_id = super(project, self).create(cr, uid, vals, context=context) obj_id = super(project, self).create(cr, uid, vals, context=context)
@ -1145,20 +1138,26 @@ class task(base_stage, osv.osv):
return 'Task' return 'Task'
def get_needaction_user_ids(self, cr, uid, ids, context=None): def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, []) """ Returns the user_ids that have to perform an action.
Add to the previous results given by super the document responsible
when in draft mode.
:return: dict { record_id: [user_ids], }
"""
result = super(task, self).get_needaction_user_ids(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if obj.state == 'draft' and obj.user_id: if obj.state == 'draft' and obj.user_id:
result[obj.id] = [obj.user_id.id] result[obj.id].append(obj.user_id.id)
return result return result
def message_get_subscribers(self, cr, uid, ids, context=None): def message_get_subscribers(self, cr, uid, ids, context=None):
sub_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context); """ Override to add responsible user and project manager. """
user_ids = super(task, self).message_get_subscribers(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if obj.user_id: if obj.user_id and not obj.user_id.id in user_ids:
sub_ids.append(obj.user_id.id) user_ids.append(obj.user_id.id)
if obj.manager_id: if obj.manager_id and not obj.manager_id.id in user_ids:
sub_ids.append(obj.manager_id.id) user_ids.append(obj.manager_id.id)
return self.pool.get('res.users').read(cr, uid, sub_ids, context=context) return user_ids
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
""" Override of the (void) default notification method. """ """ Override of the (void) default notification method. """

View File

@ -21,6 +21,43 @@
view_mode="kanban,tree,form,calendar,graph" view_mode="kanban,tree,form,calendar,graph"
view_type="form"/> view_type="form"/>
<!-- Project Read/Unread actions -->
<record id="actions_server_project_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_project_project"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_project_unread" model="ir.values">
<field name="name">action_project_unread</field>
<field name="action_id" ref="actions_server_project_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_project_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_project_project" />
<field name="model">project.project</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_project_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_project_project"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_project_read" model="ir.values">
<field name="name">action_project_read</field>
<field name="action_id" ref="actions_server_project_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_project_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_project_project" />
<field name="model">project.project</field>
<field name="key2">client_action_multi</field>
</record>
<!-- Project --> <!-- Project -->
<record id="edit_project" model="ir.ui.view"> <record id="edit_project" model="ir.ui.view">
<field name="name">project.project.form</field> <field name="name">project.project.form</field>
@ -126,6 +163,11 @@
<group> <group>
<field name="complete_name" string="Project Name"/> <field name="complete_name" string="Project Name"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<separator orientation="vertical"/>
<filter icon="terp-check" string="Open" name="Current" domain="[('state', '=','open')]" help="Open Projects"/> <filter icon="terp-check" string="Open" name="Current" domain="[('state', '=','open')]" help="Open Projects"/>
<filter icon="gtk-media-pause" string="Pending" name="Pending" domain="[('state', '=','pending')]" help="Pending Projects"/> <filter icon="gtk-media-pause" string="Pending" name="Pending" domain="[('state', '=','pending')]" help="Pending Projects"/>
<filter icon="gtk-media-pause" string="Template" name="Template" domain="[('state', '=','template')]" help="Templates of Projects"/> <filter icon="gtk-media-pause" string="Template" name="Template" domain="[('state', '=','template')]" help="Templates of Projects"/>
@ -308,6 +350,44 @@
</record> </record>
<!-- Task --> <!-- Task -->
<!-- Task Read/Unread actions -->
<record id="actions_server_project_task_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_project_task"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_project_task_unread" model="ir.values">
<field name="name">action_project_task_unread</field>
<field name="action_id" ref="actions_server_project_task_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_project_task_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_project_task" />
<field name="model">project.task</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_project_task_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_project_task"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_project_task_read" model="ir.values">
<field name="name">action_project_task_read</field>
<field name="action_id" ref="actions_server_project_task_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_project_task_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_project_task" />
<field name="model">project.task</field>
<field name="key2">client_action_multi</field>
</record>
<record id="view_task_form2" model="ir.ui.view"> <record id="view_task_form2" model="ir.ui.view">
<field name="name">project.task.form</field> <field name="name">project.task.form</field>
<field name="model">project.task</field> <field name="model">project.task</field>
@ -440,6 +520,8 @@
<field name="kanban_state"/> <field name="kanban_state"/>
<field name="remaining_hours" sum="Remaining Time" groups="project.group_time_work_estimation_tasks"/> <field name="remaining_hours" sum="Remaining Time" groups="project.group_time_work_estimation_tasks"/>
<field name="date_deadline"/> <field name="date_deadline"/>
<field name="message_summary"/>
<field name="needaction_pending"/>
<templates> <templates>
<t t-name="kanban-box"> <t t-name="kanban-box">
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click"> <div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click">
@ -568,6 +650,11 @@
<group> <group>
<field name="name" string="Tasks"/> <field name="name" string="Tasks"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<separator orientation="vertical"/>
<filter name="draft" string="New" domain="[('state','=','draft')]" help="New Tasks" icon="terp-check"/> <filter name="draft" string="New" domain="[('state','=','draft')]" help="New Tasks" icon="terp-check"/>
<filter name="open" string="In Progress" domain="[('state','=','open')]" help="In Progress Tasks" icon="terp-camera_test"/> <filter name="open" string="In Progress" domain="[('state','=','open')]" help="In Progress Tasks" icon="terp-camera_test"/>
<filter string="Pending" domain="[('state','=','pending')]" context="{'show_delegated':False}" help="Pending Tasks" icon="terp-gtk-media-pause"/> <filter string="Pending" domain="[('state','=','pending')]" context="{'show_delegated':False}" help="Pending Tasks" icon="terp-gtk-media-pause"/>

View File

@ -467,87 +467,68 @@ class project_issue(base_stage, osv.osv):
# ------------------------------------------------------- # -------------------------------------------------------
def message_new(self, cr, uid, msg, custom_values=None, context=None): def message_new(self, cr, uid, msg, custom_values=None, context=None):
"""Automatically called when new email message arrives""" """ Overrides mail_thread message_new that is called by the mailgateway
if context is None: through message_process.
context = {} This override updates the document according to the email.
subject = msg.get('subject') or _('No Title') """
body = msg.get('body_text') if custom_values is None: custom_values = {}
msg_from = msg.get('from') if context is None: context = {}
priority = msg.get('priority') context['state_to'] = 'draft'
vals = {
'name': subject, custom_values.update({
'email_from': msg_from, 'name': msg.get('subject') or _("No Subject"),
'description': msg.get('body_text'),
'email_from': msg.get('from'),
'email_cc': msg.get('cc'), 'email_cc': msg.get('cc'),
'description': body,
'user_id': False, 'user_id': False,
} })
if priority: if msg.get('priority'):
vals['priority'] = priority custom_values['priority'] = msg.get('priority')
vals.update(self.message_partner_by_email(cr, uid, msg_from)) custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from'), context=context))
context.update({'state_to' : 'draft'})
if custom_values and isinstance(custom_values, dict): res_id = super(project_issue, self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
vals.update(custom_values)
res_id = self.create(cr, uid, vals, context)
self.message_append_dict(cr, uid, [res_id], msg, context=context)
self.convert_to_bug(cr, uid, [res_id], context=context) self.convert_to_bug(cr, uid, [res_id], context=context)
return res_id return res_id
def message_update(self, cr, uid, ids, msg, vals=None, default_act='pending', context=None): def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
if vals is None: """ Overrides mail_thread message_update that is called by the mailgateway
vals = {} through message_process.
This method updates the document according to the email.
"""
if isinstance(ids, (str, int, long)): if isinstance(ids, (str, int, long)):
ids = [ids] ids = [ids]
if update_vals is None: update_vals = {}
vals.update({ # Update doc values according to the message
'description': msg['body_text'] update_vals['description'] = msg.get('body_text', '')
}) if msg.get('priority'):
if msg.get('priority', False): update_vals['priority'] = msg.get('priority')
vals['priority'] = msg.get('priority') # Parse 'body_text' to find values to update
maps = { maps = {
'cost': 'planned_cost', 'cost': 'planned_cost',
'revenue': 'planned_revenue', 'revenue': 'planned_revenue',
'probability': 'probability' 'probability': 'probability',
} }
for line in msg.get('body_text', '').split('\n'):
# Reassign the 'open' state to the case if this one is in pending or done
for record in self.browse(cr, uid, ids, context=context):
if record.state in ('pending', 'done'):
self.case_set(cr, uid, ids, 'open', {}, context=context)
vls = { }
for line in msg['body_text'].split('\n'):
line = line.strip() line = line.strip()
res = tools.misc.command_re.match(line) res = tools.misc.command_re.match(line)
if res and maps.get(res.group(1).lower(), False): if res and maps.get(res.group(1).lower(), False):
key = maps.get(res.group(1).lower()) key = maps.get(res.group(1).lower())
vls[key] = res.group(2).lower() update_vals[key] = res.group(2).lower()
vals.update(vls) return super(project_issue, self).message_update(cr, uid, ids, update_vals=update_vals, context=context)
res = self.write(cr, uid, ids, vals)
self.message_append_dict(cr, uid, ids, msg, context=context)
return res
# ------------------------------------------------------- # -------------------------------------------------------
# OpenChatter methods and notifications # OpenChatter methods and notifications
# ------------------------------------------------------- # -------------------------------------------------------
def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, [])
for obj in self.browse(cr, uid, ids, context=context):
if obj.state == 'draft' and obj.user_id:
result[obj.id] = [obj.user_id.id]
return result
def message_get_subscribers(self, cr, uid, ids, context=None): def message_get_subscribers(self, cr, uid, ids, context=None):
sub_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context); """ Override to add responsible user. """
user_ids = super(project_issue, self).message_get_subscribers(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if obj.user_id: if obj.user_id and not obj.user_id.id in user_ids:
sub_ids.append(obj.user_id.id) user_ids.append(obj.user_id.id)
return self.pool.get('res.users').read(cr, uid, sub_ids, context=context) return user_ids
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
""" Override of the (void) default notification method. """ """ Override of the (void) default notification method. """

View File

@ -227,5 +227,10 @@
<field name="stage_id" ref="project.project_tt_specification"/> <field name="stage_id" ref="project.project_tt_specification"/>
</record> </record>
<!-- Call Function to set some issues as Unread -->
<function model="project.issue" name="message_mark_as_unread"
eval="[ ref('crm_case_improvereportsinhrms0'), ref('crm_case_createnewobject0')], {}"
/>
</data> </data>
</openerp> </openerp>

View File

@ -4,6 +4,43 @@
<menuitem id="menu_project_confi" name="Issues" parent="base.menu_definitions" sequence="2"/> <menuitem id="menu_project_confi" name="Issues" parent="base.menu_definitions" sequence="2"/>
<!-- Project issue Read/Unread actions -->
<record id="actions_server_project_issue_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_project_issue"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_project_issue_unread" model="ir.values">
<field name="name">action_project_issue_unread</field>
<field name="action_id" ref="actions_server_project_issue_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_project_issue_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_project_issue" />
<field name="model">project.issue</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_project_issue_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_project_issue"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_project_issue_read" model="ir.values">
<field name="name">action_project_issue_read</field>
<field name="action_id" ref="actions_server_project_issue_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_project_issue_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_project_issue" />
<field name="model">project.issue</field>
<field name="key2">client_action_multi</field>
</record>
<record model="ir.ui.view" id="project_issue_version_search_view"> <record model="ir.ui.view" id="project_issue_version_search_view">
<field name="name">Issue Version</field> <field name="name">Issue Version</field>
<field name="model">project.issue.version</field> <field name="model">project.issue.version</field>
@ -159,9 +196,13 @@
<group> <group>
<field name="name" string="Issue" filter_domain="['|', '|',('partner_id','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/> <field name="name" string="Issue" filter_domain="['|', '|',('partner_id','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<separator orientation="vertical"/>
<filter string="New" icon="terp-document-new" domain="[('state','=','draft')]" help="New Issues"/> <filter string="New" icon="terp-document-new" domain="[('state','=','draft')]" help="New Issues"/>
<filter string="To Do" domain="[('state','=','open')]" help="To Do Issues" icon="terp-check"/> <filter string="To Do" domain="[('state','=','open')]" help="To Do Issues" icon="terp-check"/>
<filter string="Pending" domain="[('state','=','pending')]" help="Pending Issues" icon="terp-gtk-media-pause"/>
<filter string="Unassigned Issues" domain="[('user_id','=',False)]" help="Unassigned Issues" icon="terp-personal-" /> <filter string="Unassigned Issues" domain="[('user_id','=',False)]" help="Unassigned Issues" icon="terp-personal-" />
<separator orientation="vertical"/> <separator orientation="vertical"/>
<field name="user_id"/> <field name="user_id"/>

View File

@ -152,23 +152,23 @@
<field name="state" widget="statusbar" statusbar_visible="draft,open,done" statusbar_colors='{"pending":"blue"}'/> <field name="state" widget="statusbar" statusbar_visible="draft,open,done" statusbar_colors='{"pending":"blue"}'/>
</header> </header>
<sheet> <sheet>
<label for="name" class="oe_edit_only"/> <div class="oe_title">
<h1><field name="name"/></h1> <label for="name" class="oe_edit_only"/>
<label for="project_id" class="oe_edit_only"/> <h1><field name="name"/></h1>
<h2> <label for="project_id" class="oe_edit_only"/>
<field name="project_id" on_change="onchange_project(project_id)" colspan="3"/> <h2>
</h2> <field name="project_id" on_change="onchange_project(project_id)" colspan="3"/>
</h2>
</div>
<group> <group>
<group> <label for="date_start" string="Duration"/>
<field name="date_start"/> <div>
<field name="date_end"/> <div>
</group><group> <field name="duration" class="oe_inline"/>
<label for="duration"/> <field name="product_uom" class="oe_inline"/>
<div> </div>
<field name="duration" class="oe_inline"/> <field name="date_start" class="oe_inline"/><label string=" - " class="oe_inline"/><field name="date_end" class="oe_inline"/>
<field name="product_uom"/> </div>
</div>
</group>
</group> </group>
<notebook> <notebook>
<page string="Planning of Users"> <page string="Planning of Users">

View File

@ -19,30 +19,35 @@
# #
############################################################################## ##############################################################################
import binascii
from osv import fields, osv from osv import fields, osv
from tools.translate import _ from tools.translate import _
import tools import tools
import binascii
class project_tasks(osv.osv): class project_tasks(osv.osv):
_inherit = 'project.task' _inherit = 'project.task'
def message_new(self, cr, uid, msg, custom_values=None, context=None): def message_new(self, cr, uid, msg, custom_values=None, context=None):
res_id = super(project_tasks,self).message_new(cr, uid, msg, custom_values=custom_values, context=context) """ Overrides mail_thread message_new that is called by the mailgateway
subject = msg.get('subject') through message_process.
msg_from = msg.get('from') This override updates the document according to the email.
data = { """
if custom_values is None: custom_values = {}
custom_values.update({
'name': subject, 'name': subject,
'planned_hours': 0.0, 'planned_hours': 0.0,
} 'subject': msg.get('subject'),
data.update(self.message_partner_by_email(cr, uid, msg_from)) })
self.write(cr, uid, [res_id], data, context) custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from', False), context=context))
return res_id return super(project_tasks,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
def message_update(self, cr, uid, ids, msg, data={}, default_act='pending'):
act = 'do_'+default_act
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
""" Overrides mail_thread message_update that is called by the mailgateway
through message_process.
This method updates the task according to the email.
"""
if update_vals is None: update_vals = {}
act = False
maps = { maps = {
'cost':'planned_hours', 'cost':'planned_hours',
} }
@ -54,17 +59,15 @@ class project_tasks(osv.osv):
field = maps.get(match) field = maps.get(match)
if field: if field:
try: try:
data[field] = float(res.group(2).lower()) update_vals[field] = float(res.group(2).lower())
except (ValueError, TypeError): except (ValueError, TypeError):
pass pass
elif match.lower() == 'state' \ elif match.lower() == 'state' \
and res.group(2).lower() in ['cancel','close','draft','open','pending']: and res.group(2).lower() in ['cancel','close','draft','open','pending']:
act = 'do_%s' % res.group(2).lower() act = 'do_%s' % res.group(2).lower()
if act:
self.write(cr, uid, ids, data, context=context) getattr(self,act)(cr, uid, ids, context=context)
getattr(self,act)(cr, uid, ids, context=context) return super(project_tasks,self).message_update(cr, uid, msg, update_vals=update_vals, context=context)
self.message_append_note(cr, uid, [res_id], body=msg, context=context)
return True
def message_thread_followers(self, cr, uid, ids, context=None): def message_thread_followers(self, cr, uid, ids, context=None):
followers = super(project_tasks,self).message_thread_followers(cr, uid, ids, context=context) followers = super(project_tasks,self).message_thread_followers(cr, uid, ids, context=context)
@ -74,5 +77,5 @@ class project_tasks(osv.osv):
followers[task.id] = filter(None, task_followers) followers[task.id] = filter(None, task_followers)
return followers return followers
project_tasks()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -733,10 +733,10 @@ class purchase_order(osv.osv):
# -------------------------------------- # --------------------------------------
def get_needaction_user_ids(self, cr, uid, ids, context=None): def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, []) result = super(purchase_order, self).get_needaction_user_ids(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if obj.state == 'approved': if obj.state == 'approved':
result[obj.id] = [obj.validator.id] result[obj.id].append(obj.validator.id)
return result return result
def create_send_note(self, cr, uid, ids, context=None): def create_send_note(self, cr, uid, ids, context=None):

View File

@ -52,10 +52,10 @@
action="base.action_partner_category_form" id="menu_partner_categories_in_form" name="Partner Categories" action="base.action_partner_category_form" id="menu_partner_categories_in_form" name="Partner Categories"
parent="purchase.menu_purchase_partner_cat" groups="base.group_no_one"/> parent="purchase.menu_purchase_partner_cat" groups="base.group_no_one"/>
<!--supplier menu--> <!--supplier menu-->
<menuitem id="base.menu_procurement_management_supplier_name" name="Suppliers" <menuitem id="base.menu_procurement_management_supplier_name" name="Suppliers"
parent="menu_procurement_management" parent="menu_procurement_management"
action="base.action_partner_supplier_form" sequence="15"/> action="base.action_partner_supplier_form" sequence="15"/>
<!--Inventory control--> <!--Inventory control-->
<menuitem id="menu_procurement_management_inventory" name="Receive Products" <menuitem id="menu_procurement_management_inventory" name="Receive Products"
@ -65,9 +65,9 @@
<menuitem action="stock.action_reception_picking_move" id="menu_action_picking_tree_in_move" <menuitem action="stock.action_reception_picking_move" id="menu_action_picking_tree_in_move"
parent="menu_procurement_management_inventory" sequence="11"/> parent="menu_procurement_management_inventory" sequence="11"/>
<!--Invoice control--> <!--Invoice control-->
<menuitem id="menu_procurement_management_invoice" name="Invoice Control" <menuitem id="menu_procurement_management_invoice" name="Invoice Control"
parent="base.menu_purchase_root" sequence="6"/> parent="base.menu_purchase_root" sequence="6"/>
<record id="action_invoice_pending" model="ir.actions.act_window"> <record id="action_invoice_pending" model="ir.actions.act_window">
<field name="name">Based on Draft Invoices</field> <field name="name">Based on Draft Invoices</field>
@ -101,6 +101,43 @@
<menuitem name="Products" id="menu_procurement_partner_contact_form" action="product.product_normal_action_puchased" <menuitem name="Products" id="menu_procurement_partner_contact_form" action="product.product_normal_action_puchased"
parent="menu_procurement_management_product"/> parent="menu_procurement_management_product"/>
<!-- Purchase order Read/Unread actions -->
<record id="actions_server_purchase_order_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_purchase_order"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_purchase_order_unread" model="ir.values">
<field name="name">action_purchase_order_unread</field>
<field name="action_id" ref="actions_server_purchase_order_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_purchase_order_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_purchase_order" />
<field name="model">purchase.order</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_purchase_order_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_purchase_order"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_purchase_order_read" model="ir.values">
<field name="name">action_purchase_order_read</field>
<field name="action_id" ref="actions_server_purchase_order_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_purchase_order_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_purchase_order" />
<field name="model">purchase.order</field>
<field name="key2">client_action_multi</field>
</record>
<record model="ir.ui.view" id="purchase_order_calendar"> <record model="ir.ui.view" id="purchase_order_calendar">
<field name="name">purchase.order.calendar</field> <field name="name">purchase.order.calendar</field>
<field name="model">purchase.order</field> <field name="model">purchase.order</field>
@ -133,7 +170,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Purchase Order" version="7.0"> <form string="Purchase Order" version="7.0">
<header> <header>
<button name="purchase_confirm" states="draft,sent" string="Confirm Order" class="oe_highlight"/> <button name="purchase_confirm" states="draft,sent" string="Confirm Quotation" class="oe_highlight"/>
<button name="wkf_send_rfq" states="draft" string="Send RFQ" type="object" context="{'send_rfq':True}"/> <button name="wkf_send_rfq" states="draft" string="Send RFQ" type="object" context="{'send_rfq':True}"/>
<button name="wkf_send_rfq" states="confirmed" string="Resend Purchase Order" type="object" class="oe_highlight"/> <button name="wkf_send_rfq" states="confirmed" string="Resend Purchase Order" type="object" class="oe_highlight"/>
<button name="action_cancel" states="except_picking,except_invoice,wait" string="Cancel" type="object" /> <button name="action_cancel" states="except_picking,except_invoice,wait" string="Cancel" type="object" />
@ -148,11 +185,13 @@
<field name="state" widget="statusbar" statusbar_visible="draft,approved,done" statusbar_colors='{"except_picking":"red","except_invoice":"red","confirmed":"blue","wait":"blue"}' readonly="1"/> <field name="state" widget="statusbar" statusbar_visible="draft,approved,done" statusbar_colors='{"except_picking":"red","except_invoice":"red","confirmed":"blue","wait":"blue"}' readonly="1"/>
</header> </header>
<sheet> <sheet>
<h1> <div class="oe_title">
<label string="Draft Purchase Order " attrs="{'invisible': [('state','not in',('draft','sent'))]}"/> <h1>
<label string="Purchase Order " attrs="{'invisible': [('state','in',('draft','sent'))]}"/> <label string="Quotation " attrs="{'invisible': [('state','not in',('draft','sent'))]}"/>
<field name="name" class="oe_inline" readonly="1"/> <label string="Purchase Order " attrs="{'invisible': [('state','in',('draft','sent'))]}"/>
</h1> <field name="name" class="oe_inline" readonly="1"/>
</h1>
</div>
<group> <group>
<group> <group>
<field name="partner_id" on_change="onchange_partner_id(partner_id)" context="{'search_default_supplier':1,'default_supplier':1,'default_customer':0}"/> <field name="partner_id" on_change="onchange_partner_id(partner_id)" context="{'search_default_supplier':1,'default_supplier':1,'default_customer':0}"/>
@ -175,15 +214,17 @@
<field name="product_qty"/> <field name="product_qty"/>
<field name="product_uom" groups="product.group_uom"/> <field name="product_uom" groups="product.group_uom"/>
<field name="price_unit"/> <field name="price_unit"/>
<field name="price_subtotal"/> <field name="price_subtotal"/>
</tree> </tree>
</field> </field>
<group class="oe_subtotal_footer"> <group class="oe_subtotal_footer oe_right">
<field name="amount_untaxed"/> <field name="amount_untaxed"/>
<field name="amount_tax"/> <field name="amount_tax"/>
<field name="amount_total" class="oe_subtotal_footer_separator"/> <div class="oe_subtotal_footer_separator oe_inline" colspan="2">
<button name="button_dummy" states="draft" string="Compute" type="object" icon="gtk-execute"/> <button name="button_dummy" states="draft" string="Compute" type="object" icon="gtk-execute" class="oe_inline oe_left"/>
</group> <field name="amount_total"/>
</div>
</group>
<div class="oe_clear"/> <div class="oe_clear"/>
<label for="notes"/> <label for="notes"/>
<field name="notes"/> <field name="notes"/>
@ -191,23 +232,27 @@
<page string="Delivery &amp; Invoicing"> <page string="Delivery &amp; Invoicing">
<group> <group>
<group string="Delivery"> <group string="Delivery">
<field name="dest_address_id" on_change="onchange_dest_address_id(dest_address_id)"/> <field name="dest_address_id" string="Customer Address" on_change="onchange_dest_address_id(dest_address_id)"/>
<field name="minimum_planned_date"/> <field name="minimum_planned_date"/>
<field name="location_id" groups="stock.group_locations"/> <field name="location_id" groups="stock.group_locations"/>
<field name="shipped"/> <field name="shipped" groups="base.group_no_one"/>
</group> </group>
<group string="Invoice Control"> <group>
<field name="invoice_method"/> <field name="validator" groups="base.group_no_one"/>
<field name="fiscal_position" widget="selection"/>
<field name="invoiced" groups="base.group_no_one"/>
</group>
<group groups="base.group_no_one" string="Purchase Control">
<field name="validator"/>
<field name="date_approve"/> <field name="date_approve"/>
</group> </group>
<separator string="Invoices"/>
<field name="invoice_ids" context="{'type':'in_invoice', 'journal_type':'purchase'}"/>
</group> </group>
<group string="Invoicing">
<group>
<field name="invoice_method"/>
<field name="invoiced"/>
</group>
<group>
<field name="fiscal_position"/>
</group>
</group>
<separator string="Invoices"/>
<field name="invoice_ids" context="{'type':'in_invoice', 'journal_type':'purchase'}"/>
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
@ -259,6 +304,11 @@
<group> <group>
<field name="name" string="Reference"/> <field name="name" string="Reference"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<separator orientation="vertical"/>
<filter icon="terp-document-new" name="draft" string="Quotations" domain="[('state','=','draft')]" help="Purchase orders which are in draft state"/> <filter icon="terp-document-new" name="draft" string="Quotations" domain="[('state','=','draft')]" help="Purchase orders which are in draft state"/>
<filter icon="terp-check" name="approved" string="Purchase Orders" domain="[('state','not in',('draft','cancel'))]" help="Approved purchase orders"/> <filter icon="terp-check" name="approved" string="Purchase Orders" domain="[('state','not in',('draft','cancel'))]" help="Approved purchase orders"/>
<filter icon="terp-gtk-go-back-rtl" name="not_invoiced" string="Not Invoiced" domain="[('invoice_ids','=', False)]" help="Purchase orders that include lines not invoiced."/> <filter icon="terp-gtk-go-back-rtl" name="not_invoiced" string="Not Invoiced" domain="[('invoice_ids','=', False)]" help="Purchase orders that include lines not invoiced."/>
@ -336,7 +386,6 @@
</record> </record>
<menuitem action="purchase_form_action" id="menu_purchase_form_action" parent="menu_procurement_management" sequence="6"/> <menuitem action="purchase_form_action" id="menu_purchase_form_action" parent="menu_procurement_management" sequence="6"/>
<record id="purchase_order_line_form" model="ir.ui.view"> <record id="purchase_order_line_form" model="ir.ui.view">
<field name="name">purchase.order.line.form</field> <field name="name">purchase.order.line.form</field>
<field name="model">purchase.order.line</field> <field name="model">purchase.order.line</field>
@ -344,9 +393,6 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Purchase Order Line" version="7.0"> <form string="Purchase Order Line" version="7.0">
<sheet> <sheet>
<label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1>
<label for="product_id" class="oe_edit_only"/>
<group> <group>
<group> <group>
<field name="product_id" on_change="onchange_product_id(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,price_unit,notes,context)"/> <field name="product_id" on_change="onchange_product_id(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,price_unit,notes,context)"/>
@ -356,23 +402,23 @@
<field name="product_uom" groups="product.group_uom" on_change="onchange_product_uom(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,price_unit,notes,context)" class="oe_inline"/> <field name="product_uom" groups="product.group_uom" on_change="onchange_product_uom(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,price_unit,notes,context)" class="oe_inline"/>
</div> </div>
<field name="price_unit"/> <field name="price_unit"/>
<field name="taxes_id" widget="many2many_tags" domain="[('parent_id','=',False),('type_tax_use','!=','sale')]"/>
</group> </group>
<group> <group>
<field name="name"/>
<field name="date_planned" widget="date"/> <field name="date_planned" widget="date"/>
<field name="account_analytic_id" colspan="2" groups="purchase.group_analytic_accounting" domain="[('parent_id','!=',False)]" />
<field name="company_id" groups="base.group_multi_company" widget="selection"/> <field name="company_id" groups="base.group_multi_company" widget="selection"/>
<field name="account_analytic_id" colspan="4" groups="purchase.group_analytic_accounting" domain="[('parent_id','!=',False)]" />
<field name="taxes_id" widget="many2many_tags"
domain="[('parent_id','=',False),('type_tax_use','!=','sale')]"/>
</group> </group>
<group string="Notes" colspan="4"> <group string="Notes" colspan="4">
<field name="notes"/> <field name="notes" nolabel="1" placeholder="Add a note on the purchase line..."/>
</group> </group>
<group string="Invoices" colspan="4"> <group string="Invoices" colspan="4">
<field name="invoiced"/> <field name="invoice_lines" nolabel="1"/>
<field name="invoice_lines" nolabel="1" colspan="2"/> </group>
<group string="Stock Moves" colspan="4">
<field name="move_ids" nolabel="1"/>
</group> </group>
<separator string="Stock Moves"/>
<field name="move_ids"/>
</group> </group>
</sheet> </sheet>
</form> </form>
@ -410,11 +456,11 @@
<label for="order_id" class="oe_edit_only"/> <label for="order_id" class="oe_edit_only"/>
<h1> <h1>
<field name="order_id" class="oe_inline"/> <field name="order_id" class="oe_inline"/>
<label string="," attrs="{'invisible':[('date_order','=',False)]}"/>
<field name="date_order" class="oe_inline"/> <field name="date_order" class="oe_inline"/>
</h1> </h1>
<label for="partner_id" class="oe_edit_only"/> <label for="partner_id" class="oe_edit_only"/>
<h2><field name="partner_id"/></h2> <h2><field name="partner_id"/></h2>
<group> <group>
<group> <group>
<field name="name"/> <field name="name"/>

View File

@ -24,27 +24,6 @@
</field> </field>
</record> </record>
<act_window
domain="[('purchase_id', '=', active_id)]"
id="act_purchase_order_2_stock_picking"
name="Incoming Shipments"
res_model="stock.picking.in"
src_model="purchase.order"
context="{'default_purchase_id': active_id, 'contact_display': 'partner', 'default_type': 'in'}" />
<record id="action_picking_in_tree_view" model="ir.actions.act_window.view">
<field eval="1" name="sequence"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="stock.view_picking_in_tree"/>
<field name="act_window_id" ref="act_purchase_order_2_stock_picking"/>
</record>
<record id="action_picking_in_form_view" model="ir.actions.act_window.view">
<field eval="2" name="sequence"/>
<field name="view_mode">form</field>
<field name="view_id" ref="stock.view_picking_in_form"/>
<field name="act_window_id" ref="act_purchase_order_2_stock_picking"/>
</record>
<record id="stock_picking_in_inherit_purchase" model="ir.ui.view"> <record id="stock_picking_in_inherit_purchase" model="ir.ui.view">
<field name="name">Incoming Picking Inherited</field> <field name="name">Incoming Picking Inherited</field>
<field name="model">stock.picking.in</field> <field name="model">stock.picking.in</field>
@ -78,6 +57,7 @@
<separator orientation="vertical"/> <separator orientation="vertical"/>
<field name="stock_journal_id" widget="selection"/> <field name="stock_journal_id" widget="selection"/>
<field name="company_id" widget="selection" groups="base.group_multi_company"/> <field name="company_id" widget="selection" groups="base.group_multi_company"/>
<field name="purchase_id" />
</group> </group>
<newline/> <newline/>
<group expand="0" string="Group By..." colspan="4" col="8"> <group expand="0" string="Group By..." colspan="4" col="8">
@ -96,7 +76,33 @@
</search> </search>
</field> </field>
</record> </record>
<record id="act_purchase_order_2_stock_picking" model="ir.actions.act_window">
<field name="name">Incoming Shipments</field>
<field name="res_model">stock.picking.in</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar</field>
<field name="domain">[('type','=','in')]</field>
<field name="context">{'search_default_purchase_id': active_id,'default_type': 'in'}</field>
<field name="search_view_id" ref="view_picking_in_search_picking_to_invoice"/>
</record>
<record id="purchase_order_2_stock_picking" model="ir.ui.view">
<field name="name">Purchase Picking Inherited</field>
<field name="model">purchase.order</field>
<field name="type">form</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<xpath expr="//div[contains(@class, 'oe_title')]" position="before">
<div class="oe_right oe_button_box" name="buttons">
<button type="action"
name="%(act_purchase_order_2_stock_picking)d"
string="Incoming Shipments" states="approved"/>
</div>
</xpath>
</field>
</record>
<record id="action_picking_tree4_picking_to_invoice" model="ir.actions.act_window"> <record id="action_picking_tree4_picking_to_invoice" model="ir.actions.act_window">
<field name="name">Based on Incoming Shipments</field> <field name="name">Based on Incoming Shipments</field>
<field name="res_model">stock.picking</field> <field name="res_model">stock.picking</field>

View File

@ -183,13 +183,6 @@ class purchase_requisition(osv.osv):
return res return res
def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, [])
for obj in self.browse(cr, uid, ids, context=context):
if (obj.state == 'draft') and obj.user_id:
result[obj.id] = [obj.user_id.id]
return result
def create_send_note(self, cr, uid, ids, context=None): def create_send_note(self, cr, uid, ids, context=None):
return self.message_append_note(cr, uid, ids, body=_("Purchase Requisition has been <b>created</b>."), context=context) return self.message_append_note(cr, uid, ids, body=_("Purchase Requisition has been <b>created</b>."), context=context)

View File

@ -8,7 +8,7 @@
<field name="model">purchase.order</field> <field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/> <field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="shipped" position="after"> <field name="validator" position="before">
<field name="requisition_id"/> <field name="requisition_id"/>
</field> </field>
</field> </field>
@ -41,12 +41,13 @@
</header> </header>
<sheet> <sheet>
<div class="oe_edit_only"> <div class="oe_edit_only">
<label for="name" class="oe_inline"/>, <label for="name" class="oe_inline"/>
<label for="origin" class="oe_inline"/> <label for="origin" class="oe_inline"/>
</div> </div>
<h1> <h1>
<field name="name" class="oe_inline"/>, <field name="name" class="oe_inline"/>
<field name="origin" class="oe_inline"/> <label string="," attrs="{'invisible':[('origin','=',False)]}"/>
<field name="origin" class="oe_inline" placeholder="PO0025"/>
</h1> </h1>
<group> <group>
<group> <group>

View File

@ -13,7 +13,7 @@
</field> </field>
<xpath expr="//h4[@class='oe_partner_heading']" position="after"> <xpath expr="//h4[@class='oe_partner_heading']" position="after">
<a name="%(sale.act_res_partner_2_sale_order)d" type="action"> <a name="%(sale.act_res_partner_2_sale_order)d" type="action">
<t t-if="record.sale_order_count.value">Sales(<t t-esc="record.sale_order_count.value" />)</t> <t t-if="record.sale_order_count.value"><t t-esc="record.sale_order_count.value" /> Sales</t>
</a> </a>
</xpath> </xpath>
</field> </field>

View File

@ -1022,10 +1022,10 @@ class sale_order(osv.osv):
# ------------------------------------------------ # ------------------------------------------------
def get_needaction_user_ids(self, cr, uid, ids, context=None): def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = dict.fromkeys(ids, []) result = super(sale_order, self).get_needaction_user_ids(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if (obj.state == 'manual' or obj.state == 'progress'): if (obj.state == 'manual' or obj.state == 'progress'):
result[obj.id] = [obj.user_id.id] result[obj.id].append(obj.user_id.id)
return result return result
def create_send_note(self, cr, uid, ids, context=None): def create_send_note(self, cr, uid, ids, context=None):

View File

@ -12,15 +12,16 @@
<form string="Sales Shop" version="7.0"> <form string="Sales Shop" version="7.0">
<label for="name" class="oe_edit_only"/> <label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1> <h1><field name="name"/></h1>
<label for="warehouse_id" class="oe_edit_only"/>
<h2><field name="warehouse_id" required="1"/></h2>
<group> <group>
<group>
<field name="warehouse_id" required="1" widget="selection"/>
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
</group>
<group> <group>
<field name="payment_default_id"/> <field name="payment_default_id"/>
<field domain="[('type','=','sale')]" name="pricelist_id" groups="product.group_sale_pricelist"/> <field domain="[('type','=','sale')]" name="pricelist_id" groups="product.group_sale_pricelist"/>
</group>
<group>
<field name="project_id" groups="analytic.group_analytic_accounting"/> <field name="project_id" groups="analytic.group_analytic_accounting"/>
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
</group> </group>
</group> </group>
</form> </form>
@ -53,6 +54,43 @@
<menuitem action="action_shop_form" id="menu_action_shop_form" parent="base.menu_base_config" sequence="35" <menuitem action="action_shop_form" id="menu_action_shop_form" parent="base.menu_base_config" sequence="35"
groups="stock.group_locations"/> groups="stock.group_locations"/>
<!-- Sale order Read/Unread actions -->
<record id="actions_server_sale_order_unread" model="ir.actions.server">
<field name="name">Mark unread</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_sale_order"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_sale_order_unread" model="ir.values">
<field name="name">action_sale_order_unread</field>
<field name="action_id" ref="actions_server_sale_order_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_sale_order_unread'))" />
<field name="key">action</field>
<field name="model_id" ref="model_sale_order" />
<field name="model">sale.order</field>
<field name="key2">client_action_multi</field>
</record>
<record id="actions_server_sale_order_read" model="ir.actions.server">
<field name="name">Mark read</field>
<field name="condition">True</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_sale_order"/>
<field name="state">code</field>
<field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
</record>
<record id="action_sale_order_read" model="ir.values">
<field name="name">action_sale_order_read</field>
<field name="action_id" ref="actions_server_sale_order_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_sale_order_read'))" />
<field name="key">action</field>
<field name="model_id" ref="model_sale_order" />
<field name="model">sale.order</field>
<field name="key2">client_action_multi</field>
</record>
<record id="view_sale_order_calendar" model="ir.ui.view"> <record id="view_sale_order_calendar" model="ir.ui.view">
<field name="name">sale.order.calendar</field> <field name="name">sale.order.calendar</field>
<field name="model">sale.order</field> <field name="model">sale.order</field>
@ -297,6 +335,11 @@
<search string="Search Sales Order"> <search string="Search Sales Order">
<field name="name" string="Sales Order" filter_domain="['|',('name','ilike',self),('client_order_ref','ilike',self)]"/> <field name="name" string="Sales Order" filter_domain="['|',('name','ilike',self),('client_order_ref','ilike',self)]"/>
<separator orientation="vertical"/> <separator orientation="vertical"/>
<filter icon="terp-mail-message-new"
string="Inbox" help="Unread messages"
name="needaction_pending"
domain="[('needaction_pending','=',True)]"/>
<separator orientation="vertical"/>
<filter icon="terp-document-new" string="Quotations" name="draft" domain="[('state','in',('draft','sent'))]" help="Sales Order that haven't yet been confirmed"/> <filter icon="terp-document-new" string="Quotations" name="draft" domain="[('state','in',('draft','sent'))]" help="Sales Order that haven't yet been confirmed"/>
<filter icon="terp-check" string="Sales" name="sales" domain="[('state','in',('manual','progress'))]"/> <filter icon="terp-check" string="Sales" name="sales" domain="[('state','in',('manual','progress'))]"/>
<filter icon="terp-dolar_ok!" string="To Invoice" domain="[('state','=','manual')]" help="Sales Order ready to be invoiced"/> <filter icon="terp-dolar_ok!" string="To Invoice" domain="[('state','=','manual')]" help="Sales Order ready to be invoiced"/>

View File

@ -1,7 +1,4 @@
button.oe_share_mail { /* Added invite button, hidden by default */
display: none; button.oe_share_invite {
}
a.oe_share_link, a.oe_share {
display: none; display: none;
} }

View File

@ -50,29 +50,46 @@ openerp.share = function(session) {
session.connection.share_flag.done(yes).fail(no); session.connection.share_flag.done(yes).fail(no);
} }
/* Extend the Sidebar to add Share and Embed links in the 'More' menu */
session.web.Sidebar = session.web.Sidebar.extend({ session.web.Sidebar = session.web.Sidebar.extend({
add_default_sections: function() {
this._super(); start: function() {
var self = this; var self = this;
this._super(this);
has_share(function() { has_share(function() {
self.add_items('other', [{ self.add_items('other', [
label: 'Share', { label: 'Share',
callback: self.on_sidebar_click_share, callback: self.on_click_share,
classname: 'oe_share', classname: 'oe_share' },
}]); { label: 'Embed',
callback: self.on_click_share_link,
classname: 'oe_share' },
]);
}); });
}, },
on_sidebar_click_share: function(item) {
on_click_share: function(item) {
var view = this.getParent() var view = this.getParent()
launch_wizard(this, view); launch_wizard(this, view, 'emails', false);
},
on_click_share_link: function(item) {
var view = this.getParent()
launch_wizard(this, view, 'embedded', false);
}, },
}); });
/**
* Extends mail (Chatter widget)
* - show the 'invite' button' only we came on the form view through
* an action. We do this because 'invite' is based on the share
* mechanism, and it tries to share an action.
*/
session.mail.RecordThread.include( { session.mail.RecordThread.include( {
start: function() { start: function() {
start_res = this._super.apply(this, arguments); start_res = this._super.apply(this, arguments);
if (has_action_id) { if (has_action_id) {
this.$element.find('button.oe_share_mail').show(); this.$element.find('button.oe_share_invite').show();
} }
return start_res; return start_res;
} }
@ -83,12 +100,7 @@ openerp.share = function(session) {
var self = this; var self = this;
this.check_if_action_is_defined(); this.check_if_action_is_defined();
has_share(function() { has_share(function() {
self.$element.find('a.oe_share_link').click(self.on_click_share_link); self.$element.delegate('button.oe_share_invite', 'click', self.on_click_share_invite);
self.$element.find('a.oe_share').click(self.on_click_share);
self.$element.delegate('button.oe_share_mail', 'click', self.on_click_share_mail);
}, function() {
self.$element.find('a.oe_share_link').remove();
self.$element.find('a.oe_share').remove();
}); });
return this._super.apply(this, arguments); return this._super.apply(this, arguments);
}, },
@ -96,23 +108,13 @@ openerp.share = function(session) {
check_if_action_is_defined: function() { check_if_action_is_defined: function() {
if (this.action && this.action.id) { if (this.action && this.action.id) {
has_action_id = true; has_action_id = true;
this.$element.find('a.oe_share_link').show();
this.$element.find('a.oe_share').show();
} }
else { else {
has_action_id = false; has_action_id = false;
} }
}, },
on_click_share_link: function(e) { on_click_share_invite: function(e) {
e.preventDefault();
launch_wizard(this, this.views[this.active_view].controller, 'embedded', false);
},
on_click_share: function(e) {
e.preventDefault();
launch_wizard(this, this.views[this.active_view].controller, 'emails', false);
},
on_click_share_mail: function(e) {
e.preventDefault(); e.preventDefault();
launch_wizard(this, this.views[this.active_view].controller, 'emails', true); launch_wizard(this, this.views[this.active_view].controller, 'emails', true);
}, },

View File

@ -3,18 +3,11 @@
--> -->
<templates id="template" xml:space="preserve"> <templates id="template" xml:space="preserve">
<t t-extend="ViewManagerAction"> <!-- Extends Chatter widget in form view to add the invite button -->
<t t-jquery=".oe_shortcuts_toggle" t-operation="after"> <t t-extend="mail.RecordThread">
<a class="oe_share_link" href="#share_link" title="Link or embed..."><img t-att-src='_s + "/share/static/src/img/share.png"'/></a>
<a class="oe_share" href="#share" title="Share with..."><img t-att-src='_s + "/share/static/src/img/share.png"'/></a>
</t>
</t>
<t t-extend="RecordThread">
<t t-jquery="button.oe_mail_button_unfollow" t-operation="after"> <t t-jquery="button.oe_mail_button_unfollow" t-operation="after">
<button type="button" class="oe_share_mail oe_mail_button_mouseout">Invite</button> <button type="button" class="oe_share_invite">Invite</button>
</t> </t>
</t> </t>
</templates> </templates>

View File

@ -48,7 +48,7 @@ RANDOM_PASS_CHARACTERS = 'aaaabcdeeeefghjkmnpqrstuvwxyzAAAABCDEEEEFGHJKLMNPQRSTU
def generate_random_pass(): def generate_random_pass():
return ''.join(random.sample(RANDOM_PASS_CHARACTERS,10)) return ''.join(random.sample(RANDOM_PASS_CHARACTERS,10))
class share_wizard(osv.osv_memory): class share_wizard(osv.TransientModel):
_name = 'share.wizard' _name = 'share.wizard'
_description = 'Share Wizard' _description = 'Share Wizard'
@ -177,9 +177,10 @@ class share_wizard(osv.osv_memory):
'name': fields.char('Share Title', size=64, required=True, help="Title for the share (displayed to users as menu and shortcut name)"), 'name': fields.char('Share Title', size=64, required=True, help="Title for the share (displayed to users as menu and shortcut name)"),
'record_name': fields.char('Record name', size=128, help="Name of the shared record, if sharing a precise record"), 'record_name': fields.char('Record name', size=128, help="Name of the shared record, if sharing a precise record"),
'message': fields.text("Personal Message", help="An optional personal message, to be included in the email notification."), 'message': fields.text("Personal Message", help="An optional personal message, to be included in the email notification."),
'embed_code': fields.function(_embed_code, type='text', string='Code',
'embed_code': fields.function(_embed_code, type='text'), help="Embed this code in your documents to provide a link to the "\
'embed_option_title': fields.boolean("Display title"), "shared document."),
'embed_option_title': fields.boolean('Display title'),
'embed_option_search': fields.boolean('Display search view'), 'embed_option_search': fields.boolean('Display search view'),
'embed_url': fields.function(_embed_url, string='Share URL', type='char', size=512, readonly=True), 'embed_url': fields.function(_embed_url, string='Share URL', type='char', size=512, readonly=True),
} }
@ -903,8 +904,11 @@ class share_result_line(osv.osv_memory):
def _share_url(self, cr, uid, ids, _fieldname, _args, context=None): def _share_url(self, cr, uid, ids, _fieldname, _args, context=None):
result = dict.fromkeys(ids, '') result = dict.fromkeys(ids, '')
for this in self.browse(cr, uid, ids, context=context): for this in self.browse(cr, uid, ids, context=context):
data = dict(dbname=cr.dbname, login=this.login, password='') data = dict(dbname=cr.dbname, login=this.login, password=this.password)
result[this.id] = this.share_wizard_id.share_url_template() % data if this.share_wizard_id and this.share_wizard_id.action_id:
data['action_id'] = this.share_wizard_id.action_id.id
ctx = dict(context, share_url_template_hash_arguments=['action_id'])
result[this.id] = this.share_wizard_id.share_url_template(context=ctx) % data
return result return result
_columns = { _columns = {

View File

@ -39,17 +39,20 @@
<group> <group>
<field name="user_type" invisible="1"/> <field name="user_type" invisible="1"/>
<field name="invite" invisible="1"/> <field name="invite" invisible="1"/>
</group> </group>
<group> <group>
<group name="emails_group" attrs="{'invisible':['|', ('user_type', '!=', 'emails'), ('invite', '=', True)]}" string="Share with these People (one email per line)"> <group colspan="4" name="emails_group" attrs="{'invisible':['|', ('user_type', '!=', 'emails'), ('invite', '=', True)]}"
<field colspan="2" nolabel="1" name="new_users" attrs="{'required':[('user_type','=','emails'), ('invite', '!=', True)]}"/> string="Share with these People (one email per line)">
<field nolabel="1" name="new_users" attrs="{'required':[('user_type','=','emails'), ('invite', '!=', True)]}"/>
</group> </group>
<group name="email_lines" attrs="{'invisible':[('invite', '!=', True)]}" string="Share with these People (one email per line)"> <group colspan="4" name="email_lines" attrs="{'invisible':['|', ('invite', '!=', True), ('user_type', '!=', 'emails')]}"
string="Share with these People (one email per line)">
<field name="email_1"/> <field name="email_1"/>
<field name="email_2"/> <field name="email_2"/>
<field name="email_3"/> <field name="email_3"/>
</group> </group>
<group attrs="{'invisible':[('user_type', '=', 'embedded')]}" string="Include an Optional Personal Message"> <group colspan="4" attrs="{'invisible':[('user_type', '=', 'embedded')]}"
string="Include an Optional Personal Message">
<field name="message" colspan="2" nolabel="1"/> <field name="message" colspan="2" nolabel="1"/>
</group> </group>
<group attrs="{'invisible':[('invite', '=', True)]}" string="Sharing Options"> <group attrs="{'invisible':[('invite', '=', True)]}" string="Sharing Options">
@ -71,8 +74,8 @@
<field name="user_type" invisible="1"/> <field name="user_type" invisible="1"/>
<field name="access_mode" invisible="1"/> <field name="access_mode" invisible="1"/>
</header> </header>
<group attrs="{'invisible':[('user_type','=','embedded')]}"> <group attrs="{'invisible':[('user_type','=','embedded')]}"
<separator string="An email notification with instructions has been sent to the following people:"/> string="An email notification with instructions has been sent to the following people:">
<field name="result_line_ids" nolabel="1" mode="tree"> <field name="result_line_ids" nolabel="1" mode="tree">
<tree string="Summary"> <tree string="Summary">
<field name="login"/> <field name="login"/>
@ -85,14 +88,17 @@
</field> </field>
</group> </group>
<group colspan="4" col="1" attrs="{'invisible':[('user_type','!=','embedded')]}"> <group colspan="4" col="1" attrs="{'invisible':[('user_type','!=','embedded')]}">
<separator string="Use this Link"/> <group string="Use this link">
<field name="embed_url"/> <field name="embed_url"/>
<separator string="Or insert the following code where you want to embed your documents"/> </group>
<group string="Options"> <group string="Or insert the following code where you want to embed your documents">
<field name="embed_option_title" on_change="onchange_embed_options(embed_option_title, embed_option_search)"/>
<field name="embed_option_search" on_change="onchange_embed_options(embed_option_title, embed_option_search)" attrs="{'invisible':[('access_mode','=','readonly')]}"/>
<field name="embed_code"/> <field name="embed_code"/>
</group> </group>
<group string="Embedded code options">
<field name="embed_option_title" on_change="onchange_embed_options(embed_option_title, embed_option_search)"/>
<field name="embed_option_search" on_change="onchange_embed_options(embed_option_title, embed_option_search)"
attrs="{'invisible':[('access_mode','=','readonly')]}"/>
</group>
</group> </group>
</form> </form>

View File

@ -21,14 +21,14 @@
<field name="type">form</field> <field name="type">form</field>
<field name="inherit_id" ref="product.product_category_form_view"/> <field name="inherit_id" ref="product.product_category_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form position="inside" version="7.0"> <data>
<group string="Accounting Stock Properties"> <xpath expr="/form/sheet//group[@name='account_stock_property']" position="inside">
<field name="property_stock_account_input_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/> <field name="property_stock_account_input_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="property_stock_account_output_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/> <field name="property_stock_account_output_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="property_stock_valuation_account_id" domain="[('type','&lt;&gt;','view'), ('type','&lt;&gt;','consolidation')]"/> <field name="property_stock_valuation_account_id" domain="[('type','&lt;&gt;','view'), ('type','&lt;&gt;','consolidation')]"/>
<field name="property_stock_journal"/> <field name="property_stock_journal"/>
</group> </xpath>
</form> </data>
</field> </field>
</record> </record>

View File

@ -790,7 +790,7 @@
<button name="force_assign" states="confirmed" string="Force Availability" type="object" icon="gtk-jump-to"/> <button name="force_assign" states="confirmed" string="Force Availability" type="object" icon="gtk-jump-to"/>
<button name="action_confirm" states="draft" string="Confirm" type="object" icon="gtk-apply"/> <button name="action_confirm" states="draft" string="Confirm" type="object" icon="gtk-apply"/>
<button name="cancel_assign" states="assigned" string="Cancel Availability" type="object" icon="gtk-find"/> <button name="cancel_assign" states="assigned" string="Cancel Availability" type="object" icon="gtk-find"/>
<field name="state" widget="statusbar" status_visible="draft,assigned,done" /> <field name="state" widget="statusbar" statusbar_visible="draft,assigned,done" />
</header> </header>
<group> <group>
<group string="Move Information"> <group string="Move Information">
@ -1419,50 +1419,47 @@
<label for="product_qty"/> <label for="product_qty"/>
<div> <div>
<field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos)" class="oe_inline"/> <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos)" class="oe_inline"/>
<field name="product_uom" string="Unit Of Measure" groups="product.group_uom" class="oe_inline"/> <field name="product_uom" string="Unit Of Measure" groups="product.group_uom" class="oe_inline"/>
<button name="%(stock.move_scrap)d" <button name="%(stock.move_scrap)d"
string="Scrap" type="action" string="Scrap" type="action"
icon="gtk-convert" context="{'scrap': True}" icon="gtk-convert" context="{'scrap': True}"
states="draft,waiting,confirmed,assigned"/> states="draft,waiting,confirmed,assigned" colspan="1"/>
</div> </div>
<label for="product_uos_qty"/> <label for="product_uos_qty"/>
<div> <div>
<field name="product_uos_qty" groups="product.group_uos" class="oe_inline" <field name="product_uos_qty" groups="product.group_uos" class="oe_inline"
on_change="onchange_uos_quantity(product_id, product_uos_qty, product_uos, product_uom)"/> on_change="onchange_uos_quantity(product_id, product_uos_qty, product_uos, product_uom)"/>
<field name="product_uos" groups="product.group_uos"/> <field name="product_uos" groups="product.group_uos" class="oe_inline"/>
</div> </div>
<field name="name" string="Reason"/> <field name="name" string="Reason"/>
</group> <field name="company_id" groups="base.group_multi_company"/>
<group>
<field name="picking_id"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
<field name="location_id" groups="stock.group_locations"/> <field name="location_id" groups="stock.group_locations"/>
<field name="location_dest_id" groups="stock.group_locations"/> <field name="location_dest_id" groups="stock.group_locations"/>
<field name="partner_id" groups="stock.group_locations"/> <field name="partner_id" groups="stock.group_locations"/>
<field name="create_date" groups="base.group_no_one" />
<field name="date" groups="base.group_no_one" />
<field name="date_expected" on_change="onchange_date(date,date_expected)"/>
</group> </group>
<group> <group>
<label name="tracking_id"/> <field name="picking_id"/>
<field name="create_date" groups="base.group_no_one" />
<field name="date" groups="base.group_no_one" string="Move Date"/>
<field name="date_expected" on_change="onchange_date(date,date_expected)"/>
<label for="tracking_id"/>
<div> <div>
<field name="tracking_id" groups="stock.group_tracking_lot" class="oe_inline"/> <field name="tracking_id" groups="stock.group_tracking_lot" class="oe_inline"/>
<button name="%(split_into)d" string="New Pack" type="action" <button name="%(split_into)d" string="New Pack" type="action"
groups="product.group_stock_packaging" groups="product.group_stock_packaging"
icon="terp-stock_effects-object-colorize" icon="terp-stock_effects-object-colorize"
states="draft,assigned,confirmed,done" colspan="1"/> states="draft,assigned,confirmed,done" class="oe_inline"/>
</div> </div>
<label name="prodlot_id"/> <label for="prodlot_id"/>
<div> <div>
<field name="prodlot_id" groups="stock.group_production_lot" <field name="prodlot_id" groups="stock.group_production_lot"
context="{'location_id':location_id, 'product_id':product_id}" context="{'location_id':location_id, 'product_id':product_id}"
domain="[('product_id','=?',product_id)]" class="oe_inline" domain="[('product_id','=?',product_id)]" class="oe_inline"
on_change="onchange_lot_id(prodlot_id,product_qty, location_id, product_id, product_uom)"/> on_change="onchange_lot_id(prodlot_id,product_qty, location_id, product_id, product_uom)"/>
<button name="%(track_line)d" <button name="%(track_line)d"
groups="stock.group_tracking_lot" class="oe_inline" groups="stock.group_tracking_lot" class="oe_inline"
states="draft,waiting,confirmed,assigned,done" states="draft,waiting,confirmed,assigned,done"
string="Split" type="action" icon="terp-stock_effects-object-colorize"/> string="Split" type="action" icon="terp-stock_effects-object-colorize" />
</div> </div>
</group> </group>
</group> </group>
@ -1612,13 +1609,6 @@
res_model="stock.move" res_model="stock.move"
src_model="product.product"/> src_model="product.product"/>
<act_window
domain="[('move_lines','=',active_id)]"
id="act_relate_picking"
name="Related Picking"
res_model="stock.picking"
src_model="stock.move"/>
<act_window <act_window
context="{'search_default_future': 1,'search_default_product_id': [active_id], 'default_product_id': active_id}" context="{'search_default_future': 1,'search_default_product_id': [active_id], 'default_product_id': active_id}"
domain="[('state','in',('waiting','confirmed','assigned'))]" domain="[('state','in',('waiting','confirmed','assigned'))]"

View File

@ -129,16 +129,22 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Wiki" version="7.0"> <form string="Wiki" version="7.0">
<sheet> <sheet>
<group col="6" colspan="4"> <div class="oe_title">
<field name="name" colspan="6"/> <label for="name" class="oe_edit_only"/>
<field name="group_id" string="Topic" on_change="onchange_group_id(group_id, text_area)"/> <h1><field name="name" select="1" /></h1>
<field name="parent_id" domain="[('group_id','=',group_id)]"/> <label for="group_id" class="oe_edit_only"/>
<field name="section"/> <h2>
<field name="group_id" string="Topic" select="1" on_change="onchange_group_id(group_id, text_area)"/></h2>
</div>
<group>
<group>
<field name="parent_id" domain="[('group_id','=',group_id)]"/>
<field name="section"/>
</group>
</group> </group>
<notebook colspan="4"> <notebook colspan="4">
<page string="Content"> <page string="Content">
<separator colspan="4" string="Page Content"/> <field name="text_area" nolabel="1" colspan="4" widget="text_wiki" placeholder="Wiki Content"/>
<field name="text_area" nolabel="1" colspan="4" widget="text_wiki"/>
</page> </page>
</notebook> </notebook>
<group col="2" colspan="2" groups="base.group_no_one"> <group col="2" colspan="2" groups="base.group_no_one">