Browse Source

[IMP][10.0] contract: Add report + send by mail (#86)

* [IMP][9.0] contract: Add report + send by mail

* Update translation and rename contract report

* Changes requested and translation updated
pull/202/head
cubells 7 years ago
committed by Pedro M. Baeza
parent
commit
629c224638
  1. 8
      contract/README.rst
  2. 5
      contract/__manifest__.py
  3. 64
      contract/data/mail_template.xml
  4. 163
      contract/i18n/es.po
  5. 33
      contract/models/account_analytic_account.py
  6. 12
      contract/report/contract_views.xml
  7. 74
      contract/report/report_contract.xml
  8. 4
      contract/tests/test_contract.py
  9. 5
      contract/views/account_analytic_account_view.xml

8
contract/README.rst

@ -7,8 +7,9 @@ Contracts for recurrent invoicing
================================= =================================
This module forward-port to v10 the contracts management with recurring This module forward-port to v10 the contracts management with recurring
invoicing functions. In upstream Odoo, this functionality was moved into the
Enterprise edition.
invoicing functions. Also you can print and send by email contract report.
In upstream Odoo, this functionality was moved into the Enterprise edition.
Configuration Configuration
============= =============
@ -40,6 +41,8 @@ To use this module, you need to:
click on *Create invoices* to force this action. click on *Create invoices* to force this action.
#. Click *Show recurring invoices* link to show all invoices created by the #. Click *Show recurring invoices* link to show all invoices created by the
contract. contract.
#. Click on *Print > Contract* menu to print contract report.
#. Click on *Send by Email* button to send contract by email.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot :alt: Try me on Runbot
@ -68,6 +71,7 @@ Contributors
* Carlos Dauden <carlos.dauden@tecnativa.com> * Carlos Dauden <carlos.dauden@tecnativa.com>
* Angel Moya <angel.moya@domatix.com> * Angel Moya <angel.moya@domatix.com>
* Dave Lasley <dave@laslabs.com> * Dave Lasley <dave@laslabs.com>
* Vicent Cubells <vicent.cubells@tecnativa.com>
Maintainer Maintainer
---------- ----------

5
contract/__manifest__.py

@ -5,7 +5,7 @@
{ {
'name': 'Contracts Management - Recurring', 'name': 'Contracts Management - Recurring',
'version': '10.0.1.0.1',
'version': '10.0.1.1.0',
'category': 'Contract Management', 'category': 'Contract Management',
'license': 'AGPL-3', 'license': 'AGPL-3',
'author': "OpenERP SA, " 'author': "OpenERP SA, "
@ -16,7 +16,10 @@
'depends': ['base', 'account', 'analytic'], 'depends': ['base', 'account', 'analytic'],
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'report/report_contract.xml',
'report/contract_views.xml',
'data/contract_cron.xml', 'data/contract_cron.xml',
'data/mail_template.xml',
'views/account_analytic_account_view.xml', 'views/account_analytic_account_view.xml',
'views/account_analytic_contract_view.xml', 'views/account_analytic_contract_view.xml',
'views/account_invoice_view.xml', 'views/account_invoice_view.xml',

64
contract/data/mail_template.xml

@ -0,0 +1,64 @@
<?xml version="1.0" ?>
<odoo noupdate="1">
<record id="email_contract_template" model="mail.template">
<field name="name">Email Contract Template</field>
<field name="email_from">${(object.user_id.email and '%s &lt;%s&gt;' % (object.user_id.name, object.user_id.email) or '')|safe}</field>
<field name="subject">${object.company_id.name} Contract (Ref ${object.name or 'n/a'})</field>
<field name="partner_to">${object.partner_id.id}</field>
<field name="model_id" ref="contract.model_account_analytic_account"/>
<field name="auto_delete" eval="True"/>
<field name="report_template" ref="contract.report_contract"/>
<field name="report_name">Contract</field>
<field name="lang">${object.partner_id.lang}</field>
<field name="body_html"><![CDATA[
<div style="font-family: 'Lucida Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; ">
<p>Hello ${object.partner_id.name or ''},</p>
<p>A new contract has been created: </p>
<p style="border-left: 1px solid #8e0000; margin-left: 30px;">
&nbsp;&nbsp;<strong>REFERENCES</strong><br />
&nbsp;&nbsp;Contract: <strong>${object.name}</strong><br />
% if object.date_start:
&nbsp;&nbsp;Contract Date Start: ${object.date_start or ''}<br />
% endif
% if object.user_id:
% if object.user_id.email:
&nbsp;&nbsp;Your Contact: <a href="mailto:${object.user_id.email or ''}?subject=Contract%20${object.name}">${object.user_id.name}</a>
% else:
&nbsp;&nbsp;Your Contact: ${object.user_id.name}
% endif
% endif
</p>
<br/>
<p>If you have any questions, do not hesitate to contact us.</p>
<p>Thank you for choosing ${object.company_id.name or 'us'}!</p>
<br/>
<br/>
<div style="width: 375px; margin: 0px; padding: 0px; background-color: #8E0000; border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; background-repeat: repeat no-repeat;">
<h3 style="margin: 0px; padding: 2px 14px; font-size: 12px; color: #DDD;">
<strong style="text-transform:uppercase;">${object.company_id.name}</strong></h3>
</div>
<div style="width: 347px; margin: 0px; padding: 5px 14px; line-height: 16px; background-color: #F2F2F2;">
<span style="color: #222; margin-bottom: 5px; display: block; ">
${object.company_id.partner_id.sudo().with_context(show_address=True, html_format=True).name_get()[0][1] | safe}
</span>
% if object.company_id.phone:
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">
Phone: ${object.company_id.phone}
</div>
% endif
% if object.company_id.website:
<div>
Web: <a href="${object.company_id.website}">${object.company_id.website}</a>
</div>
%endif
<p></p>
</div>
</div>
]]></field>
</record>
</odoo>

163
contract/i18n/es.po

@ -18,6 +18,103 @@ msgstr ""
"Language: es\n" "Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract
#: model:mail.template,body_html:contract.email_contract_template
msgid "\n"
"<div style=\"font-family: 'Lucida Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; \">\n"
" <p>Hello ${object.partner_id.name or ''},</p>\n"
" <p>A new contract has been created: </p>\n"
"\n"
" <p style=\"border-left: 1px solid #8e0000; margin-left: 30px;\">\n"
" &nbsp;&nbsp;<strong>REFERENCES</strong><br />\n"
" &nbsp;&nbsp;Contract: <strong>${object.name}</strong><br />\n"
" % if object.date_start:\n"
" &nbsp;&nbsp;Contract Date Start: ${object.date_start or ''}<br />\n"
" % endif\n"
"\n"
" % if object.user_id:\n"
" % if object.user_id.email:\n"
" &nbsp;&nbsp;Your Contact: <a href=\"mailto:${object.user_id.email or ''}?subject=Contract%20${object.name}\">${object.user_id.name}</a>\n"
" % else:\n"
" &nbsp;&nbsp;Your Contact: ${object.user_id.name}\n"
" % endif\n"
" % endif\n"
" </p>\n"
"\n"
" <br/>\n"
" <p>If you have any questions, do not hesitate to contact us.</p>\n"
" <p>Thank you for choosing ${object.company_id.name or 'us'}!</p>\n"
" <br/>\n"
" <br/>\n"
" <div style=\"width: 375px; margin: 0px; padding: 0px; background-color: #8E0000; border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; background-repeat: repeat no-repeat;\">\n"
" <h3 style=\"margin: 0px; padding: 2px 14px; font-size: 12px; color: #DDD;\">\n"
" <strong style=\"text-transform:uppercase;\">${object.company_id.name}</strong></h3>\n"
" </div>\n"
" <div style=\"width: 347px; margin: 0px; padding: 5px 14px; line-height: 16px; background-color: #F2F2F2;\">\n"
" <span style=\"color: #222; margin-bottom: 5px; display: block; \">\n"
" ${object.company_id.partner_id.sudo().with_context(show_address=True, html_format=True).name_get()[0][1] | safe}\n"
" </span>\n"
" % if object.company_id.phone:\n"
" <div style=\"margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; \">\n"
" Phone: ${object.company_id.phone}\n"
" </div>\n"
" % endif\n"
" % if object.company_id.website:\n"
" <div>\n"
" Web: <a href=\"${object.company_id.website}\">${object.company_id.website}</a>\n"
" </div>\n"
" %endif\n"
" <p></p>\n"
" </div>\n"
"</div>\n"
" "
msgstr "\n"
"<div style=\"font-family: 'Lucida Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; \">\n"
" <p>Hola ${object.partner_id.name or ''},</p>\n"
" <p>Se ha creado un nuevo contrato: </p>\n"
"\n"
" <p style=\"border-left: 1px solid #8e0000; margin-left: 30px;\">\n"
" &nbsp;&nbsp;<strong>REFERENCIAS</strong><br />\n"
" &nbsp;&nbsp;Contrato: <strong>${object.name}</strong><br />\n"
" &nbsp;&nbsp;Fecha de inicio del contrato: ${object.date_start or ''}<br />\n"
"\n"
" % if object.user_id:\n"
" % if object.user_id.email:\n"
" &nbsp;&nbsp;Contacto: <a href=\"mailto:${object.user_id.email or ''}?subject=Contrato%20${object.name}\">${object.user_id.name}</a>\n"
" % else:\n"
" &nbsp;&nbsp;Contacto: ${object.user_id.name}\n"
" % endif\n"
" % endif\n"
" </p>\n"
"\n"
" <br/>\n"
" <p>Si tiene cualquier pregunta, no dude en contactarnos.</p>\n"
" <p>Gracias por elegir ${object.company_id.name or 'nos'}!</p>\n"
" <br/>\n"
" <br/>\n"
" <div style=\"width: 375px; margin: 0px; padding: 0px; background-color: #8E0000; border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; background-repeat: repeat no-repeat;\">\n"
" <h3 style=\"margin: 0px; padding: 2px 14px; font-size: 12px; color: #DDD;\">\n"
" <strong style=\"text-transform:uppercase;\">${object.company_id.name}</strong></h3>\n"
" </div>\n"
" <div style=\"width: 347px; margin: 0px; padding: 5px 14px; line-height: 16px; background-color: #F2F2F2;\">\n"
" <span style=\"color: #222; margin-bottom: 5px; display: block; \">\n"
" ${object.company_id.partner_id.sudo().with_context(show_address=True, html_format=True).name_get()[0][1] | safe}\n"
" </span>\n"
" % if object.company_id.phone:\n"
" <div style=\"margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; \">\n"
" Teléfono: ${object.company_id.phone}\n"
" </div>\n"
" % endif\n"
" % if object.company_id.website:\n"
" <div>\n"
" Web: <a href=\"${object.company_id.website}\">${object.company_id.website}</a>\n"
" </div>\n"
" %endif\n"
" <p></p>\n"
" </div>\n"
"</div>\n"
" "
#. module: contract #. module: contract
#: model:ir.ui.view,arch_db:contract.account_analytic_account_recurring_form_form #: model:ir.ui.view,arch_db:contract.account_analytic_account_recurring_form_form
#: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form
@ -30,6 +127,41 @@ msgstr "<strong>#END#</strong>: Fecha fin del periodo facturado"
msgid "<strong>#START#</strong>: Start date of the invoiced period" msgid "<strong>#START#</strong>: Start date of the invoiced period"
msgstr "<strong>#START#</strong>: Fecha inicio del periodo facturado" msgstr "<strong>#START#</strong>: Fecha inicio del periodo facturado"
#. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Description</strong>"
msgstr "<strong>Descripción</strong>"
#. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Recurring Items</strong>"
msgstr "<strong>Elementos recurrentes</strong>"
#. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Partner:</strong>"
msgstr "<strong>Empresa:</strong>"
#. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Price</strong>"
msgstr "<strong>Precio</strong>"
#. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Quantity</strong>"
msgstr "<strong>Cantidad</strong>"
#. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Total</strong>"
msgstr "<strong>Total</strong>"
#. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Unit Price</strong>"
msgstr "<strong>Precio unidad</strong>"
#. module: contract #. module: contract
#: model:ir.ui.view,arch_db:contract.account_analytic_account_recurring_form_form #: model:ir.ui.view,arch_db:contract.account_analytic_account_recurring_form_form
#: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form
@ -57,6 +189,12 @@ msgstr "Pinche para crear un contrato nuevo. "
msgid "Contract" msgid "Contract"
msgstr "Contrato" msgstr "Contrato"
#. module: contract
#: code:addons/contract/models/account_analytic_account.py:217
#, python-format
msgid "Compose Email"
msgstr "Componer correo electrónico"
#. module: contract #. module: contract
#: model:ir.model.fields,field_description:contract.field_account_analytic_account_contract_template_id #: model:ir.model.fields,field_description:contract.field_account_analytic_account_contract_template_id
#: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form
@ -95,6 +233,11 @@ msgstr "Creado por"
msgid "Created on" msgid "Created on"
msgstr "Creado en" msgstr "Creado en"
#. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document
msgid "Date Start:"
msgstr "Fecha de inicio:"
#. module: contract #. module: contract
#: model:ir.model.fields,field_description:contract.field_account_analytic_account_recurring_next_date #: model:ir.model.fields,field_description:contract.field_account_analytic_account_recurring_next_date
msgid "Date of Next Invoice" msgid "Date of Next Invoice"
@ -300,6 +443,21 @@ msgstr "Repetir cada"
msgid "Repeat every (Days/Week/Month/Year)" msgid "Repeat every (Days/Week/Month/Year)"
msgstr "Repetir cada (días/semana/mes/año)" msgstr "Repetir cada (días/semana/mes/año)"
#. module: contract
#: model:ir.model.fields,field_description:contract.field_account_analytic_account_user_id
msgid "Responsible"
msgstr "Responsable"
#. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document
msgid "Responsible:"
msgstr "Responsable:"
#. module: contract
#: model:ir.ui.view,arch_db:contract.account_analytic_account_recurring_form_form
msgid "Send by Email"
msgstr "Enviar por correo electrónico"
#. module: contract #. module: contract
#: model:ir.model.fields,help:contract.field_account_analytic_account_recurring_rule_type #: model:ir.model.fields,help:contract.field_account_analytic_account_recurring_rule_type
#: model:ir.model.fields,help:contract.field_account_analytic_contract_recurring_rule_type #: model:ir.model.fields,help:contract.field_account_analytic_contract_recurring_rule_type
@ -328,6 +486,11 @@ msgstr "Precio unidad"
msgid "Unit of Measure" msgid "Unit of Measure"
msgstr "Unidad de medida" msgstr "Unidad de medida"
#. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document
msgid "VAT:"
msgstr "NIF:"
#. module: contract #. module: contract
#: selection:account.analytic.account,recurring_rule_type:0 #: selection:account.analytic.account,recurring_rule_type:0
#: selection:account.analytic.contract,recurring_rule_type:0 #: selection:account.analytic.contract,recurring_rule_type:0

33
contract/models/account_analytic_account.py

@ -32,6 +32,12 @@ class AccountAnalyticAccount(models.Model):
copy=False, copy=False,
string='Date of Next Invoice', string='Date of Next Invoice',
) )
user_id = fields.Many2one(
comodel_name='res.users',
string='Responsible',
index=True,
default=lambda self: self.env.user,
)
@api.onchange('contract_template_id') @api.onchange('contract_template_id')
def _onchange_contract_template_id(self): def _onchange_contract_template_id(self):
@ -190,3 +196,30 @@ class AccountAnalyticAccount(models.Model):
[('recurring_next_date', '<=', fields.date.today()), [('recurring_next_date', '<=', fields.date.today()),
('recurring_invoices', '=', True)]) ('recurring_invoices', '=', True)])
return contracts.recurring_create_invoice() return contracts.recurring_create_invoice()
@api.multi
def action_contract_send(self):
self.ensure_one()
template = self.env.ref(
'contract.email_contract_template',
False,
)
compose_form = self.env.ref('mail.email_compose_message_wizard_form')
ctx = dict(
default_model='account.analytic.account',
default_res_id=self.id,
default_use_template=bool(template),
default_template_id=template and template.id or False,
default_composition_mode='comment',
)
return {
'name': _('Compose Email'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'mail.compose.message',
'views': [(compose_form.id, 'form')],
'view_id': compose_form.id,
'target': 'new',
'context': ctx,
}

12
contract/report/contract_views.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<report
id="report_contract"
model="account.analytic.account"
string="Contract"
report_type="qweb-pdf"
name="contract.report_contract_document"
file="contract.report_contract"/>
</odoo>

74
contract/report/report_contract.xml

@ -0,0 +1,74 @@
<?xml version="1.0" ?>
<odoo>
<template id="report_contract_document">
<t t-call="report.html_container">
<t t-foreach="docs" t-as="o">
<t t-call="report.external_layout">
<div class="page">
<div class="oe_structure"/>
<div class="row" id="partner_info">
<div class="col-xs-5 col-xs-offset-7">
<p id="partner_info"><strong>Partner:</strong></p>
<div t-field="o.partner_id" t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "mobile", "fax", "email"], "no_marker": true, "phone_icons": true}'/>
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
</div>
</div>
<div class="row" id="header_info">
<div class="col-xs-3">
<strong>Date Start: </strong><p t-field="o.date_start"/>
<strong>Responsible: </strong><p t-field="o.user_id"/>
<strong>Contract: </strong><p t-field="o.code"/>
</div>
</div>
<div class="row" id="invoice_info">
<t t-set="total" t-value="0"/>
<div class="col-xs-12">
<t t-set="total" t-value="0"/>
<p id="services_info"><strong>Recurring Items</strong></p>
<table class="table table-condensed">
<thead>
<tr>
<th><strong>Description</strong></th>
<th class="text-right"><strong>Quantity</strong></th>
<th class="text-right"><strong>Unit Price</strong></th>
<th class="text-right"><strong>Price</strong></th>
</tr>
</thead>
<tbody>
<tr t-foreach="o.recurring_invoice_line_ids" t-as="l">
<td>
<span t-field="l.name"/>
</td>
<td class="text-right">
<span t-field="l.quantity"/>
</td>
<td class="text-right">
<span t-field="l.price_unit" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
</td>
<td class="text-right">
<span t-field="l.price_subtotal" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
</td>
<t t-set="total" t-value="total + l.price_subtotal"/>
</tr>
</tbody>
</table>
</div>
<div class="col-xs-4 pull-right">
<table class="table table-condensed">
<tr class="border-black">
<td><strong>Total</strong></td>
<td class="text-right">
<span t-esc="total" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
</td>
</tr>
</table>
</div>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

4
contract/tests/test_contract.py

@ -155,3 +155,7 @@ class TestContract(TransactionCase):
} }
del self.template_vals['name'] del self.template_vals['name']
self.assertDictEqual(res, self.template_vals) self.assertDictEqual(res, self.template_vals)
def test_send_mail_contract(self):
result = self.contract.action_contract_send()
self.assertEqual(result['res_model'], 'mail.compose.message')

5
contract/views/account_analytic_account_view.xml

@ -7,6 +7,11 @@
<field name="inherit_id" ref="analytic.view_account_analytic_account_form"/> <field name="inherit_id" ref="analytic.view_account_analytic_account_form"/>
<field name="mode">primary</field> <field name="mode">primary</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//div[@name='button_box']/.." position="before">
<header>
<button name="action_contract_send" type="object" string="Send by Email" groups="base.group_user"/>
</header>
</xpath>
<group name="main" position="after"> <group name="main" position="after">
<separator string="Recurring Invoices" <separator string="Recurring Invoices"
attrs="{'invisible': [('recurring_invoices','!=',True)]}" attrs="{'invisible': [('recurring_invoices','!=',True)]}"

Loading…
Cancel
Save