[MERGE]:Merge with lp:~openerp-dev/openobject-addons/trunk-dev-addons1

bzr revid: sbh@tinyerp.com-20100609045848-ysb4bhc8l8zd2fjm
This commit is contained in:
sbh (Open ERP) 2010-06-09 10:28:48 +05:30
commit 64d9c8b104
197 changed files with 6333 additions and 3090 deletions

View File

@ -183,7 +183,7 @@ class account_account(osv.osv):
temp.append(x)
ids2 += self._get_children_and_consol(cr, uid, temp, context)
return ids2
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
if context is None:
@ -320,7 +320,7 @@ class account_account(osv.osv):
level = obj.level + 1
res[account.id] = level
return res
_columns = {
'name': fields.char('Name', size=128, required=True, select=True),
'currency_id': fields.many2one('res.currency', 'Secondary Currency', help="Forces all moves for this account to have this secondary currency."),
@ -477,7 +477,7 @@ class account_account(osv.osv):
def _check_moves(self, cr, uid, ids, method, context):
line_obj = self.pool.get('account.move.line')
account_ids = self.search(cr, uid, [('id', 'child_of', ids)])
if line_obj.search(cr, uid, [('account_id', 'in', account_ids)]):
if method == 'write':
raise osv.except_osv(_('Error !'), _('You cannot deactivate an account that contains account moves.'))
@ -511,7 +511,7 @@ class account_account(osv.osv):
context = {}
if 'active' in vals and not vals['active']:
self._check_moves(cr, uid, ids, "write", context)
if 'type' in vals.keys():
if 'type' in vals.keys():
self._check_allow_type_change(cr, uid, ids, vals['type'], context=context)
return super(account_account, self).write(cr, uid, ids, vals, context=context)
@ -559,7 +559,7 @@ class account_journal(osv.osv):
_columns = {
'name': fields.char('Journal Name', size=64, required=True, translate=True),
'code': fields.char('Code', size=16),
'type': fields.selection([('sale', 'Sale'), ('purchase', 'Purchase'), ('expanse', 'Expanse'), ('cash', 'Cash'), ('bank', 'Bank'), ('general', 'General'), ('situation', 'Situation')], 'Type', size=32, required=True,
'type': fields.selection([('sale', 'Sale'), ('purchase', 'Purchase'), ('expense', 'Expense'), ('cash', 'Cash'), ('bank', 'Bank'), ('general', 'General'), ('situation', 'Situation')], 'Type', size=32, required=True,
help="Select 'Sale' for Sale journal to be used at the time of making invoice."\
" Select 'Purchase' for Purchase Journal to be used at the time of approving purchase order."\
" Select 'Cash' to be used at the time of making payment."\
@ -683,7 +683,7 @@ class account_fiscalyear(osv.osv):
else:
return False
return ids[0]
def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=80):
if args is None:
args = []
@ -695,7 +695,7 @@ class account_fiscalyear(osv.osv):
if not ids:
ids = self.search(cr, user, [('name',operator,name)]+ args, limit=limit)
return self.name_get(cr, user, ids, context=context)
account_fiscalyear()
class account_period(osv.osv):
@ -771,7 +771,7 @@ class account_period(osv.osv):
cr.execute('update account_journal_period set state=%s where period_id=%s', (mode, id))
cr.execute('update account_period set state=%s where id=%s', (mode, id))
return True
def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=80):
if args is None:
args = []
@ -1375,7 +1375,7 @@ class account_tax_code(osv.osv):
return False
level -= 1
return True
def copy(self, cr, uid, id, default=None, context=None):
if default is None:
@ -1383,7 +1383,7 @@ class account_tax_code(osv.osv):
default = default.copy()
default.update({'line_ids': []})
return super(account_tax_code, self).copy(cr, uid, id, default, context)
_constraints = [
(_check_recursion, 'Error ! You can not create recursive accounts.', ['parent_id'])
]
@ -1441,6 +1441,7 @@ class account_tax(osv.osv):
'include_base_amount': fields.boolean('Included in base amount', help="Indicates if the amount of tax must be included in the base amount for the computation of the next taxes"),
'company_id': fields.many2one('res.company', 'Company', required=True),
'description': fields.char('Tax Code',size=32),
'price_include': fields.boolean('Tax Included in Price', help="Check this if the price you use on the product and invoices includes this tax."),
'type_tax_use': fields.selection([('sale','Sale'),('purchase','Purchase'),('all','All')], 'Tax Application', required=True)
}
@ -1473,6 +1474,7 @@ class account_tax(osv.osv):
'applicable_type': lambda *a: 'true',
'type': lambda *a: 'percent',
'amount': lambda *a: 0,
'price_include': lambda *a: 0,
'active': lambda *a: 1,
'type_tax_use': lambda *a: 'all',
'sequence': lambda *a: 1,
@ -1963,13 +1965,12 @@ class account_add_tmpl_wizard(osv.osv_memory):
if not tids or not tids[0]['parent_id']:
return False
ptids = tmpl_obj.read(cr, uid, [tids[0]['parent_id'][0]],['code'])
res = None
if not ptids or not ptids[0]['code']:
raise osv.except_osv(_('Error !'), _('Cannot locate parent code for template account!'))
res = acc_obj.search(cr,uid,[('code','=',ptids[0]['code'])])
if res:
return res[0]
else:
return False
return res and res[0] or False
_columns = {
'cparent_id':fields.many2one('account.account', 'Parent target', help="Creates an account with the selected template under this existing parent.", required=True),

View File

@ -530,9 +530,8 @@ class account_move_line(osv.osv):
date = datetime.now().strftime('%Y-%m-%d')
part = self.pool.get('res.partner').browse(cr, uid, partner_id)
if part.property_payment_term and part.property_payment_term.line_ids:
payterm = part.property_payment_term.line_ids[0]
res = self.pool.get('account.payment.term').compute(cr, uid, payterm.id, 100, date)
if part.property_payment_term:
res = self.pool.get('account.payment.term').compute(cr, uid, part.property_payment_term.id, 100, date)
if res:
val['date_maturity'] = res[0][0]
if not account_id:
@ -540,10 +539,10 @@ class account_move_line(osv.osv):
id2 = part.property_account_receivable.id
if journal:
jt = self.pool.get('account.journal').browse(cr, uid, journal).type
if jt=='sale':
if jt == 'sale':
val['account_id'] = self.pool.get('account.fiscal.position').map_account(cr, uid, part and part.property_account_position or False, id2)
elif jt=='purchase':
elif jt == 'purchase':
val['account_id'] = self.pool.get('account.fiscal.position').map_account(cr, uid, part and part.property_account_position or False, id1)
if val.get('account_id', False):
d = self.onchange_account_id(cr, uid, ids, val['account_id'])

View File

@ -283,32 +283,32 @@
<separator string="Journal View" colspan="4"/>
<field name="view_id"/>
</group>
<group colspan="2" col="2">
<separator string="Sequence" colspan="4"/>
<field name="sequence_id"/>
<field name="invoice_sequence_id"/>
</group>
<group colspan="2" col="2">
<separator string="Accounts" colspan="4"/>
<field name="default_debit_account_id" attrs="{'required':[('type','=','cash')]}" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="default_credit_account_id" attrs="{'required':[('type','=','cash')]}" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
</group>
<group colspan="2" col="2">
<separator string="Validations" colspan="4"/>
<separator string="Validations" colspan="4"/>
<field name="allow_date" groups="base.group_extended"/>
</group>
<group colspan="2" col="2">
<separator string="Company" colspan="4"/>
<separator string="Company" colspan="4"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="user_id" groups="base.group_extended"/>
<field name="currency"/>
</group>
<group colspan="2" col="2">
<separator string="Other Configuration" colspan="4"/>
<separator string="Other Configuration" colspan="4"/>
<field name="centralisation"/>
<field name="group_invoice_lines"/>
<field name="update_posted"/>
@ -623,6 +623,7 @@
<field name="arch" type="xml">
<tree string="Account Tax">
<field name="name"/>
<field name="price_include"/>
<field name="description"/>
</tree>
</field>
@ -654,6 +655,7 @@
<label colspan="2" nolabel="1" string="Keep empty to use the expense account"/>
<field groups="base.group_extended" name="child_depend"/>
<field groups="base.group_extended" name="sequence"/>
<field groups="base.group_extended" name="price_include"/>
<field name="type_tax_use"/>
<newline/>
<field colspan="4" groups="base.group_extended" name="child_ids"/>
@ -1493,7 +1495,7 @@
<act_window domain="[('partner_id', '=', active_id), ('account_id.type', 'in', ['receivable', 'payable']), ('reconcile_id','=',False)]" id="act_account_partner_account_move_unreconciled" name="Unreconciled Receivables &amp; Payables" res_model="account.move.line" src_model="res.partner"/>
<act_window domain="[('partner_id', '=', active_id), ('account_id.type', 'in', ['receivable', 'payable'])]" id="act_account_partner_account_move_all" name="Receivables &amp; Payables" res_model="account.move.line" src_model="res.partner"/>
<act_window domain="[('partner_id', '=', active_id)]" id="act_account_partner_account_move" name="All Account Entries" res_model="account.move.line" src_model="res.partner"/>
<record id="view_account_addtmpl_wizard_form" model="ir.ui.view">

View File

@ -7,30 +7,30 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
"PO-Revision-Date: 2009-04-24 15:00+0000\n"
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
"PO-Revision-Date: 2010-06-02 08:19+0000\n"
"Last-Translator: jan@synkronized.be <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-04-17 04:08+0000\n"
"X-Launchpad-Export-Date: 2010-06-03 03:33+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: account
#: field:account.tax.template,description:0
msgid "Internal Name"
msgstr ""
msgstr "Interne naam"
#. module: account
#: view:account.tax.code:0
msgid "Account Tax Code"
msgstr ""
msgstr "Belasting code"
#. module: account
#: model:ir.actions.act_window,name:account.action_invoice_tree9
#: model:ir.ui.menu,name:account.menu_action_invoice_tree9
msgid "Unpaid Supplier Invoices"
msgstr ""
msgstr "Onbetaalde inkoopfacturen"
#. module: account
#: model:ir.ui.menu,name:account.menu_finance_entries
@ -50,12 +50,12 @@ msgstr ""
#. module: account
#: model:account.account.type,name:account.account_type_asset
msgid "Asset"
msgstr ""
msgstr "Activa"
#. module: account
#: constraint:ir.actions.act_window:0
msgid "Invalid model name in the action definition."
msgstr ""
msgstr "Ongeldige modelnaam in de actie-definitie."
#. module: account
#: help:account.journal,currency:0
@ -65,7 +65,7 @@ msgstr ""
#. module: account
#: wizard_view:account_use_models,init_form:0
msgid "Select Message"
msgstr ""
msgstr "Kies bericht"
#. module: account
#: help:product.category,property_account_income_categ:0
@ -82,19 +82,19 @@ msgstr ""
#. module: account
#: wizard_view:account.automatic.reconcile,reconcile:0
msgid "Reconciliation result"
msgstr ""
msgstr "Afletterresultaat"
#. module: account
#: model:ir.actions.act_window,name:account.act_account_acount_move_line_open_unreconciled
msgid "Unreconciled entries"
msgstr ""
msgstr "Niet afgeletterde boekingen"
#. module: account
#: field:account.invoice.tax,base_code_id:0
#: field:account.tax,base_code_id:0
#: field:account.tax.template,base_code_id:0
msgid "Base Code"
msgstr ""
msgstr "Basiscode"
#. module: account
#: view:account.account:0
@ -2132,7 +2132,8 @@ msgid "Analytic Entry"
msgstr ""
#. module: account
#: view:res.company:0 field:res.company,overdue_msg:0
#: view:res.company:0
#: field:res.company,overdue_msg:0
msgid "Overdue Payments Message"
msgstr ""

View File

@ -951,23 +951,8 @@ class account_invoice(osv.osv):
return taxes.values()
def _log_event(self, cr, uid, ids, factor=1.0, name='Open Invoice'):
invs = self.read(cr, uid, ids, ['type','partner_id','amount_untaxed'])
for inv in invs:
part=inv['partner_id'] and inv['partner_id'][0]
pc = pr = 0.0
cr.execute('select sum(quantity*price_unit) from account_invoice_line where invoice_id=%s', (inv['id'],))
total = inv['amount_untaxed']
if inv['type'] in ('in_invoice','in_refund'):
partnertype='supplier'
eventtype = 'purchase'
pc = total*factor
else:
partnertype = 'customer'
eventtype = 'sale'
pr = total*factor
if self.pool.get('res.partner.event.type').check(cr, uid, 'invoice_open'):
self.pool.get('res.partner.event').create(cr, uid, {'name':'Invoice: '+name, 'som':False, 'description':name+' '+str(inv['id']), 'document':name, 'partner_id':part, 'date':time.strftime('%Y-%m-%d %H:%M:%S'), 'canal_id':False, 'user_id':uid, 'partner_type':partnertype, 'probability':1.0, 'planned_revenue':pr, 'planned_cost':pc, 'type':eventtype})
return len(invs)
#TODO: implement messages system
return True
def name_get(self, cr, uid, ids, context=None):
if not len(ids):

View File

@ -74,13 +74,13 @@
<page string="Accounting" position="inside">
<group col="2" colspan="2">
<separator string="Customer Accounting Properties" colspan="2"/>
<field name="property_account_receivable" />
<field name="property_account_receivable" groups="account.group_account_user" />
<field name="property_account_position" widget="selection"/>
<field name="property_payment_term" widget="selection"/>
</group>
<group col="2" colspan="2">
<separator string="Supplier Accounting Properties" colspan="2"/>
<field name="property_account_payable"/>
<field name="property_account_payable" groups="account.group_account_user"/>
</group>
<group col="2" colspan="2">
<separator string="Customer Credit" colspan="2"/>
@ -132,11 +132,13 @@
<field name="type">form</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Project">
<field name="contract_ids" colspan="4" nolabel="1" />
</page>
</notebook>
<xpath expr="//notebook[last()]" position="after">
<notebook colspan="4">
<page string="Project">
<field name="contract_ids" colspan="4" nolabel="1" />
</page>
</notebook>
</xpath>
</field>
</record>

View File

@ -22,9 +22,15 @@
import xml
import copy
from operator import itemgetter
import time
import datetime
from report import report_sxw
import xml.dom.minidom
import os, time
import osv
import re
import tools
import pooler
import sys
class account_balance(report_sxw.rml_parse):
_name = 'report.account.account.balance'
@ -44,6 +50,10 @@ class account_balance(report_sxw.rml_parse):
})
self.context = context
def _add_header(self, node, header=1):
if header==0:
self.rml_header = ""
return True
def get_fiscalyear(self, form):
res=[]
if form.has_key('fiscalyear'):
@ -56,16 +66,14 @@ class account_balance(report_sxw.rml_parse):
def get_periods(self, form):
result=''
if form.has_key('periods') and form['periods'][0][2]:
period_ids = form['periods'][0][2]
self.cr.execute("select name from account_period where id =ANY(%s)" ,(period_ids))
res = self.cr.fetchall()
len_res = len(res)
for r in res:
if (r == res[len_res-1]):
result+=r[0]+". "
if form.has_key('periods') and form['periods']:
period_ids = form['periods']
per_ids = self.pool.get('account.period').browse(self.cr,self.uid,form['periods'])
for r in per_ids:
if r == per_ids[len(per_ids)-1]:
result+=r.name+". "
else:
result+=r[0]+", "
result+=r.name+", "
else:
fy_obj = self.pool.get('account.fiscalyear').browse(self.cr,self.uid,form['fiscalyear'])
res = fy_obj.period_ids
@ -172,5 +180,8 @@ class account_balance(report_sxw.rml_parse):
def _sum_debit(self):
return self.sum_debit
report_sxw.report_sxw('report.account.account.balance', 'account.account', 'addons/account/report/account_balance.rml', parser=account_balance, header=False)
report_sxw.report_sxw('report.account.account.balance', 'account.account', 'addons/account/report/account_balance.rml', parser=account_balance, header=0)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -66,6 +66,27 @@
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
</blockTableStyle>
<blockTableStyle id="Table3a">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="0,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="1,0" stop="1,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="1,0" stop="1,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="2,0" stop="2,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="2,0" stop="2,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
<lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="3,0" stop="3,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/>
<lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="4,0" stop="4,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="4,0" stop="4,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/>
</blockTableStyle>
<blockTableStyle id="Table4">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
@ -95,6 +116,8 @@
<paraStyle name="P9b" fontName="Helvetica" fontSize="9" leftIndent="0.0" alignment="LEFT"/>
<paraStyle name="P9b" fontName="Helvetica" fontSize="8" leftIndent="-5.0" alignment="LEFT"/>
<paraStyle name="P12" fontName="Helvetica-Bold" fontSize="8.0" leading="14" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="terp_default_Centre_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_tblheader_General_Centre" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P12a" fontName="Helvetica-Bold" fontSize="8.0" leading="14" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P12b" fontName="Helvetica-Bold" fontSize="8.0" leading="14" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P14" rightIndent="17.0" leftIndent="-0.0" fontName="Helvetica-Bold" fontSize="8.0" leading="10" spaceBefore="0.0" spaceAfter="6.0"/>
@ -141,14 +164,46 @@
<para style="P2">
<font color="white"> </font>
</para>
<blockTable colWidths="527.00" style="Table4" repeatRows="1">
<blockTable colWidths="78.0,108.0,108.0,108.0,138" style="Table3a">
<tr>
<td>
<para style="P9a">[[ get_fiscalyear(data['form']) or removeParentNode('para') ]]:</para>
<para style="P9b"><i> [[ get_periods(data['form']) or removeParentNode('para') ]]</i></para>
<para style="terp_tblheader_General_Centre">Fiscal Year</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">End Date</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Start Date</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Display Account</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Periods</para>
</td>
</tr>
</blockTable>
</blockTable>
<blockTable colWidths="78.0,108.0,108.0,108.0,138" style="Table3a">
<tr>
<td>
<para style="terp_default_Centre_8">[[ get_fiscalyear(data['form']) ]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ data['form']['date_from'] ]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ data['form']['date_to'] ]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ (data['form']['display_account']=='bal_all' and 'All') or (data['form']['display_account']=='bal_mouvement' and 'With movements') or 'With balance is not equal to 0']]</para>
</td>
<td>
<para style="terp_default_Centre_8"> [[data['form']['periods'] and get_periods(data['form']) or '']]</para>
</td>
</tr>
</blockTable>
<para style="P2">
<font color="white"> </font>

View File

@ -153,14 +153,11 @@ class rml_parse(report_sxw.rml_parse):
return Stringer
def _add_header(self, node, header=1):
if self.name == 'account.account.balance.landscape':
if header==2:
rml_head = self.rml_header2
else:
rml_head = self.rml_header
rml_head = rml_head.replace('<pageGraphics>','''<pageGraphics> <image x="10" y="26cm" height="770.0" width="1120.0" >[[company.logo]] </image> ''')
if header==2:
rml_head = self.rml_header2
else:
return super(rml_parse, self)._add_header(node, header)
rml_head = self.rml_header
rml_head = rml_head.replace('<pageGraphics>','''<pageGraphics> <image x="10" y="26cm" height="770.0" width="1120.0" >[[company.logo]] </image> ''')
return True
# def _add_header(self, node):

View File

@ -1,166 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from report import report_sxw
import xml.dom.minidom
import os, time
import osv
import re
import tools
import pooler
import re
import sys
class rml_parse(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context):
super(rml_parse, self).__init__(cr, uid, name, context=None)
self.localcontext.update({
'comma_me': self.comma_me,
'format_date': self._get_and_change_date_format_for_swiss,
'strip_name' : self._strip_name,
'explode_name' : self._explode_name,
})
def comma_me(self,amount):
#print "#" + str(amount) + "#"
if not amount:
amount = 0.0
if type(amount) is float :
amount = str('%.2f'%amount)
else :
amount = str(amount)
if (amount == '0'):
return ' '
orig = amount
new = re.sub("^(-?\d+)(\d{3})", "\g<1>'\g<2>", amount)
if orig == new:
return new
else:
return self.comma_me(new)
def _ellipsis(self, string, maxlen=100, ellipsis = '...'):
ellipsis = ellipsis or ''
try:
return string[:maxlen - len(ellipsis) ] + (ellipsis, '')[len(string) < maxlen]
except Exception, e:
return False
def _strip_name(self, name, maxlen=50):
return self._ellipsis(name, maxlen, '...')
def _get_and_change_date_format_for_swiss (self,date_to_format):
date_formatted=''
if date_to_format:
date_formatted = strptime (date_to_format,'%Y-%m-%d').strftime('%d.%m.%Y')
return date_formatted
def _explode_name(self,chaine,length):
# We will test if the size is less then account
full_string = ''
if (len(str(chaine)) <= length):
return chaine
#
else:
chaine = unicode(chaine,'utf8').encode('iso-8859-1')
rup = 0
for carac in chaine:
rup = rup + 1
if rup == length:
full_string = full_string + '\n'
full_string = full_string + carac
rup = 0
else:
full_string = full_string + carac
return full_string
def makeAscii(self,str):
try:
Stringer = str.encode("utf-8")
except UnicodeDecodeError:
try:
Stringer = str.encode("utf-16")
except UnicodeDecodeError:
print "UTF_16 Error"
Stringer = str
else:
return Stringer
else:
return Stringer
return Stringer
def explode_this(self,chaine,length):
#chaine = self.repair_string(chaine)
chaine = rstrip(chaine)
ast = list(chaine)
i = length
while i <= len(ast):
ast.insert(i,'\n')
i = i + length
chaine = str("".join(ast))
return chaine
def repair_string(self,chaine):
ast = list(chaine)
UnicodeAst = []
_previouslyfound = False
i = 0
#print str(ast)
while i < len(ast):
elem = ast[i]
try:
Stringer = elem.encode("utf-8")
except UnicodeDecodeError:
to_reencode = elem + ast[i+1]
print str(to_reencode)
Good_char = to_reencode.decode('utf-8')
UnicodeAst.append(Good_char)
i += i +2
else:
UnicodeAst.append(elem)
i += i + 1
return "".join(UnicodeAst)
def ReencodeAscii(self,str):
print sys.stdin.encoding
try:
Stringer = str.decode("ascii")
except UnicodeEncodeError:
print "REENCODING ERROR"
return str.encode("ascii")
except UnicodeDecodeError:
print "DECODING ERROR"
return str.encode("ascii")
else:
print Stringer
return Stringer
def _add_header(self, node, header=1):
if header==2:
rml_head = self.rml_header2
else:
rml_head = self.rml_header
rml_head = rml_head.replace('<pageGraphics>','''<pageGraphics> <image x="10" y="26cm" height="770.0" width="1120.0" >[[company.logo]] </image> ''')
return True

View File

@ -30,15 +30,6 @@
<field name="target">new</field>
</record>
<!-- <record model="ir.values" id="account_change_currency">
<field name="model_id" ref="account.model_account_invoice" />
<field name="object" eval="1" />
<field name="name">Change Currency</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_account_change_currency'))"/>
<field name="key">action</field>
<field name="model">account.invoice</field>
</record>-->
</data>
</openerp>
</openerp>

View File

@ -37,10 +37,6 @@
<field name="target">new</field>
</record>
<!-- <act_window id="action_account_invoice_refund"
key2 = "client_action_multi" name="Credit Note"
res_model="account.invoice.refund" src_model="account.invoice"
view_mode="form" target="new" view_type="form" /> -->
</data>
</openerp>
</openerp>

View File

@ -58,7 +58,7 @@ class account_invoice_pay(osv.osv_memory):
'amount': fields.float('Amount paid', required=True, digits_compute = dp.get_precision('Account')),
'name': fields.char('Entry Name', size=64, required=True),
'date': fields.date('Date payment', required=True),
'journal_id': fields.many2one('account.journal', 'Journal/Payment Mode', required=True),
'journal_id': fields.many2one('account.journal', 'Journal/Payment Mode', required=True, domain=[('type','=','cash')]),
'period_id': fields.many2one('account.period', 'Period', required=True),
}
@ -188,4 +188,4 @@ class account_invoice_pay(osv.osv_memory):
account_invoice_pay()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -37,14 +37,6 @@
</record>
<!-- <act_window name="Pay Invoice"
res_model="account.invoice.pay"
src_model="account.invoice"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_view_account_invoice_pay"/> -->
<record id="view_account_invoice_pay_writeoff" model="ir.ui.view">
<field name="name">account.invoice.pay.writeoff.form</field>
<field name="model">account.invoice.pay.writeoff</field>
@ -70,4 +62,4 @@
</data>
</openerp>
</openerp>

View File

@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
"PO-Revision-Date: 2009-11-28 23:14+0000\n"
"Last-Translator: Paulino <Unknown>\n"
"PO-Revision-Date: 2010-06-01 10:22+0000\n"
"Last-Translator: cmsa <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-04-17 04:11+0000\n"
"X-Launchpad-Export-Date: 2010-06-02 03:33+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: account_analytic_analysis
@ -38,12 +38,12 @@ msgstr "Data da última factura"
#: help:account.analytic.account,remaining_ca:0
msgid "Computed using the formula: Max Invoice Price - Invoiced Amount."
msgstr ""
"Processado usando a formula: Preço máximo da factura - Montante facturado"
"Processado usando a fórmula: Preço Máximo da Factura - Montante Facturado"
#. module: account_analytic_analysis
#: help:account.analytic.account,remaining_hours:0
msgid "Computed using the formula: Maximum Quantity - Hours Tot."
msgstr "Processado usando a formula: Quantidade máxima - Horas totais."
msgstr "Processado usando a fórmula: Quantidade Máxima - Horas Totais."
#. module: account_analytic_analysis
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_account_analytic_all
@ -54,32 +54,32 @@ msgstr "Todas as contas de contabilidade analítica"
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_managed_open
#: model:ir.ui.menu,name:account_analytic_analysis.menu_analytic_account_to_valid_open
msgid "My Current Accounts"
msgstr "Minhas contas correntes"
msgstr "As minhas contas correntes"
#. module: account_analytic_analysis
#: constraint:ir.ui.view:0
msgid "Invalid XML for View Architecture!"
msgstr "XML inválido para a arquitectura de vista"
msgstr "XML inválido para a arquitectura de vista!"
#. module: account_analytic_analysis
#: help:account.analytic.account,last_invoice_date:0
msgid "Date of the last invoice created for this analytic account."
msgstr "Data da última factura criada por esta conta analítica."
msgstr "Data da última factura criada para esta conta analítica."
#. module: account_analytic_analysis
#: field:account.analytic.account,ca_theorical:0
msgid "Theorical Revenue"
msgstr "Rendimento teórico"
msgstr "Rendimento Teórico"
#. module: account_analytic_analysis
#: constraint:ir.actions.act_window:0
msgid "Invalid model name in the action definition."
msgstr "Nome de modelo invalido na definição da acção"
msgstr "Nome de modelo inválido na definição da acção."
#. module: account_analytic_analysis
#: help:account.analytic.account,theorical_margin:0
msgid "Computed using the formula: Theorial Revenue - Total Costs"
msgstr "Processado usando a formula: Rendimento teórico - Custo total"
msgstr "Processado usando a fórmula: Rendimento Teórico - Custo Total"
#. module: account_analytic_analysis
#: constraint:ir.model:0
@ -113,7 +113,7 @@ msgstr "Conta analíticas correntes"
#. module: account_analytic_analysis
#: help:account.analytic.account,last_worked_date:0
msgid "Date of the latest work done on this account."
msgstr "Data do ultimo trabalho feito nesta conta"
msgstr "Data do último trabalho feito nesta conta"
#. module: account_analytic_analysis
#: help:account.analytic.account,last_worked_invoiced_date:0
@ -121,8 +121,8 @@ msgid ""
"If invoice from the costs, this is the date of the latest work or cost that "
"have been invoiced."
msgstr ""
"Se facturado dos custos, esta é a data do ultimo trabalho ou custo que foi "
"facturado."
"Se facturado sobre os custos, esta é a data do ultimo trabalho ou custo que "
"foi facturado."
#. module: account_analytic_analysis
#: model:ir.ui.menu,name:account_analytic_analysis.menu_invoicing
@ -137,7 +137,7 @@ msgstr "Data do ultimo custo/trabalho"
#. module: account_analytic_analysis
#: field:account.analytic.account,total_cost:0
msgid "Total Costs"
msgstr "Custo total"
msgstr "Custos totais"
#. module: account_analytic_analysis
#: help:account.analytic.account,hours_quantity:0
@ -145,13 +145,13 @@ msgid ""
"Number of hours you spent on the analytic account (from timesheet). It "
"computes on all journal of type 'general'."
msgstr ""
"Número de horas que você passou no conta analítica (do horário). É "
"Número de horas que você passou no conta analítica (da folha de horas). É "
"processado em todo o jornal do tipo 'general'."
#. module: account_analytic_analysis
#: field:account.analytic.account,remaining_hours:0
msgid "Remaining Hours"
msgstr "Horas restantes"
msgstr "Horas Restantes"
#. module: account_analytic_analysis
#: help:account.analytic.account,ca_theorical:0
@ -161,8 +161,8 @@ msgid ""
"the pricelist."
msgstr ""
"Baseado nos custos você teve no projecto, o que seria o rendimento se todos "
"estes custos forem facturados a preço normal da venda fornecido pela lista "
"de preço."
"estes custos fossem facturados ao preço normal da venda fornecidos pela "
"tabela de preço."
#. module: account_analytic_analysis
#: field:account.analytic.account,user_ids:0
@ -174,24 +174,24 @@ msgstr "Utilizador"
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_managed_pending
#: model:ir.ui.menu,name:account_analytic_analysis.menu_analytic_account_to_valid_pending
msgid "My Pending Accounts"
msgstr "Minhas contas pendentes"
msgstr "As minhas contas pendentes"
#. module: account_analytic_analysis
#: model:ir.actions.act_window,name:account_analytic_analysis.action_hr_tree_invoiced_my
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_hr_tree_invoiced_my
msgid "My Uninvoiced Entries"
msgstr "Minhas entradas não facturadas"
msgstr "As minhas entradas não facturadas"
#. module: account_analytic_analysis
#: help:account.analytic.account,real_margin:0
msgid "Computed using the formula: Invoiced Amount - Total Costs."
msgstr "Processado usando a formula: Montante facturado - Custo total."
msgstr "Processado usando a fórmula: Montante Facturado - Custo Total."
#. module: account_analytic_analysis
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_managed
#: model:ir.ui.menu,name:account_analytic_analysis.menu_analytic_account_managed
msgid "My Accounts"
msgstr "Minhas contas"
msgstr "As minhas contas"
#. module: account_analytic_analysis
#: model:ir.module.module,description:account_analytic_analysis.module_meta_information
@ -200,6 +200,9 @@ msgid ""
"important data for project manager of services companies.\n"
"Add menu to show relevant information for each manager."
msgstr ""
"Modificar a vista da conta analítica para mostrar\n"
"dados importantes para o gestor de projecto das empresas de serviços.\n"
"Adicione menu para mostrar as informações relevantes para cada gerente."
#. module: account_analytic_analysis
#: field:account.analytic.account,hours_qtt_non_invoiced:0
@ -219,43 +222,43 @@ msgstr "Contas da contabilidade analítica"
#. module: account_analytic_analysis
#: model:ir.module.module,shortdesc:account_analytic_analysis.module_meta_information
msgid "report_account_analytic"
msgstr ""
msgstr "report_account_analytic"
#. module: account_analytic_analysis
#: field:account.analytic.account,ca_invoiced:0
msgid "Invoiced Amount"
msgstr "Montante facturado"
msgstr "Montante Facturado"
#. module: account_analytic_analysis
#: model:ir.ui.menu,name:account_analytic_analysis.next_id_71
msgid "Financial Project Management"
msgstr "Gestão do projecto financeiro"
msgstr "Gestão do Projecto Financeiro"
#. module: account_analytic_analysis
#: field:account.analytic.account,last_worked_invoiced_date:0
msgid "Date of Last Invoiced Cost"
msgstr "Data do ultimo custo de facturado"
msgstr "Data do último custo facturado"
#. module: account_analytic_analysis
#: field:account.analytic.account,ca_to_invoice:0
msgid "Uninvoiced Amount"
msgstr "Montante facturado"
msgstr "Montante Facturado"
#. module: account_analytic_analysis
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_all_pending
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_account_analytic_all_pending
msgid "Pending Analytic Accounts"
msgstr "Contas da contabilidade analítica pendentes"
msgstr "Contabilidade analítica contas pendentes"
#. module: account_analytic_analysis
#: field:account.analytic.account,hours_qtt_invoiced:0
msgid "Invoiced Hours"
msgstr "Horas facturadas"
msgstr "Horas Facturadas"
#. module: account_analytic_analysis
#: field:account.analytic.account,real_margin:0
msgid "Real Margin"
msgstr "Margem real"
msgstr "Margem Real"
#. module: account_analytic_analysis
#: help:account.analytic.account,ca_invoiced:0
@ -265,12 +268,12 @@ msgstr "Montante da facturação total do cliente para esta conta"
#. module: account_analytic_analysis
#: model:ir.model,name:account_analytic_analysis.model_account_analytic_analysis_summary_month
msgid "Hours summary by month"
msgstr "Sumário de horas por mês"
msgstr "Resumo de horas por mês"
#. module: account_analytic_analysis
#: help:account.analytic.account,real_margin_rate:0
msgid "Computes using the formula: (Real Margin / Total Costs) * 100."
msgstr "Processado usando a formula: (Margem real / Custos total) * 100."
msgstr "Processado usando a fórmula: (Margem Real / Custos Total) * 100."
#. module: account_analytic_analysis
#: help:account.analytic.account,hours_qtt_non_invoiced:0
@ -279,17 +282,17 @@ msgid ""
"invoice based on analytic account."
msgstr ""
"Número de horas (do diário de tipo 'geral') que pode ser facturado se você "
"factura baseado na conta analítica."
"factura baseado em conta analítica."
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Analytic accounts"
msgstr "Conta da Contabilidade analítica"
msgstr "Contas da Contabilidade Analítica"
#. module: account_analytic_analysis
#: field:account.analytic.account,remaining_ca:0
msgid "Remaining Revenue"
msgstr "Lucro restante"
msgstr "Receita Restante"
#. module: account_analytic_analysis
#: help:account.analytic.account,ca_to_invoice:0
@ -297,18 +300,18 @@ msgid ""
"If invoice from analytic account, the remaining amount you can invoice to "
"the customer based on the total costs."
msgstr ""
"Se facturado da conta analítica, a quantidade restante que você pode "
"Se facturado por conta analítica, a quantidade restante que você pode "
"facturar ao cliente baseado nos custos totais."
#. module: account_analytic_analysis
#: help:account.analytic.account,revenue_per_hour:0
msgid "Computed using the formula: Invoiced Amount / Hours Tot."
msgstr "Processado usando a formula: Montante facturado / Horas totais."
msgstr "Processado usando a fórmula: Montante Facturado / Horas Totais."
#. module: account_analytic_analysis
#: field:account.analytic.account,revenue_per_hour:0
msgid "Revenue per Hours (real)"
msgstr "Lucro por hora (real)"
msgstr "Receitas por hora (real)"
#. module: account_analytic_analysis
#: field:account_analytic_analysis.summary.month,unit_amount:0
@ -332,7 +335,7 @@ msgstr "Conta da Contabilidade Analítica"
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_managed_overpassed
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_account_analytic_managed_overpassed
msgid "Overpassed Accounts"
msgstr "Contas ultrapassadas"
msgstr "Contas Excedidas"
#. module: account_analytic_analysis
#: model:ir.actions.act_window,name:account_analytic_analysis.action_hr_tree_invoiced_all
@ -347,4 +350,4 @@ msgid ""
"indirect costs, like time spent on timesheets."
msgstr ""
"Total de custos para esta conta. Inclui custos reais (das facturas) e custos "
"indirectos, como o tempo passado em folha de presença."
"indirectos, como o tempo passado em folha de horas."

View File

@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
"PO-Revision-Date: 2009-11-28 23:17+0000\n"
"Last-Translator: Paulino <Unknown>\n"
"PO-Revision-Date: 2010-06-01 10:24+0000\n"
"Last-Translator: cmsa <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-04-17 04:11+0000\n"
"X-Launchpad-Export-Date: 2010-06-02 03:33+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: account_analytic_plans
@ -26,8 +26,7 @@ msgstr "Identificação da conta4"
msgid ""
"The Object name must start with x_ and not contain any special character !"
msgstr ""
"O nome do Objecto deve começar com x_ e não pode conter nenhum caractere "
"especial !"
"O nome do objecto deve começar com x_ e não pode conter um carácter especial!"
#. module: account_analytic_plans
#: model:ir.actions.report.xml,name:account_analytic_plans.account_analytic_account_crossovered_analytic

View File

@ -178,12 +178,33 @@
</field>
</record>
<record id="view_crossovered_budget_search" model="ir.ui.view">
<field name="name">crossovered.budget.search</field>
<field name="model">crossovered.budget</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Budget">
<group col="20" colspan="4">
<filter string="Draft" domain="[('state','=','draft')]" help="Draft Budgets" default="1"/>
<filter string="To Validate" domain="[('state','=','validate')]" help="To Validate Budgets" />
<separator orientation="vertical"/>
<field name="name" select="1"/>
<field name="code" select="1" />
<field name="state"/>
<field name="date_from"/>
<field name="date_to"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="act_crossovered_budget_view">
<field name="name">Budget</field>
<field name="res_model">crossovered.budget</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="crossovered_budget_view_tree"/>
<field name="search_view_id" ref="view_crossovered_budget_search"/>
</record>
<menuitem parent="next_id_31"
id="menu_act_crossovered_budget_view"

View File

@ -170,6 +170,7 @@ class account_invoice_line(osv.osv):
_defaults = {
'state': lambda *a: 'article',
'sequence': lambda *a : 0,
# 'account_id': _default_account
}
account_invoice_line()

View File

@ -7,19 +7,19 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
"PO-Revision-Date: 2009-11-28 23:25+0000\n"
"Last-Translator: Paulino <Unknown>\n"
"PO-Revision-Date: 2010-06-01 09:55+0000\n"
"Last-Translator: cmsa <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-04-17 04:12+0000\n"
"X-Launchpad-Export-Date: 2010-06-02 03:33+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: account_invoice_layout
#: selection:account.invoice.line,state:0
msgid "Sub Total"
msgstr "Sub Total"
msgstr "Sub-total"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
@ -48,7 +48,7 @@ msgstr "Título"
#. module: account_invoice_layout
#: model:ir.actions.wizard,name:account_invoice_layout.wizard_notify_message
msgid "Invoices with Layout and Message"
msgstr "Facturas com layout e mensagem"
msgstr "Facturas com Layout e Mensagem"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
@ -84,7 +84,7 @@ msgstr "Preço Unitário"
#. module: account_invoice_layout
#: constraint:ir.actions.act_window:0
msgid "Invalid model name in the action definition."
msgstr ""
msgstr "Nome do modelo inválido na definição da acção."
#. module: account_invoice_layout
#: model:ir.model,name:account_invoice_layout.model_notify_message
@ -119,7 +119,7 @@ msgstr "Referençia do cliente:"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
msgid ")"
msgstr ""
msgstr ")"
#. module: account_invoice_layout
#: field:account.invoice.line,state:0
@ -134,7 +134,7 @@ msgstr "Preço"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
msgid "/ ("
msgstr ""
msgstr "/("
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
@ -149,7 +149,7 @@ msgstr "Conta de Origem"
#. module: account_invoice_layout
#: model:ir.actions.act_window,name:account_invoice_layout.notify_mesage_tree_form
msgid "Write Messages"
msgstr ""
msgstr "Escrever mensagens"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
@ -189,7 +189,7 @@ msgstr "Quebra de Página"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
msgid "Document:"
msgstr ""
msgstr "Documento:"
#. module: account_invoice_layout
#: wizard_view:wizard.notify_message,init:0
@ -214,7 +214,7 @@ msgstr "Facturas com disposição"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
msgid "Description / Taxes"
msgstr ""
msgstr "Descrição / Impostos"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
@ -224,7 +224,7 @@ msgstr "Montante"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
msgid "Description/Taxes"
msgstr ""
msgstr "Descrição/Impostos"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
@ -264,7 +264,7 @@ msgstr "Factura do fornecedor"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
msgid "Note :"
msgstr ""
msgstr "Nota:"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
@ -274,12 +274,12 @@ msgstr "Taxa"
#. module: account_invoice_layout
#: model:ir.module.module,shortdesc:account_invoice_layout.module_meta_information
msgid "account_invoice_layout"
msgstr ""
msgstr "account_invoice_layout"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0
msgid "Total (Excl. taxes):"
msgstr ""
msgstr "Total (Antes de Impostos):"
#. module: account_invoice_layout
#: rml:account.invoice.layout:0

View File

@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
"PO-Revision-Date: 2009-11-28 23:58+0000\n"
"Last-Translator: Paulino <Unknown>\n"
"PO-Revision-Date: 2010-06-01 09:52+0000\n"
"Last-Translator: cmsa <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-04-17 04:16+0000\n"
"X-Launchpad-Export-Date: 2010-06-02 03:33+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: account_reporting
@ -46,13 +46,13 @@ msgstr "Nota"
#. module: account_reporting
#: field:account.report.bs,report_type:0
msgid "Report Type"
msgstr "Tipo de relatório"
msgstr "Tipo de Relatório"
#. module: account_reporting
#: model:ir.ui.menu,name:account_reporting.action_account_report_bs_form
#: model:ir.ui.menu,name:account_reporting.menu_finan_config_BSheet
msgid "Balance Sheet Report"
msgstr "Relatório do balancete"
msgstr "Relatório Balancete"
#. module: account_reporting
#: constraint:ir.actions.act_window:0
@ -62,7 +62,7 @@ msgstr "Nome de modelo inválido na definição da acção"
#. module: account_reporting
#: selection:account.report.bs,font_style:0
msgid "Courier"
msgstr "Correio"
msgstr "Courier"
#. module: account_reporting
#: selection:account.report.bs,font_style:0
@ -167,7 +167,7 @@ msgstr "Cores rml"
#. module: account_reporting
#: model:ir.module.module,shortdesc:account_reporting.module_meta_information
msgid "Reporting of Balancesheet for accounting"
msgstr ""
msgstr "Relatório do balancete para a contabilidade."
#. module: account_reporting
#: field:account.report.bs,code:0

View File

@ -23,18 +23,6 @@ import time
from osv import fields, osv
import decimal_precision as dp
class account_tax(osv.osv):
_inherit = 'account.tax'
_description = 'Account Tax'
_columns = {
'price_include': fields.boolean('Tax Included in Price', help="Check this if the price you use on the product and invoices includes this tax."),
}
_defaults = {
'price_include': 0,
}
account_tax()
class account_invoice(osv.osv):
_inherit = "account.invoice"
_columns = {

View File

@ -2,32 +2,6 @@
<openerp>
<data>
<!-- Add price include (boolean) on tax form/tree view -->
<record id="view_tax_tree_inherit" model="ir.ui.view">
<field name="name">account.tax.tree.inherit.tree</field>
<field name="type">tree</field>
<field name="model">account.tax</field>
<field name="inherit_id" ref="account.view_tax_tree"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="price_include"/>
</field>
</field>
</record>
<record id="view_tax_form_inherit" model="ir.ui.view">
<field name="name">account.tax.tree.inherit.form</field>
<field name="type">form</field>
<field name="model">account.tax</field>
<field name="inherit_id" ref="account.view_tax_form"/>
<field name="arch" type="xml">
<field name="sequence" position="after">
<field groups="base.group_extended" name="price_include"/>
</field>
</field>
</record>
<!-- End -->
<record id="account_tax_view_price" model="ir.ui.view">
<field name="name">account.tax.exlcuded.view.form</field>
<field name="type">form</field>

View File

@ -46,7 +46,7 @@
</group>
<separator colspan="4" string="Note"/>
<label align="0.0" colspan="4" width="900"
string="The rule use a AND operator. The model must match all non empty fields so that the rule execute the action described in the 'Actions' tab." />
string="The rule uses the AND operator. The model must match all non-empty fields so that the rule executes the action described in the 'Actions' tab." />
</page>
<page string="Actions">
<separator colspan="4" string="Fields to Change"/>
@ -56,15 +56,15 @@
<field name="server_action_id"/>
<field name="filter_id"/>
</page>
<page string="E-Mail Actions">
<page string="Email Actions">
<!-- <group col="4" colspan="2">-->
<separator colspan="4" string="Template of Email to Send"/>
<separator colspan="4" string="Email Information"/>
<field name="act_mail_to_watchers"/>
<field name="act_mail_to_user"/>
<field colspan="4" name="act_mail_to_email"/>
<!-- </group>-->
<!-- <group col="4" colspan="2">-->
<separator colspan="4" string="E-Mail Reminders (includes the content of the object)"/>
<separator colspan="4" string="Email Reminders"/>
<field name="act_remind_partner"/>
<field name="act_remind_attach"/>
<field name="act_remind_user"/>
@ -73,7 +73,7 @@
</group>
<field colspan="4" name="act_email_cc"/>
<!-- </group>-->
<separator colspan="4" string="Mail Body"/>
<separator colspan="4" string="Email Body"/>
<field colspan="4" name="act_mail_body" height="250"
nolabel="1" attrs="{'required':[('act_remind_user','=',True)]}" />
<separator colspan="4" string="Special Keywords to Be Used in The Body"/>
@ -82,9 +82,9 @@
<label align="0.0" string="%%(object_description)s = Object description" colspan="2"/>
<label align="0.0" string="%%(object_date)s = Creation date" colspan="2"/>
<label align="0.0" string="%%(partner)s = Partner name" colspan="2"/>
<label align="0.0" string="%%(partner_email)s = Partner email" colspan="2"/>
<label align="0.0" string="%%(partner_email)s = Partner Email" colspan="2"/>
<label align="0.0" string="%%(object_user)s = Responsible name" colspan="2"/>
<label align="0.0" string="%%(object_user_email)s = Responsible email" colspan="2"/>
<label align="0.0" string="%%(object_user_email)s = Responsible Email" colspan="2"/>
<label align="0.0" string="%%(object_user_phone)s = Responsible phone" colspan="2"/>
</page>
</notebook>

View File

@ -410,7 +410,10 @@ property or property parameter."),
event.add('location').value = event_obj.location
if event_obj.rrule:
event.add('rrule').value = event_obj.rrule
if event_obj.user_id:
event_org = event.add('organizer')
event_org.params['CN'] = [event_obj.user_id.name]
event_org.value = 'MAILTO:' + (event_obj.user_id.user_email or event_obj.user_id.name)
if event_obj.alarm_id:
# computes alarm data
valarm = event.add('valarm')
@ -440,7 +443,7 @@ property or property parameter."),
attendee_add.params['CUTYPE'] = [str(attendee.cutype)]
attendee_add.params['ROLE'] = [str(attendee.role)]
attendee_add.params['RSVP'] = [str(attendee.rsvp)]
attendee_add.value = 'MAILTO:' + attendee.email
attendee_add.value = 'MAILTO:' + (attendee.email or '')
res = cal.serialize()
return res
@ -480,8 +483,8 @@ property or property parameter."),
'company': company
}
body = html_invitation % body_vals
attach = self.get_ics_file(cr, uid, res_obj, context=context)
if mail_to and email_from:
attach = self.get_ics_file(cr, uid, res_obj, context=context)
tools.email_send(
email_from,
mail_to,

View File

@ -137,15 +137,14 @@
</record>
<!-- Calenadar's menu -->
<menuitem id="base.menu_calendar_configuration" name="Calendar"
parent="base.menu_base_config" sequence="10" />
<menuitem id="base.menu_calendar_configuration" name="Calendar"
parent="base.menu_config_address_book" sequence="15" />
<!-- Invitation menu -->
<menuitem id="menu_attendee_invitations"
name="Event Invitations" parent="base.menu_calendar_configuration"
sequence="10" action="action_view_attendee_form" />
<menuitem id="menu_attendee_invitations"
name="Event Invitations" parent="base.menu_calendar_configuration"
sequence="10" action="action_view_attendee_form" />
<!-- ALARM FORM VIEW-->
@ -192,11 +191,10 @@
<!-- Menu for Alarms-->
<menuitem id="menu_crm_meeting_avail_alarm"
<menuitem id="menu_crm_meeting_avail_alarm"
groups="base.group_extended"
action="base_calendar.action_res_alarm_view"
parent="base.menu_calendar_configuration" />
<!-- Event Form View-->
<record model="ir.ui.view" id="event_form_view">
@ -427,9 +425,9 @@
<!-- Event menu -->
<menuitem id="menu_events"
name="Events" parent="base.menu_calendar_configuration"
sequence="5" action="action_view_event" />
<menuitem id="menu_events"
name="Events" parent="base.menu_calendar_configuration"
sequence="5" action="action_view_event" />
</data>
</openerp>

View File

@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
"PO-Revision-Date: 2009-11-09 13:47+0000\n"
"Last-Translator: <>\n"
"PO-Revision-Date: 2010-06-03 01:30+0000\n"
"Last-Translator: Abdul Munif Hanafi <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-04-17 04:03+0000\n"
"X-Launchpad-Export-Date: 2010-06-03 03:33+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base_vat
@ -25,7 +25,7 @@ msgstr ""
#. module: base_vat
#: constraint:ir.ui.view:0
msgid "Invalid XML for View Architecture!"
msgstr ""
msgstr "XML tidak sah untuk Menampilkan Arsitektur!"
#. module: base_vat
#: field:res.partner,vat_subjected:0
@ -35,4 +35,4 @@ msgstr ""
#. module: base_vat
#: model:ir.module.module,shortdesc:base_vat.module_meta_information
msgid "VAT"
msgstr ""
msgstr "VAT"

View File

@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
"PO-Revision-Date: 2009-09-08 13:29+0000\n"
"Last-Translator: Madalena_prime <madalena.barreto@prime.cv>\n"
"PO-Revision-Date: 2010-06-01 10:02+0000\n"
"Last-Translator: cmsa <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-04-17 04:15+0000\n"
"X-Launchpad-Export-Date: 2010-06-02 03:33+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: board
@ -26,7 +26,7 @@ msgstr ""
#. module: board
#: model:ir.model,name:board.model_board_board
msgid "board.board"
msgstr ""
msgstr "board.board"
#. module: board
#: field:board.note,user_id:0
@ -36,7 +36,7 @@ msgstr "Autor"
#. module: board
#: model:ir.module.module,shortdesc:board.module_meta_information
msgid "Dashboard main module"
msgstr ""
msgstr "Módulo Principal do Painel"
#. module: board
#: view:board.note:0
@ -52,7 +52,7 @@ msgstr "Largura"
#. module: board
#: constraint:ir.actions.act_window:0
msgid "Invalid model name in the action definition."
msgstr ""
msgstr "Nome de modelo inválido na definição da aclção."
#. module: board
#: field:board.board.line,name:0
@ -84,7 +84,7 @@ msgstr "Vista de acções"
#. module: board
#: model:ir.model,name:board.model_board_note
msgid "board.note"
msgstr ""
msgstr "board.note"
#. module: board
#: field:board.note,date:0
@ -124,7 +124,7 @@ msgstr "Notas"
#. module: board
#: model:ir.model,name:board.model_board_note_type
msgid "board.note.type"
msgstr ""
msgstr "board.note.type"
#. module: board
#: view:board.board:0
@ -136,7 +136,7 @@ msgstr "Painel"
#. module: board
#: model:ir.module.module,description:board.module_meta_information
msgid "Base module for all dashboards."
msgstr ""
msgstr "Módulo base para todos os painéis."
#. module: board
#: field:board.board.line,position:0
@ -212,7 +212,7 @@ msgstr "Vista de painel"
#. module: board
#: model:ir.model,name:board.model_board_board_line
msgid "board.board.line"
msgstr ""
msgstr "board.board.line"
#. module: board
#: field:board.note,name:0

View File

@ -10,3 +10,4 @@
"access_calendar_event_export","calendar.event.export","model_calendar_event_export","base.group_user",1,1,1,1
"access_calendar_event_import","calendar.event.import","model_calendar_event_import","base.group_user",1,1,1,1
"access_calendar_event_subscribe","calendar.event.subscribe","model_calendar_event_subscribe","base.group_user",1,1,1,1
"access_basic_calendar","basic.calendar","model_basic_calendar","base.group_user",1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
10 access_calendar_event_export calendar.event.export model_calendar_event_export base.group_user 1 1 1 1
11 access_calendar_event_import calendar.event.import model_calendar_event_import base.group_user 1 1 1 1
12 access_calendar_event_subscribe calendar.event.subscribe model_calendar_event_subscribe base.group_user 1 1 1 1
13 access_basic_calendar basic.calendar model_basic_calendar base.group_user 1 1 1 1

View File

@ -108,13 +108,13 @@ between mails and Open ERP.""",
'crm_phonecall_demo.xml'
],
'test': [
# 'test/test_crm_lead.yml',
# 'test/test_crm_meeting.yml',
# 'test/test_crm_opportunity.yml',
# 'test/test_crm_phonecall.yml',
],
'installable': True,
'active': False,
'test/test_crm_lead.yml',
'test/test_crm_meeting.yml',
'test/test_crm_opportunity.yml',
'test/test_crm_phonecall.yml',
],
'installable': True,
'active': False,
'certificate': '0079056041421',
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -203,9 +203,13 @@ class crm_case(object):
address = self.pool.get('res.partner.address').browse(cr, uid, add)
return {'value': {'email_from': address.email}}
def _history(self, cr, uid, cases, keyword, history=False, email=False, details=None, email_from=False, message_id=False, context={}):
def _history(self, cr, uid, cases, keyword, history=False, subject=None, email=False, details=None, email_from=False, message_id=False, attach=[], context={}):
mailgate_pool = self.pool.get('mailgate.thread')
return mailgate_pool._history(cr, uid, cases, keyword, history=history, email=email, details=details, email_from=email_from, message_id=message_id, context=context)
return mailgate_pool._history(cr, uid, cases, keyword, history=history,\
subject=subject, email=email, \
details=details, email_from=email_from,\
message_id=message_id, attach=attach, \
context=context)
def case_open(self, cr, uid, ids, *args):
"""Opens Case
@ -438,6 +442,7 @@ class crm_case_section(osv.osv):
'child_ids': fields.one2many('crm.case.section', 'parent_id', 'Child Teams'),
'resource_calendar_id': fields.many2one('resource.calendar', "Resource's Calendar"),
'note': fields.text('Description'),
'working_hours': fields.float('Working Hours', digits=(16,2 )),
}
_defaults = {

View File

@ -82,23 +82,9 @@ this if you want the rule to send an email to the partner."),
if hasattr(obj, 'categ_id'):
ok = ok and (not action.trg_categ_id or action.trg_categ_id.id==obj.categ_id.id)
# TODO: history_line is removed
# if hasattr(obj, 'history_line'):
# ok = ok and (not action.trg_max_history or action.trg_max_history<=(len(obj.history_line)+1))
# reg_history = action.regex_history
# result_history = True
# if reg_history:
# ptrn = re.compile(str(reg_history))
# if obj.history_line:
# _result = ptrn.search(str(obj.history_line[0].description))
# if not _result:
# result_history = False
regex_h = not reg_history or result_history
ok = ok and regex_h
return ok
def do_action(self, cr, uid, action, model_obj, obj, context={}):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@ -118,7 +104,7 @@ this if you want the rule to send an email to the partner."),
write['email_cc'] = obj.email_cc+','+obj.act_email_cc
else:
write['email_cc'] = obj.act_email_cc
model_obj.write(cr, uid, [obj.id], write, context)
emails = []

View File

@ -1,59 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="event_type_case_create" model="res.partner.event.type">
<field name="name">CRM: Create Case</field>
<field name="key">crm_case_draft</field>
</record>
<record id="event_type_case_open" model="res.partner.event.type">
<field name="name">CRM: Open Case</field>
<field name="key">crm_case_open</field>
</record>
<record id="event_type_case_pending" model="res.partner.event.type">
<field name="name">CRM: Pending Case</field>
<field name="key">crm_case_pending</field>
</record>
<record id="event_type_case_cancel" model="res.partner.event.type">
<field name="name">CRM: Cancel Case</field>
<field name="key">crm_case_cancel</field>
</record>
<record id="event_type_case_close" model="res.partner.event.type">
<field name="name">CRM: Close Case</field>
<field name="key">crm_case_done</field>
</record>
</data>
<data noupdate="1">
<record model="crm.case.section" id="section_sales_department">
<field name="name">Sales Department</field>
<field name="code">Sales</field>
</record>
<record id="event_type_case_create" model="res.partner.event.type">
<field eval="False" name="active"/>
</record>
<record id="event_type_case_open" model="res.partner.event.type">
<field eval="True" name="active"/>
</record>
<record id="event_type_case_pending" model="res.partner.event.type">
<field eval="False" name="active"/>
</record>
<record id="event_type_case_close" model="res.partner.event.type">
<field eval="True" name="active"/>
</record>
<record id="event_type_case_cancel" model="res.partner.event.type">
<field eval="False" name="active"/>
</record>
<record id="ir_cron_crm_action" model="ir.cron">
<field name="name">Check cases rules</field>

View File

@ -39,7 +39,8 @@ class crm_installer(osv.osv_memory):
'crm_caldav': fields.boolean('Calendar Synchronizing', help="Help you to synchronize the meetings with other calender clients(e.g.: Sunbird)."),
'sale_crm': fields.boolean('Create Quotation from Opportunity', help="This module relates sale to opportunity cases in the CRM."),
'fetchmail': fields.boolean('Fetch Emails', help="Fetchmail Server."),
'thunderbird': fields.boolean('Thunderbird', help="Thunderbird Interface."),
'thunderbird': fields.boolean('Thunderbird', help="Thunderbird Interface."),
'wiki_sale_faq': fields.boolean('Sale FAQ', help="Sale FAQ."),
}
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):

View File

@ -35,7 +35,8 @@
<field name="crm_claim" />
<field name="crm_helpdesk" />
<field name="crm_fundraising" />
<field name="sale_crm" invisible="1"/>
<field name="wiki_sale_faq"/>
<field name="sale_crm" invisible="1"/>
</group>
</group>
</data>

View File

@ -108,8 +108,8 @@ class crm_lead(osv.osv, crm_case):
'email_cc': fields.text('Watchers Emails', size=252 , help="These \
people will receive a copy of the future communication between partner \
and users by email"),
'description': fields.text('Description'),
'write_date': fields.datetime('Update Date' , readonly=True),
'description': fields.text('Notes'),
'write_date': fields.datetime('Update Date' , readonly=True),
# Lead fields
'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
@ -137,7 +137,6 @@ and users by email"),
method=True, multi='day_open', type="float", store=True),
'day_close': fields.function(_compute_day, string='Days to Close', \
method=True, multi='day_close', type="float", store=True),
'function_name': fields.char('Function', size=64),
'state': fields.selection(crm.AVAILABLE_STATES, 'State', size=16, readonly=True,
help='The state is set to \'Draft\', when a case is created.\
\nIf the case is in progress the state is set to \'Open\'.\

View File

@ -12,9 +12,11 @@
<field name="domain">[('object_id.model', '=', 'crm.lead')]</field>
<field name="context">{'object_id':'crm.lead'}</field>
</record>
<menuitem action="crm_lead_stage_act" id="menu_crm_lead_stage_act"
groups="base.group_extended"
parent="crm.menu_crm_case_stage" />
<menuitem action="crm_lead_stage_act" id="menu_crm_lead_stage_act" name="Stages"
groups="base.group_extended" sequence="0"
parent="menu_crm_config_lead" />
<!-- Resource Type Form View -->
@ -26,10 +28,11 @@
<field name="domain">[('object_id.model', '=', 'crm.lead')]</field>
<field name="context">{'object_id':'crm.lead'}</field>
</record>
<menuitem action="crm_lead_resource_act"
id="menu_crm_lead_resource_act"
groups="base.group_extended"
parent="crm.menu_crm_case_resource_type" />
<menuitem action="crm_lead_resource_act"
id="menu_crm_lead_resource_act" name="Resource Type"
groups="base.group_extended" sequence="2"
parent="menu_crm_config_lead" />
<!-- CRM Lead Form View -->
@ -47,7 +50,7 @@
name="convert_opportunity"
string="Convert"
help="Convert to Opportunity"
icon="gtk-index"
icon="gtk-index"
type="object"/>
<newline />
<field name="section_id" colspan="1"
@ -71,7 +74,7 @@
<field name="partner_name" string="Partner Name" colspan="4"/>
<newline/>
<field domain="[('domain', '=', 'contact')]" name="title"/>
<field name="function_name" />
<field name="function" />
<field name="street" colspan="4"/>
<field name="street2" colspan="4"/>
<field name="zip"/>
@ -160,16 +163,21 @@
<field name="email_to"/>
<field name="email_from"/>
</group>
<newline/>
<field name="description" colspan="4" nolabel="1"/>
<notebook colspan="4">
<page string="Details">
<field name="description" colspan="4" nolabel="1"/>
</page>
<page string="Attachments">
<field name="attachment_ids" colspan="4" readonly="1" nolabel="1"/>
</page>
</notebook>
<button colspan="4"
string="Reply to Last Email"
name="%(action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'crm.lead', 'include_original' : True}"
icon="gtk-undo" type="action" />
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'crm.lead', 'include_original' : True}"
icon="gtk-undo" type="action" />
</form>
<tree string="Communication history">
<field name="name" />
<field name="date"/>
<field name="email_from" />
<field name="email_to"/>
@ -177,7 +185,7 @@
</tree>
</field>
<button colspan="2" string="Send New Email"
name="%(action_crm_send_mail)d"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'new', 'model': 'crm.lead'}"
icon="gtk-go-forward" type="action" />
<button colspan="2" string="Forward to Partner"

View File

@ -13,8 +13,8 @@
<field name="context">{'object_id':'crm.meeting'}</field>
</record>
<menuitem action="crm_meeting_categ_action"
id="menu_crm_case_meeting-act" parent="crm.menu_crm_case_categ" />
<menuitem action="crm_meeting_categ_action" name="Categories"
id="menu_crm_case_meeting-act" parent="menu_crm_config_meeting" />
<!-- CRM Meetings Form View -->

View File

@ -1,23 +1,23 @@
<?xml version="1.0"?>
<openerp>
<data>
<data>
<!-- Opportunity Categories Form View -->
<!-- Opportunity Categories Form View -->
<record id="crm_opportunity_categ_action" model="ir.actions.act_window">
<field name="name">Opportunity Categories</field>
<field name="res_model">crm.case.categ</field>
<field name="view_type">form</field>
<field name="view_id" ref="crm.crm_case_categ_tree-view"/>
<field name="domain">[('object_id.model', '=', 'crm.lead')]</field>
<field name="context">{'object_id':'crm.lead'}</field>
</record>
<record id="crm_opportunity_categ_action" model="ir.actions.act_window">
<field name="name">Opportunity Categories</field>
<field name="res_model">crm.case.categ</field>
<field name="view_type">form</field>
<field name="view_id" ref="crm.crm_case_categ_tree-view"/>
<field name="domain">[('object_id.model', '=', 'crm.lead')]</field>
<field name="context">{'object_id':'crm.lead'}</field>
</record>
<menuitem action="crm_opportunity_categ_action"
id="menu_crm_case_opportunity-act"
parent="crm.menu_crm_case_categ" />
<menuitem action="crm_opportunity_categ_action"
id="menu_crm_case_opportunity-act" name="Categories"
parent="menu_crm_config_opportunity" />
<!-- Opportunity Stages Form View-->
<!-- Opportunity Stages Form View-->
<record id="crm_opportunity_stage_act" model="ir.actions.act_window">
<field name="name">Opportunity Stages</field>
@ -29,8 +29,8 @@
</record>
<menuitem action="crm_opportunity_stage_act"
id="menu_crm_opportunity_stage_act"
parent="crm.menu_crm_case_stage" />
id="menu_crm_opportunity_stage_act" name="Stages"
parent="menu_crm_config_opportunity" />
<!-- Opportunity Resource Type Form View -->
@ -44,288 +44,307 @@
</record>
<menuitem action="crm_opportunity_resource_act"
id="menu_crm_opportunity_resource_act"
parent="crm.menu_crm_case_resource_type" />
id="menu_crm_opportunity_resource_act" name="Resource"
parent="menu_crm_config_opportunity" />
<!-- Opportunities Form View -->
<!-- Opportunities Form View -->
<record model="ir.ui.view" id="crm_case_form_view_oppor">
<field name="name">Opportunities</field>
<field name="model">crm.lead</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Opportunities">
<group colspan="4" col="7">
<field name="name" required="1" string="Opportunity"/>
<label string="Stage:" align="1.0"/>
<group colspan="1" col="4">
<field name="stage_id" nolabel="1"
on_change="onchange_stage_id(stage_id)"
widget="selection"
domain="[('object_id.model', '=', 'crm.lead')]" />
<button name="stage_previous"
<record model="ir.ui.view" id="crm_case_form_view_oppor">
<field name="name">Opportunities</field>
<field name="model">crm.lead</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Opportunities">
<group colspan="4" col="7">
<field name="name" required="1" string="Opportunity"/>
<label string="Stage:" align="1.0"/>
<group colspan="1" col="4">
<field name="stage_id" nolabel="1"
on_change="onchange_stage_id(stage_id)"
widget="selection"
domain="[('object_id.model', '=', 'crm.lead')]" />
<button name="stage_previous"
states="open,pending" type="object"
icon="gtk-go-back" string="" />
<button name="stage_next" states="open,pending"
type="object" icon="gtk-go-forward" string="" />
</group>
<field name="user_id"/>
<button name="action_makeMeeting" type="object"
string="Schedule Meeting" icon="gtk-redo" />
<field name="planned_revenue"/>
<field name="probability"/>
<field name="date_deadline" string="Expected Closing"/>
<button string="Schedule Call"
name="%(opportunity2phonecall_act)d" icon="gtk-redo" type="action" />
<newline/>
<field name="date_action"/>
<field name="priority" string="Priority"/>
</group>
<notebook colspan="4">
<page string="Opportunity">
<group col="4" colspan="2">
<separator colspan="4" string="Contacts"/>
<field name="partner_id" select="1"
on_change="onchange_partner_id(partner_id, email_from)"
colspan="2" />
<field name="partner_address_id"
string="Contact"
on_change="onchange_partner_address_id(partner_address_id, email_from)"
colspan="1" />
<field name="email_from" string="Email" />
<field name="phone"/>
</group>
<group col="2" colspan="2">
<separator colspan="2" string="Categorization"/>
<field name="section_id" colspan="1" widget="selection"/>
<field name="categ_id" select="1" groups="base.group_extended"
string="Category" widget="selection"
domain="[('object_id.model', '=', 'crm.lead')]" />
</group>
<separator colspan="4" string="Details"/>
<field name="description" nolabel="1" colspan="4"/>
<separator colspan="4"/>
<group col="8" colspan="4">
<field name="state"/>
<button name="case_open" string="Open"
states="draft,pending" type="object"
icon="gtk-go-forward" />
<button name="case_pending" string="Pending"
states="draft,open" type="object"
icon="gtk-media-pause" />
<button name="case_escalate" string="Escalate"
states="open,draft,pending" type="object"
groups="base.group_extended"
icon="gtk-go-up" />
<button name="case_cancel" string="Mark Lost"
states="draft,open,pending" type="object"
icon="gtk-close" />
<button name="case_close" string="Mark Won"
states="open,draft,pending" type="object"
icon="gtk-apply" />
<button name="case_reset" string="Reset to New"
states="done,cancel" type="object"
icon="gtk-convert" />
</group>
</page>
<page string="Emails" groups="base.group_extended">
<group colspan="4">
<field colspan="4" name="email_cc" string="CC"/>
</group>
<field name="message_ids" colspan="4" nolabel="1" mode="form,tree" height="280">
<form string="Communication history">
<group col="6" colspan="4">
<field name="date"/>
<field name="email_to"/>
<field name="email_from"/>
</group>
<notebook colspan="4">
<page string="Details">
<field name="description" colspan="4" nolabel="1"/>
</page>
<page string="Attachments">
<field name="attachment_ids" colspan="4" readonly="1" nolabel="1"/>
</page>
</notebook>
<button colspan="4"
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'crm.lead', 'include_original' : True}"
icon="gtk-undo" type="action" />
</form>
<tree string="Communication history">
<field name="date"/>
<field name="email_from" />
<field name="email_to"/>
<field name="description"/>
</tree>
</field>
<button colspan="2" string="Send New Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'new', 'model': 'crm.lead'}"
icon="gtk-go-forward" type="action" />
<button colspan="2" string="Forward to Partner"
name="%(crm_lead_forward_to_partner_act)d"
icon="gtk-go-forward" type="action" />
</page>
<page string="History" groups="base.group_extended">
<group col="2" colspan="2">
<separator string="Dates" colspan="2"/>
<field name="create_date"/>
<field name="write_date"/>
<field name="date_closed"/>
<field name="date_open"/>
</group>
<group col="2" colspan="2">
<separator string="Misc" colspan="2"/>
<field name="active"/>
<field name="day_open"/>
<field name="day_close"/>
<field name="referred"/>
</group>
<separator colspan="4" string="References"/>
<field name="ref"/>
<field name="ref2"/>
<field name="log_ids" nolabel="1" colspan="4">
<tree string="Logs">
<field name="name" colspan="4"/>
<field name="date"/>
<field name="user_id"/>
</tree>
<form string="Logs">
<separator string="Action Information" colspan="4"/>
<field name="name" colspan="4"/>
<field name="date"/>
<field name="user_id"/>
</form>
</field>
</page>
</notebook>
</form>
</field>
</record>
<!-- Opportunities Tree View -->
<record model="ir.ui.view" id="crm_case_tree_view_oppor">
<field name="name">Opportunities Tree</field>
<field name="model">crm.lead</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Opportunities" colors="blue:state=='pending';grey:state in ('cancel', 'done');red:date_deadline &lt; current_date">
<field name="date_deadline" invisible="1"/>
<field name="create_date"/>
<field name="name" string="Opportunity"/>
<field name="partner_id"/>
<field name="stage_id"/>
<field name="categ_id" invisible="1" groups="base.group_extended"/>
<button name="stage_previous" string="Previous"
states="open,pending" type="object" icon="gtk-go-back" />
<button name="stage_next" string="Next"
states="open,pending" type="object"
icon="gtk-go-back" string="" />
<button name="stage_next" states="open,pending"
type="object" icon="gtk-go-forward" string="" />
</group>
<field name="user_id"/>
<button name="action_makeMeeting" type="object"
string="Schedule Meeting" icon="gtk-redo" />
<field name="planned_revenue"/>
<field name="probability"/>
<field name="date_deadline" string="Expected Closing"/>
<button string="Schedule Call"
name="%(opportunity2phonecall_act)d" icon="gtk-redo" type="action" />
<newline/>
<field name="date_action"/>
<field name="priority" string="Priority"/>
</group>
<notebook colspan="4">
<page string="Opportunity">
<group col="4" colspan="2">
<separator colspan="4" string="Contacts"/>
<field name="partner_id" select="1"
on_change="onchange_partner_id(partner_id, email_from)"
colspan="2" />
<field name="partner_address_id"
string="Contact"
on_change="onchange_partner_address_id(partner_address_id, email_from)"
colspan="1" />
<field name="email_from" string="Email" />
<field name="phone"/>
</group>
<group col="2" colspan="2">
<separator colspan="2" string="Categorization"/>
<field name="section_id" colspan="1" widget="selection"/>
<field name="categ_id" select="1" groups="base.group_extended"
string="Category" widget="selection"
domain="[('object_id.model', '=', 'crm.lead')]" />
</group>
<separator colspan="4" string="Details"/>
<field name="description" nolabel="1" colspan="4"/>
<separator colspan="4"/>
<group col="8" colspan="4">
icon="gtk-go-forward" />
<field name="planned_revenue" sum="Total of Planned Revenue"/>
<field name="probability" widget="progressbar" avg="Avg. of Probability"/>
<field name="date_action"/>
<field name="section_id" groups="base.group_extended"/>
<field name="user_id"/>
<field name="priority"/>
<field name="state"/>
<button name="case_open" string="Open"
states="draft,pending" type="object"
icon="gtk-go-forward" />
<button name="case_pending" string="Pending"
states="draft,open" type="object"
icon="gtk-media-pause" />
<button name="case_escalate" string="Escalate"
states="open,draft,pending" type="object"
groups="base.group_extended"
icon="gtk-go-up" />
<button name="case_cancel" string="Mark Lost"
states="draft,open,pending" type="object"
icon="gtk-close" />
<button name="case_close" string="Mark Won"
<button name="case_close" string="Won"
states="open,draft,pending" type="object"
icon="gtk-apply" />
<button name="case_reset" string="Reset to New"
states="done,cancel" type="object"
icon="gtk-convert" />
</group>
</page>
<page string="Emails" groups="base.group_extended">
<group colspan="4">
<field colspan="4" name="email_cc" string="CC"/>
</group>
<field name="message_ids" colspan="4" nolabel="1" mode="form,tree">
<form string="Communication history">
<group col="6" colspan="4">
<field name="date"/>
<field name="email_to"/>
<field name="email_from"/>
</group>
<newline/>
<field name="description" colspan="4" nolabel="1"/>
<button colspan="4"
string="Reply to Last Email"
name="%(action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'crm.lead'}"
icon="gtk-undo" type="action" />
</form>
<tree string="Communication history">
<field name="description"/>
<field name="email_to"/>
<field name="date"/>
</tree>
</field>
<button colspan="2" string="Send New Email"
name="%(action_crm_send_mail)d"
context="{'mail':'new', 'model': 'crm.lead'}"
icon="gtk-go-forward" type="action" />
<button colspan="2" string="Forward to Partner"
name="%(crm_lead_forward_to_partner_act)d"
icon="gtk-go-forward" type="action" />
</page>
<page string="History" groups="base.group_extended">
<group col="2" colspan="2">
<separator string="Dates" colspan="2"/>
<field name="create_date"/>
<field name="write_date"/>
<field name="date_closed"/>
<field name="date_open"/>
</group>
<group col="2" colspan="2">
<separator string="Misc" colspan="2"/>
<field name="active"/>
<field name="day_open"/>
<field name="day_close"/>
<field name="referred"/>
</group>
<separator colspan="4" string="References"/>
<field name="ref"/>
<field name="ref2"/>
<field name="log_ids" nolabel="1" colspan="4">
<tree string="Logs">
<field name="name" colspan="4"/>
<field name="date"/>
<field name="user_id"/>
</tree>
<form string="Logs">
<separator string="Action Information" colspan="4"/>
<field name="name" colspan="4"/>
<field name="date"/>
<field name="user_id"/>
</form>
</field>
</page>
</notebook>
</form>
</field>
</record>
<!-- Opportunities Tree View -->
<record model="ir.ui.view" id="crm_case_tree_view_oppor">
<field name="name">Opportunities Tree</field>
<field name="model">crm.lead</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Opportunities" colors="blue:state=='pending';grey:state in ('cancel', 'done');red:date_deadline &lt; current_date">
<field name="date_deadline" invisible="1"/>
<field name="create_date"/>
<field name="name" string="Opportunity"/>
<field name="partner_id"/>
<field name="stage_id"/>
<field name="categ_id" invisible="1" groups="base.group_extended"/>
<button name="stage_previous" string="Previous"
states="open,pending" type="object" icon="gtk-go-back" />
<button name="stage_next" string="Next"
states="open,pending" type="object"
icon="gtk-go-forward" />
<field name="planned_revenue" sum="Total of Planned Revenue"/>
<field name="probability" widget="progressbar" avg="Avg. of Probability"/>
<field name="date_action"/>
<field name="section_id" groups="base.group_extended"/>
<field name="user_id"/>
<field name="priority"/>
<field name="state"/>
<button name="case_open" string="Open"
states="draft,pending" type="object"
icon="gtk-go-forward" />
<button name="case_close" string="Won"
states="open,draft,pending" type="object"
icon="gtk-apply" />
<button name="case_pending" string="Pending"
states="open,draft" type="object"
icon="gtk-media-pause" />
<button name="case_cancel" string="Lost"
states="draft,open,pending" type="object"
icon="gtk-cancel" />
</tree>
</field>
</record>
<!-- Opportunities Graph View -->
<record model="ir.ui.view" id="crm_case_graph_view_opportunity">
<field name="name">CRM - Opportunity Graph</field>
<field name="model">crm.lead</field>
<field name="type">graph</field>
<field name="arch" type="xml">
<graph string="Opportunity by Categories" type="bar" orientation="horizontal">
<field name="categ_id"/>
<field name="planned_revenue" operator="+"/>
<field name="state" group="True"/>
</graph>
</field>
</record>
<!-- Opportunities Search View -->
<record id="view_crm_case_opportunities_filter" model="ir.ui.view">
<field name="name">CRM - Opportunities Search</field>
<field name="model">crm.lead</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search Opportunities">
<filter icon="terp-project"
string="Current"
name="current"
domain="[('state','in',('draft','open'))]"/>
<filter icon="terp-project"
string="Open"
domain="[('state','=','open')]"/>
<filter icon="terp-project"
string="Pending"
domain="[('state','=','pending')]"/>
<separator orientation="vertical"/>
<filter icon="gtk-home" string="Today"
domain="[('create_date','&lt;', time.strftime('%%Y-%%m-%%d 23:59:59')), ('create_date','&gt;=', time.strftime('%%Y-%%m-%%d 23:59:59'))]"
help="Todays' Opportunities" />
<filter icon="gtk-media-rewind" string="7 Days"
help="Opportunities during last 7 days"
domain="[('create_date','&lt;', time.strftime('%%Y-%%m-%%d')),\
('create_date','&gt;=',(datetime.date.today()-datetime.timedelta(days=7)).strftime('%%Y-%%m-%%d'))]"
/>
<separator orientation="vertical"/>
<field name="name" string="Opportunity"/>
<field name="user_id" widget="selection">
<filter icon="terp-partner"
domain="[('user_id','=',uid)]"
help="My Opportunities" default="1"/>
<filter icon="terp-partner"
domain="[('user_id','=', uid)]"
help="Unassigned Opportunities"/>
<button name="case_pending" string="Pending"
states="open,draft" type="object"
icon="gtk-media-pause" />
<button name="case_cancel" string="Lost"
states="draft,open,pending" type="object"
icon="gtk-cancel" />
</tree>
</field>
<field name="section_id"
default="context.get('section_id', False)" select="1"
widget="selection">
<filter icon="terp-crm"
domain="[('section_id','=',context.get('section_id',False))]"
help="My Sale Team" />
</field>
<newline/>
<group expand="1" string="Group By...">
<filter string="Stage" icon="terp-crm" domain="[]"
context="{'group_by':'stage_id'}"/>
<filter string="Priority" icon="terp-crm" domain="[]"
context="{'group_by':'priority'}"/>
<filter string="Category" icon="terp-crm"
domain="[]" context="{'group_by':'categ_id'}"/>
</record>
<separator orientation="vertical"/>
<filter string="Salesman" icon="terp-crm"
domain="[('user_id','=',uid)]" context="{'group_by':'user_id'}"/>
<separator orientation="vertical"/>
<filter string="Creation" icon="terp-project"
domain="[]" context="{'group_by':'create_date'}"/>
<filter string="Exp.Closing" icon="terp-project"
domain="[]" context="{'group_by':'date_deadline'}"/>
</group>
</search>
</field>
</record>
<!-- Opportunities Graph View -->
<record model="ir.ui.view" id="crm_case_graph_view_opportunity">
<field name="name">CRM - Opportunity Graph</field>
<field name="model">crm.lead</field>
<field name="type">graph</field>
<field name="arch" type="xml">
<graph string="Opportunity by Categories" type="bar" orientation="horizontal">
<field name="categ_id"/>
<field name="planned_revenue" operator="+"/>
<field name="state" group="True"/>
</graph>
</field>
</record>
<!-- Opportunities Search View -->
<record id="view_crm_case_opportunities_filter" model="ir.ui.view">
<field name="name">CRM - Opportunities Search</field>
<field name="model">crm.lead</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search Opportunities">
<filter icon="terp-project"
string="Current"
name="current"
domain="[('state','in',('draft','open'))]"/>
<filter icon="terp-project"
string="Open"
domain="[('state','=','open')]"/>
<filter icon="terp-project"
string="Pending"
domain="[('state','=','pending')]"/>
<separator orientation="vertical"/>
<filter icon="gtk-home" string="Today"
domain="[('create_date','&lt;', time.strftime('%%Y-%%m-%%d 23:59:59')), ('create_date','&gt;=', time.strftime('%%Y-%%m-%%d 23:59:59'))]"
help="Todays' Opportunities" />
<filter icon="gtk-media-rewind" string="7 Days"
help="Opportunities during last 7 days"
domain="[('create_date','&lt;', time.strftime('%%Y-%%m-%%d')),\
('create_date','&gt;=',(datetime.date.today()-datetime.timedelta(days=7)).strftime('%%Y-%%m-%%d'))]"
/>
<separator orientation="vertical"/>
<field name="name" string="Opportunity"/>
<field name="user_id" widget="selection">
<filter icon="terp-partner"
domain="[('user_id','=', False)]"
help="Unassigned Opportunities" />
</field>
<field name="section_id"
default="context.get('section_id', False)" select="1"
widget="selection">
<filter icon="terp-crm"
domain="[('section_id','=',context.get('section_id',False))]"
help="My Sale Team" />
</field>
<newline/>
<group expand="0" string="Group By..." colspan="16">
<filter string="Stage" icon="terp-crm" domain="[]"
context="{'group_by':'stage_id'}" />
<filter string="Priority" icon="terp-crm" domain="[]"
context="{'group_by':'priority'}" />
<filter string="Category" icon="terp-crm"
domain="[]" context="{'group_by':'categ_id'}" />
<separator orientation="vertical" />
<filter string="Salesman" icon="terp-crm"
domain="[('user_id','=',uid)]" context="{'group_by':'user_id'}" />
<separator orientation="vertical" />
<filter string="Creation" icon="terp-project"
domain="[]" context="{'group_by':'create_date'}" />
<filter string="Exp.Closing" icon="terp-project"
domain="[]" context="{'group_by':'date_deadline'}" />
</group>
</search>
</field>
</record>
<!-- Opportunities Graph View -->
<record model="ir.ui.view" id="crm_case_graph_view_opportunity">
<field name="name">CRM - Opportunity Graph</field>
<field name="model">crm.lead</field>
<field name="type">graph</field>
<field name="arch" type="xml">
<graph string="Opportunity by Categories" type="bar" orientation="horizontal">
<field name="categ_id"/>
<field name="planned_revenue" operator="+"/>
<field name="state" group="True"/>
</graph>
</field>
</record>
</data>
</openerp>

View File

@ -38,6 +38,9 @@ class crm_phonecall(osv.osv, crm_case):
'name': fields.char('Name', size=64),
'active': fields.boolean('Active', required=False),
'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'date_action_last': fields.datetime('Last Action', readonly=1),
'date_action_next': fields.datetime('Next Action', readonly=1),
'create_date': fields.datetime('Creation Date' , readonly=True),
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
select=True, help='Sales team to which Case belongs to.\
Define Responsible user and Email account for mail gateway.'),
@ -87,6 +90,7 @@ class crm_phonecall(osv.osv, crm_case):
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
'state': lambda *a: 'draft',
'user_id': lambda self,cr,uid,ctx: uid,
'active': lambda *a: 1,
}

View File

@ -13,8 +13,8 @@
<field name="context">{'object_id':'crm.phonecall'}</field>
</record>
<menuitem action="crm_phonecall_categ_action"
id="menu_crm_case_phonecall-act" parent="crm.menu_crm_case_categ" />
<menuitem action="crm_phonecall_categ_action" name="Categories"
id="menu_crm_case_phonecall-act" parent="menu_crm_config_phonecall" />
<!-- ResourceType Form View -->
@ -27,10 +27,9 @@
<field name="context">{'object_id':'crm.phonecall'}</field>
</record>
<menuitem action="crm_phonecall_resource_act"
id="menu_crm_phonecall_resource_act"
parent="crm.menu_crm_case_resource_type" />
<menuitem action="crm_phonecall_resource_act"
id="menu_crm_phonecall_resource_act" name="Resource Type"
parent="menu_crm_config_phonecall" />
<!-- PhoneCalls Tree View -->

View File

@ -1,8 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<menuitem id="base.menu_crm_configuration" name="Cases"
parent="base.menu_base_config" sequence="0" groups="base.group_extended"/>
<menuitem id="base.menu_crm_config_sales" name="Sales"
parent="base.menu_base_config" sequence="1" groups="base.group_extended"/>
<menuitem id="menu_crm_config_lead" name="Lead"
parent="base.menu_crm_config_sales" sequence="0" groups="base.group_extended"/>
<menuitem id="menu_crm_config_opportunity" name="Opportunity"
parent="base.menu_crm_config_sales" sequence="1" groups="base.group_extended"/>
<menuitem id="menu_crm_config_meeting" name="Meeting"
parent="base.menu_base_config" sequence="4" groups="base.group_extended"/>
<menuitem id="menu_crm_config_phonecall" name="Phone Call"
parent="base.menu_base_config" sequence="5" groups="base.group_extended"/>
<menuitem id="base.next_id_64" name="Reporting"
parent="base.menu_base_partner" sequence="8" />
@ -117,9 +129,7 @@
<field name="view_id" ref="crm_case_stage_tree"/>
</record>
<menuitem id="menu_crm_case_stage" name="Stages" parent="base.menu_crm_configuration" groups="base.group_extended"/>
<!-- Case Categories Form View -->
<!-- Case Categories Form View -->
<record id="crm_case_categ-view" model="ir.ui.view">
<field name="name">crm.case.categ.form</field>
@ -156,11 +166,11 @@
<field name="view_type">form</field>
<field name="view_id" ref="crm_case_categ_tree-view"/>
</record>
<menuitem id="menu_crm_case_categ" name="Categories" parent="base.menu_crm_configuration" groups="base.group_extended"/>
<menuitem action="crm_case_section_act"
id="menu_crm_case_section_act"
parent="base.menu_crm_configuration" />
id="menu_crm_case_section_act" sequence="4"
parent="base.menu_crm_config_sales" />
<!-- Resource Type of case Tree View -->
@ -201,8 +211,6 @@
<field name="view_type">form</field>
<field name="view_id" ref="crm_case_resource_type_tree"/>
</record>
<menuitem id="menu_crm_case_resource_type" name="Resource Type"
parent="base.menu_crm_configuration" groups="base.group_extended" />
<record id="crm_case_section_act_tree" model="ir.actions.act_window">
<field name="name">Cases by section</field>
@ -342,10 +350,11 @@
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem action="crm_segmentation_tree-act"
<menuitem action="crm_segmentation_tree-act"
id="menu_crm_segmentation-act"
groups="base.group_extended"
parent="base.menu_crm_configuration" />
groups="base.group_extended" sequence="5"
parent="base.menu_crm_config_sales" />
<record model="ir.ui.view" id="view_users_form_simple_modif_inherited1">
<field name="name">view.users.form.crm.modif.inherited1</field>

View File

@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-06-01 03:44+0000\n"
"X-Launchpad-Export-Date: 2010-06-02 03:33+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: crm

View File

@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2010-01-05 05:59+0000\n"
"PO-Revision-Date: 2010-01-22 23:56+0000\n"
"Last-Translator: Paulino <Unknown>\n"
"PO-Revision-Date: 2010-06-01 14:21+0000\n"
"Last-Translator: cmsa <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-04-17 04:02+0000\n"
"X-Launchpad-Export-Date: 2010-06-02 03:33+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: crm
@ -34,7 +34,7 @@ msgstr ""
#: help:crm.case.rule,act_mail_to_user:0
msgid ""
"Check this if you want the rule to send an email to the responsible person."
msgstr ""
msgstr "Marque isto se quer que a regra envie um email ao responsável."
#. module: crm
#: view:crm.meeting:0
@ -57,7 +57,7 @@ msgstr "Fechar dica"
#: view:crm.opportunity:0
#: view:crm.phonecall:0
msgid " 7 Days "
msgstr ""
msgstr " 7 Dias "
#. module: crm
#: help:crm.menu.config_wizard,helpdesk:0
@ -67,7 +67,7 @@ msgstr "Gere um serviço de Helpdesk"
#. module: crm
#: view:crm.job:0
msgid "Pending Jobs"
msgstr ""
msgstr "Tarefas Pendentes"
#. module: crm
#: field:crm.case.rule,trg_state_to:0
@ -82,7 +82,7 @@ msgstr "Custos previstos"
#. module: crm
#: wizard_field:crm.job.partner_create,init,close:0
msgid "Close job request"
msgstr ""
msgstr "Fechar tarefa requerida"
#. module: crm
#: field:crm.case.stage,name:0
@ -191,6 +191,8 @@ msgid ""
"Describes the action name.eg:on which object which ation to be taken on "
"basis of which condition"
msgstr ""
"Descreve o nome da acção . Ou seja, em que Objecto, que acção e em que "
"condições"
#. module: crm
#: help:crm.case,section_id:0
@ -238,7 +240,7 @@ msgstr "Salário proposto"
#. module: crm
#: help:crm.case.section,sequence:0
msgid "Gives the sequence order when displaying a list of case sections."
msgstr ""
msgstr "Devolve a ordem de sequência quando apresenta as secções de opções"
#. module: crm
#: code:addons/crm/wizard/crm_job_wizard.py:0
@ -3619,6 +3621,8 @@ msgstr ""
msgid ""
"Can not send mail with empty body,you should have description in the body"
msgstr ""
"Não pode enviar um email sem corpo de texto, deve inserir texto no corpo do "
"email."
#. module: crm
#: selection:report.crm.case.section.categ.categ2,month:0

View File

@ -35,7 +35,7 @@ class crm_lead_report(osv.osv):
_name = "crm.lead.report"
_auto = False
_description = "CRM Lead Report"
def _get_data(self, cr, uid, ids, field_name, arg, context={}):
""" @param cr: the current row, from the database cursor,
@ -89,7 +89,10 @@ class crm_lead_report(osv.osv):
('11', 'November'), ('12', 'December')], 'Month', readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True),
'create_date': fields.datetime('Create Date', readonly=True),
'day': fields.char('Day', size=128, readonly=True),
'day': fields.char('Day', size=128, readonly=True),
'email': fields.integer('# of Emails', size=128, readonly=True),
'expected_closing_days': fields.integer('# of Expected Closing Days', size=128, readonly=True),
'delay_open': fields.float('Delay to open',digits=(16,2),readonly=True, group_operator="avg",help="Number of Days to open the case"),
'delay_close': fields.float('Delay to close',digits=(16,2),readonly=True, group_operator="avg",help="Number of Days to close the case"),
'categ_id': fields.many2one('crm.case.categ', 'Category',\
domain="[('section_id','=',section_id),\
@ -98,11 +101,10 @@ class crm_lead_report(osv.osv):
domain="[('section_id','=',section_id),\
('object_id.model', '=', 'crm.lead')]", readonly=True),
'partner_id': fields.many2one('res.partner', 'Partner' , readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True),
'type':fields.selection([
('lead','Lead'),
('opportunity','Opportunity'),
],'Type', help="Type is used to separate Leads and Opportunities"),
}
def init(self, cr):
@ -132,13 +134,28 @@ class crm_lead_report(osv.osv):
0 as avg_answers,
0.0 as perc_done,
0.0 as perc_cancel,
(select count(id) from mailgate_message where thread_id=c.id) as email,
date_trunc('day',c.create_date) as create_date,
avg(extract('epoch' from (c.date_closed-c.create_date)))/(3600*24) as delay_close
sum(cast(to_char(date_trunc('day',c.date_open) - date_trunc('day',c.date_deadline),'DD') as int)) as expected_closing_days,
avg(extract('epoch' from (c.date_closed-c.create_date)))/(3600*24) as delay_close,
avg(extract('epoch' from (c.date_open-c.create_date)))/(3600*24) as delay_open
from
crm_lead c
group by to_char(c.create_date, 'YYYY'), to_char(c.create_date, 'MM'),\
c.state, c.user_id,c.section_id,c.stage_id,categ_id,c.partner_id,c.company_id, c.type
,c.create_date,to_char(c.create_date, 'YYYY-MM-DD')
group by
to_char(c.create_date, 'YYYY'),
to_char(c.create_date, 'MM'),
c.state,
c.user_id,
c.id,
c.section_id,
c.stage_id,
categ_id,
c.partner_id,
c.company_id,
c.type,
c.create_date,
to_char(c.create_date, 'YYYY-MM-DD')
)""")
crm_lead_report()

View File

@ -144,7 +144,7 @@
<field name="model">crm.lead.report</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Opportunities">
<tree string="Opportunities Analysis">
<field name="name" invisible="1"/>
<field name="month" invisible="1"/>
<field name="section_id" invisible="1" groups="base.group_extended"/>
@ -153,7 +153,10 @@
<field name="partner_id" invisible="1"/>
<field name="day" invisible="1"/>
<field name="nbr" string="#Opportunities" sum="#Opportunities"/>
<field name="delay_close" sum='Avg Closing Delay'/>
<field name="email" sum="# of Emails"/>
<field name="expected_closing_days" sum='# of Expected Closing Days'/>
<field name="delay_open" sum='Delay to open'/>
<field name="delay_close" sum='Delay to close'/>
<field name="state" invisible="1"/>
<field name="stage_id" invisible="1"/>
<field name="categ_id" invisible="1"/>
@ -188,8 +191,8 @@
<field name="act_window_id" ref="action_report_crm_lead"/>
</record>
<record id="action_report_crm_opportunity" model="ir.actions.act_window">
<field name="name">Opportunities</field>
<record id="action_report_crm_opportunity" model="ir.actions.act_window">
<field name="name">Opportunities Analysis</field>
<field name="res_model">crm.lead.report</field>
<field name="view_type">form</field>
<field name="context">{"search_default_User":1,"search_default_This Month":1,'group_by_no_leaf':1,'group_by':[]}</field>
@ -216,7 +219,7 @@
groups="base.group_extended"
parent="base.next_id_64" action="action_report_crm_lead" />
<menuitem name="Opportunities" id="menu_report_crm_opportunities_tree"
<menuitem name="Opportunities Analysis" id="menu_report_crm_opportunities_tree"
groups="base.group_extended"
parent="base.next_id_64" action="action_report_crm_opportunity" />

View File

@ -27,10 +27,12 @@ class res_partner(osv.osv):
_columns = {
'opportunity_ids': fields.one2many('crm.lead', 'partner_id',\
'Opportunities', domain=[('type', '=', 'opportunity')]),
'Opportunities', readonly=True, \
domain=[('type', '=', 'opportunity')]),
'meeting_ids': fields.one2many('crm.meeting', 'partner_id',\
'Meetings'),
'phonecall_ids': fields.one2many('crm.phonecall', 'partner_id', 'Phonecalls'),
'Meetings', readonly=True),
'phonecall_ids': fields.one2many('crm.phonecall', 'partner_id',\
'Phonecalls', readonly=True),
}
res_partner()

View File

@ -10,52 +10,54 @@
<field name="type">form</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<notebook position="inside">
<page string="CRM">
<field name="meeting_ids" colspan="4" nolabel="1" />
<field name="phonecall_ids" colspan="4" nolabel="1" />
<field name="opportunity_ids" colspan="4" nolabel="1" domain="[('type', '=', 'opportunity')]">
<tree string="Opportunities" colors="blue:state=='pending';grey:state in ('cancel', 'done')">
<field name="create_date"/>
<field name="partner_name"/>
<field name="name"/>
<field name="email_from"/>
<field name="phone"/>
<field name="categ_id" invisible="1"/>
<field name="type_id" invisible="1"/>
<field name="referred" invisible="1"/>
<field name="stage_id"/>
<button name="stage_previous" string="Previous"
states="open,pending" type="object" icon="gtk-go-back" />
<button name="stage_next" string="Next"
states="open,pending" type="object"
icon="gtk-go-forward" />
<field name="section_id"
invisible="context.get('invisible_section', True)" />
<field name="user_id" />
<field name="state" />
<button name="case_open" string="Open"
states="draft,pending" type="object"
icon="gtk-go-forward" />
<button name="case_close" string="Close"
states="open,draft,pending" type="object"
icon="gtk-close" />
<button string="Convert to Opportunity"
name="convert_opportunity"
states="draft,open,pending" icon="gtk-index"
type="object" />
<button name="case_escalate" string="Escalate"
states="open,draft,pending" type="object"
icon="gtk-go-up" />
<button name="case_cancel" string="Cancel"
states="draft,open,pending" type="object"
icon="gtk-cancel" />
</tree>
</field>
</page>
</notebook>
<xpath expr="//notebook[last()]" position="after">
<notebook colspan="4">
<page string="CRM">
<field name="meeting_ids" colspan="4" nolabel="1" />
<field name="phonecall_ids" colspan="4" nolabel="1" />
<field name="opportunity_ids" colspan="4" nolabel="1" domain="[('type', '=', 'opportunity')]">
<tree string="Opportunities" colors="blue:state=='pending';grey:state in ('cancel', 'done')">
<field name="create_date"/>
<field name="partner_name"/>
<field name="name"/>
<field name="email_from"/>
<field name="phone"/>
<field name="categ_id" invisible="1"/>
<field name="type_id" invisible="1"/>
<field name="referred" invisible="1"/>
<field name="stage_id"/>
<button name="stage_previous" string="Previous"
states="open,pending" type="object" icon="gtk-go-back" />
<button name="stage_next" string="Next"
states="open,pending" type="object"
icon="gtk-go-forward" />
<field name="section_id"
invisible="context.get('invisible_section', True)" />
<field name="user_id" />
<field name="state" />
<button name="case_open" string="Open"
states="draft,pending" type="object"
icon="gtk-go-forward" />
<button name="case_close" string="Close"
states="open,draft,pending" type="object"
icon="gtk-close" />
<button string="Convert to Opportunity"
name="convert_opportunity"
states="draft,open,pending" icon="gtk-index"
type="object" />
<button name="case_escalate" string="Escalate"
states="open,draft,pending" type="object"
icon="gtk-go-up" />
<button name="case_cancel" string="Cancel"
states="draft,open,pending" type="object"
icon="gtk-cancel" />
</tree>
</field>
</page>
</notebook>
</xpath>
</field>
</record>

View File

@ -117,7 +117,7 @@ class Contact
"email_from" => new xmlrpcval($post['email'], "string"),
"phone" => new xmlrpcval($post['phone'], "string"),
"partner_name" => new xmlrpcval($post['name'], "string"),
"function_name" => new xmlrpcval($post["jobtitle"], "string"),
"function" => new xmlrpcval($post["jobtitle"], "string"),
"zip" => new xmlrpcval($post['zip'], "string"),
"stage_id" => new xmlrpcval(6, "int"),
"city" => new xmlrpcval($post['city'], "string"),

View File

@ -26,3 +26,4 @@
"access_crm_lead2opportunity_partner","crm.lead2opportunity.partner","model_crm_lead2opportunity_partner","crm.group_crm_user",1,1,1,1
"access_crm_installer","crm.installer.rule","model_crm_installer","crm.group_crm_user",1,1,1,1
"access_crm_lead_forward_to_partner","crm.lead.forward.to.partner","model_crm_lead_forward_to_partner","crm.group_crm_user",2,2,2,2
"access_mailgate_thread","mailgate.thread","model_mailgate_thread","crm.group_crm_user",1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
26 access_crm_lead2opportunity_partner crm.lead2opportunity.partner model_crm_lead2opportunity_partner crm.group_crm_user 1 1 1 1
27 access_crm_installer crm.installer.rule model_crm_installer crm.group_crm_user 1 1 1 1
28 access_crm_lead_forward_to_partner crm.lead.forward.to.partner model_crm_lead_forward_to_partner crm.group_crm_user 2 2 2 2
29 access_mailgate_thread mailgate.thread model_mailgate_thread crm.group_crm_user 1 1 1 1

View File

@ -82,9 +82,9 @@
- |
I can check that a lead and a business opportunity is now assigned to this
lead.
-
# !python {model: crm.lead, id: crm_lead_newcustomer0}:
# - opportunity_id == False
#-
# !python {model: crm.lead, id: crm_lead_newcustomer0}:
# - opportunity_id == False
- |
I check that the partner associated to this lead as the same country, phone number
@ -97,10 +97,11 @@
opportunity = obj_opportunity.browse(cr, uid, ids)[0]
assert lead.partner_name == opportunity.partner_id.name
assert lead.phone == opportunity.phone
-
|
# yaml is also not working smpt server and send new email.
#-
# |
# yaml is also not working smpt server and send new email.
- |
I configure with smtp server.
- |
@ -113,4 +114,4 @@
- |
I Reply to last Email to lead with some document attached.and check that communication history generated or not.

View File

@ -107,8 +107,8 @@ class crm_lead_forward_to_partner(osv.osv_memory):
#TODO: ids and context are not comming
res = False
msg_val = ''
res_id = False # Comes from context
model = None # Comes from context
res_id = context.get('active_id')
model = context.get('active_model')
model_pool = self.pool.get(model)
if not res_id or not model:
return res
@ -212,7 +212,7 @@ class crm_lead_forward_to_partner(osv.osv_memory):
lead = lead_proxy.browse(cr, uid, lead_id, context=context)
if lead.type == 'lead':
field_names = [
'partner_name', 'title', 'function_name', 'street', 'street2',
'partner_name', 'title', 'function', 'street', 'street2',
'zip', 'city', 'country_id', 'state_id', 'email_from',
'phone', 'fax', 'mobile'
]

View File

@ -9,7 +9,7 @@
<form string="Forward to Partner">
<separator string="User" colspan="4" />
<field name="email_from" colspan="2" />
<field name="history" colspan="2" on_change="on_change_history(history)"/>
<field name="history" colspan="2" on_change="on_change_history(history, context)"/>
<separator string="Send to" colspan="4" />
<field name="name" colspan="2" />
<group col="2" colspan="2" attrs="{ 'invisible' : [('name','!=','user')]}">

View File

@ -155,7 +155,7 @@ class crm_lead2partner(osv.osv_memory):
'email': lead.email_from,
'fax': lead.fax,
'title': lead.title,
'function': lead.function_name,
'function': lead.function,
'street': lead.street,
'street2': lead.street2,
'zip': lead.zip,

View File

@ -99,7 +99,7 @@ class crm_send_new_email(osv.osv_memory):
model = hist.model_id.model
model_pool = self.pool.get(model)
res_ids = model_pool.search(cr, uid, [('thread_id','=', hist.thread_id.id)])
res_id = res_ids and res_ids[0] or False
res_id = res_ids and res_ids[0] or False
case = model_pool.browse(cr, uid, res_id)
emails = [obj.email_to] + (obj.email_cc or '').split(',')
emails = filter(None, emails)
@ -107,7 +107,11 @@ class crm_send_new_email(osv.osv_memory):
body = case_pool.format_body(body)
email_from = getattr(obj, 'email_from', False)
case_pool._history(cr, uid, [case], _('Send'), history=True, email=obj.email_to, details=body, email_from=email_from, message_id=message_id)
case_pool._history(cr, uid, [case], _('Send'), history=True, \
email=obj.email_to, details=body, \
subject=obj.subject, email_from=email_from, \
message_id=message_id, attach=attach)
x_headers = dict()
#x_headers = {

View File

@ -2,6 +2,10 @@
<openerp>
<data>
<menuitem id="menu_config_claim" name="Claim"
groups="base.group_extended"
parent="base.menu_base_config" sequence="8" />
<!-- Claims categories -->
<record id="crm_claim_categ_action" model="ir.actions.act_window">
@ -13,8 +17,9 @@
<field name="context">{'object_id':'crm.claim'}</field>
</record>
<menuitem action="crm_claim_categ_action"
id="menu_crm_case_claim-act" parent="crm.menu_crm_case_categ" />
<menuitem action="crm_claim_categ_action" name="Categories"
id="menu_crm_case_claim-act" parent="menu_config_claim" />
<!-- Claim Stages -->
@ -27,8 +32,8 @@
<field name="context">{'object_id':'crm.claim'}</field>
</record>
<menuitem action="crm_claim_stage_act"
id="menu_crm_claim_stage_act" parent="crm.menu_crm_case_stage" />
<menuitem action="crm_claim_stage_act" name="Stages"
id="menu_crm_claim_stage_act" parent="menu_config_claim" />
<!-- Claim Resource Type -->
@ -41,9 +46,9 @@
<field name="context">{'object_id':'crm.claim'}</field>
</record>
<menuitem action="crm_claim_resource_act"
<menuitem action="crm_claim_resource_act" name="Resource Type"
id="menu_crm_claim_stage_act"
parent="crm.menu_crm_case_resource_type" />
parent="menu_config_claim" />
<!-- Claims -->
@ -174,31 +179,38 @@
<group colspan="4">
<field colspan="4" name="email_cc" string="CC"/>
</group>
<field name="message_ids" colspan="4" nolabel="1" mode="form,tree">
<form string="Communication history">
<group col="6" colspan="4">
<field name="date"/>
<field name="email_to"/>
<field name="email_from"/>
</group>
<newline/>
<field name="description" colspan="4" nolabel="1"/>
<button colspan="4"
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'crm.claim'}"
icon="gtk-undo" type="action" />
</form>
<tree string="Communication history">
<field name="description"/>
<field name="email_to"/>
<field name="date"/>
</tree>
</field>
<button colspan="4" string="Send New Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'new', 'model': 'crm.claim'}"
icon="gtk-go-forward" type="action" />
<field name="message_ids" colspan="4" nolabel="1" mode="form,tree" height="280">
<form string="Communication history">
<group col="6" colspan="4">
<field name="date"/>
<field name="email_to"/>
<field name="email_from"/>
</group>
<notebook colspan="4">
<page string="Details">
<field name="description" colspan="4" nolabel="1"/>
</page>
<page string="Attachments">
<field name="attachment_ids" colspan="4" readonly="1" nolabel="1"/>
</page>
</notebook>
<button colspan="4"
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'crm.lead'}"
icon="gtk-undo" type="action" />
</form>
<tree string="Communication history">
<field name="date"/>
<field name="email_from" />
<field name="email_to"/>
<field name="description"/>
</tree>
</field>
<button colspan="4" string="Send New Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'new', 'model': 'crm.claim'}"
icon="gtk-go-forward" type="action" />
</page>
</notebook>

View File

@ -1,6 +1,10 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- Fund Raising Configuration Menu -->
<menuitem id="menu_config_fundrising" name="Fund Raising"
groups="base.group_extended"
parent="base.menu_base_config" sequence="7" />
<!-- Fund Raising Categories Form View -->
@ -13,9 +17,9 @@
<field name="context">{'object_id':'crm.fundraising'}</field>
</record>
<menuitem action="crm_fund_categ_action"
<menuitem action="crm_fund_categ_action" name="Categories"
id="menu_crm_case_fundraising-act" groups="base.group_extended"
parent="crm.menu_crm_case_categ" />
parent="menu_config_fundrising" />
<!-- Fund Stage Form View -->
@ -28,10 +32,11 @@
<field name="context">{'object_id':'crm.fundraising'}</field>
</record>
<menuitem action="crm_fundraising_stage_act"
groups="base.group_extended"
<menuitem action="crm_fundraising_stage_act"
groups="base.group_extended" name="Stages"
id="menu_crm_fundraising_stage_act"
parent="crm.menu_crm_case_stage" />
parent="menu_config_fundrising" />
<!-- Fund Resource Type Form View -->
@ -44,10 +49,10 @@
<field name="context">{'object_id':'crm.fundraising'}</field>
</record>
<menuitem action="crm_fundraising_resource_act"
groups="base.group_extended"
<menuitem action="crm_fundraising_resource_act"
groups="base.group_extended" name="Resource Type"
id="menu_crm_fundraising_resource_act"
parent="crm.menu_crm_case_resource_type" />
parent="menu_config_fundrising" />
<!-- Fund Raising Tree View -->
@ -195,18 +200,25 @@
<field name="email_to"/>
<field name="email_from"/>
</group>
<newline/>
<field name="description" colspan="4" nolabel="1"/>
<notebook colspan="4">
<page string="Details">
<field name="description" colspan="4" nolabel="1"/>
</page>
<page string="Attachments">
<field name="attachment_ids" colspan="4" readonly="1" nolabel="1"/>
</page>
</notebook>
<button colspan="4"
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'crm.fundraising'}"
icon="gtk-undo" type="action" />
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'crm.fundraising'}"
icon="gtk-undo" type="action" />
</form>
<tree string="Communication history">
<field name="description"/>
<field name="email_to"/>
<field name="date"/>
<field name="email_from" />
<field name="email_to"/>
<field name="description"/>
</tree>
</field>
<button colspan="4" string="Send New Email"

View File

@ -1,6 +1,10 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- Helpdesk Support Categories Configuration Menu-->
<menuitem id="menu_config_helpdesk" name="Helpdesk"
groups="base.group_extended"
parent="base.menu_base_config" sequence="8" />
<!-- Helpdesk Support Categories Form View -->
@ -13,8 +17,8 @@
<field name="context">{'object_id':'crm.helpdesk'}</field>
</record>
<menuitem action="crm_helpdesk_categ_action"
id="menu_crm_case_helpdesk-act" parent="crm.menu_crm_case_categ" />
<menuitem action="crm_helpdesk_categ_action" name="Categories"
id="menu_crm_case_helpdesk-act" parent="menu_config_helpdesk" />
<!-- Helpdesk Support Form View -->
@ -135,18 +139,25 @@
<field name="email_to"/>
<field name="email_from"/>
</group>
<newline/>
<field name="description" colspan="4" nolabel="1"/>
<notebook colspan="4">
<page string="Details">
<field name="description" colspan="4" nolabel="1"/>
</page>
<page string="Attachments">
<field name="attachment_ids" colspan="4" readonly="1" nolabel="1"/>
</page>
</notebook>
<button colspan="4"
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'crm.helpdesk'}"
icon="gtk-undo" type="action" />
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'crm.helpdesk'}"
icon="gtk-undo" type="action" />
</form>
<tree string="Communication history">
<field name="description"/>
<field name="email_to"/>
<field name="date"/>
<field name="email_from" />
<field name="email_to"/>
<field name="description"/>
</tree>
</field>
<button colspan="4" string="Send New Email"

View File

@ -15,9 +15,9 @@
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem parent="base.menu_crm_configuration" id="menu_segm_questionnaire"
action="open_questionnaires" />
<menuitem parent="base.menu_crm_config_sales" id="menu_segm_questionnaire"
action="open_questionnaires" />
<record model="ir.actions.act_window" id="open_questions">
<field name="name">Questions</field>
@ -25,7 +25,8 @@
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem parent="base.menu_crm_configuration" id="menu_segm_answer"
<menuitem parent="base.menu_crm_config_sales" id="menu_segm_answer"
action="open_questions" />
<!-- Profiling Questionnaire Tree view -->

View File

@ -26,7 +26,7 @@
'category': 'Generic Modules/Others',
'description': """This is a complete document management system:
* User Authentication
* Document Indexation
* Document Indexation :- .pptx and .docx files are not support in windows platform.
ATTENTION:
- When you install this module in a running company that have already PDF files stored into the database,

View File

@ -75,7 +75,7 @@ class document_file(osv.osv):
'user_id': fields.many2one('res.users', 'Owner', select=1),
'group_ids': fields.many2many('res.groups', 'document_group_rel', 'item_id', 'group_id', 'Groups'),
# the directory id now is mandatory. It can still be computed automatically.
'parent_id': fields.many2one('document.directory', 'Directory', select=1, required=True),
'parent_id': fields.many2one('document.directory', 'Directory', select=1),
'file_size': fields.integer('File Size', required=True),
'file_type': fields.char('Content Type', size=128),
# If ir.attachment contained any data before document is installed, preserve
@ -88,11 +88,16 @@ class document_file(osv.osv):
'create_uid': fields.many2one('res.users', 'Creator', readonly=True),
'store_method': fields.selection([('db', 'Database'), ('fs', 'Filesystem'), ('link', 'Link')], "Storing Method"),
'datas': fields.function(_data_get, method=True, fnct_inv=_data_set, string='File Content', type="binary", nodrop=True),
'url': fields.char('File URL',size=64),
'store_fname': fields.char('Stored Filename', size=200),
'res_model': fields.char('Attached Model', size=64), #res_model
'res_id': fields.integer('Attached ID'), #res_id
'partner_id':fields.many2one('res.partner', 'Partner', select=1),
'title': fields.char('Resource Title', size=64),
'type':fields.selection([
('url','URL'),
('binary','Binary'),
],'Type', help="Type is used to separate URL and binary File"),
}
def __get_def_directory(self, cr, uid, context=None):
@ -103,6 +108,7 @@ class document_file(osv.osv):
'user_id': lambda self, cr, uid, ctx:uid,
'file_size': lambda self, cr, uid, ctx:0,
'store_method': lambda *args: 'db',
'type': 'binary',
'parent_id': __get_def_directory
}
_sql_constraints = [
@ -155,7 +161,6 @@ class document_file(osv.osv):
def create(self, cr, uid, vals, context=None):
if not context:
context = {}
vals['title'] = vals['name']
vals['parent_id'] = context.get('parent_id', False) or vals.get('parent_id', False)
if not vals['parent_id']:
vals['parent_id'] = self.pool.get('document.directory')._get_root_directory(cr,uid, context)
@ -168,8 +173,6 @@ class document_file(osv.osv):
result = obj_model.read(cr, uid, [vals['res_id']], ['name', 'partner_id', 'address_id'], context=context)
if len(result):
obj = result[0]
if obj.get('name', False):
vals['title'] = (obj.get('name', ''))[:60]
if obj_model._name == 'res.partner':
vals['partner_id'] = obj['id']
elif obj.get('address_id', False):

View File

@ -104,11 +104,9 @@ class document_directory(osv.osv):
]
def name_get(self, cr, uid, ids, context={}):
res = []
all_ids = self.search(cr,uid,[])
if not self.search(cr,uid,[('id','in',ids)]):
ids = []
for d in self.browse(cr, uid, ids, context=context):
if d.id not in all_ids:
continue
s = ''
d2 = d
while d2 and d2.parent_id:

View File

@ -118,7 +118,7 @@
<record model="ir.ui.view" id="view_document_directory_tree">
<field name="name">document.directory</field>
<field name="model">document.directory</field>
<field name="type">tree</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Directories" toolbar="1">
<field name="name"/>
@ -179,71 +179,96 @@
<form string="Documents">
<group colspan="4" col="6">
<field name="name" select="1" />
<field name="title" select="1"/>
<field name="partner_id"/>
<field name="user_id"/>
<field name="parent_id"/>
<field name="type"/>
<field name="parent_id"/>
</group>
<notebook colspan="4">
<page string="Attachment">
<group col="2" colspan="2">
<separator string="Data" colspan="2"/>
<group col="2" colspan="2" attrs="{'invisible':[('type','=','url')]}">
<field name="datas" filename="datas_fname"/>
<field name="datas_fname" select="1"/>
</group>
<group col="2" colspan="2">
<separator string="Attached To" colspan="2"/>
<field name="res_model" readonly="1"/>
<field name="res_id" readonly="1"/>
</group>
<separator string="Preview" colspan="4"/>
<field
name="preview"
widget="image"
readonly="1"
nolabel="1"
colspan="4"
img_height="400"
img_width="800"/>
</group>
<group col="2" colspan="2" attrs="{'invisible':[('type','=','binary')]}">
<field name="url" widget="url"/>
</group>
</page><page string="Indexed Content">
<field name="index_content" nolabel="1" colspan="4" select="1"/>
</page><page string="Security">
<field name="group_ids" colspan="4" nolabel="1"/>
</page><page string="Others Info">
<group colspan="4" col="4">
<separator string="File Information" colspan="4"/>
<field name="file_size" readonly="1"/>
<newline/>
</group>
<group col="2" colspan="2">
<separator string="Relation" colspan="2"/>
<field name="res_name" readonly="1"/>
<field name="partner_id"/>
<field name="user_id"/>
</group>
<group col="4" colspan="4">
<separator string="History" colspan="4"/>
<group col="4" colspan="4">
<field name="create_uid"/>
<field name="create_date"/>
</group>
<group col="4" colspan="4">
<field name="write_uid"/>
<field name="write_date"/>
</group>
</group>
</page><page string="Notes">
</page>
<page string="Security">
<field name="group_ids" colspan="4" nolabel="1"/>
</page>
<page string="Notes">
<field colspan="4" name="description" nolabel="1"/>
</page>
</notebook>
</form>
</field>
</record>
<record id="view_attach_filter" model="ir.ui.view">
<field name="name">IR Attachment</field>
<field name="model">ir.attachment</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="IR Attachment">
<filter icon="gtk-media-rewind" string="Recent"
help="less 1 month modified/created attachments"
domain="[('create_date','&lt;=', time.strftime('%%Y-%%m-%%d')),('create_date','&gt;',(datetime.date.today()-datetime.timedelta(days=30)).strftime('%%Y-%%m-%%d'))]"
/>
<separator orientation="vertical"/>
<field name="user_id" widget="selection">
<filter icon="terp-partner"
domain="[('user_id','=', False)]"
help="Filter on my Attachment" />
</field>
<field name="partner_id" widget="selection"/>
<newline/>
<group expand="1" string="Group By...">
<filter string="Partner" icon="terp-partner" domain="[]"
context="{'group_by':'partner_id'}" />
<filter string="Directory" icon="gtk-open" domain="[]" context="{'group_by':'parent_id'}"/>
</group>
</search>
</field>
</record>
<record model="ir.ui.view" id="view_document_file_tree">
<field name="name">ir.attachment</field>
<field name="model">ir.attachment</field>
<field name="type">tree</field>
<field name="priority" eval="1"/>
<field name="arch" type="xml">
<tree string="Documents">
<tree colors="blue:type in ('url')" string="Documents">
<field name="name"/>
<field name="title" />
<field name="partner_id"/>
<field name="type"/>
<field name="datas_fname"/>
<field name="user_id"/>
<field name="create_date"/>
<field name="write_date"/>
</tree>
</field>
</record>

View File

@ -44,7 +44,6 @@ class report_document_user(osv.osv):
('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')],'Month',readonly=True),
'user_id':fields.integer('Owner', readonly=True),
'user':fields.char('User',size=64,readonly=True),
'file_title': fields.char('File Name',size=64,readonly=True),
'directory': fields.char('Directory',size=64,readonly=True),
'create_date': fields.datetime('Date Created', readonly=True),
'change_date': fields.datetime('Modified Date', readonly=True),
@ -66,7 +65,6 @@ class report_document_user(osv.osv):
d.name as directory,
f.create_date as create_date,
f.file_size as file_size,
min(f.title) as file_title,
min(d.type) as type,
f.write_date as change_date
from ir_attachment f
@ -83,7 +81,6 @@ class report_files_partner(osv.osv):
_auto = False
_columns = {
'name': fields.char('Year',size=64,required=False, readonly=True),
'file_title': fields.char('File Name',size=64,readonly=True),
'directory': fields.char('Directory',size=64,readonly=True),
'create_date': fields.datetime('Date Created', readonly=True),
'change_date': fields.datetime('Modified Date', readonly=True),
@ -101,7 +98,6 @@ class report_files_partner(osv.osv):
select min(f.id) as id,count(*) as nbr,
to_char(f.create_date,'YYYY') as name,
min(to_char(f.create_date,'MM')) as month,
min(f.title) as file_title,
p.name as partner
from ir_attachment f
inner join res_partner p
@ -145,7 +141,6 @@ class report_document_wall(osv.osv):
'user_id':fields.many2one('res.users', 'Owner',readonly=True),
'user':fields.char('User',size=64,readonly=True),
'month': fields.char('Month', size=24,readonly=True),
'file_name':fields.char('Last Posted File Name',size=64,readonly=True),
'last':fields.datetime('Last Posted Time', readonly=True),
}
@ -153,7 +148,6 @@ class report_document_wall(osv.osv):
cr.execute("""
create or replace view report_document_wall as (
select max(f.id) as id,
min(title) as file_name,
to_char(min(f.create_date),'YYYY-MM-DD HH24:MI:SS') as last,
f.user_id as user_id, f.user_id as user,
to_char(f.create_date,'Month') as month

View File

@ -8,7 +8,6 @@
<field name="arch" type="xml">
<form string="Files">
<field name="name" select="1"/>
<field name="file_title" select="1"/>
<field name="user" select="1"/>
<field name="directory" select="1"/>
<field name="file_size"/>
@ -26,7 +25,6 @@
<tree string="Files">
<field name="name" select="1"/>
<field name="month" select="1"/>
<field name="file_title"/>
<field name="user" select="1"/>
<field name="directory" select="1"/>
<field name="file_size"/>
@ -48,7 +46,6 @@
<separator orientation="vertical"/>
<field name="name" select="1"/>
<field name="month" select="1"/>
<field name="file_title" select="1"/>
<field name="user" select="1"/>
<field name="directory" select="1"/>
</group>
@ -79,13 +76,11 @@
<form string="Wall of Shame">
<field name="user_id" select="1"/>
<field name="month" select="1"/>
<field name="file_name" select="1"/>
<field name="last"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_document_wall_tree">
<field name="name">report.document.wall.tree</field>
<field name="model">report.document.wall</field>
@ -94,7 +89,6 @@
<tree string="Wall of Shame">
<field name="user_id" select="1"/>
<field name="month" select="1"/>
<field name="file_name"/>
<field name="last"/>
</tree>
</field>

View File

@ -57,6 +57,7 @@ class PptxIndex(indexer):
return ['.pptx']
def _doIndexFile(self,fname):
# pptx2txt.pl package not support in windows platform.
# Download pptx2txt package from http://sourceforge.net/projects/pptx2txt/" link.
# To install this tool, just copy pptx2txt.pl to appropriate place (e.g. /usr/bin directory)
fp = Popen(['pptx2txt.pl', fname], shell=False, stdout=PIPE).stdout
@ -88,6 +89,7 @@ class DocxIndex(indexer):
return ['.docx']
def _doIndexFile(self,fname):
# docx2txt.pl package not support in windows platform.
# Download docx2txt package from "http://sourceforge.net/projects/docx2txt/" link.
# In case, you don't want to use Makefile for installation, you can follow these steps for manual installation.
# Copy docx2txt.pl, docx2txt.sh and docx2txt.config to appropriate place (e.g. /usr/bin directory) . used following command.

View File

@ -558,8 +558,7 @@ class abstracted_fs:
if dst_obj2:
ressource_type_id = pool.get('ir.model').search(cr, uid, [('model','=',dst_obj2._name)])[0]
ressource_id = dst_obj2.id
title = dst_obj2.name
ressource_id = dst_obj2.id
ressource_model = dst_obj2._name
if dst_obj2._name == 'res.partner':
partner_id = dst_obj2.id
@ -569,8 +568,7 @@ class abstracted_fs:
ressource_type_id = False
ressource_id = False
ressource_model = False
partner_id = False
title = False
partner_id = False
pool.get('document.directory').write(cr, uid, result['directory'], {
'name' : dst_basename,
'ressource_id': ressource_id,
@ -579,8 +577,7 @@ class abstracted_fs:
})
val = {
'res_id': ressource_id,
'res_model': ressource_model,
'title': title,
'res_model': ressource_model,
'partner_id': partner_id
}
pool.get('ir.attachment').write(cr, uid, result['attachment'], val)
@ -603,7 +600,6 @@ class abstracted_fs:
'res_model': False,
'name': dst_basename,
'datas_fname': dst_basename,
'title': dst_basename,
}
if (dst_obj and (dst_obj.type in ('directory','ressource'))) or not dst_obj2:
@ -613,8 +609,7 @@ class abstracted_fs:
if dst_obj2:
val['res_model'] = dst_obj2._name
val['res_id'] = dst_obj2.id
val['title'] = dst_obj2.name
val['res_id'] = dst_obj2.id
if dst_obj2._name == 'res.partner':
val['partner_id'] = dst_obj2.id
else:

View File

@ -1975,7 +1975,7 @@ class FTPHandler(asynchat.async_chat):
# which IPv6 address to use for binding the socket?
# Unfortunately RFC-2428 does not provide satisfing information
# on how to do that. The assumption is that we don't have any way
# to know wich address to use, hence we just use the same address
# to know which address to use, hence we just use the same address
# family used on the control connection.
if not line:
self._make_epasv(extmode=True)

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@ -15,7 +15,7 @@
# 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/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

View File

@ -0,0 +1,5 @@
import email_template_account
import email_template
import email_template_mailbox
import wizard

View File

@ -0,0 +1,24 @@
{
"name" : "Email Template for Open ERP",
"version" : "0.7 RC",
"author" : "Open ERP",
"website" : "http://openerp.com",
"category" : "Added functionality",
"depends" : ['base'],
"description": """
Email Template is extraction of Power Email basically just to send the emails.
""",
"init_xml": ['email_template_scheduler_data.xml'],
"update_xml": [
'security/email_template_security.xml',
'email_template_workflow.xml',
'email_template_account_view.xml',
'email_template_view.xml',
'email_template_mailbox_view.xml',
'wizard/email_template_send_wizard_view.xml',
],
"installable": True,
"active": False,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,698 @@
import base64
import random
import time
import types
import netsvc
LOGGER = netsvc.Logger()
TEMPLATE_ENGINES = []
from osv import osv, fields
from tools.translate import _
from mako.template import Template #For backward combatibility
try:
from mako.template import Template as MakoTemplate
from mako import exceptions
TEMPLATE_ENGINES.append(('mako', 'Mako Templates'))
except:
LOGGER.notifyChannel(
_("Email Template"),
netsvc.LOG_ERROR,
_("Mako templates not installed")
)
try:
from django.template import Context, Template as DjangoTemplate
#Workaround for bug:
#http://code.google.com/p/django-tagging/issues/detail?id=110
from django.conf import settings
settings.configure()
#Workaround ends
TEMPLATE_ENGINES.append(('django', 'Django Template'))
except:
LOGGER.notifyChannel(
_("Email Template"),
netsvc.LOG_ERROR,
_("Django templates not installed")
)
import email_template_engines
import tools
import report
import pooler
def get_value(cursor, user, recid, message=None, template=None, context=None):
"""
Evaluates an expression and returns its value
@param cursor: Database Cursor
@param user: ID of current user
@param recid: ID of the target record under evaluation
@param message: The expression to be evaluated
@param template: BrowseRecord object of the current template
@param context: Open ERP Context
@return: Computed message (unicode) or u""
"""
pool = pooler.get_pool(cursor.dbname)
if message is None:
message = {}
#Returns the computed expression
if message:
try:
message = tools.ustr(message)
object = pool.get(template.model_int_name).browse(cursor, user, recid, context)
env = {
'user':pool.get('res.users').browse(cursor, user, user, context),
'db':cursor.dbname
}
if template.template_language == 'mako':
templ = MakoTemplate(message, input_encoding='utf-8')
reply = MakoTemplate(message).render_unicode(object=object,
peobject=object,
env=env,
format_exceptions=True)
elif template.template_language == 'django':
templ = DjangoTemplate(message)
env['object'] = object
env['peobject'] = object
reply = templ.render(Context(env))
return reply or False
except Exception:
return u""
else:
return message
class email_template(osv.osv):
"Templates for sending Email"
_name = "email.template"
_description = 'Email Templates for Models'
def change_model(self, cursor, user, ids, object_name, context=None):
if object_name:
mod_name = self.pool.get('ir.model').read(
cursor,
user,
object_name,
['model'], context)['model']
else:
mod_name = False
return {
'value':{'model_int_name':mod_name}
}
_columns = {
'name' : fields.char('Name of Template', size=100, required=True),
'object_name':fields.many2one('ir.model', 'Model'),
'model_int_name':fields.char('Model Internal Name', size=200,),
'def_to':fields.char(
'Recepient (To)',
size=250,
help="The default recepient of email."
"Placeholders can be used here."),
'def_cc':fields.char(
'Default CC',
size=250,
help="The default CC for the email."
" Placeholders can be used here."),
'def_bcc':fields.char(
'Default BCC',
size=250,
help="The default BCC for the email."
" Placeholders can be used here."),
'lang':fields.char(
'Language',
size=250,
help="The default language for the email."
" Placeholders can be used here. "
"eg. ${object.partner_id.lang}"),
'def_subject':fields.char(
'Default Subject',
size=200,
help="The default subject of email."
" Placeholders can be used here.",
translate=True),
'def_body_text':fields.text(
'Standard Body (Text)',
help="The text version of the mail",
translate=True),
'def_body_html':fields.text(
'Body (Text-Web Client Only)',
help="The text version of the mail",
translate=True),
'use_sign':fields.boolean(
'Use Signature',
help="the signature from the User details"
"will be appened to the mail"),
'file_name':fields.char(
'File Name Pattern',
size=200,
help="File name pattern can be specified with placeholders."
"eg. 2009_SO003.pdf",
translate=True),
'report_template':fields.many2one(
'ir.actions.report.xml',
'Report to send'),
'ref_ir_act_window':fields.many2one(
'ir.actions.act_window',
'Window Action',
readonly=True),
'ref_ir_value':fields.many2one(
'ir.values',
'Wizard Button',
readonly=True),
'allowed_groups':fields.many2many(
'res.groups',
'template_group_rel',
'templ_id', 'group_id',
string="Allowed User Groups",
help="Only users from these groups will be"
" allowed to send mails from this Template"),
'enforce_from_account':fields.many2one(
'email_template.account',
string="Enforce From Account",
help="Emails will be sent only from this account.",
domain="[('company','=','yes')]"),
'model_object_field':fields.many2one(
'ir.model.fields',
string="Field",
help="Select the field from the model you want to use."
"\nIf it is a relationship field you will be able to "
"choose the nested values in the box below\n(Note:If "
"there are no values make sure you have selected the"
" correct model)",
store=False),
'sub_object':fields.many2one(
'ir.model',
'Sub-model',
help='When a relation field is used this field'
' will show you the type of field you have selected',
store=False),
'sub_model_object_field':fields.many2one(
'ir.model.fields',
'Sub Field',
help="When you choose relationship fields "
"this field will specify the sub value you can use.",
store=False),
'null_value':fields.char(
'Null Value',
help="This Value is used if the field is empty",
size=50, store=False),
'copyvalue':fields.char(
'Expression',
size=100,
help="Copy and paste the value in the "
"location you want to use a system value.",
store=False),
'table_html':fields.text(
'HTML code',
help="Copy this html code to your HTML message"
" body for displaying the info in your mail.",
store=False),
#Template language(engine eg.Mako) specifics
'template_language':fields.selection(
TEMPLATE_ENGINES,
'Templating Language',
required=True
)
}
_defaults = {
}
_sql_constraints = [
('name', 'unique (name)', _('The template name must be unique !'))
]
def create(self, cr, uid, vals, context=None):
id = super(email_template, self).create(cr, uid, vals, context)
src_obj = self.pool.get('ir.model').read(cr, uid, vals['object_name'], ['model'], context)['model']
vals['ref_ir_act_window'] = self.pool.get('ir.actions.act_window').create(cr, uid, {
'name': _("%s Mail Form") % vals['name'],
'type': 'ir.actions.act_window',
'res_model': 'email_template.send.wizard',
'src_model': src_obj,
'view_type': 'form',
'context': "{'src_model':'%s','template_id':'%d','src_rec_id':active_id,'src_rec_ids':active_ids}" % (src_obj, id),
'view_mode':'form,tree',
'view_id': self.pool.get('ir.ui.view').search(cr, uid, [('name', '=', 'email_template.send.wizard.form')], context=context)[0],
'target': 'new',
'auto_refresh':1
}, context)
vals['ref_ir_value'] = self.pool.get('ir.values').create(cr, uid, {
'name': _('Send Mail (%s)') % vals['name'],
'model': src_obj,
'key2': 'client_action_multi',
'value': "ir.actions.act_window," + str(vals['ref_ir_act_window']),
'object': True,
}, context)
self.write(cr, uid, id, {
'ref_ir_act_window': vals['ref_ir_act_window'],
'ref_ir_value': vals['ref_ir_value'],
}, context)
return id
def unlink(self, cr, uid, ids, context=None):
for template in self.browse(cr, uid, ids, context):
obj = self.pool.get(template.object_name.model)
try:
if template.ref_ir_act_window:
self.pool.get('ir.actions.act_window').unlink(cr, uid, template.ref_ir_act_window.id, context)
if template.ref_ir_value:
self.pool.get('ir.values').unlink(cr, uid, template.ref_ir_value.id, context)
except:
raise osv.except_osv(_("Warning"), _("Deletion of Record failed"))
return super(email_template, self).unlink(cr, uid, ids, context)
def copy(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
default = default.copy()
old = self.read(cr, uid, id, ['name'], context=context)
new_name = _("Copy of template ") + old.get('name', 'No Name')
check = self.search(cr, uid, [('name', '=', new_name)], context=context)
if check:
new_name = new_name + '_' + random.choice('abcdefghij') + random.choice('lmnopqrs') + random.choice('tuvwzyz')
default.update({'name':new_name})
return super(email_template, self).copy(cr, uid, id, default, context)
def compute_pl(self,
model_object_field,
sub_model_object_field,
null_value, template_language='mako'):
"""
Returns the expression based on data provided
@param model_object_field: First level field
@param sub_model_object_field: Second level drilled down field (M2O)
@param null_value: What has to be returned if the value is empty
@param template_language: The language used for templating
@return: computed expression
"""
#Configure for MAKO
copy_val = ''
if template_language == 'mako':
if model_object_field:
copy_val = "${object." + model_object_field
if sub_model_object_field:
copy_val += "." + sub_model_object_field
if null_value:
copy_val += " or '" + null_value + "'"
if model_object_field:
copy_val += "}"
elif template_language == 'django':
if model_object_field:
copy_val = "{{object." + model_object_field
if sub_model_object_field:
copy_val += "." + sub_model_object_field
if null_value:
copy_val = copy_val + '|default:"' + null_value + '"'
copy_val = copy_val + "}}"
return copy_val
def onchange_model_object_field(self, cr, uid, ids, model_object_field, template_language, context=None):
if not model_object_field:
return {}
result = {}
field_obj = self.pool.get('ir.model.fields').browse(cr, uid, model_object_field, context)
#Check if field is relational
if field_obj.ttype in ['many2one', 'one2many', 'many2many']:
res_ids = self.pool.get('ir.model').search(cr, uid, [('model', '=', field_obj.relation)], context=context)
if res_ids:
result['sub_object'] = res_ids[0]
result['copyvalue'] = self.compute_pl(False,
False,
False,
template_language)
result['sub_model_object_field'] = False
result['null_value'] = False
else:
#Its a simple field... just compute placeholder
result['sub_object'] = False
result['copyvalue'] = self.compute_pl(field_obj.name,
False,
False,
template_language
)
result['sub_model_object_field'] = False
result['null_value'] = False
return {'value':result}
def onchange_sub_model_object_field(self, cr, uid, ids, model_object_field, sub_model_object_field, template_language, context=None):
if not model_object_field or not sub_model_object_field:
return {}
result = {}
field_obj = self.pool.get('ir.model.fields').browse(cr, uid, model_object_field, context)
if field_obj.ttype in ['many2one', 'one2many', 'many2many']:
res_ids = self.pool.get('ir.model').search(cr, uid, [('model', '=', field_obj.relation)], context=context)
sub_field_obj = self.pool.get('ir.model.fields').browse(cr, uid, sub_model_object_field, context)
if res_ids:
result['sub_object'] = res_ids[0]
result['copyvalue'] = self.compute_pl(field_obj.name,
sub_field_obj.name,
False,
template_language
)
result['sub_model_object_field'] = sub_model_object_field
result['null_value'] = False
else:
#Its a simple field... just compute placeholder
result['sub_object'] = False
result['copyvalue'] = self.compute_pl(field_obj.name,
False,
False,
template_language
)
result['sub_model_object_field'] = False
result['null_value'] = False
return {'value':result}
def onchange_null_value(self, cr, uid, ids, model_object_field, sub_model_object_field, null_value, template_language, context=None):
if not model_object_field and not null_value:
return {}
result = {}
field_obj = self.pool.get('ir.model.fields').browse(cr, uid, model_object_field, context)
if field_obj.ttype in ['many2one', 'one2many', 'many2many']:
res_ids = self.pool.get('ir.model').search(cr, uid, [('model', '=', field_obj.relation)], context=context)
sub_field_obj = self.pool.get('ir.model.fields').browse(cr, uid, sub_model_object_field, context)
if res_ids:
result['sub_object'] = res_ids[0]
result['copyvalue'] = self.compute_pl(field_obj.name,
sub_field_obj.name,
null_value,
template_language
)
result['sub_model_object_field'] = sub_model_object_field
result['null_value'] = null_value
else:
#Its a simple field... just compute placeholder
result['sub_object'] = False
result['copyvalue'] = self.compute_pl(field_obj.name,
False,
null_value,
template_language
)
result['sub_model_object_field'] = False
result['null_value'] = null_value
return {'value':result}
def generate_attach_reports(self,
cursor,
user,
template,
record_id,
mail,
context=None):
"""
Generate report to be attached and attach it
to the email
@param cursor: Database Cursor
@param user: ID of User
@param template: Browse record of
template
@param record_id: ID of the target model
for which this mail has
to be generated
@param mail: Browse record of email object
@return: True
"""
reportname = 'report.' + \
self.pool.get('ir.actions.report.xml').read(
cursor,
user,
template.report_template.id,
['report_name'],
context)['report_name']
service = netsvc.LocalService(reportname)
data = {}
data['model'] = template.model_int_name
(result, format) = service.create(cursor,
user,
[record_id],
data,
context)
attachment_obj = self.pool.get('ir.attachment')
new_att_vals = {
'name':mail.subject + ' (Email Attachment)',
'datas':base64.b64encode(result),
'datas_fname':tools.ustr(
get_value(
cursor,
user,
record_id,
template.file_name,
template,
context
) or 'Report') + "." + format,
'description':mail.subject or "No Description",
'res_model':'email_template.mailbox',
'res_id':mail.id
}
attachment_id = attachment_obj.create(cursor,
user,
new_att_vals,
context)
if attachment_id:
self.pool.get('email_template.mailbox').write(
cursor,
user,
mail.id,
{
'attachments_ids':[
[6, 0, [attachment_id]]
],
'mail_type':'multipart/mixed'
},
context)
return True
def generate_mailbox_item_from_template(self,
cursor,
user,
template,
record_id,
context=None):
"""
Generates an email from the template for
record record_id of target object
@param cursor: Database Cursor
@param user: ID of User
@param template: Browse record of
template
@param record_id: ID of the target model
for which this mail has
to be generated
@return: ID of created object
"""
if context is None:
context = {}
#If account to send from is in context select it, else use enforced account
if 'account_id' in context.keys():
from_account = self.pool.get('email_template.account').read(
cursor,
user,
context.get('account_id'),
['name', 'email_id'],
context
)
else:
from_account = {
'id':template.enforce_from_account.id,
'name':template.enforce_from_account.name,
'email_id':template.enforce_from_account.email_id
}
lang = get_value(cursor,
user,
record_id,
template.lang,
template,
context)
if lang:
ctx = context.copy()
ctx.update({'lang':lang})
template = self.browse(cursor, user, template_id, context=ctx)
mailbox_values = {
'email_from': tools.ustr(from_account['name']) + \
"<" + tools.ustr(from_account['email_id']) + ">",
'email_to':get_value(cursor,
user,
record_id,
template.def_to,
template,
context),
'email_cc':get_value(cursor,
user,
record_id,
template.def_cc,
template,
context),
'email_bcc':get_value(cursor,
user,
record_id,
template.def_bcc,
template,
context),
'subject':get_value(cursor,
user,
record_id,
template.def_subject,
template,
context),
'body_text':get_value(cursor,
user,
record_id,
template.def_body_text,
template,
context),
'body_html':get_value(cursor,
user,
record_id,
template.def_body_html,
template,
context),
'account_id' :from_account['id'],
#This is a mandatory field when automatic emails are sent
'state':'na',
'folder':'drafts',
'mail_type':'multipart/alternative'
}
#Use signatures if allowed
if template.use_sign:
sign = self.pool.get('res.users').read(cursor,
user,
user,
['signature'],
context)['signature']
if mailbox_values['body_text']:
mailbox_values['body_text'] += sign
if mailbox_values['body_html']:
mailbox_values['body_html'] += sign
mailbox_id = self.pool.get('email_template.mailbox').create(
cursor,
user,
mailbox_values,
context)
return mailbox_id
def generate_mail(self,
cursor,
user,
template_id,
record_ids,
context=None):
if context is None:
context = {}
template = self.browse(cursor, user, template_id, context=context)
if not template:
raise Exception("The requested template could not be loaded")
for record_id in record_ids:
mailbox_id = self._generate_mailbox_item_from_template(
cursor,
user,
template,
record_id,
context)
mail = self.pool.get('email_template.mailbox').browse(
cursor,
user,
mailbox_id,
context=context
)
if template.report_template:
self._generate_attach_reports(
cursor,
user,
template,
record_id,
mail,
context
)
self.pool.get('email_template.mailbox').write(
cursor,
user,
mailbox_id,
{'folder':'outbox'},
context=context
)
return True
email_template()
class email_template_preview(osv.osv_memory):
_name = "email_template.preview"
_description = "Email Template Preview"
def _get_model_recs(self, cr, uid, context=None):
if context is None:
context = {}
#Fills up the selection box which allows records from the selected object to be displayed
self.context = context
if 'active_id' in context.keys():
# context['active_id'] = 5
ref_obj_id = self.pool.get('email.template').read(cr, uid, context['active_id'], ['object_name'], context)
ref_obj_name = self.pool.get('ir.model').read(cr, uid, ref_obj_id[0], ['model'], context)['model']
ref_obj_ids = self.pool.get(ref_obj_name).search(cr, uid, [], context=context)
ref_obj_recs = self.pool.get(ref_obj_name).name_get(cr, uid, ref_obj_ids, context)
return ref_obj_recs
def _default_model(self, cursor, user, context=None):
"""
Returns the default value for model field
@param cursor: Database Cursor
@param user: ID of current user
@param context: Open ERP Context
"""
return self.pool.get('email.template').read(
cursor,
user,
context['active_id'],
['object_name'],
context)['object_name']
_columns = {
'ref_template':fields.many2one(
'email.template',
'Template', readonly=True),
'rel_model':fields.many2one('ir.model', 'Model', readonly=True),
'rel_model_ref':fields.selection(_get_model_recs, 'Referred Document'),
'to':fields.char('To', size=250, readonly=True),
'cc':fields.char('CC', size=250, readonly=True),
'bcc':fields.char('BCC', size=250, readonly=True),
'subject':fields.char('Subject', size=200, readonly=True),
'body_text':fields.text('Body', readonly=True),
'body_html':fields.text('Body', readonly=True),
'report':fields.char('Report Name', size=100, readonly=True),
}
_defaults = {
'ref_template': lambda self, cr, uid, ctx:ctx['active_id'],
'rel_model': _default_model
}
def on_change_ref(self, cr, uid, ids, rel_model_ref, context=None):
if context is None:
context = {}
if not rel_model_ref:
return {}
vals = {}
if context == {}:
context = self.context
template = self.pool.get('email.template').browse(cr, uid, context['active_id'], context)
#Search translated template
lang = get_value(cr, uid, rel_model_ref, template.lang, template, context)
if lang:
ctx = context.copy()
ctx.update({'lang':lang})
template = self.pool.get('email.template').browse(cr, uid, context['active_id'], ctx)
vals['to'] = get_value(cr, uid, rel_model_ref, template.def_to, template, context)
vals['cc'] = get_value(cr, uid, rel_model_ref, template.def_cc, template, context)
vals['bcc'] = get_value(cr, uid, rel_model_ref, template.def_bcc, template, context)
vals['subject'] = get_value(cr, uid, rel_model_ref, template.def_subject, template, context)
vals['body_text'] = get_value(cr, uid, rel_model_ref, template.def_body_text, template, context)
vals['body_html'] = get_value(cr, uid, rel_model_ref, template.def_body_html, template, context)
vals['report'] = get_value(cr, uid, rel_model_ref, template.file_name, template, context)
return {'value':vals}
email_template_preview()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,440 @@
from osv import osv, fields
from html2text import html2text
import re
import smtplib
import base64
from email import Encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import decode_header, Header
from email.utils import formatdate
import re
import netsvc
import string
import email
import time, datetime
import email_template_engines
from tools.translate import _
import tools
class email_template_account(osv.osv):
"""
Object to store email account settings
"""
_name = "email_template.account"
_known_content_types = ['multipart/mixed',
'multipart/alternative',
'multipart/related',
'text/plain',
'text/html'
]
_columns = {
'name': fields.char('Email Account Desc',
size=64, required=True,
readonly=True, select=True,
states={'draft':[('readonly', False)]}),
'user':fields.many2one('res.users',
'Related User', required=True,
readonly=True, states={'draft':[('readonly', False)]}),
'email_id': fields.char('Email ID',
size=120, required=True,
readonly=True, states={'draft':[('readonly', False)]} ,
help=" eg:yourname@yourdomain.com "),
'smtpserver': fields.char('Server',
size=120, required=True,
readonly=True, states={'draft':[('readonly', False)]},
help="Enter name of outgoing server,eg:smtp.gmail.com "),
'smtpport': fields.integer('SMTP Port ',
size=64, required=True,
readonly=True, states={'draft':[('readonly', False)]},
help="Enter port number,eg:SMTP-587 "),
'smtpuname': fields.char('User Name',
size=120, required=False,
readonly=True, states={'draft':[('readonly', False)]}),
'smtppass': fields.char('Password',
size=120, invisible=True,
required=False, readonly=True,
states={'draft':[('readonly', False)]}),
'smtptls':fields.boolean('Use TLS',
states={'draft':[('readonly', False)]}, readonly=True),
'smtpssl':fields.boolean('Use SSL/TLS (only in python 2.6)',
states={'draft':[('readonly', False)]}, readonly=True),
'send_pref':fields.selection([
('html', 'HTML otherwise Text'),
('text', 'Text otherwise HTML'),
('both', 'Both HTML & Text')
], 'Mail Format', required=True),
'allowed_groups':fields.many2many(
'res.groups',
'account_group_rel', 'templ_id', 'group_id',
string="Allowed User Groups",
help="Only users from these groups will be" \
"allowed to send mails from this ID"),
'company':fields.selection([
('yes', 'Yes'),
('no', 'No')
], 'Company Mail A/c',
readonly=True,
help="Select if this mail account does not belong" \
"to specific user but the organisation as a whole." \
"eg:info@somedomain.com",
required=True, states={
'draft':[('readonly', False)]
}),
'state':fields.selection([
('draft', 'Initiated'),
('suspended', 'Suspended'),
('approved', 'Approved')
],
'Account Status', required=True, readonly=True),
}
_defaults = {
'name':lambda self, cursor, user, context:self.pool.get(
'res.users'
).read(
cursor,
user,
user,
['name'],
context
)['name'],
'smtpssl':lambda * a:True,
'state':lambda * a:'draft',
'user':lambda self, cursor, user, context:user,
'send_pref':lambda * a: 'html',
'smtptls':lambda * a:True,
}
_sql_constraints = [
(
'email_uniq',
'unique (email_id)',
'Another setting already exists with this email ID !')
]
def _constraint_unique(self, cursor, user, ids):
"""
This makes sure that you dont give personal
users two accounts with same ID (Validated in sql constaints)
However this constraint exempts company accounts.
Any no of co accounts for a user is allowed
"""
if self.read(cursor, user, ids, ['company'])[0]['company'] == 'no':
accounts = self.search(cursor, user, [
('user', '=', user),
('company', '=', 'no')
])
if len(accounts) > 1 :
return False
else :
return True
else:
return True
_constraints = [
(_constraint_unique,
'Error: You are not allowed to have more than 1 account.',
[])
]
def on_change_emailid(self, cursor, user, ids, name=None, email_id=None, context=None):
"""
Called when the email ID field changes.
UI enhancement
Writes the same email value to the smtpusername
and incoming username
"""
#TODO: Check and remove the write. Is it needed?
self.write(cursor, user, ids, {'state':'draft'}, context=context)
return {
'value': {
'state': 'draft',
'smtpuname':email_id,
'isuser':email_id
}
}
def get_outgoing_server(self, cursor, user, ids, context=None):
"""
Returns the Out Going Connection (SMTP) object
@attention: DO NOT USE except_osv IN THIS METHOD
@param cursor: Database Cursor
@param user: ID of current user
@param ids: ID/list of ids of current object for
which connection is required
First ID will be chosen from lists
@param context: Context
@return: SMTP server object or Exception
"""
#Type cast ids to integer
if type(ids) == list:
ids = ids[0]
this_object = self.browse(cursor, user, ids, context)
if this_object:
if this_object.smtpserver and this_object.smtpport:
try:
if this_object.smtpssl:
serv = smtplib.SMTP_SSL(this_object.smtpserver, this_object.smtpport)
else:
serv = smtplib.SMTP(this_object.smtpserver, this_object.smtpport)
if this_object.smtptls:
serv.ehlo()
serv.starttls()
serv.ehlo()
except Exception, error:
raise error
try:
if serv.has_extn('AUTH') or this_object.smtpuname or this_object.smtppass:
serv.login(this_object.smtpuname, this_object.smtppass)
except Exception, error:
raise error
return serv
raise Exception(_("SMTP SERVER or PORT not specified"))
raise Exception(_("Core connection for the given ID does not exist"))
def check_outgoing_connection(self, cursor, user, ids, context=None):
"""
checks SMTP credentials and confirms if outgoing connection works
(Attached to button)
@param cursor: Database Cursor
@param user: ID of current user
@param ids: list of ids of current object for
which connection is required
@param context: Context
"""
try:
self.get_outgoing_server(cursor, user, ids, context)
raise osv.except_osv(_("SMTP Test Connection Was Successful"), '')
except osv.except_osv, success_message:
raise success_message
except Exception, error:
raise osv.except_osv(
_("Out going connection test failed"),
_("Reason: %s") % error
)
def do_approval(self, cr, uid, ids, context={}):
#TODO: Check if user has rights
self.write(cr, uid, ids, {'state':'approved'}, context=context)
# wf_service = netsvc.LocalService("workflow")
def smtp_connection(self, cursor, user, id, context=None):
"""
This method should now wrap smtp_connection
"""
#This function returns a SMTP server object
logger = netsvc.Logger()
core_obj = self.browse(cursor, user, id, context)
if core_obj.smtpserver and core_obj.smtpport and core_obj.state == 'approved':
try:
serv = self.get_outgoing_server(cursor, user, id, context)
except Exception, error:
logger.notifyChannel(_("Email Template"), netsvc.LOG_ERROR, _("Mail from Account %s failed on login. Probable Reason:Could not login to server\nError: %s") % (id, error))
return False
#Everything is complete, now return the connection
return serv
else:
logger.notifyChannel(_("Email Template"), netsvc.LOG_ERROR, _("Mail from Account %s failed. Probable Reason:Account not approved") % id)
return False
#**************************** MAIL SENDING FEATURES ***********************#
def split_to_ids(self, ids_as_str):
"""
Identifies email IDs separated by separators
and returns a list
TODO: Doc this
"a@b.com,c@bcom; d@b.com;e@b.com->['a@b.com',...]"
"""
email_sep_by_commas = ids_as_str \
.replace('; ', ',') \
.replace(';', ',') \
.replace(', ', ',')
return email_sep_by_commas.split(',')
def get_ids_from_dict(self, addresses={}):
"""
TODO: Doc this
"""
result = {'all':[]}
keys = ['To', 'CC', 'BCC']
for each in keys:
ids_as_list = self.split_to_ids(addresses.get(each, u''))
while u'' in ids_as_list:
ids_as_list.remove(u'')
result[each] = ids_as_list
result['all'].extend(ids_as_list)
return result
def send_mail(self, cr, uid, ids, addresses, subject='', body=None, payload=None, context=None):
#TODO: Replace all this crap with a single email object
if body is None:
body = {}
if payload is None:
payload = {}
if context is None:
context = {}
logger = netsvc.Logger()
for id in ids:
core_obj = self.browse(cr, uid, id, context)
serv = self.smtp_connection(cr, uid, id)
if serv:
try:
msg = MIMEMultipart()
if subject:
msg['Subject'] = subject
sender_name = Header(core_obj.name, 'utf-8').encode()
msg['From'] = sender_name + " <" + core_obj.email_id + ">"
msg['Organization'] = tools.ustr(core_obj.user.company_id.name)
msg['Date'] = formatdate()
addresses_l = self.get_ids_from_dict(addresses)
if addresses_l['To']:
msg['To'] = u','.join(addresses_l['To'])
if addresses_l['CC']:
msg['CC'] = u','.join(addresses_l['CC'])
# if addresses_l['BCC']:
# msg['BCC'] = u','.join(addresses_l['BCC'])
if body.get('text', False):
temp_body_text = body.get('text', '')
l = len(temp_body_text.replace(' ', '').replace('\r', '').replace('\n', ''))
if l == 0:
body['text'] = u'No Mail Message'
# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
if core_obj.send_pref == 'text' or core_obj.send_pref == 'both':
body_text = body.get('text', u'No Mail Message')
body_text = tools.ustr(body_text)
msg.attach(MIMEText(body_text.encode("utf-8"), _charset='UTF-8'))
if core_obj.send_pref == 'html' or core_obj.send_pref == 'both':
html_body = body.get('html', u'')
if len(html_body) == 0 or html_body == u'':
html_body = body.get('text', u'<p>No Mail Message</p>').replace('\n', '<br/>').replace('\r', '<br/>')
html_body = tools.ustr(html_body)
msg.attach(MIMEText(html_body.encode("utf-8"), _subtype='html', _charset='UTF-8'))
#Now add attachments if any
for file in payload.keys():
part = MIMEBase('application', "octet-stream")
part.set_payload(base64.decodestring(payload[file]))
part.add_header('Content-Disposition', 'attachment; filename="%s"' % file)
Encoders.encode_base64(part)
msg.attach(part)
except Exception, error:
logger.notifyChannel(_("Email Template"), netsvc.LOG_ERROR, _("Mail from Account %s failed. Probable Reason:MIME Error\nDescription: %s") % (id, error))
return error
try:
#print msg['From'],toadds
serv.sendmail(msg['From'], addresses_l['all'], msg.as_string())
except Exception, error:
logger.notifyChannel(_("Email Template"), netsvc.LOG_ERROR, _("Mail from Account %s failed. Probable Reason:Server Send Error\nDescription: %s") % (id, error))
return error
#The mail sending is complete
serv.close()
logger.notifyChannel(_("Email Template"), netsvc.LOG_INFO, _("Mail from Account %s successfully Sent.") % (id))
return True
else:
logger.notifyChannel(_("Email Template"), netsvc.LOG_ERROR, _("Mail from Account %s failed. Probable Reason:Account not approved") % id)
def extracttime(self, time_as_string):
"""
TODO: DOC THis
"""
logger = netsvc.Logger()
#The standard email dates are of format similar to:
#Thu, 8 Oct 2009 09:35:42 +0200
#print time_as_string
date_as_date = False
convertor = {'+':1, '-':-1}
try:
time_as_string = time_as_string.replace(',', '')
date_list = time_as_string.split(' ')
date_temp_str = ' '.join(date_list[1:5])
if len(date_list) >= 6:
sign = convertor.get(date_list[5][0], False)
else:
sign = False
try:
dt = datetime.datetime.strptime(
date_temp_str,
"%d %b %Y %H:%M:%S")
except:
try:
dt = datetime.datetime.strptime(
date_temp_str,
"%d %b %Y %H:%M")
except:
return False
if sign:
try:
offset = datetime.timedelta(
hours=sign * int(
date_list[5][1:3]
),
minutes=sign * int(
date_list[5][3:5]
)
)
except Exception, e2:
"""Looks like UT or GMT, just forget decoding"""
return False
else:
offset = datetime.timedelta(hours=0)
dt = dt + offset
date_as_date = dt.strftime('%Y-%m-%d %H:%M:%S')
#print date_as_date
except Exception, e:
logger.notifyChannel(
_("Email Template"),
netsvc.LOG_WARNING,
_(
"Datetime Extraction failed.Date:%s \
\tError:%s") % (
time_as_string,
e)
)
return date_as_date
def send_receive(self, cr, uid, ids, context=None):
self.get_mails(cr, uid, ids, context)
for id in ids:
ctx = context.copy()
ctx['filters'] = [('account_id', '=', id)]
self.pool.get('email_template.mailbox').send_all_mail(cr, uid, [], context=ctx)
return True
def decode_header_text(self, text):
""" Decode internationalized headers RFC2822.
To, CC, BCC, Subject fields can contain
text slices with different encodes, like:
=?iso-8859-1?Q?Enric_Mart=ED?= <enricmarti@company.com>,
=?Windows-1252?Q?David_G=F3mez?= <david@company.com>
Sometimes they include extra " character at the beginning/
end of the contact name, like:
"=?iso-8859-1?Q?Enric_Mart=ED?=" <enricmarti@company.com>
and decode_header() does not work well, so we use regular
expressions (?= ? ? ?=) to split the text slices
"""
if not text:
return text
p = re.compile("(=\?.*?\?.\?.*?\?=)")
text2 = ''
try:
for t2 in p.split(text):
text2 += ''.join(
[s.decode(
t or 'ascii'
) for (s, t) in decode_header(t2)]
).encode('utf-8')
except:
return text
return text2
email_template_account()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<menuitem name="Tools" id="base.menu_tools" icon="STOCK_PREFERENCES" sequence="15"/>
<menuitem name="Email Template" id="menu_email_template" parent="base.menu_tools"/>
<record model="ir.ui.view" id="email_template_account_form">
<field name="name">email_template.account.form</field>
<field name="model">email_template.account</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Email Account Configuration">
<group colspan="2">
<field name="name" select="1" />
</group>
<notebook colspan="4">
<page string="Outgoing">
<separator string="Server Information" colspan="4" />
<group colspan="4">
<field name="smtpserver" select="1" colspan="2" />
<field name="smtpport" select="2" colspan="2" />
<field name="smtpssl" select="2" colspan="2" />
<field name="smtptls" select="2" colspan="2" />
</group>
<button name="check_outgoing_connection" type="object" string="Check Outgoing Connection" />
<separator string="User Information" colspan="4" />
<group col="2" colspan="2">
<field name="email_id" select="1" on_change="on_change_emailid(name,email_id)" colspan="2" />
<field name="smtppass" password="True" colspan="2" />
<field name="company" select="2" colspan="2" />
</group>
<group col="2" colspan="2">
<field name="smtpuname" select="1" colspan="2" />
<field name="user" select="2" colspan="2" />
<field name="send_pref" colspan="2" />
</group>
</page>
<page string="security" attrs="{'invisible':[('company','!=','yes')]}">
<field name="allowed_groups" attrs="{'required':[('company','=','yes')]}" nolabel="1"/>
</page>
</notebook>
<group colspan="4" col="10">
<field name="state" select="1"/>
<button string="Approve Account" name="button_approval" states="draft" type="workflow"/>
<button string="Suspend Account" name="button_suspended" states="approved" type="workflow" />
<button string="Request Re-activation" name="get_reapprove" states="suspended" type="workflow" />
<button string="Send/Receive" name="send_receive" states="approved" type="object" />
</group>
</form>
</field>
</record>
<record model="ir.ui.view" id="email_template_account_tree">
<field name="name">email_template.account.tree</field>
<field name="model">email_template.account</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="SMTP Server">
<field name="name" select="2" />
<field name="email_id" select="2" />
<field name="smtpuname" select="2" />
<field name="user" select="2" />
<field name="smtpserver" select="2" />
<field name="smtpport" select="2" />
<field name="state" select="2" />
</tree>
</field>
</record>
<record id="view_email_template_account_search" model="ir.ui.view">
<field name="name">email_template.account.search</field>
<field name="model">email_template.account</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Accounts">
<filter icon="terp-crm" string="My Accounts" name="my" domain="[('user','=',uid)]"/>
<filter icon="terp-crm" string="Personal Accounts" domain="[('company','=','no')]"/>
<filter icon="terp-crm" string="Company Accounts" domain="[('company','=','yes')]"/>
<separator orientation="vertical"/>
<filter icon="terp-crm" string="Draft" name="draft" domain="[('state','=','draft')]"/>
<filter icon="terp-crm" string="Suspended" domain="[('state','=','suspended')]"/>
<separator orientation="vertical"/>
<field name="name" select="1"/>
<field name="user" select="1"/>
<field name="email_id" select="1"/>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_email_template_account_tree_all">
<field name="name">Accounts</field>
<field name="res_model">email_template.account</field>
<field name="view_type">form</field>
<field name="view_mode">form,tree</field>
<field name="view_id" ref="email_template_account_tree" />
<field name="context">{'group_by': [], 'search_default_draft': 1, 'search_default_my': 1}</field>
<field name="search_view_id" ref="view_email_template_account_search"/>
</record>
<menuitem name="Configuration" id="menu_email_template_configuration" parent="menu_email_template" />
<menuitem name="All Accounts" id="menu_email_template_account_all" parent="menu_email_template_configuration" action="action_email_template_account_tree_all" groups="res_groups_email_template_manager" />
</data>
</openerp>

View File

@ -0,0 +1,84 @@
# To change this template, choose Tools | Templates
# and open the template in the editor.
from osv import fields,osv
import pooler
import netsvc
import re
class email_template_engines(osv.osv):
_name = "email_template.engines"
_description = "Email Template Engine"
# def __init__(self):
# print "Started Engine"
def check(self):
print "Start self check"
def strip_html(self,text):
#Removes HTML, Have to check if still relevent
if text:
def fixup(m):
text = m.group(0)
if text[:1] == "<":
return "" # ignore tags
if text[:2] == "&#":
try:
if text[:3] == "&#x":
return unichr(int(text[3:-1], 16))
else:
return unichr(int(text[2:-1]))
except ValueError:
pass
elif text[:1] == "&":
import htmlentitydefs
entity = htmlentitydefs.entitydefs.get(text[1:-1])
if entity:
if entity[:2] == "&#":
try:
return unichr(int(entity[2:-1]))
except ValueError:
pass
else:
return unicode(entity, "iso-8859-1")
return text # leave as is
return re.sub("(?s)<[^>]*>|&#?\w+;", fixup, text)
def parsevalue(self,cr,uid,id,message,templateid,context):
#id: ID of the template's model's record to be used
#message: the complete text including placeholders
#templateid: the template id of the template
#context: TODO
#print cr,uid,id,message,templateid,context
if message:
logger = netsvc.Logger()
def merge(match):
template = self.pool.get("email.template").browse(cr,uid,templateid,context)
obj_pool = self.pool.get(template.object_name.model)
obj = obj_pool.browse(cr, uid, id, context)
exp = str(match.group()[2:-2]).strip()
#print "level 1:",exp
exp_spl = exp.split('/')
#print "level 2:",exp_spl
try:
result = eval(exp_spl[0], {'object':obj,})
except:
result = "Rendering Error"
#print "result:",result
try:
if result in (None, False):
if len(exp_spl)>1:
return exp_spl[1]
else:
return 'Not Available'
return str(result)
except:
return "Rendering Error"
if message:
com = re.compile('(\[\[.+?\]\])')
retmessage = com.sub(merge, message)
else:
retmessage=""
return retmessage
email_template_engines()

View File

@ -0,0 +1,182 @@
from osv import osv, fields
import time
import email_template_engines
import netsvc
from tools.translate import _
import tools
LOGGER = netsvc.Logger()
class email_template_mailbox(osv.osv):
_name = "email_template.mailbox"
_description = 'Email Mailbox'
_rec_name = "subject"
_order = "date_mail desc"
def run_mail_scheduler(self, cursor, user, context=None):
"""
This method is called by Open ERP Scheduler
to periodically send emails
"""
try:
self.send_all_mail(cursor, user, context)
except Exception, e:
LOGGER.notifyChannel(
_("Email Template"),
netsvc.LOG_ERROR,
_("Error sending mail: %s" % str(e)))
def send_all_mail(self, cr, uid, ids=None, context=None):
if ids is None:
ids = []
if context is None:
context = {}
filters = [('folder', '=', 'outbox'), ('state', '!=', 'sending')]
if 'filters' in context.keys():
for each_filter in context['filters']:
filters.append(each_filter)
ids = self.search(cr, uid, filters, context=context)
self.write(cr, uid, ids, {'state':'sending'}, context)
self.send_this_mail(cr, uid, ids, context)
return True
def send_this_mail(self, cr, uid, ids=None, context=None):
if ids is None:
ids = []
for id in ids:
try:
account_obj = self.pool.get('email_template.account')
values = self.read(cr, uid, id, [], context)
payload = {}
if values['attachments_ids']:
for attid in values['attachments_ids']:
attachment = self.pool.get('ir.attachment').browse(cr, uid, attid, context)#,['datas_fname','datas'])
payload[attachment.datas_fname] = attachment.datas
print "233333333333333"
result = account_obj.send_mail(cr, uid,
[values['account_id'][0]],
{'To':values.get('email_to', u'') or u'', 'CC':values.get('email_cc', u'') or u'', 'BCC':values.get('email_bcc', u'') or u''},
values['subject'] or u'',
{'text':values.get('body_text', u'') or u'', 'html':values.get('body_html', u'') or u''},
payload=payload, context=context)
if result == True:
self.write(cr, uid, id, {'folder':'sent', 'state':'na', 'date_mail':time.strftime("%Y-%m-%d %H:%M:%S")}, context)
self.historise(cr, uid, [id], "Email sent successfully", context)
else:
self.historise(cr, uid, [id], result, context)
except Exception, error:
logger = netsvc.Logger()
logger.notifyChannel(_("Power Email"), netsvc.LOG_ERROR, _("Sending of Mail %s failed. Probable Reason:Could not login to server\nError: %s") % (id, error))
self.historise(cr, uid, [id], error, context)
self.write(cr, uid, id, {'state':'na'}, context)
return True
def historise(self, cr, uid, ids, message='', context=None):
for id in ids:
history = self.read(cr, uid, id, ['history'], context).get('history', '')
self.write(cr, uid, id, {'history':history or '' + "\n" + time.strftime("%Y-%m-%d %H:%M:%S") + ": " + tools.ustr(message)}, context)
_columns = {
'email_from':fields.char(
'From',
size=64),
'email_to':fields.char(
'Recepient (To)',
size=250,),
'email_cc':fields.char(
' CC',
size=250),
'email_bcc':fields.char(
' BCC',
size=250),
'subject':fields.char(
' Subject',
size=200,),
'body_text':fields.text(
'Standard Body (Text)'),
'body_html':fields.text(
'Body (Text-Web Client Only)'),
'attachments_ids':fields.many2many(
'ir.attachment',
'mail_attachments_rel',
'mail_id',
'att_id',
'Attachments'),
'account_id' :fields.many2one(
'email_template.account',
'User account',
required=True),
'user':fields.related(
'account_id',
'user',
type="many2one",
relation="res.users",
string="User"),
'server_ref':fields.integer(
'Server Reference of mail',
help="Applicable for inward items only"),
'mail_type':fields.selection([
('multipart/mixed',
'Has Attachments'),
('multipart/alternative',
'Plain Text & HTML with no attachments'),
('multipart/related',
'Intermixed content'),
('text/plain',
'Plain Text'),
('text/html',
'HTML Body'),
], 'Mail Contents'),
#I like GMAIL which allows putting same mail in many folders
#Lets plan it for 0.9
'folder':fields.selection([
('drafts', 'Drafts'),
('outbox', 'Outbox'),
('trash', 'Trash'),
('sent', 'Sent Items'),
], 'Folder', required=True),
'state':fields.selection([
('na', 'Not Applicable'),
('sending', 'Sending'),
], 'Status', required=True),
'date_mail':fields.datetime(
'Rec/Sent Date'),
'history':fields.text(
'History',
readonly=True,
store=True)
}
_defaults = {
'state': lambda * a: 'na',
'folder': lambda * a: 'outbox',
}
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
if context is None:
context = {}
if context.get('company', False):
users_groups = self.pool.get('res.users').browse(cr, uid, uid, context).groups_id
group_acc_rel = {}
#get all accounts and get a table of {group1:[account1,account2],group2:[account1]}
for each_account_id in self.pool.get('email_template.account').search(cr, uid, [('state', '=', 'approved'), ('company', '=', 'yes')], context=context):
account = self.pool.get('email_template.account').browse(cr, uid, each_account_id, context)
for each_group in account.allowed_groups:
if not account.id in group_acc_rel.get(each_group, []):
groups = group_acc_rel.get(each_group, [])
groups.append(account.id)
group_acc_rel[each_group] = groups
users_company_accounts = []
for each_group in group_acc_rel.keys():
if each_group in users_groups:
for each_account in group_acc_rel[each_group]:
if not each_account in users_company_accounts:
users_company_accounts.append(each_account)
args.append(('account_id', 'in', users_company_accounts))
return super(osv.osv, self).search(cr, uid, args, offset, limit,
order, context=context, count=count)
email_template_mailbox()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<!-- Email Template-->
<record model="ir.ui.view" id="email_template_mailbox_form">
<field name="name">email_template.mailbox.form</field>
<field name="model">email_template.mailbox</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Outbox">
<group col="4" colspan="2">
<field name="email_from" colspan="4" select="1"/>
<field name="email_cc" colspan="4" select="1"/>
<field name="date_mail" colspan="4" select="2"/>
</group>
<group col="4" colspan="2">
<field name="email_to" colspan="4" required="1" select="1" />
<field name="email_bcc" colspan="4" select="2"/>
<field name="subject" colspan="4" select="1"/>
</group>
<notebook colspan="4">
<page string="Standard Body">
<separator colspan="4" string="Standard Body" />
<notebook colspan="4">
<page string="Standard Body (Text)">
<field name="body_text" nolabel="1" colspan="4" select="1"/>
</page>
<page string="Body (HTML-Web Client Only)">
<field name="body_html" nolabel="1" colspan="4" />
<!--<label string="Note: HTML body can't be edited with GTK desktop client." colspan="4"/>
--></page>
</notebook>
</page>
<page string="Attachments">
<group col="4">
<separator colspan="4" string="Attachments" />
<field name="attachments_ids" colspan="4" nolabel="1" />
</group>
</page>
<page string="Advanced">
<group col="4">
<field name="account_id" colspan="2" />
<field name="server_ref" colspan="2" />
<field name="mail_type" colspan="2" />
<field name="folder" colspan="2" select="2"/>
<separator string="History" colspan="4" />
<field name="history" nolabel="1" colspan="4"/>
</group>
</page>
</notebook>
<separator colspan="4" string="" />
<group col="4" colspan="4">
<field name="state" colspan="2" readonly="1" />
<button name="complete_mail" type="object" string="Download Full Mail" colspan="2" states="read,unread" />
<button name="send_this_mail" type="object" string="Send Mail" />
</group>
</form>
</field>
</record>
<!--============================================= TREE VIEWS =============================================-->
<!--DRAFTS-->
<record model="ir.ui.view" id="email_template_drafts_tree">
<field name="name">email_template.mailbox.draftstree</field>
<field name="model">email_template.mailbox</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Drafts">
<field name="user" />
<field name="email_from" select="1" />
<field name="subject" select="1" />
<field name="attachments_ids" select="2" />
<field name="date_mail" select="2" />
</tree>
</field>
</record>
<!--OUTBOX-->
<record model="ir.ui.view" id="email_template_outbox_tree">
<field name="name">email_template.mailbox.outboxtree</field>
<field name="model">email_template.mailbox</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Outbox">
<field name="user" />
<field name="email_from" select="1" />
<field name="subject" select="1" />
<field name="attachments_ids" select="2" />
<field name="date_mail" select="2" />
</tree>
</field>
</record>
<!--SENT-->
<record model="ir.ui.view" id="email_template_sentbox_tree">
<field name="name">email_template.mailbox.sentboxtree</field>
<field name="model">email_template.mailbox</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Sent">
<field name="user" />
<field name="email_from" select="1" />
<field name="subject" select="1" />
<field name="attachments_ids" select="2" />
<field name="date_mail" select="2" />
</tree>
</field>
</record>
<!--TRASH-->
<record model="ir.ui.view" id="email_template_trashbox_tree">
<field name="name">email_template.mailbox.trashboxtree</field>
<field name="model">email_template.mailbox</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Trash">
<field name="user" />
<field name="email_from" select="1" />
<field name="subject" select="1" />
<field name="attachments_ids" select="2" />
<field name="date_mail" select="2" />
</tree>
</field>
</record>
<record id="view_email_template_mailbox_search" model="ir.ui.view">
<field name="name">email_template.mailbox.search</field>
<field name="model">email_template.mailbox</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Mailboxes">
<filter icon="terp-crm" string="Drafts" name="draft" domain="[('folder','=','drafts']"/>
<filter icon="terp-crm" string="Outbox" name="outbox" domain="[('folder','=','outbox')]"/>
<separator orientation="vertical"/>
<filter icon="terp-crm" string="Sent" domain="[('folder','=','sent')]"/>
<filter icon="terp-crm" string="Trash" domain="[('folder','=','trash')]"/>
<separator orientation="vertical"/>
<filter icon="terp-crm" string="Not Applicable" domain="[('state','=','na')]"/>
<filter icon="terp-crm" string="Sending" domain="[('state','=','sending')]"/>
<separator orientation="vertical"/>
<field name="email_from" select="1"/>
<field name="email_to" select="1"/>
<field name="subject" select="1"/>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_email_template_mailbox">
<field name="name">Mailbox</field>
<field name="res_model">email_template.mailbox</field>
<field name="view_type">form</field>
<field name="view_mode">form,tree</field>
<field name="view_id" ref="email_template_outbox_tree" />
<field name="context">{'group_by': [], 'search_default_draft': 1, 'search_default_outbox': 1}</field>
<field name="search_view_id" ref="view_email_template_mailbox_search"/>
</record>
<!--======================================== MENUS ========================================-->
<menuitem name="MailBox" id="menu_email_template_mailbox_all_main2" parent="menu_email_template" />
<menuitem name="Personal" id="menu_email_template_personal" parent="menu_email_template_mailbox_all_main2" />
<menuitem name="Mails" id="menu_email_template_personal_mails" parent="menu_email_template_personal" action="action_email_template_mailbox"/>
<menuitem name="Company" id="menu_email_template_company" parent="menu_email_template_mailbox_all_main2" />
<menuitem name="Mails" id="menu_email_template_company_mails" parent="menu_email_template_company" action="action_email_template_mailbox"/>
</data>
</openerp>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record forcecreate="True" id="ir_cron_mail_scheduler_action" model="ir.cron">
<field name="name">Email Template scheduler</field>
<field name="user_id" ref="base.user_root"/>
<field name="interval_number">1</field>
<field name="interval_type">hours</field>
<field name="numbercall">12</field>
<field eval="False" name="doall"/>
<field eval="'email_template.mailbox'" name="model"/>
<field eval="'run_mail_scheduler'" name="function"/>
<field eval="'()'" name="args"/>
</record>
</data>
</openerp>

View File

@ -0,0 +1,188 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<!-- Email Template PReview -->
<record model="ir.ui.view" id="email_template_preview_form">
<field name="name">email_template.preview.form</field>
<field name="model">email_template.preview</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Email Preview">
<field name="rel_model" />
<newline />
<field name="rel_model_ref" on_change="on_change_ref(rel_model_ref, context)" />
<newline />
<field name="to" />
<newline />
<field name="cc" />
<newline />
<field name="bcc" />
<newline />
<field name="subject" />
<newline />
<field name="body_text" />
<newline />
<!-- <field name="body_html" widget="text_html" />-->
<!--
Removed text_html because it doesnt work in GTK
And TinyMCE messes up the HTML in Web Client
-->
<field name="body_html"/>
<newline />
<field name="report" />
<group>
<button icon="gtk-ok" special="cancel" string="OK" />
</group>
</form>
</field>
</record>
<record id="wizard_email_template_preview" model="ir.actions.act_window">
<field name="name">Template Preview</field>
<field name="res_model">email_template.preview</field>
<field name="src_model">email_template.preview</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="auto_refresh" eval="1" />
<field name="target">new</field>
<field name="context">{'ids':active_id}</field>
</record>
<!--EMail client Form view -->
<record model="ir.ui.view" id="email_template_form">
<field name="name">email.template.form</field>
<field name="model">email.template</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Email Templates">
<field name="name" />
<field name="object_name" required="1"
on_change="change_model(object_name)" />
<field name="model_int_name" invisible="1" />
<notebook colspan="4">
<page string="Mail Details">
<group col="4" colspan="2">
<field name="def_to" colspan="4" required="1" />
<field name="def_cc" colspan="4" />
<field name="def_bcc" colspan="4" />
</group>
<group col="2" colspan="2">
<field name="def_subject" colspan="4" required="1" />
<field name="use_sign" colspan="4" />
<field name="lang" colspan="4" />
</group>
<separator colspan="3" string="Standard Body" />
<separator colspan="1" string="Expression Builder" />
<notebook>
<page string="Body (Text)">
<field name="def_body_text" colspan="4" nolabel="1" />
</page>
<page string="Body (Raw HTML)">
<field name="def_body_html" colspan="4" nolabel="1" />
<label string="Note: This is Raw HTML." colspan="4" />
</page>
</notebook>
<group col="4">
<field name="template_language"
on_change="onchange_null_value(model_object_field,sub_model_object_field,null_value,template_language,context)" />
<notebook>
<page string="Insert Simple Field">
<field name="model_object_field"
domain="[('model_id','=',object_name),('ttype','!=','one2many'),('ttype','!=','many2many')]"
on_change="onchange_model_object_field(model_object_field, template_language,context)"
colspan="4" />
<field name="sub_object" readonly="1" colspan="4" />
<field name="sub_model_object_field"
domain="[('model_id','=',sub_object),('ttype','!=','one2many'),('ttype','!=','many2many')]"
colspan="4"
attrs="{'readonly':[('sub_object','=',False)],'required':[('sub_object','!=',False)]}"
on_change="onchange_sub_model_object_field(model_object_field,sub_model_object_field,template_language,context)" />
<field name="null_value" colspan="4"
on_change="onchange_null_value(model_object_field,sub_model_object_field,null_value,template_language,context)" />
<field name="copyvalue" colspan="4" />
</page>
</notebook>
<button name="%(wizard_email_template_preview)d" string="Preview Template"
type="action" colspan="4" target="new" />
</group>
</page>
<page string="Security">
<separator colspan="4" string="Allowed User Groups" />
<field name="allowed_groups" string="Allowed User Groups"
nolabel="1" />
</page>
<page string="Advanced">
<separator string="Automatic Email" colspan="4" />
<field name="enforce_from_account" attrs="{'required':[('auto_email','=',True)]}" />
<newline/>
<field name="ref_ir_act_window" />
<field name="ref_ir_value" />
<separator string="Attachments (Report to attach)" colspan="4"/>
<field name="file_name" colspan="2" />
<field name="report_template" colspan="2"
domain="[('model','=',model_int_name)]" />
</page>
</notebook>
</form>
</field>
</record>
<record model="ir.ui.view" id="email_template_tree">
<field name="name">email.template.tree</field>
<field name="model">email.template</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Email Templates">
<field name="name" select="1" />
<field name="object_name" required="1" select="1" />
<field name="def_to" colspan="4" select="2" />
<field name="def_cc" colspan="4" select="2" />
<field name="def_bcc" colspan="4" select="2" />
<field name="def_subject" colspan="4" select="2" />
<field name="use_sign" colspan="4" select="2" />
<field name="file_name" colspan="4" />
<field name="enforce_from_account" />
</tree>
</field>
</record>
<record id="view_email_template_search" model="ir.ui.view">
<field name="name">email.template.search</field>
<field name="model">email.template</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Templates">
<separator orientation="vertical"/>
<field name="name" select="1"/>
<field name="object_name" select="1"/>
<field name="def_to" select="1"/>
<separator orientation="vertical"/>
<field name="lang" select="1"/>
<field name="def_subject" select="1"/>
<field name="file_name" select="1"/>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_email_template_tree_all">
<field name="name">Email Templates</field>
<field name="res_model">email.template</field>
<field name="view_type">form</field>
<field name="view_mode">form,tree</field>
<field name="view_id" ref="email_template_tree" />
<field name="search_view_id" ref="view_email_template_search"/>
</record>
<menuitem name="E-MAIL Templates" id="menu_email_template_all"
parent="menu_email_template_configuration" action="action_email_template_tree_all" />
</data>
</openerp>

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="PE_ADMIN" model="res.roles">
<field name="name">Email Administrator</field>
</record>
<record id="wkf_email_template_setting" model="workflow">
<field name="name">Email Template Workflow</field>
<field name="osv">email_template.account</field>
<field name="on_create">True</field>
</record>
<!--Activity -->
<record id="act_draft" model="workflow.activity">
<field name="wkf_id" ref="wkf_email_template_setting"/>
<field name="flow_start">True</field>
<field name="name">draft</field>
<field name="kind">function</field>
<field name="action">write({'state':'draft'})</field>
</record>
<record id="act_approved" model="workflow.activity">
<field name="name">approval</field>
<field name="wkf_id" ref="wkf_email_template_setting"/>
<field name="kind">function</field>
<field name="action">do_approval()</field>
</record>
<record id="act_suspended" model="workflow.activity">
<field name="name">suspended</field>
<field name="wkf_id" ref="wkf_email_template_setting"/>
<field name="kind">function</field>
<field name="action">write({'state':'suspended'})</field>
</record>
<record id="act_dummy" model="workflow.activity">
<field name="name">dummy</field>
<field name="wkf_id" ref="wkf_email_template_setting"/>
<field name="flow_stop">True</field>
</record>
<!-- Transition -->
<record id="trans_awaiting_approved" model="workflow.transition">
<field name="act_from" ref="act_draft"/>
<field name="act_to" ref="act_approved"/>
<field name="signal">button_approval</field>
<field name="role_id" ref="PE_ADMIN"/>
</record>
<record id="trans_approved_suspended" model="workflow.transition">
<field name="act_from" ref="act_approved"/>
<field name="act_to" ref="act_suspended"/>
<field name="signal">button_suspended</field>
<field name="role_id" ref="PE_ADMIN"/>
</record>
<record id="trans_suspended_reapproved" model="workflow.transition">
<field name="act_from" ref="act_suspended"/>
<field name="act_to" ref="act_draft"/>
<field name="signal">get_reapprove</field>
<field name="role_id" ref="PE_ADMIN"/>
</record>
<record id="trans_suspended_dummy" model="workflow.transition">
<field name="act_from" ref="act_suspended"/>
<field name="act_to" ref="act_dummy"/>
<field name="signal">get_never</field>
<field name="role_id" ref="PE_ADMIN"/>
</record>
</data>
</openerp>

View File

@ -0,0 +1,455 @@
#!/usr/bin/env python
"""html2text: Turn HTML into equivalent Markdown-structured text."""
__version__ = "2.36"
__author__ = "Aaron Swartz (me@aaronsw.com)"
__copyright__ = "(C) 2004-2008 Aaron Swartz. GNU GPL 3."
__contributors__ = ["Martin 'Joey' Schulze", "Ricardo Reyes", "Kevin Jay North"]
# TODO:
# Support decoded entities with unifiable.
if not hasattr(__builtins__, 'True'): True, False = 1, 0
import re, sys, urllib, htmlentitydefs, codecs, StringIO, types
import sgmllib
import urlparse
sgmllib.charref = re.compile('&#([xX]?[0-9a-fA-F]+)[^0-9a-fA-F]')
try: from textwrap import wrap
except: pass
# Use Unicode characters instead of their ascii psuedo-replacements
UNICODE_SNOB = 0
# Put the links after each paragraph instead of at the end.
LINKS_EACH_PARAGRAPH = 0
# Wrap long lines at position. 0 for no wrapping. (Requires Python 2.3.)
BODY_WIDTH = 78
# Don't show internal links (href="#local-anchor") -- corresponding link targets
# won't be visible in the plain text file anyway.
SKIP_INTERNAL_LINKS = False
### Entity Nonsense ###
def name2cp(k):
if k == 'apos': return ord("'")
if hasattr(htmlentitydefs, "name2codepoint"): # requires Python 2.3
return htmlentitydefs.name2codepoint[k]
else:
k = htmlentitydefs.entitydefs[k]
if k.startswith("&#") and k.endswith(";"): return int(k[2:-1]) # not in latin-1
return ord(codecs.latin_1_decode(k)[0])
unifiable = {'rsquo':"'", 'lsquo':"'", 'rdquo':'"', 'ldquo':'"',
'copy':'(C)', 'mdash':'--', 'nbsp':' ', 'rarr':'->', 'larr':'<-', 'middot':'*',
'ndash':'-', 'oelig':'oe', 'aelig':'ae',
'agrave':'a', 'aacute':'a', 'acirc':'a', 'atilde':'a', 'auml':'a', 'aring':'a',
'egrave':'e', 'eacute':'e', 'ecirc':'e', 'euml':'e',
'igrave':'i', 'iacute':'i', 'icirc':'i', 'iuml':'i',
'ograve':'o', 'oacute':'o', 'ocirc':'o', 'otilde':'o', 'ouml':'o',
'ugrave':'u', 'uacute':'u', 'ucirc':'u', 'uuml':'u'}
unifiable_n = {}
for k in unifiable.keys():
unifiable_n[name2cp(k)] = unifiable[k]
def charref(name):
if name[0] in ['x','X']:
c = int(name[1:], 16)
else:
c = int(name)
if not UNICODE_SNOB and c in unifiable_n.keys():
return unifiable_n[c]
else:
return unichr(c)
def entityref(c):
if not UNICODE_SNOB and c in unifiable.keys():
return unifiable[c]
else:
try: name2cp(c)
except KeyError: return "&" + c
else: return unichr(name2cp(c))
def replaceEntities(s):
s = s.group(1)
if s[0] == "#":
return charref(s[1:])
else: return entityref(s)
r_unescape = re.compile(r"&(#?[xX]?(?:[0-9a-fA-F]+|\w{1,8}));")
def unescape(s):
return r_unescape.sub(replaceEntities, s)
def fixattrs(attrs):
# Fix bug in sgmllib.py
if not attrs: return attrs
newattrs = []
for attr in attrs:
newattrs.append((attr[0], unescape(attr[1])))
return newattrs
### End Entity Nonsense ###
def onlywhite(line):
"""Return true if the line does only consist of whitespace characters."""
for c in line:
if c is not ' ' and c is not ' ':
return c is ' '
return line
def optwrap(text):
"""Wrap all paragraphs in the provided text."""
if not BODY_WIDTH:
return text
assert wrap, "Requires Python 2.3."
result = ''
newlines = 0
for para in text.split("\n"):
if len(para) > 0:
if para[0] is not ' ' and para[0] is not '-' and para[0] is not '*':
for line in wrap(para, BODY_WIDTH):
result += line + "\n"
result += "\n"
newlines = 2
else:
if not onlywhite(para):
result += para + "\n"
newlines = 1
else:
if newlines < 2:
result += "\n"
newlines += 1
return result
def hn(tag):
if tag[0] == 'h' and len(tag) == 2:
try:
n = int(tag[1])
if n in range(1, 10): return n
except ValueError: return 0
class _html2text(sgmllib.SGMLParser):
def __init__(self, out=sys.stdout.write, baseurl=''):
sgmllib.SGMLParser.__init__(self)
if out is None: self.out = self.outtextf
else: self.out = out
self.outtext = u''
self.quiet = 0
self.p_p = 0
self.outcount = 0
self.start = 1
self.space = 0
self.a = []
self.astack = []
self.acount = 0
self.list = []
self.blockquote = 0
self.pre = 0
self.startpre = 0
self.lastWasNL = 0
self.abbr_title = None # current abbreviation definition
self.abbr_data = None # last inner HTML (for abbr being defined)
self.abbr_list = {} # stack of abbreviations to write later
self.baseurl = baseurl
def outtextf(self, s):
self.outtext += s
def close(self):
sgmllib.SGMLParser.close(self)
self.pbr()
self.o('', 0, 'end')
return self.outtext
def handle_charref(self, c):
self.o(charref(c))
def handle_entityref(self, c):
self.o(entityref(c))
def unknown_starttag(self, tag, attrs):
self.handle_tag(tag, attrs, 1)
def unknown_endtag(self, tag):
self.handle_tag(tag, None, 0)
def previousIndex(self, attrs):
""" returns the index of certain set of attributes (of a link) in the
self.a list
If the set of attributes is not found, returns None
"""
if not attrs.has_key('href'): return None
i = -1
for a in self.a:
i += 1
match = 0
if a.has_key('href') and a['href'] == attrs['href']:
if a.has_key('title') or attrs.has_key('title'):
if (a.has_key('title') and attrs.has_key('title') and
a['title'] == attrs['title']):
match = True
else:
match = True
if match: return i
def handle_tag(self, tag, attrs, start):
attrs = fixattrs(attrs)
if hn(tag):
self.p()
if start: self.o(hn(tag)*"#" + ' ')
if tag in ['p', 'div']: self.p()
if tag == "br" and start: self.o(" \n")
if tag == "hr" and start:
self.p()
self.o("* * *")
self.p()
if tag in ["head", "style", 'script']:
if start: self.quiet += 1
else: self.quiet -= 1
if tag in ["body"]:
self.quiet = 0 # sites like 9rules.com never close <head>
if tag == "blockquote":
if start:
self.p(); self.o('> ', 0, 1); self.start = 1
self.blockquote += 1
else:
self.blockquote -= 1
self.p()
if tag in ['em', 'i', 'u']: self.o("_")
if tag in ['strong', 'b']: self.o("**")
if tag == "code" and not self.pre: self.o('`') #TODO: `` `this` ``
if tag == "abbr":
if start:
attrsD = {}
for (x, y) in attrs: attrsD[x] = y
attrs = attrsD
self.abbr_title = None
self.abbr_data = ''
if attrs.has_key('title'):
self.abbr_title = attrs['title']
else:
if self.abbr_title != None:
self.abbr_list[self.abbr_data] = self.abbr_title
self.abbr_title = None
self.abbr_data = ''
if tag == "a":
if start:
attrsD = {}
for (x, y) in attrs: attrsD[x] = y
attrs = attrsD
if attrs.has_key('href') and not (SKIP_INTERNAL_LINKS and attrs['href'].startswith('#')):
self.astack.append(attrs)
self.o("[")
else:
self.astack.append(None)
else:
if self.astack:
a = self.astack.pop()
if a:
i = self.previousIndex(a)
if i is not None:
a = self.a[i]
else:
self.acount += 1
a['count'] = self.acount
a['outcount'] = self.outcount
self.a.append(a)
self.o("][" + `a['count']` + "]")
if tag == "img" and start:
attrsD = {}
for (x, y) in attrs: attrsD[x] = y
attrs = attrsD
if attrs.has_key('src'):
attrs['href'] = attrs['src']
alt = attrs.get('alt', '')
i = self.previousIndex(attrs)
if i is not None:
attrs = self.a[i]
else:
self.acount += 1
attrs['count'] = self.acount
attrs['outcount'] = self.outcount
self.a.append(attrs)
self.o("![")
self.o(alt)
self.o("]["+`attrs['count']`+"]")
if tag == 'dl' and start: self.p()
if tag == 'dt' and not start: self.pbr()
if tag == 'dd' and start: self.o(' ')
if tag == 'dd' and not start: self.pbr()
if tag in ["ol", "ul"]:
if start:
self.list.append({'name':tag, 'num':0})
else:
if self.list: self.list.pop()
self.p()
if tag == 'li':
if start:
self.pbr()
if self.list: li = self.list[-1]
else: li = {'name':'ul', 'num':0}
self.o(" "*len(self.list)) #TODO: line up <ol><li>s > 9 correctly.
if li['name'] == "ul": self.o("* ")
elif li['name'] == "ol":
li['num'] += 1
self.o(`li['num']`+". ")
self.start = 1
else:
self.pbr()
if tag in ["table", "tr"] and start: self.p()
if tag == 'td': self.pbr()
if tag == "pre":
if start:
self.startpre = 1
self.pre = 1
else:
self.pre = 0
self.p()
def pbr(self):
if self.p_p == 0: self.p_p = 1
def p(self): self.p_p = 2
def o(self, data, puredata=0, force=0):
if self.abbr_data is not None: self.abbr_data += data
if not self.quiet:
if puredata and not self.pre:
data = re.sub('\s+', ' ', data)
if data and data[0] == ' ':
self.space = 1
data = data[1:]
if not data and not force: return
if self.startpre:
#self.out(" :") #TODO: not output when already one there
self.startpre = 0
bq = (">" * self.blockquote)
if not (force and data and data[0] == ">") and self.blockquote: bq += " "
if self.pre:
bq += " "
data = data.replace("\n", "\n"+bq)
if self.start:
self.space = 0
self.p_p = 0
self.start = 0
if force == 'end':
# It's the end.
self.p_p = 0
self.out("\n")
self.space = 0
if self.p_p:
self.out(('\n'+bq)*self.p_p)
self.space = 0
if self.space:
if not self.lastWasNL: self.out(' ')
self.space = 0
if self.a and ((self.p_p == 2 and LINKS_EACH_PARAGRAPH) or force == "end"):
if force == "end": self.out("\n")
newa = []
for link in self.a:
if self.outcount > link['outcount']:
self.out(" ["+`link['count']`+"]: " + urlparse.urljoin(self.baseurl, link['href']))
if link.has_key('title'): self.out(" ("+link['title']+")")
self.out("\n")
else:
newa.append(link)
if self.a != newa: self.out("\n") # Don't need an extra line when nothing was done.
self.a = newa
if self.abbr_list and force == "end":
for abbr, definition in self.abbr_list.items():
self.out(" *[" + abbr + "]: " + definition + "\n")
self.p_p = 0
self.out(data)
self.lastWasNL = data and data[-1] == '\n'
self.outcount += 1
def handle_data(self, data):
if r'\/script>' in data: self.quiet -= 1
self.o(data, 1)
def unknown_decl(self, data): pass
def wrapwrite(text): sys.stdout.write(text.encode('utf8'))
def html2text_file(html, out=wrapwrite, baseurl=''):
h = _html2text(out, baseurl)
h.feed(html)
h.feed("")
return h.close()
def html2text(html, baseurl=''):
return optwrap(html2text_file(html, None, baseurl))
if __name__ == "__main__":
baseurl = ''
if sys.argv[1:]:
arg = sys.argv[1]
if arg.startswith('http://'):
baseurl = arg
j = urllib.urlopen(baseurl)
try:
from feedparser import _getCharacterEncoding as enc
except ImportError:
enc = lambda x, y: ('utf-8', 1)
text = j.read()
encoding = enc(j.headers, text)[0]
if encoding == 'us-ascii': encoding = 'utf-8'
data = text.decode(encoding)
else:
encoding = 'utf8'
if len(sys.argv) > 2:
encoding = sys.argv[2]
f = open(arg, 'r')
try:
data = f.read().decode(encoding)
finally:
f.close()
else:
data = sys.stdin.read().decode('utf8')
wrapwrite(html2text(data, baseurl))

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<record id="res_groups_email_template_manager" model="res.groups">
<field name="name">Email Template / Settings_Manager</field>
</record>
<record id="res_groups_email_template_userse" model="res.groups">
<field name="name">Email Template / External_users</field>
</record>
<record id="res_groups_email_template_usersi" model="res.groups">
<field name="name">Email Template / Internal_users</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1 @@
import email_template_send_wizard

View File

@ -0,0 +1,235 @@
from osv import osv, fields
from mako.template import Template
from mako import exceptions
import netsvc
import base64
import time
from tools.translate import _
import tools
from email_template.email_template import get_value
class email_template_send_wizard(osv.osv_memory):
_name = 'email_template.send.wizard'
_description = 'This is the wizard for sending mail'
_rec_name = "subject"
def _get_accounts(self, cr, uid, context=None):
if context is None:
context = {}
template = self._get_template(cr, uid, context)
if not template:
return []
logger = netsvc.Logger()
if template.enforce_from_account:
return [(template.enforce_from_account.id, '%s (%s)' % (template.enforce_from_account.name, template.enforce_from_account.email_id))]
else:
account_id = self.pool.get('email_template.account').search(cr,uid,[('company','=','no'),('user','=',uid)], context=context)
if account_id:
account = self.pool.get('email_template.account').browse(cr,uid,account_id, context)
return [(r.id,r.name + " (" + r.email_id + ")") for r in account]
else:
logger.notifyChannel(_("Power Email"), netsvc.LOG_ERROR, _("No personal email accounts are configured for you. \nEither ask admin to enforce an account for this template or get yourself a personal power email account."))
raise osv.except_osv(_("Power Email"),_("No personal email accounts are configured for you. \nEither ask admin to enforce an account for this template or get yourself a personal power email account."))
def get_value(self, cursor, user, template, message, context=None, id=None):
"""Gets the value of the message parsed with the content of object id (or the first 'src_rec_ids' if id is not given)"""
if not message:
return ''
if not id:
id = context['src_rec_ids'][0]
return get_value(cursor, user, id, message, template, context)
def _get_template(self, cr, uid, context=None):
if context is None:
context = {}
if not 'template' in context and not 'template_id' in context:
return None
if 'template_id' in context.keys():
template_ids = self.pool.get('email.template').search(cr, uid, [('id','=',context['template_id'])], context=context)
elif 'template' in context.keys():
# Old versions of email_template used the name of the template. This caused
# problems when the user changed the name of the template, but we keep the code
# for compatibility with those versions.
template_ids = self.pool.get('email.template').search(cr, uid, [('name','=',context['template'])], context=context)
if not template_ids:
return None
template = self.pool.get('email.template').browse(cr, uid, template_ids[0], context)
lang = self.get_value(cr, uid, template, template.lang, context)
if lang:
# Use translated template if necessary
ctx = context.copy()
ctx['lang'] = lang
template = self.pool.get('email.template').browse(cr, uid, template.id, ctx)
return template
def _get_template_value(self, cr, uid, field, context=None):
template = self._get_template(cr, uid, context)
if not template:
return False
if len(context['src_rec_ids']) > 1: # Multiple Mail: Gets original template values for multiple email change
return getattr(template, field)
else: # Simple Mail: Gets computed template values
return self.get_value(cr, uid, template, getattr(template, field), context)
_columns = {
'state':fields.selection([
('single','Simple Mail Wizard Step 1'),
('multi','Multiple Mail Wizard Step 1'),
('done','Wizard Complete')
],'Status',readonly=True),
'ref_template':fields.many2one('email.template','Template',readonly=True),
'rel_model':fields.many2one('ir.model','Model',readonly=True),
'rel_model_ref':fields.integer('Referred Document',readonly=True),
'from':fields.selection(_get_accounts,'From Account',select=True),
'to':fields.char('To',size=250,required=True),
'cc':fields.char('CC',size=250,),
'bcc':fields.char('BCC',size=250,),
'subject':fields.char('Subject',size=200),
'body_text':fields.text('Body',),
'body_html':fields.text('Body',),
'report':fields.char('Report File Name',size=100,),
'signature':fields.boolean('Attach my signature to mail'),
#'filename':fields.text('File Name'),
'requested':fields.integer('No of requested Mails',readonly=True),
'generated':fields.integer('No of generated Mails',readonly=True),
'full_success':fields.boolean('Complete Success',readonly=True),
'attachment_ids': fields.many2many('ir.attachment','send_wizard_attachment_rel', 'wizard_id', 'attachment_id', 'Attachments'),
}
_defaults = {
'state': lambda self,cr,uid,ctx: len(ctx['src_rec_ids']) > 1 and 'multi' or 'single',
'rel_model': lambda self,cr,uid,ctx: self.pool.get('ir.model').search(cr,uid,[('model','=',ctx['src_model'])],context=ctx)[0],
'rel_model_ref': lambda self,cr,uid,ctx: ctx['active_id'],
'to': lambda self,cr,uid,ctx: self._get_template_value(cr, uid, 'def_to', ctx),
'cc': lambda self,cr,uid,ctx: self._get_template_value(cr, uid, 'def_cc', ctx),
'bcc': lambda self,cr,uid,ctx: self._get_template_value(cr, uid, 'def_bcc', ctx),
'subject':lambda self,cr,uid,ctx: self._get_template_value(cr, uid, 'def_subject', ctx),
'body_text':lambda self,cr,uid,ctx: self._get_template_value(cr, uid, 'def_body_text', ctx),
'body_html':lambda self,cr,uid,ctx: self._get_template_value(cr, uid, 'def_body_html', ctx),
'report': lambda self,cr,uid,ctx: self._get_template_value(cr, uid, 'file_name', ctx),
'signature': lambda self,cr,uid,ctx: self._get_template(cr, uid, ctx).use_sign,
'ref_template':lambda self,cr,uid,ctx: self._get_template(cr, uid, ctx).id,
'requested':lambda self,cr,uid,ctx: len(ctx['src_rec_ids']),
'full_success': lambda *a: False
}
def fields_get(self, cr, uid, fields=None, context=None, read_access=True):
result = super(email_template_send_wizard, self).fields_get(cr, uid, fields, context, read_access)
if 'attachment_ids' in result and 'src_model' in context:
result['attachment_ids']['domain'] = [('res_model','=',context['src_model']),('res_id','=',context['active_id'])]
return result
def sav_to_drafts(self, cr, uid, ids, context=None):
if context is None:
context = {}
mailid = self.save_to_mailbox(cr, uid, ids, context)
if self.pool.get('email_template.mailbox').write(cr, uid, mailid, {'folder':'drafts'}, context):
return {'type':'ir.actions.act_window_close' }
def send_mail(self, cr, uid, ids, context=None):
if context is None:
context = {}
mailid = self.save_to_mailbox(cr, uid, ids, context)
if self.pool.get('email_template.mailbox').write(cr, uid, mailid, {'folder':'outbox'}, context):
return {'type':'ir.actions.act_window_close' }
def get_generated(self, cr, uid, ids=None, context=None):
if ids is None:
ids = []
if context is None:
context = {}
logger = netsvc.Logger()
if context['src_rec_ids'] and len(context['src_rec_ids'])>1:
#Means there are multiple items selected for email.
mail_ids = self.save_to_mailbox(cr, uid, ids, context)
if mail_ids:
self.pool.get('email_template.mailbox').write(cr, uid, mail_ids, {'folder':'outbox'}, context)
logger.notifyChannel(_("Power Email"), netsvc.LOG_INFO, _("Emails for multiple items saved in outbox."))
self.write(cr, uid, ids, {
'generated':len(mail_ids),
'state':'done'
}, context)
else:
raise osv.except_osv(_("Power Email"),_("Email sending failed for one or more objects."))
return True
def save_to_mailbox(self, cr, uid, ids, context=None):
def get_end_value(id, value):
if len(context['src_rec_ids']) > 1: # Multiple Mail: Gets value from the template
return self.get_value(cr, uid, template, value, context, id)
else:
return value
mail_ids = []
template = self._get_template(cr, uid, context)
for id in context['src_rec_ids']:
print "@22222222222222222222222",ids
screen_vals = self.read(cr, uid, ids[0], [],context)
account = self.pool.get('email_template.account').read(cr, uid, screen_vals['from'], context=context)
vals = {
'email_from': tools.ustr(account['name']) + "<" + tools.ustr(account['email_id']) + ">",
'email_to': get_end_value(id, screen_vals['to']),
'email_cc': get_end_value(id, screen_vals['cc']),
'email_bcc': get_end_value(id, screen_vals['bcc']),
'subject': get_end_value(id, screen_vals['subject']),
'body_text': get_end_value(id, screen_vals['body_text']),
'body_html': get_end_value(id, screen_vals['body_html']),
'account_id': screen_vals['from'],
'state':'na',
'mail_type':'multipart/alternative' #Options:'multipart/mixed','multipart/alternative','text/plain','text/html'
}
if screen_vals['signature']:
signature = self.pool.get('res.users').read(cr, uid, uid, ['signature'], context)['signature']
if signature:
vals['body_text'] = tools.ustr(vals['body_text'] or '') + signature
vals['body_html'] = tools.ustr(vals['body_html'] or '') + signature
attachment_ids = []
#Create partly the mail and later update attachments
mail_id = self.pool.get('email_template.mailbox').create(cr, uid, vals, context)
mail_ids.append(mail_id)
if template.report_template:
reportname = 'report.' + self.pool.get('ir.actions.report.xml').read(cr, uid, template.report_template.id, ['report_name'], context)['report_name']
data = {}
data['model'] = self.pool.get('ir.model').browse(cr, uid, screen_vals['rel_model'], context).model
# Ensure report is rendered using template's language
ctx = context.copy()
if template.lang:
ctx['lang'] = self.get_value(cr, uid, template, template.lang, context, id)
service = netsvc.LocalService(reportname)
(result, format) = service.create(cr, uid, [id], data, ctx)
attachment_id = self.pool.get('ir.attachment').create(cr, uid, {
'name': _('%s (Email Attachment)') % tools.ustr(vals['subject']),
'datas': base64.b64encode(result),
'datas_fname': tools.ustr(get_end_value(id, screen_vals['report']) or _('Report')) + "." + format,
'description': vals['body_text'] or _("No Description"),
'res_model': 'email_template.mailbox',
'res_id': mail_id
}, context)
attachment_ids.append( attachment_id )
# Add document attachments
for attachment_id in screen_vals.get('attachment_ids',[]):
new_id = self.pool.get('ir.attachment').copy(cr, uid, attachment_id, {
'res_model': 'email_template.mailbox',
'res_id': mail_id,
}, context)
attachment_ids.append( new_id )
if attachment_ids:
self.pool.get('email_template.mailbox').write(cr, uid, mail_id, {
'attachments_ids': [[6, 0, attachment_ids]],
'mail_type': 'multipart/mixed'
}, context)
return mail_ids
email_template_send_wizard()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="email_template_send_wizard_form">
<field name="name">email_template.send.wizard.form</field>
<field name="model">email_template.send.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Send mail Wizard">
<group col="4" colspan="4">
<field name="rel_model" colspan="2" />
<field name="from" required="1" colspan="2" />
</group>
<group col="4" colspan="4">
<group col="6" colspan="4">
<field name="to" select="1" colspan="4" />
<newline />
<field name="cc" select="2" colspan="4" />
<newline />
<field name="bcc" select="2" colspan="4" />
<newline />
<field name="subject" select="2" colspan="4" attrs="{'required':[('state','=','single')]}" />
<newline />
<field name="report" colspan="4" />
</group>
<separator string="" colspan="4" />
<notebook colspan="4">
<page string="Body (Plain Text)">
<field name="body_text" select="2" colspan="4" nolabel="1" />
</page>
<page string="Body (HTML)">
<field name="body_html" select="2" colspan="4" nolabel="1" />
<!--<label string="Note: HTML body can't be edited with GTK desktop client." colspan="4"/>
--></page>
<page string="Attachments">
<label string="Add here all attachments of the current document you want to include in the e-mail." colspan="4"/>
<field name="attachment_ids" colspan="4" nolabel="1"/>
</page>
</notebook>
<field name="signature" colspan="4" />
</group>
<group col="4" colspan="4" attrs="{'invisible':[('state','!=','single')]}">
<button icon="gtk-apply" name="sav_to_drafts" string="Save in Drafts" type="object" />
<button icon="gtk-ok" name="send_mail" string="Send now" type="object" />
<button icon="gtk-cancel" special="cancel" string="Discard Mail" />
</group>
<group col="4" colspan="4" attrs="{'invisible':[('state','=','single')]}">
<label string="Tip: Multiple emails are sent in the same language (the first one is proposed). We suggest you send emails in groups according to language." colspan="4"/>
<field name="requested" />
<field name="generated" />
<button icon="gtk-ok" name="get_generated" string="Send all mails" type="object" states="multi" colspan="2" />
<button icon="gtk-cancel" special="cancel" string="Discard Mail" colspan="2" states="multi" />
</group>
<button icon="gtk-ok" special="cancel" string="Close" colspan="4" states="done" />
<field name="state" />
<newline />
<label string="After clicking send all mails, mails will be sent to outbox and cleared in next Send/Recieve" colspan="4"/>
</form>
</field>
</record>
</data>
</openerp>

View File

@ -223,25 +223,32 @@
<page string="History">
<field name="message_ids" colspan="4" nolabel="1" mode="tree,form">
<form string="Communication history">
<group col="6" colspan="4">
<field name="date"/>
<field name="email_to"/>
<field name="email_from"/>
</group>
<newline/>
<field name="description" colspan="4" nolabel="1"/>
<button colspan="4"
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'crm.lead'}"
icon="gtk-undo" type="action" />
</form>
<tree string="Communication history">
<field name="description"/>
<field name="email_to"/>
<field name="date"/>
</tree>
</field>
<group col="6" colspan="4">
<field name="date"/>
<field name="email_to"/>
<field name="email_from"/>
</group>
<notebook colspan="4">
<page string="Details">
<field name="description" colspan="4" nolabel="1"/>
</page>
<page string="Attachments">
<field name="attachment_ids" colspan="4" readonly="1" nolabel="1"/>
</page>
</notebook>
<button colspan="4"
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'event.registration'}"
icon="gtk-undo" type="action" />
</form>
<tree string="Communication history">
<field name="date"/>
<field name="email_from" />
<field name="email_to"/>
<field name="description"/>
</tree>
</field>
<field name="log_ids" nolabel="1" colspan="4" mode="tree,form" readonly="1">
<tree string="Actions">
<separator string="Action Information" colspan="4"/>

View File

@ -69,7 +69,7 @@ class event_make_invoice(osv.osv_memory):
inv_rej_reason += "ID "+str(reg.id)+": Registration doesn't have any partner to invoice. \n"
continue
else:
val_invoice = pool_obj.get('account.invoice').onchange_partner_id(cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False)
val_invoice = inv_obj.onchange_partner_id(cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False)
val_invoice['value'].update({'partner_id': reg.partner_invoice_id.id})
partner_address_id = val_invoice['value']['address_invoice_id']

View File

@ -7,6 +7,7 @@
<field eval="[(6,0,[])]" name="users"/>
<field name="type" ref="survey.survey_type1"/>
<field name="responsible_id" ref="base.user_demo"/>
<field name="response_user">5</field>
</record>
</data>
<data>
@ -16,6 +17,7 @@
<field eval="[(6,0,[])]" name="users"/>
<field name="type" ref="survey.survey_type1"/>
<field name="responsible_id" ref="base.user_root"/>
<field name="response_user">5</field>
</record>
</data>
<data>

View File

@ -2,7 +2,7 @@
<openerp>
<data noupdate="1">
<record id="product_product_expense_0" model="product.product">
<record id="product_product_expense_air" model="product.product">
<field name="list_price">1.0</field>
<field name="standard_price">1.0</field>
<field name="uom_id" ref="product.product_uom_unit"/>
@ -10,11 +10,11 @@
<field name="type">service</field>
<field name="name">Air Ticket</field>
<field name="default_code">AT</field>
<field name="categ_id" ref="product.product_category_7"/>
<field name="categ_id" ref="product.cat2"/>
<field name="hr_expense_ok" eval="True" />
</record>
<record id="product_product_expense_2" model="product.product">
<record id="product_product_expense_hotel" model="product.product">
<field name="list_price">1.0</field>
<field name="standard_price">1.0</field>
<field name="uom_id" ref="product.product_uom_unit"/>
@ -22,7 +22,19 @@
<field name="type">service</field>
<field name="name">Hotel Accommodation</field>
<field name="default_code">HA0</field>
<field name="categ_id" ref="product.product_category_7"/>
<field name="categ_id" ref="product.cat2"/>
<field name="hr_expense_ok" eval="True" />
</record>
<record id="product_product_expense_car" model="product.product">
<field name="list_price">0.30</field>
<field name="standard_price">0.30</field>
<field name="uom_id" ref="product.product_uom_km"/>
<field name="uom_po_id" ref="product.product_uom_km"/>
<field name="type">consu</field>
<field name="name">Car Travel</field>
<field name="default_code">CAR</field>
<field name="categ_id" ref="product.cat2"/>
<field name="hr_expense_ok" eval="True" />
</record>
@ -30,29 +42,29 @@
<field name="currency_id" ref="base.EUR"/>
<field name="employee_id" ref="hr.employee1"/>
<field name="user_id" ref="base.user_root"/>
<field name="name">September Expenses</field>
<field name="name">May Expenses</field>
<field name="company_id" ref="base.main_company"/>
<field name="date">2010-05-03</field>
<field name="state">draft</field>
</record>
<record id="hr_expense_line_travelbycarcustomerseagatedouble0" model="hr.expense.line">
<field name="name">Travel by Air - Customer Seagate 2 - Double</field>
<field name="name">Travel by Air</field>
<field name="date_value">2010-05-03</field>
<field name="analytic_account" ref="account.analytic_thymbra"/>
<field name="product_id" ref="product_product_expense_0"/>
<field model="hr.expense.expense" name="expense_id" search="[('name', '=', u'September Expenses')]"/>
<field name="analytic_account" ref="account.analytic_consultancy"/>
<field name="product_id" ref="product_product_expense_air"/>
<field model="hr.expense.expense" name="expense_id" search="[('name', '=', u'May Expenses')]"/>
<field eval="700.0" name="unit_amount"/>
<field name="uom_id" ref="product.product_uom_unit"/>
<field eval="200.0" name="unit_quantity"/>
<field eval="1.0" name="unit_quantity"/>
</record>
<record id="hr_expense_line_basicpcserverforseagate0" model="hr.expense.line">
<field name="name">Basic PC - Server for Seagate</field>
<field name="date_value">2010-05-03</field>
<field name="analytic_account" ref="account.analytic_seagate_p2"/>
<field name="product_id" ref="product.product_product_25"/>
<field model="hr.expense.expense" name="expense_id" search="[('name', '=', u'September Expenses')]"/>
<field eval="35.5" name="unit_amount"/>
<field name="product_id" ref="product.product_product_pc4"/>
<field model="hr.expense.expense" name="expense_id" search="[('name', '=', u'May Expenses')]"/>
<field eval="1200.0" name="unit_amount"/>
<field name="uom_id" ref="product.product_uom_unit"/>
<field eval="1.0" name="unit_quantity"/>
</record>
@ -62,7 +74,7 @@
<field name="currency_id" ref="base.EUR"/>
<field name="employee_id" ref="hr.employee1"/>
<field name="user_id" ref="base.user_root"/>
<field name="name">Hotel Expenses</field>
<field name="name">Travel Expenses</field>
<field name="company_id" ref="base.main_company"/>
<field name="date">2010-04-20</field>
<field name="state">draft</field>
@ -71,12 +83,23 @@
<field name="name">Hotel Expenses - Thymbra</field>
<field name="date_value">2010-05-03</field>
<field name="analytic_account" ref="account.analytic_thymbra"/>
<field name="product_id" ref="product_product_expense_2"/>
<field model="hr.expense.expense" name="expense_id" search="[('name', '=', u'Hotel Expenses')]"/>
<field name="product_id" ref="product_product_expense_hotel"/>
<field model="hr.expense.expense" name="expense_id" search="[('name', '=', u'Travel Expenses')]"/>
<field eval="400.0" name="unit_amount"/>
<field name="uom_id" ref="product.product_uom_unit"/>
<field eval="5.0" name="unit_quantity"/>
</record>
<record id="hr_expense_line_car_travel" model="hr.expense.line">
<field name="name">Bruxelles - Paris</field>
<field name="date_value">2010-05-03</field>
<field name="analytic_account" ref="account.analytic_thymbra"/>
<field name="product_id" ref="product_product_expense_car"/>
<field model="hr.expense.expense" name="expense_id" search="[('name', '=', u'Travel Expenses')]"/>
<field eval="0.30" name="unit_amount"/>
<field name="uom_id" ref="product.product_uom_km"/>
<field eval="622.0" name="unit_quantity"/>
</record>
</data>
</openerp>
</openerp>

View File

@ -148,6 +148,7 @@
<field eval="[(6,0,[])]" name="users"/>
<field name="type" ref="survey.survey_type1"/>
<field name="responsible_id" ref="base.user_root"/>
<field name="response_user">5</field>
</record>
</data>
<data>

View File

@ -2,6 +2,12 @@
<openerp>
<data>
<menuitem
id="menu_hr_config_applicant"
name="Applicant"
parent="hr.menu_hr_configuration"
/>
# ------------------------------------------------------
# Job Categories
# ------------------------------------------------------
@ -25,7 +31,8 @@
<field name="domain">[('object_id.model', '=', 'hr.applicant')]</field>
<field name="context">{'object_id':'hr.applicant'}</field>
</record>
<menuitem action="hr_job_stage_act" id="menu_hr_job_stage_act" parent="crm.menu_crm_case_stage"/>
<menuitem action="hr_job_stage_act" id="menu_hr_job_stage_act" name="Stages" parent="menu_hr_config_applicant"/>
# ------------------------------------------------------
# Jobs
@ -152,26 +159,33 @@
<field colspan="4" name="email_cc" string="CC"/>
</group>
<field name="message_ids" colspan="4" nolabel="1" mode="form,tree">
<form string="Communication history">
<group col="6" colspan="4">
<field name="date"/>
<field name="email_to"/>
<field name="email_from"/>
</group>
<newline/>
<field name="description" colspan="4" nolabel="1"/>
<button colspan="4"
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'hr.applicant'}"
icon="gtk-undo" type="action" />
</form>
<tree string="Communication history">
<field name="description"/>
<field name="email_to"/>
<field name="date"/>
</tree>
</field>
<form string="Communication history">
<group col="6" colspan="4">
<field name="date"/>
<field name="email_to"/>
<field name="email_from"/>
</group>
<notebook colspan="4">
<page string="Details">
<field name="description" colspan="4" nolabel="1"/>
</page>
<page string="Attachments">
<field name="attachment_ids" colspan="4" readonly="1" nolabel="1"/>
</page>
</notebook>
<button colspan="4"
string="Reply to Last Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'reply', 'model': 'hr.applicant'}"
icon="gtk-undo" type="action" />
</form>
<tree string="Communication history">
<field name="date"/>
<field name="email_from" />
<field name="email_to"/>
<field name="description"/>
</tree>
</field>
<button colspan="4" string="Send New Email"
name="%(crm.action_crm_send_mail)d"
context="{'mail':'new', 'model': 'hr.applicant'}"

View File

@ -57,8 +57,7 @@ class hr_analytic_timesheet(osv.osv):
def on_change_unit_amount(self, cr, uid, id, prod_id, unit_amount, unit, context={}):
res = {}
# if prod_id and unit_amount:
if prod_id:
if prod_id and unit_amount:
# find company
company_id = self.pool.get('res.company')._company_default_get(cr, uid, 'account.analytic.line', context=context)
res = self.pool.get('account.analytic.line').on_change_unit_amount(cr, uid, id, prod_id, unit_amount, company_id, unit, context=context)

View File

@ -115,31 +115,19 @@ class hr_si_project(osv.osv_memory):
# get the latest action (sign_in or out) for this employee
cr.execute('select action from hr_attendance where employee_id=%s and action in (\'sign_in\',\'sign_out\') order by name desc limit 1', (emp_id,))
res = (cr.fetchone() or ('sign_out',))[0]
in_out = res == 'sign_out' and 'out' or 'in'
#TODO: invert sign_in et sign_out
if res == 'sign_out':
model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'),('name','=','view_hr_timesheet_sign_in')])
resource_id = obj_model.read(cr,uid,model_data_ids,fields=['res_id'])[0]['res_id']
return {
'name': 'Sign in / Sign out',
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'hr.sign.in.project',
'views': [(False,'tree'), (resource_id,'form')],
'type': 'ir.actions.act_window',
'target': 'new'
}
else:
model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'),('name','=','view_hr_timesheet_sign_out')])
resource_id = obj_model.read(cr,uid,model_data_ids,fields=['res_id'])[0]['res_id']
return {
'name': 'Sign in / Sign out',
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'hr.sign.out.project',
'views': [(False,'tree'), (resource_id,'form')],
'type': 'ir.actions.act_window',
'target': 'new'
}
model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'),('name','=','view_hr_timesheet_sign_%s' % in_out)])
resource_id = obj_model.read(cr,uid,model_data_ids,fields=['res_id'])[0]['res_id']
return {
'name': 'Sign in / Sign out',
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'hr.sign.%s.project' % in_out,
'views': [(False,'tree'), (resource_id,'form')],
'type': 'ir.actions.act_window',
'target': 'new'
}
def _get_empid(self, cr, uid, context=None):
emp_obj = self.pool.get('hr.employee')
@ -153,10 +141,7 @@ class hr_si_project(osv.osv_memory):
emp_obj = self.pool.get('hr.employee')
data = self.read(cr, uid, ids, [], context)[0]
emp_id = data['emp_id']
try:
success = emp_obj.attendance_action_change(cr, uid, [emp_id], type = 'sign_in' ,dt=data['date'] or False)
except except_osv, e:
raise osv.except_osv(e.name, e.value)
success = emp_obj.attendance_action_change(cr, uid, [emp_id], type = 'sign_in' ,dt=data['date'] or False)
return {}
def default_get(self, cr, uid, fields_list, context=None):
@ -166,4 +151,4 @@ class hr_si_project(osv.osv_memory):
hr_si_project()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -462,6 +462,7 @@
<newline/>
<group expand="1" string="Group By...">
<filter string="User" icon="terp-project" domain="[]" context="{'group_by':'user_id'}"/>
<separator orientation="vertical"/>
<filter string="Product" icon="terp-project" domain="[]" context="{'group_by':'product_id'}"/>
<filter string="Analytic Account" icon="terp-project" domain="[]" context="{'group_by':'analytic_account_id'}"/>
<filter string="General Account" icon="terp-project" domain="[]" context="{'group_by':'general_account_id'}"/>

View File

@ -74,12 +74,12 @@
domain="[('user_id','=',False)]"/>
</field>
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
</group>
<newline/>
</group>
<newline/>
<group expand="1" string="Group By...">
<filter string="User" name="User" icon="terp-hr" context="{'group_by':'user_id'}"/>
<filter string="Product" icon="terp-hr" context="{'group_by':'product_id'}"/>
<separator orientation="vertical"/>
<filter string="Product" icon="terp-hr" context="{'group_by':'product_id'}"/>
<filter string="Type of Invoicing" icon="terp-hr" context="{'group_by':'to_invoice'}"/>
<filter string="Analytic Account" icon="terp-hr" context="{'group_by':'account_id'}"/>
<filter string="General Account" icon="terp-hr" context="{'group_by':'general_account_id'}"/>
@ -111,7 +111,7 @@
<separator orientation="vertical"/>
<field name="general_account_id"/>
<field name="to_invoice" widget="selection"/>
</group>
</group>
</search>
</field>
</record>

View File

@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-06-01 03:44+0000\n"
"X-Launchpad-Export-Date: 2010-06-02 03:33+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: idea

View File

@ -22,6 +22,7 @@
from osv import osv
from osv import fields
from tools.translate import _
import time
VoteValues = [('-1', 'Not Voted'), ('0', 'Very Bad'), ('25', 'Bad'), \
('50', 'Normal'), ('75', 'Good'), ('100', 'Very Good') ]
@ -29,7 +30,7 @@ DefaultVoteValue = '50'
class idea_category(osv.osv):
""" Category of Idea """
_name = "idea.category"
_description = "Idea Category"
@ -155,16 +156,16 @@ class idea_idea(osv.osv):
'title': fields.char('Idea Summary', size=64, required=True, readonly=True, states={'draft':[('readonly',False)]}),
'description': fields.text('Description', help='Content of the idea', readonly=True, states={'draft':[('readonly',False)]}),
'comment_ids': fields.one2many('idea.comment', 'idea_id', 'Comments'),
'create_date': fields.datetime('Creation date', readonly=True),
'created_date': fields.datetime('Creation date', readonly=True),
'vote_ids': fields.one2many('idea.vote', 'idea_id', 'Vote'),
'my_vote': fields.function(_vote_read, fnct_inv = _vote_save, string="My Vote", method=True, type="selection", selection=VoteValues),
'vote_avg': fields.function(_vote_avg_compute, method=True, string="Average Score", type="float"),
'count_votes': fields.function(_vote_count, method=True, string="Count of votes", type="integer"),
'count_comments': fields.function(_comment_count, method=True, string="Count of comments", type="integer"),
'category_id': fields.many2one('idea.category', 'Category', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'state': fields.selection([('draft', 'Draft'),
'state': fields.selection([('draft', 'Draft'),
('open', 'Opened'),
('close', 'Accepted'),
('close', 'Accepted'),
('cancel', 'Cancelled')],
'State', readonly=True,
help='When the Idea is created the state is \'Draft\'.\n It is \
@ -173,12 +174,16 @@ class idea_idea(osv.osv):
),
'visibility':fields.boolean('Open Idea?', required=False),
'stat_vote_ids': fields.one2many('idea.vote.stat', 'idea_id', 'Statistics', readonly=True),
'vote_limit': fields.integer('Maximum Vote per User',
help="Set to one if you require only one Vote per user"),
}
_defaults = {
'user_id': lambda self,cr,uid,context: uid,
'my_vote': lambda *a: '-1',
'state': lambda *a: 'draft',
'vote_limit': lambda * a: 1,
'created_date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'visibility': lambda *a: True,
}
_order = 'id desc'
@ -190,11 +195,11 @@ class idea_idea(osv.osv):
@param user: ID of the user currently logged in
@param vals: provides data for new record
@param context: context arguments, like lang, time zone
@return: Returns an id of the new record
"""
visibility = False
if vals.get('category_id', False):
category_pool = self.pool.get('idea.category')
category = category_pool.browse(cr, user, vals.get('category_id'), context)
@ -215,41 +220,41 @@ class idea_idea(osv.osv):
@param id: list of record ids on which copy method executes
@param default: dict type contains the values to be overridden during copy of object
@param context: context arguments, like lang, time zone
@return: Returns the id of the new record
"""
default.update({
'comment_ids':False,
'vote_ids':False,
'stat_vote_ids':False
})
res_id = super(idea_idea, self).copy(cr, uid, id, default, context)
return res_id
def write(self, cr, user, ids, vals, context=None):
"""
Update redord(s) exist in {ids}, with new value provided in {vals}
@param cr: A database cursor
@param user: ID of the user currently logged in
@param ids: list of record ids to update
@param vals: dict of new values to be set
@param context: context arguments, like lang, time zone
@return: Returns True on success, False otherwise
"""
state = self.browse(cr, user, ids[0]).state
if vals.get('my_vote', False):
if vals.get('state', state) != 'open':
raise osv.except_osv(_("Warning !"), _("Draft/Accepted/Cancelled ideas Could not be voted"))
res = super(idea_idea, self).write(cr, user, ids, vals, context)
return res
def idea_cancel(self, cr, uid, ids):
self.write(cr, uid, ids, { 'state': 'cancel' })
return True
@ -261,7 +266,7 @@ class idea_idea(osv.osv):
def idea_close(self, cr, uid, ids):
self.write(cr, uid, ids, { 'state': 'close' })
return True
def idea_draft(self, cr, uid, ids):
self.write(cr, uid, ids, { 'state': 'draft' })
return True
@ -299,12 +304,15 @@ class idea_vote(osv.osv):
_rec_name = 'score'
_columns = {
'user_id': fields.many2one('res.users', 'User'),
'idea_id': fields.many2one('idea.idea', 'Idea', required=True, ondelete='cascade'),
'score': fields.selection(VoteValues, 'Score', required=True)
'user_id': fields.many2one('res.users', 'By user', readonly="True"),
'idea_id': fields.many2one('idea.idea', 'Idea', readonly="True", ondelete='cascade'),
'score': fields.selection(VoteValues, 'Vote Status', readonly="True"),
'date': fields.datetime('Date', readonly="True"),
'comment': fields.text('Comment', readonly="True"),
}
_defaults = {
'score': lambda *a: DefaultVoteValue,
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
}
idea_vote()

View File

@ -50,6 +50,7 @@
<menuitem name="Categories" parent="menu_ideas" id="menu_idea_category" action="action_idea_category" />
<!-- Idea Category Action -->
<record model="ir.actions.act_window" id="action_idea_category_tree">
@ -60,8 +61,18 @@
</record>
<menuitem name="Ideas" parent="base.menu_tools" id="menu_ideas1" sequence="4"/>
<menuitem
name="Ideas by Categories" parent="menu_ideas1"
id="menu_idea_category_tree"
action="action_idea_category_tree"/>
<menuitem name="Give Vote" parent="menu_ideas1"
id="menu_give_vote"
action="action_idea_select"/>
<!-- Oepn Ideas Action -->
<!-- Open Ideas Action -->
<record model="ir.actions.act_window" id="action_idea_idea_categ_open">
<field name="name">Open Ideas</field>
@ -102,9 +113,9 @@
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Votes">
<field name="idea_id"/>
<field name="user_id"/>
<field name="score" />
<field name="user_id" />
<field name="score"/>
<field name="date"/>
</tree>
</field>
</record>
@ -117,12 +128,39 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Votes">
<field name="idea_id" select="1" />
<field name="user_id" select="1" />
<field name="score"/>
<group colspan="4">
<field name="user_id" select="1" />
<field name="date"/>
<newline/>
<field name="score"/>
</group>
<separator string="Comments:" colspan="4"/>
<field name="comment" colspan="4" nolabel="1"/>
</form>
</field>
</record>
<!-- Search view for Idea vote -->
<record model="ir.ui.view" id="view_idea_vote_search">
<field name="name">idea.vote.search</field>
<field name="model">idea.vote</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Ideas vote">
<group col="10" colspan="4">
<field name="idea_id" widget="selection"/>
<field name="user_id" widget="selection"/>
</group>
<newline/>
<group expand="1" string="Group By..." colspan="14">
<filter string="Vote date" icon="terp-crm" domain="[]" context="{'group_by':'date'}"/>
<filter string="Idea" icon="terp-crm" domain="[]" context="{'group_by':'idea_id'}"/>
<filter string="User" name="user" icon="terp-partner" domain="[]" context="{'group_by':'user_id'}"/>
</group>
</search>
</field>
</record>
<!-- New Idea Form View -->
@ -180,7 +218,8 @@
<field name="score"/>
<field name="nbr"/>
</tree>
</field>
</field>
</page>
</notebook>
<group colspan="4" col="6">
@ -188,7 +227,6 @@
<button name="idea_open" string="Open" states="draft" icon="gtk-go-forward"/>
<button name="idea_close" string="Accept" states="open" icon="gtk-jump-to"/>
<button name="idea_cancel" string="Refuse" states="open" icon="gtk-cancel"/>
</group>
</form>
</field>
@ -201,15 +239,15 @@
<field name="model">idea.idea</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="All Ideas">
<tree string="Ideas">
<field name="title"/>
<field name="category_id" />
<field name="create_date"/>
<field name="created_date"/>
<field name="vote_avg" widget="progressbar"/>
<field name="count_comments" />
<field name="count_votes" />
<field name="state"/>
<button name="%(action_idea_post_vote)d" icon="gtk-execute" type="action" states="draft,open" string="Vote"/>
<button name="%(idea.action_idea_post_vote)d" icon="gtk-execute" type="action" states="open" string="Submit Vote"/>
<button name="idea_close" string="Accept" states="open" icon="gtk-jump-to"/>
<button name="idea_cancel" string="Refuse" states="open" icon="gtk-cancel"/>
</tree>
@ -244,23 +282,6 @@
</field>
</record>
<!-- Comments on Idea Tree View -->
<record model="ir.ui.view" id="view_idea_comment_tree">
<field name="name">idea.comment.tree</field>
<field name="model">idea.comment</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Comments">
<field name="create_date" />
<field name="user_id" />
<field name="content" string="Comment" />
</tree>
</field>
</record>
<!-- Idea Action -->
<record model="ir.actions.act_window" id="action_idea_idea">
<field name="name">Ideas</field>
<field name="res_model">idea.idea</field>
@ -348,9 +369,10 @@
<field name="res_model">idea.vote</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_idea_vote_search"/>
</record>
<menuitem name="All Votes" parent="menu_ideas" id="menu_idea_vote" action="action_idea_vote"/>
<menuitem name="Votes" parent="menu_ideas" id="menu_idea_vote" action="action_idea_vote"/>
</data>
</openerp>

View File

@ -1,8 +1,9 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_idea_category","idea.category","model_idea_category","base.group_user",1,0,0,0
"access_idea_idea","idea.idea","model_idea_idea","base.group_user",1,1,1,1
"access_idea_comment","idea.comment","model_idea_comment","base.group_user",1,1,1,1
"access_idea_vote","idea.vote","model_idea_vote","base.group_user",1,1,1,1
"access_idea_vote_stat","idea.vote.stat","model_idea_vote_stat","base.group_user",1,0,0,0
"access_idea_category_system","idea.category system","model_idea_category","base.group_system",1,1,1,1
"idea_post_vote","idea.post.vote","model_idea_post_vote","base.group_user",1,1,1,1
"access_idea_select","idea.select","model_idea_select","base.group_user",1,1,1,1
"access_idea_comment","idea.comment","model_idea_comment","base.group_system",1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_idea_category idea.category model_idea_category base.group_user 1 0 0 0
3 access_idea_idea idea.idea model_idea_idea base.group_user 1 1 1 1
access_idea_comment idea.comment model_idea_comment base.group_user 1 1 1 1
4 access_idea_vote idea.vote model_idea_vote base.group_user 1 1 1 1
5 access_idea_vote_stat idea.vote.stat model_idea_vote_stat base.group_user 1 0 0 0
6 access_idea_category_system idea.category system model_idea_category base.group_system 1 1 1 1
7 idea_post_vote idea.post.vote model_idea_post_vote base.group_user 1 1 1 1
8 access_idea_select idea.select model_idea_select base.group_user 1 1 1 1
9 access_idea_comment idea.comment model_idea_comment base.group_system 1 1 1 1

View File

@ -8,10 +8,10 @@
name: Technical
- |
I create a New Idea of "Technical presentation for 1 hours in every day" and specify category "Technical".
-
!record {model: idea.idea, id: idea_idea_0}:
category_id: idea_category_technical0
created_date: '05/13/2010 19:16:26'
description: I want that Technical presentation are arranged for 1 hours in every
day.\nso, on that presentation, we can know all things what improvement and development
are done in our company.\n\n\n\n\n
@ -44,52 +44,50 @@
!record {model: res.users, id: res_users_user1}:
company_id: base.main_company
context_lang: en_US
groups_id:
- base.group_system
- base.group_user
login: user2
name: user2
password: user2
- |
In order to post vote I connect as user1 and open the idea page
I click on "Vote" wizard and vote the idea as "Normal"
I click on "Submit Vote" wizard button and vote the idea as "Normal"
-
!record {model: idea.post.vote, id: idea_post_vote_0}:
vote: 50
- |
Now I click on "Post Vote" button of wizard.
Now I click on "Post" button of this wizard.
-
!python {model: idea.post.vote}: |
uid = ref('res_users_user0')
self.do_vote(cr, uid, [ref("idea_post_vote_0")], {'active_id': ref('idea_idea_0')})
self.do_vote(cr, uid, [ref("idea_post_vote_0")], {'active_ids': [ref('idea_idea_0')]})
- |
To add other vote I connect as user2 and open the idea page
I click on "Vote" wizard and vote the idea as "Very Good"
To add other vote I connect as user2 and open the idea page.
I click on "Submit Vote" wizard button and vote the idea as "Very Good".
and put comment "We can learn many things from technical presentation".
-
!record {model: idea.post.vote, id: idea_post_vote_1}:
vote: 100
note: 'We can learn many things from technical presentation'
- |
I click on "Post Vote" button of this wizard.
I click on "Post" button of this wizard.
-
!python {model: idea.post.vote}: |
uid = ref('res_users_user1')
self.do_vote(cr, uid, [ref("idea_post_vote_1")], {'active_id': ref('idea_idea_0')})
self.do_vote(cr, uid, [ref("idea_post_vote_1")], {'active_ids': [ref('idea_idea_0')]})
- |
I can see that the Average score changed in "Average score" field with value 75
-
!record {model: idea.idea, id: idea_idea_0}:
vote_avg: 75
- |
I put one comment "We can learn many things from technical presentation" for the idea.
-
!record {model: idea.idea, id: idea.idea_idea_0}:
comment_ids:
- content: "We can learn many things from technical presentation"
idea_id: idea.idea_idea_0
user_id: res_users_user1
- |
I connect as Manager and close this idea by click on "Close" button.

View File

@ -34,11 +34,11 @@ class idea_post_vote(osv.osv_memory):
('25', 'Bad'),
('50', 'Normal'),
('75', 'Good'),
('100', 'Very Good') ],
('100', 'Very Good') ],
'Post Vote', required=True),
'note': fields.text('Description'),
}
def get_default(self, cr, uid, context={}):
"""
This function checks for precondition before wizard executes
@ -49,17 +49,17 @@ class idea_post_vote(osv.osv_memory):
@param context: A standard dictionary for contextual values
"""
idea_obj = self.pool.get('idea.idea')
if context.get('active_id'):
idea = idea_obj.browse(cr, uid, context.get('active_id'))
return idea.my_vote
else:
return 75
_defaults = {
'vote': get_default,
}
def view_init(self, cr, uid, fields, context=None):
"""
This function checks for precondition before wizard executes
@ -70,15 +70,28 @@ class idea_post_vote(osv.osv_memory):
@param context: A standard dictionary for contextual values
"""
idea_obj = self.pool.get('idea.idea')
vote_obj = self.pool.get('idea.vote')
for idea in idea_obj.browse(cr, uid, context.get('active_ids', [])):
if idea.state in ['draft', 'close', 'cancel']:
raise osv.except_osv(_("Warning !"), _("Draft/Accepted/Cancelled ideas Could not be voted"))
for active_id in context.get('active_ids'):
vote_ids = vote_obj.search(cr, uid, [('user_id', '=', uid), ('idea_id', '=', active_id)])
vote_obj_id = vote_obj.browse(cr, uid, vote_ids)
count = 0
for vote in vote_obj_id:
count += 1
user_limit = idea.vote_limit
if count >= user_limit:
raise osv.except_osv(_('Warning !'),_("You can not give Vote for this idea more than %s times") % (user_limit))
if idea.state != 'open':
raise osv.except_osv(_('Warning !'), _('idea should be in \'Open\' state before vote for that idea.'))
raise osv.except_osv(_('Warning !'), _('Idea should be in \
\'Open\' state before vote for that idea.'))
return False
def do_vote(self, cr, uid, ids, context):
def do_vote(self, cr, uid, ids, context=None):
"""
Create idea vote.
@param cr: the current row, from the database cursor,
@ -86,8 +99,8 @@ class idea_post_vote(osv.osv_memory):
@param ids: List of Idea Post votes IDs.
@return: Dictionary {}
"""
vote_id = context and context.get('active_id', False) or False
vote_ids = context and context.get('active_ids', []) or []
vote_pool = self.pool.get('idea.vote')
idea_pool = self.pool.get('idea.idea')
comment_pool = self.pool.get('idea.comment')
@ -96,8 +109,8 @@ class idea_post_vote(osv.osv_memory):
score = str(do_vote_obj['vote'])
comment = do_vote_obj.get('note', False)
vote = {
'idea_id': vote_id,
'user_id': uid,
'idea_id': vote_id,
'user_id': uid,
'score': score
}
if comment:
@ -114,5 +127,44 @@ class idea_post_vote(osv.osv_memory):
idea_post_vote()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
class idea_select(osv.osv_memory):
""" Select idea for vote."""
_name = "idea.select"
_description = "select idea"
_columns = {
'idea_id': fields.many2one('idea.idea', 'Idea', required=True),
}
def open_vote(self, cr, uid, ids, context=None):
"""
This function load column.
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of load column,
@return: dictionary of query logs clear message window
"""
idea_obj = self.browse(cr, uid, ids)
for idea in idea_obj:
idea_id = idea.idea_id.id
data_obj = self.pool.get('ir.model.data')
id2 = data_obj._get_id(cr, uid, 'idea', 'view_idea_post_vote')
if id2:
id2 = data_obj.browse(cr, uid, id2, context=context).res_id
value = {
'view_type': 'form',
'view_mode': 'form',
'res_model': 'idea.post.vote',
'views': [(id2, 'form'), (False, 'tree'), (False, 'calendar'), (False, 'graph')],
'type': 'ir.actions.act_window',
'target': 'new',
'context': {'active_ids': [idea_id]}
}
return value
idea_select()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

Some files were not shown because too many files have changed in this diff Show More