[FWD] [MERGE] Forward port of addons-v7 until rev. 8736.

bzr revid: tde@openerp.com-20130221105247-ezl63lpl4vdjxtys
This commit is contained in:
Thibault Delavallée 2013-02-21 11:52:47 +01:00
commit e0372e8c6d
33 changed files with 340 additions and 290 deletions

View File

@ -343,7 +343,7 @@ class account_journal_cashbox_line(osv.osv):
_rec_name = 'pieces'
_columns = {
'pieces': fields.float('Values', digits_compute=dp.get_precision('Account')),
'journal_id' : fields.many2one('account.journal', 'Journal', required=True, select=1),
'journal_id' : fields.many2one('account.journal', 'Journal', required=True, select=1, ondelete="cascade"),
}
_order = 'pieces asc'

View File

@ -449,11 +449,15 @@ class account_invoice(osv.osv):
context = {}
invoices = self.read(cr, uid, ids, ['state','internal_number'], context=context)
unlink_ids = []
for t in invoices:
if t['state'] in ('draft', 'cancel') and t['internal_number']== False:
unlink_ids.append(t['id'])
if t['state'] not in ('draft', 'cancel'):
raise openerp.exceptions.Warning(_('You cannot delete an invoice which is not draft or cancelled. You should refund it instead.'))
elif t['internal_number']:
raise openerp.exceptions.Warning(_('You cannot delete an invoice after it has been validated (and received a number). You can set it back to "Draft" state and modify its content, then re-confirm it.'))
else:
raise osv.except_osv(_('Invalid Action!'), _('You can not delete an invoice which is not cancelled. You should refund it instead.'))
unlink_ids.append(t['id'])
osv.osv.unlink(self, cr, uid, unlink_ids, context=context)
return True
@ -1147,6 +1151,11 @@ class account_invoice(osv.osv):
return self.name_get(cr, user, ids, context)
def _refund_cleanup_lines(self, cr, uid, lines, context=None):
"""Convert records to dict of values suitable for one2many line creation
:param list(browse_record) lines: records to convert
:return: list of command tuple for one2many line creation [(0, 0, dict of valueis), ...]
"""
clean_lines = []
for line in lines:
clean_line = {}

View File

@ -18,6 +18,7 @@
<field name="parent_id" invisible="1"/>
<field name="state" invisible="1"/>
<field name="type" invisible="1"/>
<field name="template_id" invisible="1"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>

View File

@ -56,7 +56,7 @@ class report_account_common(report_sxw.rml_parse, common_report_header):
for report in self.pool.get('account.financial.report').browse(self.cr, self.uid, ids2, context=data['form']['used_context']):
vals = {
'name': report.name,
'balance': report.balance * report.sign,
'balance': report.balance * report.sign or 0.0,
'type': 'report',
'level': bool(report.style_overwrite) and report.style_overwrite or report.level,
'account_type': report.type =='sum' and 'view' or False, #used to underline the financial report balances

View File

@ -180,9 +180,9 @@ class account_invoice_refund(osv.osv_memory):
'journal_id', 'period_id'], context=context)
invoice = invoice[0]
del invoice['id']
invoice_lines = inv_line_obj.read(cr, uid, invoice['invoice_line'], context=context)
invoice_lines = inv_line_obj.browse(cr, uid, invoice['invoice_line'], context=context)
invoice_lines = inv_obj._refund_cleanup_lines(cr, uid, invoice_lines)
tax_lines = inv_tax_obj.read(cr, uid, invoice['tax_line'], context=context)
tax_lines = inv_tax_obj.browse(cr, uid, invoice['tax_line'], context=context)
tax_lines = inv_obj._refund_cleanup_lines(cr, uid, tax_lines)
invoice.update({
'type': inv.type,

View File

@ -20,7 +20,6 @@
##############################################################################
import account_analytic_analysis
import cron_account_analytic_account
import res_config
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -38,7 +38,6 @@ Adds menu to show relevant information to each manager.You can also view the rep
'security/ir.model.access.csv',
'security/account_analytic_analysis_security.xml',
'account_analytic_analysis_view.xml',
'account_analytic_analysis_menu.xml',
'account_analytic_analysis_cron.xml',
'res_config_view.xml',
],

View File

@ -18,6 +18,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import datetime
import logging
import time
from openerp.osv import osv, fields
from openerp.osv.orm import intersect, except_orm
@ -26,6 +29,7 @@ from openerp.tools.translate import _
from openerp.addons.decimal_precision import decimal_precision as dp
_logger = logging.getLogger(__name__)
class account_analytic_account(osv.osv):
_name = "account.analytic.account"
@ -484,7 +488,48 @@ class account_analytic_account(osv.osv):
res['value']['to_invoice'] = template.to_invoice.id
res['value']['pricelist_id'] = template.pricelist_id.id
return res
account_analytic_account()
def cron_account_analytic_account(self, cr, uid, context=None):
if context is None:
context = {}
remind = {}
def fill_remind(key, domain, write_pending=False):
base_domain = [
('type', '=', 'contract'),
('partner_id', '!=', False),
('manager_id', '!=', False),
('manager_id.email', '!=', False),
]
base_domain.extend(domain)
accounts_ids = self.search(cr, uid, base_domain, context=context, order='name asc')
accounts = self.browse(cr, uid, accounts_ids, context=context)
for account in accounts:
if write_pending:
account.write({'state' : 'pending'}, context=context)
remind_user = remind.setdefault(account.manager_id.id, {})
remind_type = remind_user.setdefault(key, {})
remind_partner = remind_type.setdefault(account.partner_id, []).append(account)
# Already expired
fill_remind("old", [('state', 'in', ['pending'])])
# Expires now
fill_remind("new", [('state', 'in', ['draft', 'open']), '|', '&', ('date', '!=', False), ('date', '<=', time.strftime('%Y-%m-%d')), ('is_overdue_quantity', '=', True)], True)
# Expires in less than 30 days
fill_remind("future", [('state', 'in', ['draft', 'open']), ('date', '!=', False), ('date', '<', (datetime.datetime.now() + datetime.timedelta(30)).strftime("%Y-%m-%d"))])
context['base_url'] = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
context['action_id'] = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_analytic_analysis', 'action_account_analytic_overdue_all')[1]
template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_analytic_analysis', 'account_analytic_cron_email_template')[1]
for user_id, data in remind.items():
context["data"] = data
_logger.debug("Sending reminder to uid %s", user_id)
self.pool.get('email.template').send_mail(cr, uid, template_id, user_id, context=context)
return True
class account_analytic_account_summary_user(osv.osv):
_name = "account_analytic_analysis.summary.user"
@ -538,8 +583,6 @@ class account_analytic_account_summary_user(osv.osv):
lu.user_id as "user",
unit_amount
from lu, mu)''')
account_analytic_account_summary_user()
class account_analytic_account_summary_month(osv.osv):
_name = "account_analytic_analysis.summary.month"
@ -600,6 +643,4 @@ class account_analytic_account_summary_month(osv.osv):
'GROUP BY d.month, d.account_id ' \
')')
account_analytic_account_summary_month()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,15 +1,77 @@
<?xml version="1.0" encoding='UTF-8'?>
<openerp>
<data>
<record id="account_analytic_cron_email_template" model="email.template">
<field name="name">Contract expiration reminder</field>
<field name="email_from">${object.email or ''}</field>
<field name="subject">Contract expiration reminder ${user.company_id.name}</field>
<field name="email_to">${object.email}</field>
<field name="lang">${object.lang}</field>
<field name="model_id" ref="base.model_res_users"/>
<field name="auto_delete" eval="True"/>
<field name="body_html"><![CDATA[
Hello ${object.name},
% macro account_table(values):
<table cellspacing="1" border="1" cellpadding="4">
<tr>
<th>Customer</th>
<th>Contract</th>
<th>Dates</th>
<th>Prepaid Units</th>
<th>Contact</th>
</tr>
% for partner, accounts in values:
% for account in accounts:
<tr>
<td>${partner.name}</td>
<td><a href="${ctx["base_url"]}/#action=${ctx["action_id"]}&id=${account.id}&view_type=form">${account.name}</a></td>
<td>${account.date_start} to ${account.date and account.date or '???'}</td>
<td>
% if account.quantity_max != 0.0:
${account.remaining_hours}/${account.quantity_max} units
% endif
</td>
<td>${account.partner_id.phone or ''}, ${account.partner_id.email or ''}</td>
</tr>
% endfor
% endfor
</table>
% endmacro
% if "new" in ctx["data"]:
<h2>The following contracts just expired: </h2>
${account_table(ctx["data"]["new"].iteritems())}
% endif
% if "old" in ctx["data"]:
<h2>The following expired contracts are still not processed: </h2>
${account_table(ctx["data"]["old"].iteritems())}
% endif
% if "future" in ctx["data"]:
<h2>The following contracts will expire in less than one month: </h2>
${account_table(ctx["data"]["future"].iteritems())}
% endif
</pre>
]]></field>
</record>
<!--
-->
<record model="ir.cron" id="account_analytic_cron">
<field name="name">Analytic Account Report for Sales</field>
<field name="name">Contract expiration reminder</field>
<field name="interval_number">1</field>
<field name="interval_type">weeks</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
<field eval="'account.analytic.account'" name="model"/>
<field eval="'cron_account_analytic_account'" name="function"/>
<field eval="'()'" name="args"/>
<field name="doall" eval="False"/>
<field name="model" eval="'account.analytic.account'"/>
<field name="function" eval="'cron_account_analytic_account'"/>
<field name="args" eval="'()'" />
</record>
</data>
</openerp>

View File

@ -1,104 +0,0 @@
<openerp>
<data>
<menuitem id="base.menu_invoiced" name="Invoicing" parent="base.menu_base_partner" sequence="5"/>
<record id="action_hr_tree_invoiced_all" model="ir.actions.act_window">
<field name="name">Time &amp; Materials to Invoice</field>
<field name="res_model">account.analytic.line</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_id','=',False)]</field>
<field name="context">{'search_default_to_invoice': 1, 'search_default_sales': 1}</field>
<field name="search_view_id" ref="account.view_account_analytic_line_filter"/>
<field name="help" type="html">
<p>
You will find here timesheets and purchases you did for
contracts that can be reinvoiced to the customer. If you want
to record new activities to invoice, you should use the timesheet
menu instead.
</p>
</field>
</record>
<menuitem action="action_hr_tree_invoiced_all" id="menu_action_hr_tree_invoiced_all" parent="base.menu_invoiced" sequence="5"/>
<record id="view_account_analytic_account_overdue_search" model="ir.ui.view">
<field name="name">account.analytic.account.search</field>
<field name="model">account.analytic.account</field>
<field name="arch" type="xml">
<search string="Contracts">
<field name="name" filter_domain="['|', ('name','ilike',self),('code','ilike',self)]" string="Contract"/>
<field name="date"/>
<field name="partner_id"/>
<field name="manager_id"/>
<field name="parent_id"/>
<filter name="open" string="Open" domain="[('state','in',('open','draft'))]" help="Contracts in progress"/>
<filter name="pending" string="Pending" domain="[('state','=','pending')]" help="Pending contracts to renew with your customer"/>
<filter string="To Renew" domain="['|', '&amp;', ('date', '!=', False), ('date', '&lt;=', time.strftime('%%Y-%%m-%%d')), ('is_overdue_quantity', '=', True)]" name="renew"
help="The contracts to be renewed because the deadline is passed or the working hours are higher than the allocated hours" />
<separator/>
<filter string="Customer Contracts" help="Contracts assigned to a customer." name="has_partner" domain="[('partner_id', '!=', False)]"/>
<filter string="Contracts not assigned" help="Contracts that are not assigned to an account manager." domain="[('manager_id', '=', False)]"/>
<separator/>
<group expand="0" string="Group By...">
<filter string="Status" domain="[]" context="{'group_by':'state'}"/>
<filter string="Account Manager" domain="[]" context="{'group_by':'manager_id'}"/>
<filter string="Partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Parent" domain="[]" context="{'group_by':'parent_id'}"/>
<filter string="Start Date" domain="[]" context="{'group_by' : 'date_start'}" />
<filter string="End Date" domain="[]" context="{'group_by' : 'date'}" />
</group>
</search>
</field>
</record>
<record id="action_account_analytic_overdue" model="ir.actions.act_window">
<field name="name">Contracts to Renew</field>
<field name="res_model">account.analytic.account</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context">{'search_default_manager_id':uid, 'search_default_pending':1, 'search_default_renew':1}</field>
<field name="domain">[('type','=','contract')]</field>
<field name="search_view_id" ref="view_account_analytic_account_overdue_search"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to define a new contract.
</p><p>
You will find here the contracts to be renewed because the
end date is passed or the working effort is higher than the
maximum authorized one.
</p><p>
OpenERP automatically sets contracts to be renewed in a pending
state. After the negociation, the salesman should close or renew
pending contracts.
</p>
</field>
</record>
<menuitem action="action_account_analytic_overdue" id="menu_action_account_analytic_overdue" sequence="50" parent="base.menu_invoiced"/>
<record id="action_account_analytic_overdue_all" model="ir.actions.act_window">
<field name="name">Contracts</field>
<field name="res_model">account.analytic.account</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context">{'default_type':'contract', 'search_default_open':1, 'search_default_pending':1, 'default_manager_id':uid}</field>
<field name="domain">[('type','=','contract')]</field>
<field name="search_view_id" ref="view_account_analytic_account_overdue_search"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new contract.
</p><p>
Use contracts to follow tasks, issues, timesheets or invoicing based on
work done, expenses and/or sales orders. OpenERP will automatically manage
the alerts for the renewal of the contracts to the right salesperson.
</p>
</field>
</record>
<menuitem id="base.menu_sales" name="Sales"
parent="base.menu_base_partner"
sequence="1"/>
<menuitem action="action_account_analytic_overdue_all" id="menu_action_account_analytic_overdue_all" sequence="7" parent="base.menu_sales"/>
</data>
</openerp>

View File

@ -1,17 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!--
Analytic Account form
-->
<record model="ir.actions.act_window" id="action_sales_order">
<field name="name">Sales Orders</field>
<field name="res_model">sale.order</field>
<field name="src_model">account.analytic.account</field>
</record>
<!-- Inherited Analytic Account form for contracts -->
<record id="account_analytic_account_form_form" model="ir.ui.view">
<field name="name">account.analytic.account.invoice.form.inherit</field>
<field name="model">account.analytic.account</field>
@ -142,19 +138,7 @@
</field>
</record>
<record id="view_account_analytic_account_tree_c2c_3" model="ir.ui.view">
<field name="name">account.analytic.account.tree</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="account.view_account_analytic_account_list"/>
<field name="arch" type="xml">
<field name="date" position="before">
<field name="last_invoice_date"/>
<field name="toinvoice_total"/>
<field name="remaining_hours"/>
</field>
</field>
</record>
<!-- Inherited Analytic Account form for template required -->
<record id="view_account_analytic_account_template_required" model="ir.ui.view">
<field name="name">account.analytic.account.form.template.required</field>
<field name="model">account.analytic.account</field>
@ -167,6 +151,132 @@
</field>
</record>
<!-- Inherited Analytic Account list for contracts -->
<record id="view_account_analytic_account_tree_c2c_3" model="ir.ui.view">
<field name="name">account.analytic.account.list.contract</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="account.view_account_analytic_account_list"/>
<field name="arch" type="xml">
<field name="date" position="before">
<field name="last_invoice_date"/>
<field name="toinvoice_total"/>
<field name="remaining_hours"/>
<field name="pricelist_id" invisible="1"/>
</field>
</field>
</record>
<!-- Analytic Account search view for contract -->
<record id="view_account_analytic_account_overdue_search" model="ir.ui.view">
<field name="name">account.analytic.account.search</field>
<field name="model">account.analytic.account</field>
<field name="arch" type="xml">
<search string="Contracts">
<field name="name" filter_domain="['|', ('name','ilike',self),('code','ilike',self)]" string="Contract"/>
<field name="date"/>
<field name="partner_id"/>
<field name="manager_id"/>
<field name="parent_id"/>
<filter name="open" string="In Progress" domain="[('state','in',('open','draft'))]" help="Contracts in progress (open, draft)"/>
<filter name="pending" string="To Renew" domain="[('state','=','pending')]" help="Pending contracts"/>
<filter name="closed" string="Closed" domain="[('state','=','pending')]" help="Closed contracts"/>
<filter name="cancelled" string="Cancelled" domain="[('state','=','cancel')]" help="Cancelled contracts"/>
<separator/>
<filter
string="Expired or consumed"
domain="[('state','in',('open','draft','pending')), '|', '&amp;', ('date', '!=', False), ('date', '&lt;=', time.strftime('%%Y-%%m-%%d')), ('is_overdue_quantity', '=', True)]"
help="End date passed or prepaid unit consumed" />
<filter
string="Expiring soon"
domain="[('date', '!=', False), ('date', '&lt;=', (context_today() + datetime.timedelta(30)).strftime('%%Y-%%m-%%d') )]"
help="End date is in the next month" />
<separator/>
<filter string="Customer Contracts" help="Contracts assigned to a customer." name="has_partner" domain="[('partner_id', '!=', False)]"/>
<filter string="Contracts not assigned" help="Contracts that are not assigned to an account manager." domain="[('manager_id', '=', False)]"/>
<separator/>
<group expand="0" string="Group By...">
<filter string="Status" domain="[]" context="{'group_by':'state'}"/>
<filter string="Account Manager" domain="[]" context="{'group_by':'manager_id'}"/>
<filter string="Partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Parent" domain="[]" context="{'group_by':'parent_id'}"/>
<filter string="Template" domain="[]" context="{'group_by':'template_id'}"/>
<filter string="Start Date" domain="[]" context="{'group_by' : 'date_start'}" />
<filter string="End Date" domain="[]" context="{'group_by' : 'date'}" />
<filter string="Pricelist" domain="[]" context="{'group_by' : 'pricelist_id'}" />
</group>
</search>
</field>
</record>
<!-- Action Sales/Sales/Contracts -->
<record id="action_account_analytic_overdue_all" model="ir.actions.act_window">
<field name="name">Contracts</field>
<field name="res_model">account.analytic.account</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context">{'default_type':'contract', 'search_default_open':1, 'search_default_pending':1, 'default_manager_id':uid}</field>
<field name="domain">[('type','=','contract')]</field>
<field name="search_view_id" ref="view_account_analytic_account_overdue_search"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new contract.
</p><p>
Use contracts to follow tasks, issues, timesheets or invoicing based on
work done, expenses and/or sales orders. OpenERP will automatically manage
the alerts for the renewal of the contracts to the right salesperson.
</p>
</field>
</record>
<menuitem id="base.menu_sales" name="Sales" parent="base.menu_base_partner" sequence="1"/>
<menuitem action="action_account_analytic_overdue_all" id="menu_action_account_analytic_overdue_all" sequence="7" parent="base.menu_sales"/>
<!-- Action Sales/Invoicing/Time and Material to Invoice -->
<record id="action_hr_tree_invoiced_all" model="ir.actions.act_window">
<field name="name">Time &amp; Materials to Invoice</field>
<field name="res_model">account.analytic.line</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_id','=',False)]</field>
<field name="context">{'search_default_to_invoice': 1, 'search_default_sales': 1}</field>
<field name="search_view_id" ref="account.view_account_analytic_line_filter"/>
<field name="help" type="html">
<p>
You will find here timesheets and purchases you did for
contracts that can be reinvoiced to the customer. If you want
to record new activities to invoice, you should use the timesheet
menu instead.
</p>
</field>
</record>
<menuitem id="base.menu_invoiced" name="Invoicing" parent="base.menu_base_partner" sequence="5"/>
<menuitem action="action_hr_tree_invoiced_all" id="menu_action_hr_tree_invoiced_all" parent="base.menu_invoiced" sequence="5"/>
<!-- Action Sales/Invoicing/Contract to renew -->
<record id="action_account_analytic_overdue" model="ir.actions.act_window">
<field name="name">Contracts to Renew</field>
<field name="res_model">account.analytic.account</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context">{'search_default_manager_id':uid, 'search_default_pending':1, 'search_default_renew':1}</field>
<field name="domain">[('type','=','contract')]</field>
<field name="search_view_id" ref="view_account_analytic_account_overdue_search"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to define a new contract.
</p><p>
You will find here the contracts to be renewed because the
end date is passed or the working effort is higher than the
maximum authorized one.
</p><p>
OpenERP automatically sets contracts to be renewed in a pending
state. After the negociation, the salesman should close or renew
pending contracts.
</p>
</field>
</record>
<menuitem action="action_account_analytic_overdue" id="menu_action_account_analytic_overdue" sequence="50" parent="base.menu_invoiced"/>
<!-- Action Sales/Configuration/Contract template -->
<record id="template_of_contract_action" model="ir.actions.act_window">
<field name="name">Contract Template</field>
<field name="type">ir.actions.act_window</field>
@ -184,8 +294,8 @@
terms and conditions of the contract.
</p>
</field>
</record>
<menuitem action="template_of_contract_action" id="menu_template_of_contract_action" parent="base.menu_base_config"/>
</data>
</openerp>

View File

@ -1,79 +0,0 @@
#!/usr/bin/env python
from mako.template import Template
import time
try:
import cStringIO as StringIO
except ImportError:
import StringIO
from openerp import tools
from openerp.osv import osv
MAKO_TEMPLATE = u"""Hello ${user.name},
Here is a list of contracts that have to be renewed for two
possible reasons:
- the end of contract date is passed
- the customer consumed more hours than expected
Can you contact the customer in order to sell a new or renew its contract.
The contract has been set with a pending state, can you update the status
of the analytic account following this rule:
- Set Done: if the customer does not want to renew
- Set Open: if the customer purchased an extra contract
Here is the list of contracts to renew:
% for partner, accounts in partners.iteritems():
* ${partner.name}
% for account in accounts:
- Name: ${account.name}
% if account.quantity_max != 0.0:
- Quantity: ${account.quantity}/${account.quantity_max} hours
% endif
- Dates: ${account.date_start} to ${account.date and account.date or '???'}
- Contacts:
${account.partner_id.name}, ${account.partner_id.phone or ''}, ${account.partner_id.email or ''}
% endfor
% endfor
You can use the report in the menu: Sales > Invoicing > Overdue Accounts
Regards,
--
OpenERP
"""
class analytic_account(osv.osv):
_inherit = 'account.analytic.account'
def cron_account_analytic_account(self, cr, uid, context=None):
domain = [
('name', 'not ilike', 'maintenance'),
('partner_id', '!=', False),
('user_id', '!=', False),
('user_id.email', '!=', False),
('state', 'in', ('draft', 'open')),
'|', ('date', '<', time.strftime('%Y-%m-%d')), ('date', '=', False),
]
account_ids = self.search(cr, uid, domain, context=context, order='name asc')
accounts = self.browse(cr, uid, account_ids, context=context)
users = dict()
for account in accounts:
users.setdefault(account.user_id, dict()).setdefault(account.partner_id, []).append(account)
account.write({'state' : 'pending'}, context=context)
for user, data in users.iteritems():
subject = '[OPENERP] Reporting: Analytic Accounts'
body = Template(MAKO_TEMPLATE).render_unicode(user=user, partners=data)
tools.email_send('noreply@openerp.com', [user.email, ], subject, body)
return True
analytic_account()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -26,8 +26,6 @@ from openerp import tools
from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp import SUPERUSER_ID
class account_followup_stat_by_partner(osv.osv):
_name = "account_followup.stat.by.partner"
_description = "Follow-up Statistics by Partner"
@ -315,13 +313,6 @@ class account_followup_print(osv.osv_memory):
if stat_line_id not in partner_list:
partner_list.append(stat_line_id)
to_update[str(id)]= {'level': fups[followup_line_id][1], 'partner_id': stat_line_id}
#Remove partners that are other companies in OpenERP
comp_obj = self.pool.get("res.company")
comp_ids = comp_obj.search(cr, SUPERUSER_ID, [], context=context)
for comp in comp_obj.browse(cr, SUPERUSER_ID, comp_ids, context=context):
company_partner_wiz_id = comp.partner_id.id * 10000 + company_id
if company_partner_wiz_id in partner_list:
partner_list.remove(company_partner_wiz_id)
return {'partner_ids': partner_list, 'to_update': to_update}
account_followup_print()

View File

@ -196,7 +196,7 @@ class account_analytic_account(osv.osv):
'date_start': fields.date('Start Date'),
'date': fields.date('Date End', select=True),
'company_id': fields.many2one('res.company', 'Company', required=False), #not required because we want to allow different companies to use the same chart of account, except for leaf accounts.
'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'), ('cancelled', 'Cancelled'),('pending','To Renew'),('close','Closed')], 'Status', required=True, track_visibility='onchange'),
'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'),('pending','To Renew'),('close','Closed'),('cancelled', 'Cancelled')], 'Status', required=True, track_visibility='onchange'),
'currency_id': fields.function(_currency, fnct_inv=_set_company_currency, #the currency_id field is readonly except if it's a view account and if there is no company
store = {
'res.company': (_get_analytic_account, ['currency_id'], 10),
@ -258,6 +258,9 @@ class account_analytic_account(osv.osv):
(check_recursion, 'Error! You cannot create recursive analytic accounts.', ['parent_id']),
]
def name_create(self, cr, uid, name, context=None):
raise osv.except_osv(_('Warning'), _("Quick account creation disallowed."))
def copy(self, cr, uid, id, default=None, context=None):
if not default:
default = {}
@ -349,6 +352,4 @@ class account_analytic_line(osv.osv):
(_check_no_view, 'You cannot create analytic line on view account.', ['account_id']),
]
account_analytic_line()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -41,7 +41,7 @@ class res_users(osv.Model):
state = simplejson.loads(params['state'])
token = state.get('t')
oauth_uid = validation['user_id']
email = validation.get('email', 'provider_%d_user_%d' % (provider, oauth_uid))
email = validation.get('email', 'provider_%s_user_%s' % (provider, oauth_uid))
name = validation.get('name', email)
values = {
'name': name,

View File

@ -21,8 +21,8 @@
<!-- add Reset Password button -->
<xpath expr="//div[@class='oe_right oe_button_box']" position="replace">
<div class="oe_right oe_button_box">
<button string="Reset Password" type="object" name="action_reset_password"
help="Send an email to the user to (re)set their password."/>
<button string="Send reset password instructions by email"
type="object" name="action_reset_password" />
</div>
</xpath>
</field>

View File

@ -587,27 +587,25 @@ class crm_lead(base_stage, format_address, osv.osv):
return True
def _merge_opportunity_attachments(self, cr, uid, opportunity_id, opportunities, context=None):
attachment = self.pool.get('ir.attachment')
attach_obj = self.pool.get('ir.attachment')
# return attachments of opportunity
def _get_attachments(opportunity_id):
attachment_ids = attachment.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', opportunity_id)], context=context)
return attachment.browse(cr, uid, attachment_ids, context=context)
attachment_ids = attach_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', opportunity_id)], context=context)
return attach_obj.browse(cr, uid, attachment_ids, context=context)
count = 1
first_attachments = _get_attachments(opportunity_id)
#counter of all attachments to move. Used to make sure the name is different for all attachments
count = 1
for opportunity in opportunities:
attachments = _get_attachments(opportunity.id)
for first in first_attachments:
for attachment in attachments:
if attachment.name == first.name:
values = dict(
name = "%s (%s)" % (attachment.name, count,),
res_id = opportunity_id,
)
attachment.write(values)
count+=1
for attachment in attachments:
values = {'res_id': opportunity_id,}
for attachment_in_first in first_attachments:
if attachment.name == attachment_in_first.name:
name = "%s (%s)" % (attachment.name, count,),
count+=1
attachment.write(values)
return True
def merge_opportunity(self, cr, uid, ids, context=None):

View File

@ -2,7 +2,6 @@
<openerp>
<data>
<!--
CRM CASE STAGE
-->
@ -110,7 +109,7 @@
string="Phone Calls"/>
</div>
<div class="oe_title">
<label for="name" class="oe_edit_only" string="Lead Description"/>
<label for="name" class="oe_edit_only"/>
<h1><field name="name" placeholder="Describe the lead..."/></h1>
</div>
<group>
@ -217,9 +216,8 @@
<field name="arch" type="xml">
<tree string="Leads" fonts="bold:message_unread==True" colors="grey:state in ('cancel', 'done')">
<field name="date_deadline" invisible="1"/>
<field name="create_date" groups="base.group_no_one"/>
<field name="create_date"/>
<field name="name"/>
<field name="type"/>
<field name="contact_name"/>
<field name="country_id" invisible="context.get('invisible_country', True)"/>
<field name="email_from"/>
@ -390,8 +388,7 @@
<button string="Meeting"
name="action_makeMeeting"
type="object"
context="{'search_default_attendee_id': active_id, 'default_attendee_id' : active_id}"
/>
context="{'search_default_attendee_id': active_id, 'default_attendee_id' : active_id}"/>
</div>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
@ -512,7 +509,7 @@
<field name="arch" type="xml">
<tree string="Opportunities" fonts="bold:message_unread==True" colors="gray:state in ('cancel', 'done');red:date_deadline and (date_deadline &lt; current_date)">
<field name="date_deadline" invisible="1"/>
<field name="create_date" groups="base.group_no_one"/>
<field name="create_date"/>
<field name="name" string="Opportunity"/>
<field name="partner_id" string="Customer"/>
<field name="country_id" invisible="context.get('invisible_country', True)"/>
@ -527,8 +524,8 @@
<field name="user_id"/>
<field name="referred" invisible="1"/>
<field name="priority" invisible="1"/>
<field name="state" groups="base.group_no_one"/>
<field name="message_unread" invisible="1"/>
<field name="state" invisible="1"/>
</tree>
</field>
</record>

View File

@ -45,8 +45,8 @@ class test_message_compose(TestMailBase):
# Mail data
_subject1 = 'Pigs'
_subject2 = 'Bird'
_body_html1 = '<div><p>Fans of Pigs, unite !\n</p><p>Admin</p></div>'
_body_html2 = '<div><p>I am angry !\n</p><p>Admin</p></div>'
_body_html1 = 'Fans of Pigs, unite !'
_body_html2 = 'I am angry !'
_attachments = [
{'name': 'First', 'datas_fname': 'first.txt', 'datas': base64.b64encode('My first attachment')},
{'name': 'Second', 'datas_fname': 'second.txt', 'datas': base64.b64encode('My second attachment')}
@ -113,7 +113,7 @@ class test_message_compose(TestMailBase):
partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])])
# Test: mail.compose.message: subject, body, partner_ids
self.assertEqual(compose.subject, _subject1, 'mail.compose.message subject incorrect')
self.assertEqual(compose.body, _body_html1, 'mail.compose.message body incorrect')
self.assertIn(_body_html1, compose.body, 'mail.compose.message body incorrect')
self.assertEqual(set(message_pids), set(partner_ids), 'mail.compose.message partner_ids incorrect')
# Test: mail.compose.message: attachments
# Test: mail.message: attachments
@ -159,8 +159,8 @@ class test_message_compose(TestMailBase):
# Test: subject, body
self.assertEqual(message_pigs.subject, _subject1, 'mail.message subject on Pigs incorrect')
self.assertEqual(message_bird.subject, _subject2, 'mail.message subject on Bird incorrect')
self.assertEqual(message_pigs.body, _body_html1, 'mail.message body on Pigs incorrect')
self.assertEqual(message_bird.body, _body_html2, 'mail.message body on Bird incorrect')
self.assertIn(_body_html1, message_pigs.body, 'mail.message body on Pigs incorrect')
self.assertIn(_body_html2, message_bird.body, 'mail.message body on Bird incorrect')
# Test: partner_ids: p_a_id (default) + 3 newly created partners
message_pigs_pids = [partner.id for partner in message_pigs.notified_partner_ids]
message_bird_pids = [partner.id for partner in message_bird.notified_partner_ids]

View File

@ -150,8 +150,8 @@ class mail_compose_message(osv.TransientModel):
values = {}
# get values to return
email_dict = super(mail_compose_message, self).render_message(cr, uid, wizard, res_id, context)
email_dict.update(values)
return email_dict
values.update(email_dict)
return values
def render_template(self, cr, uid, template, model, res_id, context=None):
return self.pool.get('email.template').render_template(cr, uid, template, model, res_id, context=context)

View File

@ -49,7 +49,7 @@
</group>
<group string="Actions to Perform on Incoming Mails">
<field name="object_id" on_change="onchange_server_type(type, is_ssl, object_id)"/>
<field name="action_id"/>
<field name="action_id" groups="base.group_no_one"/>
</group>
<group attrs="{'invisible' : [('type', '!=', 'local')]}" string="Configuration">
<field name="configuration" colspan="4"/>

View File

@ -9,7 +9,6 @@
</record>
<record id="hr.employee" model="hr.employee">
<field name="product_id" ref="product.product_product_consultant"/>
<field name="journal_id" ref="analytic_journal"/>
</record>

View File

@ -372,12 +372,25 @@ class lunch_order_line(osv.Model):
cash_ids = [cash.id for cash in order_line.cashmove]
cashmove_ref.unlink(cr, uid, cash_ids, context=context)
return self._update_order_lines(cr, uid, ids, context=context)
def _get_line_order_ids(self, cr, uid, ids, context=None):
"""
return the list of lunch.order.lines ids to which belong the lunch.order 'ids'
"""
result = set()
for lunch_order in self.browse(cr, uid, ids, context=context):
for lines in lunch_order.order_line_ids:
result.add(lines.id)
return list(result)
_columns = {
'name': fields.related('product_id', 'name', readonly=True),
'order_id': fields.many2one('lunch.order', 'Order', ondelete='cascade'),
'product_id': fields.many2one('lunch.product', 'Product', required=True),
'date': fields.related('order_id', 'date', type='date', string="Date", readonly=True, store=True),
'date': fields.related('order_id', 'date', type='date', string="Date", readonly=True, store={
'lunch.order': (_get_line_order_ids, ['date'], 10),
'lunch.order.line': (lambda self, cr, uid, ids, ctx: ids, [], 10),
}),
'supplier': fields.related('product_id', 'supplier', type='many2one', relation='res.partner', string="Supplier", readonly=True, store=True),
'user_id': fields.related('order_id', 'user_id', type='many2one', relation='res.users', string='User', readonly=True, store=True),
'note': fields.text('Note'),

View File

@ -157,7 +157,7 @@ class mail_mail(osv.Model):
:param browse_record partner: specific recipient partner
"""
if force or (not mail.subject and mail.model and mail.res_id):
return '%s posted on %s' % (mail.author_id.name, mail.record_name)
return 'Re: %s' % (mail.record_name)
return mail.subject
def send_get_mail_body(self, cr, uid, mail, partner=None, context=None):

View File

@ -592,7 +592,7 @@ class mail_thread(osv.AbstractModel):
thread_id = False
for model, thread_id, custom_values, user_id in routes:
if self._name != model:
if self._name == 'mail.thread':
context.update({'thread_model': model})
if model:
model_pool = self.pool.get(model)
@ -772,7 +772,7 @@ class mail_thread(osv.AbstractModel):
if author_ids:
msg_dict['author_id'] = author_ids[0]
else:
msg_dict['email_from'] = message.get('from')
msg_dict['email_from'] = decode(message.get('from'))
partner_ids = self._message_find_partners(cr, uid, message, ['To', 'Cc'], context=context)
msg_dict['partner_ids'] = [(4, partner_id) for partner_id in partner_ids]
@ -883,7 +883,12 @@ class mail_thread(osv.AbstractModel):
if isinstance(thread_id, (list, tuple)):
thread_id = thread_id and thread_id[0]
mail_message = self.pool.get('mail.message')
model = context.get('thread_model', self._name) if thread_id else False
# if we're processing a message directly coming from the gateway, the destination model was
# set in the context.
model = False
if thread_id:
model = context.get('thread_model', self._name) if self._name == 'mail.thread' else self._name
attachment_ids = kwargs.pop('attachment_ids', [])
for name, content in attachments:
@ -961,13 +966,12 @@ class mail_thread(osv.AbstractModel):
mail_message_obj = self.pool.get('mail.message')
ir_attachment = self.pool.get('ir.attachment')
# 1.A.1: add recipients of parent message
# 1.A.1: add recipients of parent message (# TDE FIXME HACK: mail.thread -> private message)
partner_ids = set([])
if parent_id:
if parent_id and self._name == 'mail.thread':
parent_message = mail_message_obj.browse(cr, uid, parent_id, context=context)
partner_ids |= set([(4, partner.id) for partner in parent_message.partner_ids])
# TDE FIXME HACK: mail.thread -> private message
if self._name == 'mail.thread' and parent_message.author_id.id:
if parent_message.author_id.id:
partner_ids.add((4, parent_message.author_id.id))
# 1.A.2: add specified recipients

View File

@ -206,21 +206,23 @@ openerp_mail_followers = function(session, mail) {
/** Fetch subtypes, only if current user is follower */
fetch_subtypes: function () {
var self = this;
var subtype_list_ul = this.$('.oe_subtype_list').empty();
if (! this.message_is_follower) return;
var context = new session.web.CompoundContext(this.build_context(), {});
this.ds_model.call('message_get_subscription_data', [[this.view.datarecord.id], context]).then(this.proxy('display_subtypes'));
var id = this.view.datarecord.id;
this.ds_model.call('message_get_subscription_data', [[id], new session.web.CompoundContext(this.build_context(), {})])
.then(function (data) {self.display_subtypes(data, id);});
},
/** Display subtypes: {'name': default, followed} */
display_subtypes:function (data) {
display_subtypes:function (data, id) {
var self = this;
var subtype_list_ul = this.$('.oe_subtype_list');
var records = [];
var nb_subtype = 0;
subtype_list_ul.empty();
if (this.view.datarecord.id) {
records = data[this.view.datarecord.id].message_subtype_data;
if (data[id]) {
records = data[id].message_subtype_data;
}
_(records).each(function (record) {nb_subtype++;});
if (nb_subtype > 1) {

View File

@ -339,7 +339,7 @@ class test_mail(TestMailBase):
# Mail data
_subject = 'Pigs'
_mail_subject = '%s posted on %s' % (user_raoul.name, group_pigs.name)
_mail_subject = 'Re: %s' % (group_pigs.name)
_body1 = '<p>Pigs rules</p>'
_mail_body1 = '<p>Pigs rules</p>\n<div><p>Raoul</p></div>\n'
_mail_bodyalt1 = 'Pigs rules\nRaoul\n'

View File

@ -7,6 +7,7 @@
id="base.marketing_menu"
groups="marketing.group_marketing_user,marketing.group_marketing_manager"
sequence="85"/>
<record id="view_crm_lead_form" model="ir.ui.view">
<field name="name">crm.lead.inherit.form</field>
<field name="model">crm.lead</field>
@ -14,6 +15,7 @@
<field name="arch" type="xml">
<xpath expr="//group[@name='categorization']" position="attributes">
<attribute name="string">Marketing</attribute>
<attribute name="groups"></attribute>
</xpath>
<xpath expr="//field[@name='company_id']" position="after">
<field name="type_id"/>
@ -21,6 +23,7 @@
</xpath>
</field>
</record>
<record id="view_crm_opportunity_form" model="ir.ui.view">
<field name="name">crm.lead.inherit.form</field>
<field name="model">crm.lead</field>

View File

@ -58,7 +58,7 @@
<field name="arch" type="xml">
<form string="Issue" version="7.0">
<header>
<button name="case_close" string="Done" type="object"
<button name="case_close" string="Done" type="object"
states="open" groups="base.group_user"/>
<button name="case_close" string="Done" type="object"
states="draft,pending" groups="base.group_user"/>
@ -129,11 +129,11 @@
<tree string="Issue Tracker Tree" fonts="bold:message_unread==True" colors="black:state=='open';blue:state=='pending';grey:state in ('cancel', 'done')">
<field name="message_unread" invisible="1"/>
<field name="id"/>
<field name="create_date" groups="base.group_no_one"/>
<field name="name"/>
<field name="partner_id"/>
<field name="project_id"/>
<field name="priority" string="Priority" groups="base.group_user"/>
<field name="create_date"/>
<field name="version_id" widget="selection"/>
<field name="user_id"/>
<field name="progress" widget="progressbar" attrs="{'invisible':[('task_id','=',False)]}"/>
@ -157,7 +157,7 @@
<filter string="New" icon="terp-document-new" domain="[('state','=','draft')]" help="New Issues"/>
<filter string="To Do" domain="[('state','=','open')]" help="To Do Issues" icon="terp-check"/>
<separator/>
<filter string="Unassigned Issues" domain="[('user_id','=',False)]" help="Unassigned Issues" icon="terp-personal-" />
<filter string="Unassigned Issues" domain="[('user_id','=',False)]" help="Unassigned Issues" icon="terp-personal-"/>
<field name="user_id"/>
<field name="project_id"/>
<field name="categ_ids"/>

View File

@ -220,7 +220,7 @@ class WebKitParser(report_sxw):
if report_xml.report_file :
path = addons.get_module_resource(*report_xml.report_file.split(os.path.sep))
if os.path.exists(path) :
if path and os.path.exists(path) :
template = file(path).read()
if not template and report_xml.report_webkit_data :
template = report_xml.report_webkit_data

View File

@ -51,9 +51,9 @@ class sale_make_invoice(osv.osv_memory):
if context is None:
context = {}
data = self.read(cr, uid, ids)[0]
order_obj.action_invoice_create(cr, uid, context.get(('active_ids'), []), data['grouped'], date_inv = data['invoice_date'])
order_obj.action_invoice_create(cr, uid, context.get(('active_ids'), []), data['grouped'], date_invoice = data['invoice_date'])
order_obj.signal_manual_invoice(cr, uid, context.get(('active_ids'), []))
for o in order_obj.browse(cr, uid, context.get(('active_ids'), []), context=context):
for i in o.invoice_ids:
newinv.append(i.id)

View File

@ -29,11 +29,14 @@ import openerp.addons.decimal_precision as dp
class stock_return_picking_memory(osv.osv_memory):
_name = "stock.return.picking.memory"
_rec_name = 'product_id'
_columns = {
'product_id' : fields.many2one('product.product', string="Product", required=True),
'quantity' : fields.float("Quantity", digits_compute=dp.get_precision('Product Unit of Measure'), required=True),
'wizard_id' : fields.many2one('stock.return.picking', string="Wizard"),
'move_id' : fields.many2one('stock.move', "Move"),
'prodlot_id': fields.related('move_id', 'prodlot_id', type='many2one', relation='stock.production.lot', string='Serial Number', readonly=True),
}
stock_return_picking_memory()
@ -74,7 +77,7 @@ class stock_return_picking(osv.osv_memory):
for line in pick.move_lines:
qty = line.product_qty - return_history.get(line.id, 0)
if qty > 0:
result1.append({'product_id': line.product_id.id, 'quantity': qty,'move_id':line.id})
result1.append({'product_id': line.product_id.id, 'quantity': qty,'move_id':line.id, 'prodlot_id': line.prodlot_id and line.prodlot_id.id or False})
if 'product_return_moves' in fields:
res.update({'product_return_moves': result1})
return res

View File

@ -32,8 +32,8 @@
<field name="arch" type="xml">
<tree editable="bottom" string="Product Moves">
<field name="product_id" />
<field name="prodlot_id" groups="stock.group_production_lot"/>
<field name="quantity" />
</tree>
</field>
</record>
@ -45,6 +45,7 @@
<form string="Return Picking Memory" version="7.0">
<group col="4">
<field name="product_id" />
<field name="prodlot_id" groups="stock.group_production_lot"/>
<field name="quantity" />
</group>
</form>