Merge PR #584 into 12.0

Signed-off-by pedrobaeza
This commit is contained in:
OCA-git-bot
2020-12-15 19:11:16 +00:00
23 changed files with 742 additions and 284 deletions

View File

@@ -1,2 +1,3 @@
from . import controllers
from . import models
from . import wizards

View File

@@ -1,10 +1,10 @@
# Copyright 2004-2010 OpenERP SA
# Copyright 2014-2018 Tecnativa - Pedro M. Baeza
# Copyright 2015 Domatix
# Copyright 2016-2018 Tecnativa - Carlos Dauden
# Copyright 2017 Tecnativa - Vicent Cubells
# Copyright 2016-2017 LasLabs Inc.
# Copyright 2018-2019 ACSONE SA/NV
# Copyright 2020 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
@@ -17,7 +17,7 @@
"LasLabs, "
"Odoo Community Association (OCA)",
'website': 'https://github.com/oca/contract',
'depends': ['base', 'account', 'product'],
'depends': ['base', 'account', 'product', 'portal'],
"external_dependencies": {"python": ["dateutil"]},
'data': [
'security/groups.xml',
@@ -45,6 +45,10 @@
'views/res_partner_view.xml',
'views/res_config_settings.xml',
'views/contract_terminate_reason.xml',
"views/contract_portal_templates.xml",
],
"demo": [
"demo/assets.xml",
],
'installable': True,
}

View File

@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import main

View File

@@ -0,0 +1,91 @@
# Copyright 2020 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import _, http
from odoo.exceptions import AccessError, MissingError
from odoo.http import request
from odoo.addons.portal.controllers.portal import CustomerPortal,\
pager as portal_pager
class PortalContract(CustomerPortal):
def _prepare_portal_layout_values(self):
values = super()._prepare_portal_layout_values()
model = 'contract.contract'
values['contract_count'] = 0
if request.env[model].check_access_rights('read', raise_exception=False):
values['contract_count'] = request.env[model].search_count([])
return values
def _contract_get_page_view_values(self, contract, access_token, **kwargs):
values = {
"page_name": "Contracts",
"contract": contract,
}
return self._get_page_view_values(
contract, access_token, values, 'my_contracts_history', False, **kwargs)
def _get_filter_domain(self, kw):
return []
@http.route(['/my/contracts', '/my/contracts/page/<int:page>'],
type='http', auth="user", website=True)
def portal_my_contracts(self, page=1, date_begin=None, date_end=None,
sortby=None, **kw):
values = self._prepare_portal_layout_values()
contract_obj = request.env['contract.contract']
domain = self._get_filter_domain(kw)
searchbar_sortings = {
"date": {"label": _("Date"), "order": "recurring_next_date desc"},
"name": {"label": _("Name"), "order": "name desc"},
"code": {"label": _("Reference"), "order": "code desc"},
}
# default sort by order
if not sortby:
sortby = 'date'
order = searchbar_sortings[sortby]['order']
# count for pager
contract_count = contract_obj.search_count(domain)
# pager
pager = portal_pager(
url="/my/contracts",
url_args={
"date_begin": date_begin,
"date_end": date_end,
"sortby": sortby,
},
total=contract_count,
page=page,
step=self._items_per_page
)
# content according to pager and archive selected
contracts = contract_obj.search(
domain,
order=order,
limit=self._items_per_page,
offset=pager['offset']
)
request.session['my_contracts_history'] = contracts.ids[:100]
values.update({
"date": date_begin,
"contracts": contracts,
"page_name": "Contracts",
"pager": pager,
"default_url": "/my/contracts",
"searchbar_sortings": searchbar_sortings,
"sortby": sortby
})
return request.render("contract.portal_my_contracts", values)
@http.route(['/my/contracts/<int:contract_contract_id>'],
type='http', auth="public", website=True)
def portal_my_contract_detail(self, contract_contract_id, access_token=None, **kw):
try:
contract_sudo = self._document_check_access(
'contract.contract', contract_contract_id, access_token
)
except (AccessError, MissingError):
return request.redirect('/my')
values = self._contract_get_page_view_values(contract_sudo, access_token, **kw)
return request.render("contract.portal_contract_page", values)

View File

@@ -57,6 +57,8 @@
%endif
<p></p>
</div>
<p></p>
<a href="${object.get_base_url()}/my/contracts/${object.id}?access_token=${object.access_token}" target="_blank" style="background-color:#875A7B;padding: 8px 16px 8px 16px; text-decoration: none; color: #fff; border-radius: 5px; font-size:13px;">View contract</a>
</div>
]]></field>
</record>

12
contract/demo/assets.xml Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- License AGPL-3.0 (http://www.gnu.org/licenses/agpl.html). -->
<odoo>
<template id="contract_frontend_demo" inherit_id="web.assets_frontend">
<xpath expr="//script[last()]" position="after">
<script
type="text/javascript"
src="/contract/static/src/js/contract_portal_tour.js"
/>
</xpath>
</template>
</odoo>

View File

@@ -6,6 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-09 16:09+0000\n"
"PO-Revision-Date: 2020-12-09 16:09+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@@ -61,6 +63,8 @@ msgid "\n"
" %endif\n"
" <p></p>\n"
" </div>\n"
" <p></p>\n"
" <a href=\"${object.get_base_url()}/my/contracts/${object.id}?access_token=${object.access_token}\" target=\"_blank\" style=\"background-color:#875A7B;padding: 8px 16px 8px 16px; text-decoration: none; color: #fff; border-radius: 5px; font-size:13px;\">View contract</a>\n"
"</div>\n"
" "
msgstr ""
@@ -116,11 +120,26 @@ msgstr ""
msgid "<strong>Contract: </strong>"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "<strong>Customer:</strong>"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Date Start</strong>"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "<strong>Date end</strong>"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "<strong>Date of Next Invoice</strong>"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Description</strong>"
@@ -151,11 +170,21 @@ msgstr ""
msgid "<strong>Recurring Items</strong>"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "<strong>Reference</strong>"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Responsible: </strong>"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "<strong>Responsible:</strong>"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Total</strong>"
@@ -194,6 +223,11 @@ msgstr ""
msgid "Abstract Recurring Contract Line"
msgstr ""
#. module: contract
#: model:ir.model.fields,field_description:contract.field_contract_contract__access_warning
msgid "Access warning"
msgstr ""
#. module: contract
#: model:ir.model.fields,field_description:contract.field_contract_contract__message_needaction
msgid "Action Needed"
@@ -353,6 +387,11 @@ msgstr ""
msgid "Commercial Entity"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Communication"
msgstr ""
#. module: contract
#: model:ir.model,name:contract.model_res_company
msgid "Companies"
@@ -367,7 +406,7 @@ msgid "Company"
msgstr ""
#. module: contract
#: code:addons/contract/models/contract.py:393
#: code:addons/contract/models/contract.py:394
#, python-format
msgid "Compose Email"
msgstr ""
@@ -379,6 +418,7 @@ msgstr ""
#. module: contract
#: model:ir.model,name:contract.model_res_partner
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Contact"
msgstr ""
@@ -395,6 +435,11 @@ msgstr ""
msgid "Contract"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.portal_my_contracts
msgid "Contract #"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.contract_contract_terminate_form_view
msgid "Contract Contract Terminate"
@@ -432,6 +477,11 @@ msgstr ""
msgid "Contract Name"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Contract Order -"
msgstr ""
#. module: contract
#: model:ir.model,name:contract.model_contract_tag
#: model:ir.ui.menu,name:contract.contract_tag_menu
@@ -577,7 +627,7 @@ msgid "Contract lines"
msgstr ""
#. module: contract
#: code:addons/contract/models/contract.py:549
#: code:addons/contract/models/contract.py:550
#, python-format
msgid "Contract manually invoiced: <a href=\"#\" data-oe-model=\"%s\" data-oe-id=\"%s\">Invoice</a>"
msgstr ""
@@ -593,11 +643,12 @@ msgid "Contract: Can Terminate Contracts"
msgstr ""
#. module: contract
#: model:ir.model.fields,field_description:contract.field_fsm_location__contract_ids
#: model:ir.model.fields,field_description:contract.field_fsm_person__contract_ids
#: model:ir.model.fields,field_description:contract.field_res_partner__contract_ids
#: model:ir.model.fields,field_description:contract.field_res_users__contract_ids
#: model:ir.ui.menu,name:contract.menu_config_contract
#: model_terms:ir.ui.view,arch_db:contract.portal_my_contracts
#: model_terms:ir.ui.view,arch_db:contract.portal_my_home_contract
#: model_terms:ir.ui.view,arch_db:contract.portal_my_home_menu_contract
msgid "Contracts"
msgstr ""
@@ -682,6 +733,18 @@ msgstr ""
msgid "Customer Contracts"
msgstr ""
#. module: contract
#: model:ir.model.fields,help:contract.field_contract_contract__access_url
msgid "Customer Portal URL"
msgstr ""
#. module: contract
#: code:addons/contract/controllers/main.py:40
#: model_terms:ir.ui.view,arch_db:contract.portal_my_contracts
#, python-format
msgid "Date"
msgstr ""
#. module: contract
#: model:ir.model.fields,field_description:contract.field_contract_contract__date_end
#: model:ir.model.fields,field_description:contract.field_contract_line__date_end
@@ -698,6 +761,11 @@ msgstr ""
msgid "Date Start"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.portal_my_contracts
msgid "Date end"
msgstr ""
#. module: contract
#: model:ir.model.fields,field_description:contract.field_contract_abstract_contract_line__recurring_next_date
#: model:ir.model.fields,field_description:contract.field_contract_contract__recurring_next_date
@@ -706,6 +774,11 @@ msgstr ""
msgid "Date of Next Invoice"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Date of next invoice"
msgstr ""
#. module: contract
#: selection:contract.abstract.contract.line,auto_renew_rule_type:0
#: selection:contract.abstract.contract.line,recurring_rule_type:0
@@ -716,6 +789,7 @@ msgstr ""
#: selection:contract.template.line,auto_renew_rule_type:0
#: selection:contract.template.line,recurring_rule_type:0
#: selection:contract.template.line,termination_notice_rule_type:0
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Day(s)"
msgstr ""
@@ -734,6 +808,7 @@ msgstr ""
#: model:ir.model.fields,field_description:contract.field_contract_line__name
#: model:ir.model.fields,field_description:contract.field_contract_template_line__name
#: model_terms:ir.ui.view,arch_db:contract.contract_abstract_contract_line_form_view
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Description"
msgstr ""
@@ -1017,6 +1092,11 @@ msgstr ""
msgid "Last Updated on"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Last date invoice"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.contract_contract_form_view
#: model_terms:ir.ui.view,arch_db:contract.contract_template_form_view
@@ -1071,6 +1151,7 @@ msgstr ""
#: selection:contract.template.line,auto_renew_rule_type:0
#: selection:contract.template.line,recurring_rule_type:0
#: selection:contract.template.line,termination_notice_rule_type:0
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Month(s)"
msgstr ""
@@ -1078,16 +1159,19 @@ msgstr ""
#: selection:contract.abstract.contract.line,recurring_rule_type:0
#: selection:contract.line,recurring_rule_type:0
#: selection:contract.template.line,recurring_rule_type:0
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Month(s) last day"
msgstr ""
#. module: contract
#: code:addons/contract/controllers/main.py:41
#: model:ir.model.fields,field_description:contract.field_contract_abstract_contract__name
#: model:ir.model.fields,field_description:contract.field_contract_contract__name
#: model:ir.model.fields,field_description:contract.field_contract_tag__name
#: model:ir.model.fields,field_description:contract.field_contract_template__name
#: model:ir.model.fields,field_description:contract.field_contract_terminate_reason__name
#: model_terms:ir.ui.view,arch_db:contract.contract_contract_tree_view
#, python-format
msgid "Name"
msgstr ""
@@ -1228,11 +1312,16 @@ msgid "Planned"
msgstr ""
#. module: contract
#: code:addons/contract/models/contract.py:351
#: code:addons/contract/models/contract.py:352
#, python-format
msgid "Please define a %s journal for the company '%s'."
msgstr ""
#. module: contract
#: model:ir.model.fields,field_description:contract.field_contract_contract__access_url
msgid "Portal Access URL"
msgstr ""
#. module: contract
#: selection:contract.abstract.contract.line,recurring_invoicing_type:0
#: selection:contract.line,recurring_invoicing_type:0
@@ -1252,6 +1341,11 @@ msgstr ""
msgid "Predecessor Contract Line"
msgstr ""
#. module: contract
#: model_terms:ir.ui.view,arch_db:contract.contract_contract_form_view
msgid "Preview"
msgstr ""
#. module: contract
#: model:ir.model.fields,field_description:contract.field_contract_abstract_contract__pricelist_id
#: model:ir.model.fields,field_description:contract.field_contract_contract__pricelist_id
@@ -1268,8 +1362,6 @@ msgid "Product"
msgstr ""
#. module: contract
#: model:ir.model.fields,field_description:contract.field_fsm_location__purchase_contract_count
#: model:ir.model.fields,field_description:contract.field_fsm_person__purchase_contract_count
#: model:ir.model.fields,field_description:contract.field_res_partner__purchase_contract_count
#: model:ir.model.fields,field_description:contract.field_res_users__purchase_contract_count
#: model_terms:ir.ui.view,arch_db:contract.view_partner_form
@@ -1287,6 +1379,7 @@ msgstr ""
#: selection:contract.abstract.contract.line,recurring_rule_type:0
#: selection:contract.line,recurring_rule_type:0
#: selection:contract.template.line,recurring_rule_type:0
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Quarter(s)"
msgstr ""
@@ -1294,6 +1387,7 @@ msgstr ""
#: model:ir.model.fields,field_description:contract.field_contract_abstract_contract_line__recurring_rule_type
#: model:ir.model.fields,field_description:contract.field_contract_line__recurring_rule_type
#: model:ir.model.fields,field_description:contract.field_contract_template_line__recurring_rule_type
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Recurrence"
msgstr ""
@@ -1303,7 +1397,10 @@ msgid "Recurring Invoices"
msgstr ""
#. module: contract
#: code:addons/contract/controllers/main.py:42
#: model:ir.model.fields,field_description:contract.field_contract_contract__code
#: model_terms:ir.ui.view,arch_db:contract.portal_my_contracts
#, python-format
msgid "Reference"
msgstr ""
@@ -1358,8 +1455,6 @@ msgid "Responsible User"
msgstr ""
#. module: contract
#: model:ir.model.fields,field_description:contract.field_fsm_location__sale_contract_count
#: model:ir.model.fields,field_description:contract.field_fsm_person__sale_contract_count
#: model:ir.model.fields,field_description:contract.field_res_partner__sale_contract_count
#: model:ir.model.fields,field_description:contract.field_res_users__sale_contract_count
#: model_terms:ir.ui.view,arch_db:contract.view_partner_form
@@ -1374,10 +1469,16 @@ msgstr ""
msgid "Section"
msgstr ""
#. module: contract
#: model:ir.model.fields,field_description:contract.field_contract_contract__access_token
msgid "Security Token"
msgstr ""
#. module: contract
#: selection:contract.abstract.contract.line,recurring_rule_type:0
#: selection:contract.line,recurring_rule_type:0
#: selection:contract.template.line,recurring_rule_type:0
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Semester(s)"
msgstr ""
@@ -1540,7 +1641,7 @@ msgid "Technical field for UX purpose."
msgstr ""
#. module: contract
#: code:addons/contract/models/contract.py:584
#: code:addons/contract/models/contract.py:585
#: model_terms:ir.ui.view,arch_db:contract.contract_contract_form_view
#: model_terms:ir.ui.view,arch_db:contract.contract_contract_terminate_form_view
#, python-format
@@ -1709,6 +1810,7 @@ msgstr ""
#: selection:contract.template.line,auto_renew_rule_type:0
#: selection:contract.template.line,recurring_rule_type:0
#: selection:contract.template.line,termination_notice_rule_type:0
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Week(s)"
msgstr ""
@@ -1738,11 +1840,12 @@ msgstr ""
#: selection:contract.line,recurring_rule_type:0
#: selection:contract.template.line,auto_renew_rule_type:0
#: selection:contract.template.line,recurring_rule_type:0
#: model_terms:ir.ui.view,arch_db:contract.portal_contract_page
msgid "Year(s)"
msgstr ""
#. module: contract
#: code:addons/contract/models/contract.py:598
#: code:addons/contract/models/contract.py:599
#, python-format
msgid "You are not allowed to terminate contracts."
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,7 @@ class ContractContract(models.Model):
'mail.thread',
'mail.activity.mixin',
'contract.abstract.contract',
'portal.mixin'
]
active = fields.Boolean(
@@ -614,3 +615,16 @@ class ContractContract(models.Model):
'terminate_comment': False,
'terminate_date': False,
})
def _compute_access_url(self):
for record in self:
record.access_url = '/my/contracts/{}'.format(record.id)
def action_preview(self):
"""Invoked when 'Preview' button in contract form view is clicked."""
self.ensure_one()
return {
'type': 'ir.actions.act_url',
'target': 'self',
'url': self.get_portal_url(),
}

View File

@@ -1,2 +1,4 @@
To view discount field in contract line, you need to set *Discount on lines* in
user access rights.
Contracts can be viewed on the portal (list and detail) if the user logged into the portal is a follower of the contract.

View File

@@ -2,3 +2,5 @@ This module enables contracts management with recurring
invoicing functions. Also you can print and send by email contract report.
It works for customer contract and supplier contracts.
Contracts are shown in portal.

View File

@@ -23,3 +23,9 @@
#. Contract templates can be created from the Configuration -> Contracts -> Contract Templates menu.
They allow to define default journal, price list and lines when creating a contract.
To use it, just select the template on the contract and fields will be filled automatically.
* Contracts appear in portal to following users in every contract:
.. image:: ../static/src/screenshots/portal-my.png
.. image:: ../static/src/screenshots/portal-list.png
.. image:: ../static/src/screenshots/portal-detail.png

View File

@@ -7,6 +7,13 @@
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record>
<record id="rule_contract_contract_portal" model="ir.rule">
<field name="name">Contract contract portal</field>
<field name="model_id" ref="model_contract_contract"/>
<field name="domain_force">[('message_partner_ids', 'in', [user.partner_id.id])]</field>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record>
<record id="rule_contract_line_multi_company" model="ir.rule">
<field name="name">Contract line multi-company</field>
<field name="model_id" ref="model_contract_line"/>

View File

@@ -3,7 +3,9 @@
"contract_template_user","Recurring user","model_contract_template","account.group_account_invoice",1,0,0,0
"contract_manager","Recurring manager","model_contract_contract","account.group_account_manager",1,1,1,1
"contract_user","Recurring user","model_contract_contract","account.group_account_invoice",1,0,0,0
"contract_portal","Recurring portal","model_contract_contract","base.group_portal",1,0,0,0
"contract_line_manager","Recurring manager","model_contract_line","account.group_account_manager",1,1,1,1
"contract_line_user","Recurring user","model_contract_line","account.group_account_invoice",1,0,0,0
"contract_line_portal","Recurring portal","model_contract_line","base.group_portal",1,0,0,0
"contract_template_line_manager","Recurring manager","model_contract_template_line","account.group_account_manager",1,1,1,1
"contract_template_line_user","Recurring user","model_contract_template_line","account.group_account_invoice",1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
3 contract_template_user Recurring user model_contract_template account.group_account_invoice 1 0 0 0
4 contract_manager Recurring manager model_contract_contract account.group_account_manager 1 1 1 1
5 contract_user Recurring user model_contract_contract account.group_account_invoice 1 0 0 0
6 contract_portal Recurring portal model_contract_contract base.group_portal 1 0 0 0
7 contract_line_manager Recurring manager model_contract_line account.group_account_manager 1 1 1 1
8 contract_line_user Recurring user model_contract_line account.group_account_invoice 1 0 0 0
9 contract_line_portal Recurring portal model_contract_line base.group_portal 1 0 0 0
10 contract_template_line_manager Recurring manager model_contract_template_line account.group_account_manager 1 1 1 1
11 contract_template_line_user Recurring user model_contract_template_line account.group_account_invoice 1 0 0 0

View File

@@ -0,0 +1,25 @@
odoo.define("contract.tour", function(require) {
"use strict";
var tour = require("web_tour.tour");
var base = require("web_editor.base");
tour.register(
"contract_portal_tour",
{
test: true,
url: "/my",
wait_for: base.ready(),
},
[
{
content: "Go /my/contracts url",
trigger: 'a[href*="/my/contracts"]',
},
{
content: "Go to Contract item",
trigger: ".tr_contract_link:eq(0)",
},
]
);
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1,4 +1,5 @@
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
# Copyright 2016 Tecnativa - Carlos Dauden
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_contract
from . import test_portal

View File

@@ -169,6 +169,11 @@ class TestContract(TestContractBase):
self.assertAlmostEqual(self.inv_line.price_subtotal, 50.0)
self.assertEqual(self.contract.user_id, self.invoice_monthly.user_id)
def test_contract_action_preview(self):
action = self.contract.action_preview()
self.assertIn("/my/contracts/", action["url"])
self.assertIn("access_token=", action["url"])
def test_contract_recurring_next_date(self):
recurring_next_date = to_date('2018-01-15')
self.assertEqual(

View File

@@ -0,0 +1,36 @@
# Copyright 2020 Tecnativa - Víctor Martínez
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl)
import odoo.tests
from odoo import http
@odoo.tests.tagged("post_install", "-at_install")
class TestContractPortal(odoo.tests.HttpCase):
def test_tour(self):
partner = self.env['res.partner'].create({
'name': 'partner test contract'
})
contract = self.env['contract.contract'].create(
{
'name': 'Test Contract',
'partner_id': partner.id
}
)
user_portal = self.env.ref('base.demo_user0')
contract.message_subscribe(partner_ids=user_portal.partner_id.ids)
self.phantom_js(
"/",
"odoo.__DEBUG__.services['web_tour.tour'].run('contract_portal_tour')",
"odoo.__DEBUG__.services['web_tour.tour'].tours.contract_portal_tour.ready",
login="portal",
)
# Contract access
self.authenticate('portal', 'portal')
http.root.session_store.save(self.session)
url_contract = "/my/contracts/%s?access_token=%s" % (
contract.id, contract.access_token
)
self.assertEqual(self.url_open(url=url_contract).status_code, 200)
contract.message_unsubscribe(partner_ids=user_portal.partner_id.ids)
self.assertEqual(self.url_open(url=url_contract).status_code, 200)

View File

@@ -39,6 +39,9 @@
string="Cancel Contract Termination"
attrs="{'invisible': [('is_terminated','=',False)]}"
groups="contract.can_terminate_contract"/>
<button type="object"
string="Preview"
name="action_preview"/>
</header>
<sheet string="Contract">
<div class="oe_button_box" name="button_box">

View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 Tecnativa - Víctor Martínez
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<template id="portal_my_home_menu_contract" name="Portal layout : Contract menu entries" inherit_id="portal.portal_breadcrumbs" priority="35">
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
<li t-if="page_name == 'Contracts'" t-attf-class="breadcrumb-item #{'active ' if not contract else ''}">
<a t-if="contract" t-attf-href="/my/contracts?{{ keep_query() }}">Contracts</a>
<t t-else="">Contracts</t>
</li>
<li t-if="contract" class="breadcrumb-item active">
<t t-esc="contract.name"/>
</li>
</xpath>
</template>
<template id="portal_my_home_contract" name="Portal My Home : Contract entries" inherit_id="portal.portal_my_home" priority="30">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-call="portal.portal_docs_entry" t-if="contract_count">
<t t-set="title">Contracts</t>
<t t-set="url" t-value="'/my/contracts'"/>
<t t-set="count" t-value="contract_count"/>
</t>
</xpath>
</template>
<template id="portal_my_contracts" name="My Contracts">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<t t-set="title">Contracts</t>
</t>
<t t-if="contracts" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>Contract #</th>
<th class='d-none d-md-table-cell'>Date</th>
<th class='d-none d-md-table-cell'>Date end</th>
<th class='text-right'>Reference</th>
</tr>
</thead>
<tbody>
<t t-foreach="contracts" t-as="contract">
<tr>
<td>
<a
t-att-href="contract.get_portal_url()"
t-attf-class="tr_contract_link"
t-att-title="contract.name"
>
<t t-esc="contract.name"/>
</a>
</td>
<td class="d-none d-md-table-cell"><span t-field="contract.recurring_next_date"/></td>
<td class="d-none d-md-table-cell"><span t-field="contract.date_end"/></td>
<td class='text-right'><span t-field="contract.code"/></td>
</tr>
</t>
</tbody>
</t>
</t>
</template>
<template id="portal_contract_page" name="My Contract">
<t t-call="portal.portal_layout">
<t t-set="o_portal_fullwidth_alert">
<t t-call="portal.portal_back_in_edit_mode">
<t t-set="backend_url" t-value="'/web#return_label=Website&amp;model=contract.contract&amp;id=%s&amp;view_type=form' % (contract.id)"/>
</t>
</t>
<t t-call="portal.portal_record_layout">
<t t-set="card_header">
<h5 class="mb-0">
<span>
Contract Order - <span t-field="contract.name"/>
</span>
</h5>
</t>
<t t-set="card_body">
<div id="general_information">
<div class="row mt4">
<div t-if="contract.partner_id" class="col-12 col-md-6 mb-4 mb-md-0">
<h6><strong>Customer:</strong></h6>
<div class="row">
<div class="col flex-grow-0 pr-3">
<img t-if="contract.partner_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-att-src="image_data_uri(contract.partner_id.image)" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
<div class="col pl-sm-0">
<address t-field="contract.partner_id" t-options='{"widget": "contact", "fields": ["name", "email", "phone"]}'/>
</div>
</div>
</div>
<div t-if="contract.user_id" class="col-12 col-md-6">
<h6><strong>Responsible:</strong></h6>
<div class="row">
<div class="col flex-grow-0 pr-3">
<img t-if="contract.user_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-att-src="image_data_uri(contract.user_id.image)" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
<div class="col pl-sm-0">
<address t-field="contract.user_id" t-options='{"widget": "contact", "fields": ["name", "email", "phone"]}'/>
</div>
</div>
</div>
</div>
<div class="row mt32" id="product_information">
<div class="col-12 col-md-6 mb-4 mb-md-0">
<div t-if="contract.code" class="row mb-2 mb-sm-1">
<div class="col-12 col-sm-4">
<strong>Reference</strong>
</div>
<div class="col-12 col-sm-8">
<span t-field="contract.code"/>
</div>
</div>
<div t-if="contract.recurring_next_date" class="row mb-2 mb-sm-1">
<div class="col-12 col-sm-4">
<strong>Date of Next Invoice</strong>
</div>
<div class="col-12 col-sm-8">
<span t-field="contract.recurring_next_date" t-options='{"widget": "date"}'/>
</div>
</div>
<div t-if="contract.date_end" class="row mb-2 mb-sm-1">
<div class="col-12 col-sm-4">
<strong>Date end</strong>
</div>
<div class="col-12 col-sm-8">
<span t-field="contract.date_end" t-options='{"widget": "date"}'/>
</div>
</div>
</div>
</div>
<div id="item_details">
<table class="table table-sm" id="sales_order_table">
<thead class="bg-100">
<tr>
<th class="text-left">Description</th>
<th class="text-right">Recurrence</th>
<th class="text-right">Date of next invoice</th>
<th class="text-right">Last date invoice</th>
</tr>
</thead>
<tbody class="contract_tbody">
<t t-foreach="contract.contract_line_ids" t-as="line">
<tr>
<td id="line_name"><span t-field="line.name"/></td>
<td class="text-right">
<span t-field="line.recurring_interval"/>
<t t-if="line.recurring_rule_type=='daily'">Day(s)</t>
<t t-if="line.recurring_rule_type=='weekly'">Week(s)</t>
<t t-if="line.recurring_rule_type=='monthly'">Month(s)</t>
<t t-if="line.recurring_rule_type=='monthlylastday'">Month(s) last day</t>
<t t-if="line.recurring_rule_type=='quarterly'">Quarter(s)</t>
<t t-if="line.recurring_rule_type=='semesterly'">Semester(s)</t>
<t t-if="line.recurring_rule_type=='yearly'">Year(s)</t>
</td>
<td class="text-right"><span t-field="line.recurring_next_date"/></td>
<td class="text-right"><span t-field="line.last_date_invoiced"/></td>
</tr>
</t>
</tbody>
</table>
</div>
</div>
</t>
</t>
<!-- chatter -->
<div id="contract_communication" class="mt-4">
<h2>Communication</h2>
<t t-call="portal.message_thread">
<t t-set="object" t-value="contract"/>
<t t-set="token" t-value="contract.access_token"/>
<t t-set="pid" t-value="pid"/>
<t t-set="hash" t-value="hash"/>
</t>
</div>
</t>
</template>
</odoo>