diff --git a/addons/account/edi/invoice.py b/addons/account/edi/invoice.py index 3e27bc5ea99..ca25d4e6e90 100644 --- a/addons/account/edi/invoice.py +++ b/addons/account/edi/invoice.py @@ -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' diff --git a/addons/account/edi/invoice_action_data.xml b/addons/account/edi/invoice_action_data.xml index c4b0c8103f1..18ac71f55ce 100644 --- a/addons/account/edi/invoice_action_data.xml +++ b/addons/account/edi/invoice_action_data.xml @@ -23,7 +23,7 @@ Invoice - Send by Email ${object.user_id.email or object.company_id.email or 'noreply@localhost'} - ${object.company_id.name} Invoice (Ref ${object.number or 'n/a' }) + ${object.company_id.name} Invoice (Ref ${object.number or 'n/a'}) ${object.partner_id.id} @@ -33,7 +33,7 @@ -

Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},

+

Hello ${object.partner_id.name},

A new invoice is available for you:

@@ -50,20 +50,10 @@ % 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:

It is also possible to directly pay with Paypal:

- + % endif diff --git a/addons/account_followup/account_followup.py b/addons/account_followup/account_followup.py index 17a09d51e6e..30bd543f7ca 100644 --- a/addons/account_followup/account_followup.py +++ b/addons/account_followup/account_followup.py @@ -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 += ''' - - - - - - - - - ''' % (currency.symbol) - total = 0 - for aml in currency_dict['line']: - block = aml['blocked'] and 'X' or ' ' - total += aml['balance'] - strbegin = "" - date = aml['date_maturity'] or aml['date'] - if date <= current_date and aml['balance'] > 0: - strbegin = "" - followup_table +="" + strbegin + str(aml['date']) + strend + strbegin + aml['ref'] + strend + strbegin + str(date) + strend + strbegin + str(aml['balance']) + strend + strbegin + block + strend + "" - total = rml_parse.formatLang(total, dp='Account', currency_obj=currency) - followup_table += ''' -
Invoice dateReferenceDue dateAmount (%s)Lit.
" - strend = "" - strend = "
-
Amount due: %s
''' % (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 += ''' + + + + + + + + + ''' % (currency.symbol) + total = 0 + for aml in currency_dict['line']: + block = aml['blocked'] and 'X' or ' ' + total += aml['balance'] + strbegin = "" + date = aml['date_maturity'] or aml['date'] + if date <= current_date and aml['balance'] > 0: + strbegin = "" + followup_table +="" + strbegin + str(aml['date']) + strend + strbegin + aml['ref'] + strend + strbegin + str(date) + strend + strbegin + str(aml['balance']) + strend + strbegin + block + strend + "" + total = rml_parse.formatLang(total, dp='Account', currency_obj=currency) + followup_table += ''' +
Invoice dateReferenceDue dateAmount (%s)Lit.
" + strend = "" + strend = "
+
Amount due: %s
''' % (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) diff --git a/addons/account_followup/account_followup_data.xml b/addons/account_followup/account_followup_data.xml index 62ea7bce9c6..d7e6d029ae9 100644 --- a/addons/account_followup/account_followup_data.xml +++ b/addons/account_followup/account_followup_data.xml @@ -3,19 +3,19 @@ - - + + First polite payment follow-up reminder email - ${user.email or '' | h} - ${user.company_id.name | h} Payment Reminder - ${object.email | h} - ${object.lang | h} + ${user.email or ''} + ${user.company_id.name} Payment Reminder + ${object.email} + ${object.lang} -

Dear ${object.name | h},

+

Dear ${object.name},

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,

-${user.name | h} +${user.name}

-${ctx.get('followup_table','')} +${object.get_followup_table_html() | safe}
@@ -42,23 +42,21 @@ ${ctx.get('followup_table','')} ]]> - - - - + + A bit urging second payment follow-up reminder email - ${user.email or '' | h} - ${user.company_id.name | h} Payment Reminder - ${object.email | h} - ${object.lang | h} + ${user.email or ''} + ${user.company_id.name} Payment Reminder + ${object.email} + ${object.lang} -

Dear ${object.name | h},

+

Dear ${object.name},

- 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,

-${user.name | h} +${user.name}

-${ctx.get('followup_table','')} +${object.get_followup_table_html() | safe}
]]> - + + Urging payment follow-up reminder email - ${user.email or '' | h} - ${user.company_id.name | h} Payment Reminder - ${object.email | h} - ${object.lang | h} + ${user.email or ''} + ${user.company_id.name} Payment Reminder + ${object.email} + ${object.lang} -

Dear ${object.name | h},

+

Dear ${object.name},

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,

-${user.name | h} +${user.name}

-${ctx.get('followup_table','')} +${object.get_followup_table_html() | safe}
@@ -121,19 +120,18 @@ ${ctx.get('followup_table','')} - - + Default payment follow-up reminder e-mail - ${user.email or '' | h} - ${user.company_id.name | h} Payment Reminder - ${object.email | h} - ${object.lang | h} + ${user.email or ''} + ${user.company_id.name} Payment Reminder + ${object.email} + ${object.lang} -

Dear ${object.name | h},

+

Dear ${object.name},

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,

-${user.name | h} +${user.name}

-${ctx.get('followup_table','')} +${object.get_followup_table_html() | safe}
@@ -174,7 +172,7 @@ Would your payment have been carried out after this mail was sent, please ignore Best Regards, - + @@ -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, - + + Call the customer on the phone 3 @@ -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, - + diff --git a/addons/account_followup/report/account_followup_print.py b/addons/account_followup/report/account_followup_print.py index f101aeaa369..67ce062dcd1 100644 --- a/addons/account_followup/report/account_followup_print.py +++ b/addons/account_followup/report/account_followup_print.py @@ -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: diff --git a/addons/email_template/email_template.py b/addons/email_template/email_template.py index a9bee623f66..619569f4c81 100644 --- a/addons/email_template/email_template.py +++ b/addons/email_template/email_template.py @@ -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="", + 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) diff --git a/addons/portal_sale/__init__.py b/addons/portal_sale/__init__.py index 296de46594a..ba847ba7169 100644 --- a/addons/portal_sale/__init__.py +++ b/addons/portal_sale/__init__.py @@ -19,7 +19,5 @@ # ############################################################################## -import account_invoice -import sale import portal_sale import res_config diff --git a/addons/portal_sale/account_invoice.py b/addons/portal_sale/account_invoice.py deleted file mode 100644 index fa81b2049e0..00000000000 --- a/addons/portal_sale/account_invoice.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2011 OpenERP S.A (). -# -# 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 . -# -############################################################################## - -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) \ No newline at end of file diff --git a/addons/portal_sale/portal_sale.py b/addons/portal_sale/portal_sale.py index 7cda77ed9ea..3556fd5ca0e 100644 --- a/addons/portal_sale/portal_sale.py +++ b/addons/portal_sale/portal_sale.py @@ -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) diff --git a/addons/portal_sale/portal_sale_data.xml b/addons/portal_sale/portal_sale_data.xml index f40897f6998..0ef9b1ec5cc 100644 --- a/addons/portal_sale/portal_sale_data.xml +++ b/addons/portal_sale/portal_sale_data.xml @@ -16,7 +16,7 @@ -

Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},

+

Hello ${object.partner_id.name},

Here is your ${object.state in ('draft', 'sent') and 'quotation' or 'order confirmation'} from ${object.company_id.name}:

@@ -36,11 +36,7 @@ % endif

- <% - 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:

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'} % 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:

It is also possible to directly pay with Paypal:

- + % endif @@ -101,7 +86,7 @@ - %endif + % endif

@@ -120,7 +105,7 @@ -

Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},

+

Hello ${object.partner_id.name},

A new invoice is available for you:

@@ -137,11 +122,7 @@ % endif

- <% - 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:

You can access the invoice document and pay online via our Customer Portal: @@ -150,20 +131,10 @@ href="${signup_url}">View Invoice % 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:

It is also possible to directly pay with Paypal:

- + % endif @@ -201,7 +172,7 @@ - %endif + % endif

diff --git a/addons/portal_sale/sale.py b/addons/portal_sale/sale.py deleted file mode 100644 index 79fcbdef6fd..00000000000 --- a/addons/portal_sale/sale.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2010 Tiny SPRL (). -# -# 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 . -# -############################################################################## - -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() \ No newline at end of file diff --git a/addons/purchase/edi/purchase_order_action_data.xml b/addons/purchase/edi/purchase_order_action_data.xml index 42efd08d44c..d616ff1d116 100644 --- a/addons/purchase/edi/purchase_order_action_data.xml +++ b/addons/purchase/edi/purchase_order_action_data.xml @@ -30,7 +30,7 @@ -

Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},

+

Hello$ ${object.partner_id.name},

Here is a ${object.state in ('draft', 'sent') and 'request for quotation' or 'purchase order confirmation'} from ${object.company_id.name}:

diff --git a/addons/sale/edi/sale_order.py b/addons/sale/edi/sale_order.py index 15389f1481c..b906f9a6926 100644 --- a/addons/sale/edi/sale_order.py +++ b/addons/sale/edi/sale_order.py @@ -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' diff --git a/addons/sale/edi/sale_order_action_data.xml b/addons/sale/edi/sale_order_action_data.xml index 6907be52acf..a157a96172c 100644 --- a/addons/sale/edi/sale_order_action_data.xml +++ b/addons/sale/edi/sale_order_action_data.xml @@ -31,7 +31,7 @@ -

Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},

+

Hello ${object.partner_id.name},

Here is your ${object.state in ('draft', 'sent') and 'quotation' or 'order confirmation'} from ${object.company_id.name}:

@@ -51,21 +51,10 @@ % 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.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:

It is also possible to directly pay with Paypal:

- + % endif