[MERGE] trunk-mako_to_jinja-rco: use Jinja2 instead of mako to render email templates (fixes security vulnerability)
bzr revid: rco@openerp.com-20121217102829-zzj1974m9ojdp1zy
This commit is contained in:
@@ -19,7 +19,9 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import osv
|
||||
from urllib import urlencode
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
from edi import EDIMixin
|
||||
|
||||
INVOICE_LINE_EDI_STRUCT = {
|
||||
@@ -258,6 +260,28 @@ class account_invoice(osv.osv, EDIMixin):
|
||||
pass
|
||||
return action
|
||||
|
||||
def _edi_paypal_url(self, cr, uid, ids, field, arg, context=None):
|
||||
res = dict.fromkeys(ids, False)
|
||||
for inv in self.browse(cr, uid, ids, context=context):
|
||||
if inv.type == 'out_invoice' and inv.company_id.paypal_account:
|
||||
params = {
|
||||
"cmd": "_xclick",
|
||||
"business": inv.company_id.paypal_account,
|
||||
"item_name": inv.company_id.name + " Invoice " + inv.number,
|
||||
"invoice": inv.number,
|
||||
"amount": inv.residual,
|
||||
"currency_code": inv.currency_id.name,
|
||||
"button_subtype": "services",
|
||||
"no_note": "1",
|
||||
"bn": "OpenERP_Invoice_PayNow_" + inv.currency_id.name,
|
||||
}
|
||||
res[inv.id] = "https://www.paypal.com/cgi-bin/webscr?" + urlencode(params)
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'paypal_url': fields.function(_edi_paypal_url, type='char', string='Paypal Url'),
|
||||
}
|
||||
|
||||
|
||||
class account_invoice_line(osv.osv, EDIMixin):
|
||||
_inherit='account.invoice.line'
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<record id="email_template_edi_invoice" model="email.template">
|
||||
<field name="name">Invoice - Send by Email</field>
|
||||
<field name="email_from">${object.user_id.email or object.company_id.email or 'noreply@localhost'}</field>
|
||||
<field name="subject">${object.company_id.name} Invoice (Ref ${object.number or 'n/a' })</field>
|
||||
<field name="subject">${object.company_id.name} Invoice (Ref ${object.number or 'n/a'})</field>
|
||||
<field name="email_recipients">${object.partner_id.id}</field>
|
||||
<field name="model_id" ref="account.model_account_invoice"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
@@ -33,7 +33,7 @@
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; ">
|
||||
|
||||
<p>Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},</p>
|
||||
<p>Hello ${object.partner_id.name},</p>
|
||||
|
||||
<p>A new invoice is available for you: </p>
|
||||
|
||||
@@ -50,20 +50,10 @@
|
||||
% endif
|
||||
</p>
|
||||
|
||||
% if object.company_id.paypal_account and object.type in ('out_invoice'):
|
||||
<%
|
||||
comp_name = quote(object.company_id.name)
|
||||
inv_number = quote(object.number)
|
||||
paypal_account = quote(object.company_id.paypal_account)
|
||||
inv_amount = quote(str(object.residual))
|
||||
cur_name = quote(object.currency_id.name)
|
||||
paypal_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=%s&item_name=%s%%20Invoice%%20%s&" \
|
||||
"invoice=%s&amount=%s&currency_code=%s&button_subtype=services&no_note=1&bn=OpenERP_Invoice_PayNow_%s" % \
|
||||
(paypal_account,comp_name,inv_number,inv_number,inv_amount,cur_name,cur_name)
|
||||
%>
|
||||
% if object.paypal_url:
|
||||
<br/>
|
||||
<p>It is also possible to directly pay with Paypal:</p>
|
||||
<a style="margin-left: 120px;" href="${paypal_url}">
|
||||
<a style="margin-left: 120px;" href="${object.paypal_url}">
|
||||
<img class="oe_edi_paypal_button" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
|
||||
</a>
|
||||
% endif
|
||||
|
||||
@@ -113,66 +113,6 @@ class account_move_line(osv.osv):
|
||||
}
|
||||
|
||||
|
||||
|
||||
class email_template(osv.osv):
|
||||
_inherit = 'email.template'
|
||||
|
||||
def _get_followup_table_html(self, cr, uid, res_id, context=None):
|
||||
'''
|
||||
Build the html tables to be included in emails send to partners, when reminding them their
|
||||
overdue invoices.
|
||||
|
||||
:param res_id: ID of the partner for whom we are building the tables
|
||||
:rtype: string
|
||||
'''
|
||||
from report import account_followup_print
|
||||
|
||||
partner = self.pool.get('res.partner').browse(cr, uid, res_id, context=context)
|
||||
followup_table = ''
|
||||
if partner.unreconciled_aml_ids:
|
||||
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
|
||||
current_date = fields.date.context_today(cr, uid, context)
|
||||
rml_parse = account_followup_print.report_rappel(cr, uid, "followup_rml_parser")
|
||||
final_res = rml_parse._lines_get_with_partner(partner, company.id)
|
||||
|
||||
for currency_dict in final_res:
|
||||
currency = currency_dict.get('line', [{'currency_id': company.currency_id}])[0]['currency_id']
|
||||
followup_table += '''
|
||||
<table border="2" width=100%%>
|
||||
<tr>
|
||||
<td>Invoice date</td>
|
||||
<td>Reference</td>
|
||||
<td>Due date</td>
|
||||
<td>Amount (%s)</td>
|
||||
<td>Lit.</td>
|
||||
</tr>
|
||||
''' % (currency.symbol)
|
||||
total = 0
|
||||
for aml in currency_dict['line']:
|
||||
block = aml['blocked'] and 'X' or ' '
|
||||
total += aml['balance']
|
||||
strbegin = "<TD>"
|
||||
strend = "</TD>"
|
||||
date = aml['date_maturity'] or aml['date']
|
||||
if date <= current_date and aml['balance'] > 0:
|
||||
strbegin = "<TD><B>"
|
||||
strend = "</B></TD>"
|
||||
followup_table +="<TR>" + strbegin + str(aml['date']) + strend + strbegin + aml['ref'] + strend + strbegin + str(date) + strend + strbegin + str(aml['balance']) + strend + strbegin + block + strend + "</TR>"
|
||||
total = rml_parse.formatLang(total, dp='Account', currency_obj=currency)
|
||||
followup_table += '''<tr> </tr>
|
||||
</table>
|
||||
<center>Amount due: %s </center>''' % (total)
|
||||
return followup_table
|
||||
|
||||
|
||||
def render_template(self, cr, uid, template, model, res_id, context=None):
|
||||
if model == 'res.partner' and context.get('followup'):
|
||||
context['followup_table'] = self._get_followup_table_html(cr, uid, res_id, context=context)
|
||||
# Adds current_date to the context. That way it can be used to put
|
||||
# the account move lines in bold that are overdue in the email
|
||||
context['current_date'] = fields.date.context_today(cr, uid, context)
|
||||
return super(email_template, self).render_template(cr, uid, template, model, res_id, context=context)
|
||||
|
||||
class res_partner(osv.osv):
|
||||
|
||||
def fields_view_get(self, cr, uid, view_id=None, view_type=None, context=None, toolbar=False, submenu=False):
|
||||
@@ -289,6 +229,52 @@ class res_partner(osv.osv):
|
||||
'payment_next_action': payment_next_action}, context=ctx)
|
||||
return unknown_mails
|
||||
|
||||
def get_followup_table_html(self, cr, uid, ids, context=None):
|
||||
""" Build the html tables to be included in emails send to partners,
|
||||
when reminding them their overdue invoices.
|
||||
:param ids: [id] of the partner for whom we are building the tables
|
||||
:rtype: string
|
||||
"""
|
||||
from report import account_followup_print
|
||||
|
||||
assert len(ids) == 1
|
||||
partner = self.browse(cr, uid, ids[0], context=context)
|
||||
followup_table = ''
|
||||
if partner.unreconciled_aml_ids:
|
||||
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
|
||||
current_date = fields.date.context_today(cr, uid, context)
|
||||
rml_parse = account_followup_print.report_rappel(cr, uid, "followup_rml_parser")
|
||||
final_res = rml_parse._lines_get_with_partner(partner, company.id)
|
||||
|
||||
for currency_dict in final_res:
|
||||
currency = currency_dict.get('line', [{'currency_id': company.currency_id}])[0]['currency_id']
|
||||
followup_table += '''
|
||||
<table border="2" width=100%%>
|
||||
<tr>
|
||||
<td>Invoice date</td>
|
||||
<td>Reference</td>
|
||||
<td>Due date</td>
|
||||
<td>Amount (%s)</td>
|
||||
<td>Lit.</td>
|
||||
</tr>
|
||||
''' % (currency.symbol)
|
||||
total = 0
|
||||
for aml in currency_dict['line']:
|
||||
block = aml['blocked'] and 'X' or ' '
|
||||
total += aml['balance']
|
||||
strbegin = "<TD>"
|
||||
strend = "</TD>"
|
||||
date = aml['date_maturity'] or aml['date']
|
||||
if date <= current_date and aml['balance'] > 0:
|
||||
strbegin = "<TD><B>"
|
||||
strend = "</B></TD>"
|
||||
followup_table +="<TR>" + strbegin + str(aml['date']) + strend + strbegin + aml['ref'] + strend + strbegin + str(date) + strend + strbegin + str(aml['balance']) + strend + strbegin + block + strend + "</TR>"
|
||||
total = rml_parse.formatLang(total, dp='Account', currency_obj=currency)
|
||||
followup_table += '''<tr> </tr>
|
||||
</table>
|
||||
<center>Amount due: %s </center>''' % (total)
|
||||
return followup_table
|
||||
|
||||
def action_done(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'payment_next_action_date': False, 'payment_next_action':'', 'payment_responsible_id': False}, context=context)
|
||||
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
<!-- Mail template is done in a NOUPDATE block
|
||||
so users can freely customize/delete them -->
|
||||
<data noupdate="1">
|
||||
<!--Mail template level 0-->
|
||||
<record id="email_template_account_followup_level0" model="email.template">
|
||||
<!--Mail template level 0-->
|
||||
<record id="email_template_account_followup_level0" model="email.template">
|
||||
<field name="name">First polite payment follow-up reminder email</field>
|
||||
<field name="email_from">${user.email or '' | h}</field>
|
||||
<field name="subject">${user.company_id.name | h} Payment Reminder</field>
|
||||
<field name="email_to">${object.email | h}</field>
|
||||
<field name="lang">${object.lang | h}</field>
|
||||
<field name="email_from">${user.email or ''}</field>
|
||||
<field name="subject">${user.company_id.name} Payment Reminder</field>
|
||||
<field name="email_to">${object.email}</field>
|
||||
<field name="lang">${object.lang}</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
|
||||
|
||||
<p>Dear ${object.name | h},</p>
|
||||
<p>Dear ${object.name},</p>
|
||||
<p>
|
||||
Exception made if there was a mistake of ours, it seems that the following amount stays unpaid. Please, take
|
||||
appropriate measures in order to carry out this payment in the next 8 days.
|
||||
@@ -28,13 +28,13 @@ contact our accounting department.
|
||||
Best Regards,
|
||||
<br/>
|
||||
<br/>
|
||||
${user.name | h}
|
||||
${user.name}
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
${ctx.get('followup_table','')}
|
||||
${object.get_followup_table_html() | safe}
|
||||
|
||||
<br/>
|
||||
|
||||
@@ -42,23 +42,21 @@ ${ctx.get('followup_table','')}
|
||||
]]></field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<!--Mail template level 1 -->
|
||||
<record id="email_template_account_followup_level1" model="email.template">
|
||||
<!--Mail template level 1 -->
|
||||
<record id="email_template_account_followup_level1" model="email.template">
|
||||
<field name="name">A bit urging second payment follow-up reminder email</field>
|
||||
<field name="email_from">${user.email or '' | h}</field>
|
||||
<field name="subject">${user.company_id.name | h} Payment Reminder</field>
|
||||
<field name="email_to">${object.email | h}</field>
|
||||
<field name="lang">${object.lang | h}</field>
|
||||
<field name="email_from">${user.email or ''}</field>
|
||||
<field name="subject">${user.company_id.name} Payment Reminder</field>
|
||||
<field name="email_to">${object.email}</field>
|
||||
<field name="lang">${object.lang}</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
|
||||
|
||||
<p>Dear ${object.name | h},</p>
|
||||
<p>Dear ${object.name},</p>
|
||||
<p>
|
||||
We are disappointed to see that despite sending a reminder, that your account is now seriously overdue.
|
||||
We are disappointed to see that despite sending a reminder, that your account is now seriously overdue.
|
||||
It is essential that immediate payment is made, otherwise we will have to consider placing a stop on your account
|
||||
which means that we will no longer be able to supply your company with (goods/services).
|
||||
Please, take appropriate measures in order to carry out this payment in the next 8 days.
|
||||
@@ -71,31 +69,32 @@ Best Regards,
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
${user.name | h}
|
||||
${user.name}
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
${ctx.get('followup_table','')}
|
||||
${object.get_followup_table_html() | safe}
|
||||
|
||||
<br/>
|
||||
|
||||
</div>
|
||||
]]></field>
|
||||
</record>
|
||||
<!--Email template -->
|
||||
|
||||
<!--Mail template level 2 -->
|
||||
<record id="email_template_account_followup_level2" model="email.template">
|
||||
<field name="name">Urging payment follow-up reminder email</field>
|
||||
<field name="email_from">${user.email or '' | h}</field>
|
||||
<field name="subject">${user.company_id.name | h} Payment Reminder</field>
|
||||
<field name="email_to">${object.email | h}</field>
|
||||
<field name="lang">${object.lang | h}</field>
|
||||
<field name="email_from">${user.email or ''}</field>
|
||||
<field name="subject">${user.company_id.name} Payment Reminder</field>
|
||||
<field name="email_to">${object.email}</field>
|
||||
<field name="lang">${object.lang}</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
|
||||
|
||||
<p>Dear ${object.name | h},</p>
|
||||
<p>Dear ${object.name},</p>
|
||||
<p>
|
||||
Despite several reminders, your account is still not settled.
|
||||
Unless full payment is made in next 8 days, legal action for the recovery of the debt will be taken without
|
||||
@@ -107,12 +106,12 @@ In case of any queries concerning this matter, do not hesitate to contact our ac
|
||||
Best Regards,
|
||||
<br/>
|
||||
<br/>
|
||||
${user.name | h}
|
||||
${user.name}
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
${ctx.get('followup_table','')}
|
||||
${object.get_followup_table_html() | safe}
|
||||
|
||||
<br/>
|
||||
|
||||
@@ -121,19 +120,18 @@ ${ctx.get('followup_table','')}
|
||||
</record>
|
||||
|
||||
<!-- Default follow up message -->
|
||||
|
||||
<record id="email_template_account_followup_default" model="email.template">
|
||||
<record id="email_template_account_followup_default" model="email.template">
|
||||
<field name="name">Default payment follow-up reminder e-mail</field>
|
||||
<field name="email_from">${user.email or '' | h}</field>
|
||||
<field name="subject">${user.company_id.name | h} Payment Reminder</field>
|
||||
<field name="email_to">${object.email | h}</field>
|
||||
<field name="lang">${object.lang | h}</field>
|
||||
<field name="email_from">${user.email or ''}</field>
|
||||
<field name="subject">${user.company_id.name} Payment Reminder</field>
|
||||
<field name="email_to">${object.email}</field>
|
||||
<field name="lang">${object.lang}</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
|
||||
|
||||
<p>Dear ${object.name | h},</p>
|
||||
<p>Dear ${object.name},</p>
|
||||
<p>
|
||||
Exception made if there was a mistake of ours, it seems that the following amount stays unpaid. Please, take
|
||||
appropriate measures in order to carry out this payment in the next 8 days.
|
||||
@@ -144,11 +142,11 @@ contact our accounting department.
|
||||
Best Regards,
|
||||
<br/>
|
||||
<br/>
|
||||
${user.name | h}
|
||||
${user.name}
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
${ctx.get('followup_table','')}
|
||||
${object.get_followup_table_html() | safe}
|
||||
|
||||
<br/>
|
||||
</div>
|
||||
@@ -174,7 +172,7 @@ Would your payment have been carried out after this mail was sent, please ignore
|
||||
|
||||
Best Regards,
|
||||
</field>
|
||||
<field name="email_template_id" ref="email_template_account_followup_level0"/>
|
||||
<field name="email_template_id" ref="email_template_account_followup_level0"/>
|
||||
</record>
|
||||
|
||||
<record id="demo_followup_line2" model="account_followup.followup.line">
|
||||
@@ -198,8 +196,9 @@ If there is a problem with paying invoice that we are not aware of, do not hesit
|
||||
Details of due payments is printed below.
|
||||
|
||||
Best Regards,
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="demo_followup_line3" model="account_followup.followup.line">
|
||||
<field name="name">Call the customer on the phone</field>
|
||||
<field name="sequence">3</field>
|
||||
@@ -221,7 +220,7 @@ I trust that this action will prove unnecessary and details of due payments is p
|
||||
In case of any queries concerning this matter, do not hesitate to contact our accounting department.
|
||||
|
||||
Best Regards,
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
import pooler
|
||||
from report import report_sxw
|
||||
@@ -50,36 +51,30 @@ class report_rappel(report_sxw.rml_parse):
|
||||
def _lines_get_with_partner(self, partner, company_id):
|
||||
pool = pooler.get_pool(self.cr.dbname)
|
||||
moveline_obj = pool.get('account.move.line')
|
||||
company_obj = pool.get('res.company')
|
||||
obj_currency = pool.get('res.currency')
|
||||
movelines = moveline_obj.search(self.cr, self.uid,
|
||||
[('partner_id', '=', partner.id),
|
||||
('account_id.type', '=', 'receivable'),
|
||||
('reconcile_id', '=', False), ('state', '<>', 'draft'),('company_id','=', company_id)])
|
||||
movelines = moveline_obj.browse(self.cr, self.uid, movelines)
|
||||
base_currency = movelines[0].company_id.currency_id
|
||||
final_res = []
|
||||
line_cur = {base_currency.id: {'line': []}}
|
||||
moveline_ids = moveline_obj.search(self.cr, self.uid, [
|
||||
('partner_id', '=', partner.id),
|
||||
('account_id.type', '=', 'receivable'),
|
||||
('reconcile_id', '=', False),
|
||||
('state', '!=', 'draft'),
|
||||
('company_id', '=', company_id),
|
||||
])
|
||||
|
||||
for line in movelines:
|
||||
if line.currency_id and (not line.currency_id.id in line_cur):
|
||||
line_cur[line.currency_id.id] = {'line': []}
|
||||
# lines_per_currency = {currency: [line data, ...], ...}
|
||||
lines_per_currency = defaultdict(list)
|
||||
for line in moveline_obj.browse(self.cr, self.uid, moveline_ids):
|
||||
currency = line.currency_id or line.company_id.currency_id
|
||||
line_data = {
|
||||
'name': line.move_id.name,
|
||||
'ref': line.ref,
|
||||
'date':line.date,
|
||||
'date_maturity': line.date_maturity,
|
||||
'balance': currency.id <> line.company_id.currency_id.id and line.amount_currency or (line.debit - line.credit),
|
||||
'blocked': line.blocked,
|
||||
'currency_id': currency,
|
||||
}
|
||||
line_cur[currency.id]['line'].append(line_data)
|
||||
'name': line.move_id.name,
|
||||
'ref': line.ref,
|
||||
'date': line.date,
|
||||
'date_maturity': line.date_maturity,
|
||||
'balance': line.amount_currency if currency != line.company_id.currency_id else line.debit - line.credit,
|
||||
'blocked': line.blocked,
|
||||
'currency_id': currency,
|
||||
}
|
||||
lines_per_currency[currency].append(line_data)
|
||||
|
||||
for cur in line_cur:
|
||||
if line_cur[cur]['line']:
|
||||
final_res.append({'line': line_cur[cur]['line']})
|
||||
return final_res
|
||||
return [{'line': lines} for lines in lines_per_currency.values()]
|
||||
|
||||
def _get_text(self, stat_line, followup_id, context=None):
|
||||
if context is None:
|
||||
|
||||
@@ -28,13 +28,38 @@ from osv import osv
|
||||
from osv import fields
|
||||
import tools
|
||||
from tools.translate import _
|
||||
from urllib import quote as quote
|
||||
from urllib import quote, urlencode
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
from mako.template import Template as MakoTemplate
|
||||
# We use a jinja2 sandboxed environment to render mako templates.
|
||||
# Note that the rendering does not cover all the mako syntax, in particular
|
||||
# arbitrary Python statements are not accepted, and not all expressions are
|
||||
# allowed: only "public" attributes (not starting with '_') of objects may
|
||||
# be accessed.
|
||||
# This is done on purpose: it prevents incidental or malicious execution of
|
||||
# Python code that may break the security of the server.
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
mako_template_env = SandboxedEnvironment(
|
||||
block_start_string="<%",
|
||||
block_end_string="%>",
|
||||
variable_start_string="${",
|
||||
variable_end_string="}",
|
||||
comment_start_string="<%doc>",
|
||||
comment_end_string="</%doc>",
|
||||
line_statement_prefix="%",
|
||||
line_comment_prefix="##",
|
||||
trim_blocks=True, # do not output newline after blocks
|
||||
autoescape=True, # XML/HTML automatic escaping
|
||||
)
|
||||
mako_template_env.globals.update({
|
||||
'str': str,
|
||||
'quote': quote,
|
||||
'urlencode': urlencode,
|
||||
})
|
||||
except ImportError:
|
||||
_logger.warning("email_template: mako templates not available, templating features will not work!")
|
||||
_logger.warning("jinja2 not available, templating features will not work!")
|
||||
|
||||
class email_template(osv.osv):
|
||||
"Templates for sending email"
|
||||
@@ -55,7 +80,8 @@ class email_template(osv.osv):
|
||||
:param str model: model name of the document record this mail is related to.
|
||||
:param int res_id: id of the document record this mail is related to.
|
||||
"""
|
||||
if not template: return u""
|
||||
if not template:
|
||||
return u""
|
||||
if context is None:
|
||||
context = {}
|
||||
try:
|
||||
@@ -64,14 +90,14 @@ class email_template(osv.osv):
|
||||
if res_id:
|
||||
record = self.pool.get(model).browse(cr, uid, res_id, context=context)
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
result = MakoTemplate(template).render_unicode(object=record,
|
||||
user=user,
|
||||
# context kw would clash with mako internals
|
||||
ctx=context,
|
||||
quote=quote,
|
||||
format_exceptions=True)
|
||||
if result == u'False':
|
||||
result = u''
|
||||
variables = {
|
||||
'object': record,
|
||||
'user': user,
|
||||
'ctx': context, # context kw would clash with mako internals
|
||||
}
|
||||
result = mako_template_env.from_string(template).render(variables)
|
||||
if result == u"False":
|
||||
result = u""
|
||||
return result
|
||||
except Exception:
|
||||
_logger.exception("failed to render mako template value %r", template)
|
||||
|
||||
@@ -19,7 +19,5 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import account_invoice
|
||||
import sale
|
||||
import portal_sale
|
||||
import res_config
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2011 OpenERP S.A (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields,osv
|
||||
|
||||
class account_invoice(osv.osv):
|
||||
_inherit = 'account.invoice'
|
||||
|
||||
def invoice_validate(self, cr, uid, ids, context=None):
|
||||
# fetch the partner's id and subscribe the partner to the sale order
|
||||
partner = self.browse(cr, uid, ids[0], context=context)['partner_id']
|
||||
if partner.id not in self.browse(cr, uid, ids[0], context=context)['message_follower_ids']:
|
||||
self.message_subscribe(cr, uid, ids, [partner.id], context=context)
|
||||
document = self.browse(cr, uid, ids[0], context=context)
|
||||
mail_values = {
|
||||
'email_from': self.pool.get('res.users').browse(cr, uid, uid, context=context)['partner_id']['email'],
|
||||
'email_to': partner.email,
|
||||
'subject': 'Invitation to follow %s' % document.name_get()[0][1],
|
||||
'body_html': 'You have been invited to follow %s' % document.name_get()[0][1],
|
||||
'auto_delete': True,
|
||||
}
|
||||
mail_obj = self.pool.get('mail.mail')
|
||||
mail_id = mail_obj.create(cr, uid, mail_values, context=context)
|
||||
mail_obj.send(cr, uid, [mail_id], recipient_ids=[partner.id], context=context)
|
||||
return super(account_invoice, self).invoice_validate(cr, uid, ids, context=context)
|
||||
@@ -21,11 +21,12 @@
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
|
||||
|
||||
class sale_order(osv.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
# make the real method inheritable
|
||||
_payment_block_proxy = lambda self,*a,**kw: self._portal_payment_block(*a, **kw)
|
||||
_payment_block_proxy = lambda self, *a, **kw: self._portal_payment_block(*a, **kw)
|
||||
|
||||
_columns = {
|
||||
'portal_payment_options': fields.function(_payment_block_proxy, type="html", string="Portal Payment Options"),
|
||||
@@ -35,14 +36,14 @@ class sale_order(osv.Model):
|
||||
result = dict.fromkeys(ids, False)
|
||||
payment_acquirer = self.pool.get('portal.payment.acquirer')
|
||||
for this in self.browse(cr, uid, ids, context=context):
|
||||
if this.state not in ('draft','cancel') and not this.invoiced:
|
||||
if this.state not in ('draft', 'cancel') and not this.invoiced:
|
||||
result[this.id] = payment_acquirer.render_payment_block(cr, uid, this, this.name,
|
||||
this.pricelist_id.currency_id, this.amount_total, context=context)
|
||||
return result
|
||||
|
||||
def action_quotation_send(self, cr, uid, ids, context=None):
|
||||
''' Override to use a modified template that includes a portal signup link '''
|
||||
action_dict = super(sale_order, self).action_quotation_send(cr, uid, ids, context=context)
|
||||
action_dict = super(sale_order, self).action_quotation_send(cr, uid, ids, context=context)
|
||||
try:
|
||||
template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'portal_sale', 'email_template_edi_sale')[1]
|
||||
# assume context is still a dict, as prepared by super
|
||||
@@ -53,11 +54,40 @@ class sale_order(osv.Model):
|
||||
pass
|
||||
return action_dict
|
||||
|
||||
def action_button_confirm(self, cr, uid, ids, context=None):
|
||||
# fetch the partner's id and subscribe the partner to the sale order
|
||||
assert len(ids) == 1
|
||||
document = self.browse(cr, uid, ids[0], context=context)
|
||||
partner = document.partner_id
|
||||
if partner.id not in document.message_follower_ids:
|
||||
self.message_subscribe(cr, uid, ids, [partner.id], context=context)
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
mail_values = {
|
||||
'email_from': user.partner_id.email,
|
||||
'email_to': partner.email,
|
||||
'subject': 'Invitation to follow %s' % document.name_get()[0][1],
|
||||
'body_html': 'You have been invited to follow %s' % document.name_get()[0][1],
|
||||
'auto_delete': True,
|
||||
}
|
||||
mail_obj = self.pool.get('mail.mail')
|
||||
mail_id = mail_obj.create(cr, uid, mail_values, context=context)
|
||||
mail_obj.send(cr, uid, [mail_id], recipient_ids=[partner.id], context=context)
|
||||
return super(sale_order, self).action_button_confirm(cr, uid, ids, context=context)
|
||||
|
||||
def get_signup_url(self, cr, uid, ids, context=None):
|
||||
assert len(ids) == 1
|
||||
document = self.browse(cr, uid, ids[0], context=context)
|
||||
partner = document.partner_id
|
||||
action = 'portal_sale.action_quotations_portal' if document.state in ('draft', 'sent') else 'portal_sale.action_orders_portal'
|
||||
partner.signup_prepare()
|
||||
return partner._get_signup_url_for_action(action=action, view_type='form', res_id=document.id)[partner.id]
|
||||
|
||||
|
||||
class account_invoice(osv.Model):
|
||||
_inherit = 'account.invoice'
|
||||
|
||||
# make the real method inheritable
|
||||
_payment_block_proxy = lambda self,*a,**kw: self._portal_payment_block(*a, **kw)
|
||||
_payment_block_proxy = lambda self, *a, **kw: self._portal_payment_block(*a, **kw)
|
||||
|
||||
_columns = {
|
||||
'portal_payment_options': fields.function(_payment_block_proxy, type="html", string="Portal Payment Options"),
|
||||
@@ -67,14 +97,14 @@ class account_invoice(osv.Model):
|
||||
result = dict.fromkeys(ids, False)
|
||||
payment_acquirer = self.pool.get('portal.payment.acquirer')
|
||||
for this in self.browse(cr, uid, ids, context=context):
|
||||
if this.type == 'out_invoice' and this.state not in ('draft','done') and not this.reconciled:
|
||||
if this.type == 'out_invoice' and this.state not in ('draft', 'done') and not this.reconciled:
|
||||
result[this.id] = payment_acquirer.render_payment_block(cr, uid, this, this.number,
|
||||
this.currency_id, this.residual, context=context)
|
||||
return result
|
||||
|
||||
def action_invoice_sent(self, cr, uid, ids, context=None):
|
||||
''' Override to use a modified template that includes a portal signup link '''
|
||||
action_dict = super(account_invoice, self).action_invoice_sent(cr, uid, ids, context=context)
|
||||
action_dict = super(account_invoice, self).action_invoice_sent(cr, uid, ids, context=context)
|
||||
try:
|
||||
template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'portal_sale', 'email_template_edi_invoice')[1]
|
||||
# assume context is still a dict, as prepared by super
|
||||
@@ -84,3 +114,48 @@ class account_invoice(osv.Model):
|
||||
except Exception:
|
||||
pass
|
||||
return action_dict
|
||||
|
||||
def invoice_validate(self, cr, uid, ids, context=None):
|
||||
# fetch the partner's id and subscribe the partner to the invoice
|
||||
document = self.browse(cr, uid, ids[0], context=context)
|
||||
partner = document.partner_id
|
||||
if partner.id not in document.message_follower_ids:
|
||||
self.message_subscribe(cr, uid, ids, [partner.id], context=context)
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
mail_values = {
|
||||
'email_from': user.partner_id.email,
|
||||
'email_to': partner.email,
|
||||
'subject': 'Invitation to follow %s' % document.name_get()[0][1],
|
||||
'body_html': 'You have been invited to follow %s' % document.name_get()[0][1],
|
||||
'auto_delete': True,
|
||||
}
|
||||
mail_obj = self.pool.get('mail.mail')
|
||||
mail_id = mail_obj.create(cr, uid, mail_values, context=context)
|
||||
mail_obj.send(cr, uid, [mail_id], recipient_ids=[partner.id], context=context)
|
||||
return super(account_invoice, self).invoice_validate(cr, uid, ids, context=context)
|
||||
|
||||
def get_signup_url(self, cr, uid, ids, context=None):
|
||||
assert len(ids) == 1
|
||||
document = self.browse(cr, uid, ids[0], context=context)
|
||||
partner = document.partner_id
|
||||
action = 'portal_sale.portal_action_invoices'
|
||||
partner.signup_prepare()
|
||||
return partner._get_signup_url_for_action(action=action, view_type='form', res_id=document.id)[partner.id]
|
||||
|
||||
|
||||
class mail_mail(osv.osv):
|
||||
_inherit = 'mail.mail'
|
||||
|
||||
def _postprocess_sent_message(self, cr, uid, mail, context=None):
|
||||
if mail.model == 'sale.order':
|
||||
so_obj = self.pool.get('sale.order')
|
||||
order = so_obj.browse(cr, uid, mail.res_id, context=context)
|
||||
partner = order.partner_id
|
||||
# Add the customer in the SO as follower
|
||||
if partner.id not in order.message_follower_ids:
|
||||
so_obj.message_subscribe(cr, uid, [mail.res_id], [partner.id], context=context)
|
||||
# Add all recipients of the email as followers
|
||||
for p in mail.partner_ids:
|
||||
if p.id not in order.message_follower_ids:
|
||||
so_obj.message_subscribe(cr, uid, [mail.res_id], [p.id], context=context)
|
||||
return super(mail_mail, self)._postprocess_sent_message(cr, uid, mail=mail, context=context)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
|
||||
|
||||
<p>Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},</p>
|
||||
<p>Hello ${object.partner_id.name},</p>
|
||||
|
||||
<p>Here is your ${object.state in ('draft', 'sent') and 'quotation' or 'order confirmation'} from ${object.company_id.name}: </p>
|
||||
|
||||
@@ -36,11 +36,7 @@
|
||||
% endif
|
||||
</p>
|
||||
|
||||
<%
|
||||
action = 'portal_sale.action_quotations_portal' if object.state in ('draft', 'sent') else 'portal_sale.action_orders_portal'
|
||||
object.partner_id.signup_prepare()
|
||||
signup_url = object.partner_id._get_signup_url_for_action(action=action,view_type='form',res_id=object.id)[object.partner_id.id]
|
||||
%>
|
||||
<% set signup_url = object.get_signup_url() %>
|
||||
% if signup_url:
|
||||
<p>
|
||||
You can access this document and pay online via our Customer Portal:
|
||||
@@ -49,21 +45,10 @@
|
||||
href="${signup_url}">View ${object.state in ('draft', 'sent') and 'Quotation' or 'Order'}</a>
|
||||
% endif
|
||||
|
||||
% if object.order_policy in ('prepaid','manual') and object.company_id.paypal_account and object.state != 'draft':
|
||||
<%
|
||||
comp_name = quote(object.company_id.name)
|
||||
order_name = quote(object.name)
|
||||
paypal_account = quote(object.company_id.paypal_account)
|
||||
order_amount = quote(str(object.residual))
|
||||
cur_name = quote(object.pricelist_id.currency_id.name)
|
||||
paypal_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=%s&item_name=%s%%20Order%%20%s" \
|
||||
"&invoice=%s&amount=%s&currency_code=%s&button_subtype=services&no_note=1" \
|
||||
"&bn=OpenERP_Order_PayNow_%s" % \
|
||||
(paypal_account,comp_name,order_name,order_name,order_amount,cur_name,cur_name)
|
||||
%>
|
||||
% if object.paypal_url:
|
||||
<br/>
|
||||
<p>It is also possible to directly pay with Paypal:</p>
|
||||
<a style="margin-left: 120px;" href="${paypal_url}">
|
||||
<a style="margin-left: 120px;" href="${object.paypal_url}">
|
||||
<img class="oe_edi_paypal_button" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
|
||||
</a>
|
||||
% endif
|
||||
@@ -101,7 +86,7 @@
|
||||
<div>
|
||||
Web : <a href="${object.company_id.website}">${object.company_id.website}</a>
|
||||
</div>
|
||||
%endif
|
||||
% endif
|
||||
<p></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -120,7 +105,7 @@
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
|
||||
|
||||
<p>Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},</p>
|
||||
<p>Hello ${object.partner_id.name},</p>
|
||||
|
||||
<p>A new invoice is available for you: </p>
|
||||
|
||||
@@ -137,11 +122,7 @@
|
||||
% endif
|
||||
</p>
|
||||
|
||||
<%
|
||||
action = 'portal_sale.portal_action_invoices'
|
||||
object.partner_id.signup_prepare()
|
||||
signup_url = object.partner_id._get_signup_url_for_action(action=action,view_type='form',res_id=object.id)[object.partner_id.id]
|
||||
%>
|
||||
<% set signup_url = object.get_signup_url() %>
|
||||
% if signup_url:
|
||||
<p>
|
||||
You can access the invoice document and pay online via our Customer Portal:
|
||||
@@ -150,20 +131,10 @@
|
||||
href="${signup_url}">View Invoice</a>
|
||||
% endif
|
||||
|
||||
% if object.company_id.paypal_account and object.type in ('out_invoice'):
|
||||
<%
|
||||
comp_name = quote(object.company_id.name)
|
||||
inv_number = quote(object.number)
|
||||
paypal_account = quote(object.company_id.paypal_account)
|
||||
inv_amount = quote(str(object.residual))
|
||||
cur_name = quote(object.currency_id.name)
|
||||
paypal_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=%s&item_name=%s%%20Invoice%%20%s&" \
|
||||
"invoice=%s&amount=%s&currency_code=%s&button_subtype=services&no_note=1&bn=OpenERP_Invoice_PayNow_%s" % \
|
||||
(paypal_account,comp_name,inv_number,inv_number,inv_amount,cur_name,cur_name)
|
||||
%>
|
||||
% if object.paypal_url:
|
||||
<br/>
|
||||
<p>It is also possible to directly pay with Paypal:</p>
|
||||
<a style="margin-left: 120px;" href="${paypal_url}">
|
||||
<a style="margin-left: 120px;" href="${object.paypal_url}">
|
||||
<img class="oe_edi_paypal_button" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
|
||||
</a>
|
||||
% endif
|
||||
@@ -201,7 +172,7 @@
|
||||
<div>
|
||||
Web : <a href="${object.company_id.website}">${object.company_id.website}</a>
|
||||
</div>
|
||||
%endif
|
||||
% endif
|
||||
<p></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields, osv
|
||||
|
||||
class sale_order(osv.osv):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
def action_button_confirm(self, cr, uid, ids, context=None):
|
||||
# fetch the partner's id and subscribe the partner to the sale order
|
||||
partner = self.browse(cr, uid, ids[0], context=context)['partner_id']
|
||||
if partner.id not in self.browse(cr, uid, ids[0], context=context)['message_follower_ids']:
|
||||
self.message_subscribe(cr, uid, ids, [partner.id], context=context)
|
||||
document = self.browse(cr, uid, ids[0], context=context)
|
||||
mail_values = {
|
||||
'email_from': self.pool.get('res.users').browse(cr, uid, uid, context=context)['partner_id']['email'],
|
||||
'email_to': partner.email,
|
||||
'subject': 'Invitation to follow %s' % document.name_get()[0][1],
|
||||
'body_html': 'You have been invited to follow %s' % document.name_get()[0][1],
|
||||
'auto_delete': True,
|
||||
}
|
||||
mail_obj = self.pool.get('mail.mail')
|
||||
mail_id = mail_obj.create(cr, uid, mail_values, context=context)
|
||||
mail_obj.send(cr, uid, [mail_id], recipient_ids=[partner.id], context=context)
|
||||
return super(sale_order, self).action_button_confirm(cr, uid, ids, context=context)
|
||||
|
||||
sale_order()
|
||||
|
||||
class mail_mail(osv.osv):
|
||||
_inherit = 'mail.mail'
|
||||
|
||||
def _postprocess_sent_message(self, cr, uid, mail, context=None):
|
||||
if mail.model == 'sale.order':
|
||||
so_obj = self.pool.get('sale.order')
|
||||
partner = so_obj.browse(cr, uid, mail.res_id, context=context)['partner_id']
|
||||
# Add the customer in the SO as follower
|
||||
if partner.id not in so_obj.browse(cr, uid, mail.res_id, context=context)['message_follower_ids']:
|
||||
so_obj.message_subscribe(cr, uid, [mail.res_id], [partner.id], context=context)
|
||||
# Add all recipients of the email as followers
|
||||
for p in mail.partner_ids:
|
||||
if p.id not in so_obj.browse(cr, uid, mail.res_id, context=context)['message_follower_ids']:
|
||||
so_obj.message_subscribe(cr, uid, [mail.res_id], [p.id], context=context)
|
||||
return super(mail_mail, self)._postprocess_sent_message(cr, uid, mail=mail, context=context)
|
||||
|
||||
mail_mail()
|
||||
@@ -30,7 +30,7 @@
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; ">
|
||||
|
||||
<p>Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},</p>
|
||||
<p>Hello$ ${object.partner_id.name},</p>
|
||||
|
||||
<p>Here is a ${object.state in ('draft', 'sent') and 'request for quotation' or 'purchase order confirmation'} from ${object.company_id.name}: </p>
|
||||
|
||||
|
||||
@@ -19,7 +19,10 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import osv
|
||||
from urllib import urlencode
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.tools.translate import _
|
||||
from edi import EDIMixin
|
||||
|
||||
SALE_ORDER_LINE_EDI_STRUCT = {
|
||||
@@ -118,7 +121,6 @@ class sale_order(osv.osv, EDIMixin):
|
||||
edi_document.pop('partner_address', None) # ignored, that's supposed to be our own address!
|
||||
return partner_id
|
||||
|
||||
|
||||
def _edi_get_pricelist(self, cr, uid, partner_id, currency, context=None):
|
||||
# TODO: refactor into common place for purchase/sale, e.g. into product module
|
||||
partner_model = self.pool.get('res.partner')
|
||||
@@ -180,6 +182,30 @@ class sale_order(osv.osv, EDIMixin):
|
||||
order_line.pop('price_subtotal', None)
|
||||
return super(sale_order,self).edi_import(cr, uid, edi_document, context=context)
|
||||
|
||||
def _edi_paypal_url(self, cr, uid, ids, field, arg, context=None):
|
||||
res = dict.fromkeys(ids, False)
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
if order.order_policy in ('prepaid', 'manual') and \
|
||||
order.company_id.paypal_account and order.state != 'draft':
|
||||
params = {
|
||||
"cmd": "_xclick",
|
||||
"business": order.company_id.paypal_account,
|
||||
"item_name": order.company_id.name + " Order " + order.name,
|
||||
"invoice": order.name,
|
||||
"amount": order.amount_total,
|
||||
"currency_code": order.pricelist_id.currency_id.name,
|
||||
"button_subtype": "services",
|
||||
"no_note": "1",
|
||||
"bn": "OpenERP_Order_PayNow_" + order.pricelist_id.currency_id.name,
|
||||
}
|
||||
res[order.id] = "https://www.paypal.com/cgi-bin/webscr?" + urlencode(params)
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'paypal_url': fields.function(_edi_paypal_url, type='char', string='Paypal Url'),
|
||||
}
|
||||
|
||||
|
||||
class sale_order_line(osv.osv, EDIMixin):
|
||||
_inherit='sale.order.line'
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; ">
|
||||
|
||||
<p>Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},</p>
|
||||
<p>Hello ${object.partner_id.name},</p>
|
||||
|
||||
<p>Here is your ${object.state in ('draft', 'sent') and 'quotation' or 'order confirmation'} from ${object.company_id.name}: </p>
|
||||
|
||||
@@ -51,21 +51,10 @@
|
||||
% endif
|
||||
</p>
|
||||
|
||||
% if object.order_policy in ('prepaid','manual') and object.company_id.paypal_account and object.state != 'draft':
|
||||
<%
|
||||
comp_name = quote(object.company_id.name)
|
||||
order_name = quote(object.name)
|
||||
paypal_account = quote(object.company_id.paypal_account)
|
||||
order_amount = quote(str(object.amount_total))
|
||||
cur_name = quote(object.pricelist_id.currency_id.name)
|
||||
paypal_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=%s&item_name=%s%%20Order%%20%s" \
|
||||
"&invoice=%s&amount=%s&currency_code=%s&button_subtype=services&no_note=1" \
|
||||
"&bn=OpenERP_Order_PayNow_%s" % \
|
||||
(paypal_account,comp_name,order_name,order_name,order_amount,cur_name,cur_name)
|
||||
%>
|
||||
% if object.paypal_url:
|
||||
<br/>
|
||||
<p>It is also possible to directly pay with Paypal:</p>
|
||||
<a style="margin-left: 120px;" href="${paypal_url}">
|
||||
<a style="margin-left: 120px;" href="${object.paypal_url}">
|
||||
<img class="oe_edi_paypal_button" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
|
||||
</a>
|
||||
% endif
|
||||
|
||||
Reference in New Issue
Block a user