[ADD]mandates_bank_accounts_portal
This commit is contained in:
2
partner_bank_account_portal/.gitignore
vendored
Normal file
2
partner_bank_account_portal/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.*~
|
||||||
|
*pyc
|
49
partner_bank_account_portal/README.rst
Normal file
49
partner_bank_account_portal/README.rst
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
===============
|
||||||
|
partner_bank_account_portal
|
||||||
|
===============
|
||||||
|
|
||||||
|
Provide portal pages and forms to manage partner's contract, bank accounts and mandates from portal home space.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Use Odoo normal module installation procedure to install
|
||||||
|
``partner_bank_account_portal``.
|
||||||
|
|
||||||
|
Description
|
||||||
|
===========
|
||||||
|
|
||||||
|
Provide portal pages and forms to manage partner's bank accounts and mandates from portal home space.
|
||||||
|
Also add the mandate in contract portal view
|
||||||
|
|
||||||
|
Known issues / Roadmap
|
||||||
|
======================
|
||||||
|
|
||||||
|
None yet.
|
||||||
|
Bug Tracker
|
||||||
|
===========
|
||||||
|
|
||||||
|
Bugs are tracked on `our issues website <https://github.com/elabore-coop/partner-tools/issues>`_. In case of
|
||||||
|
trouble, please check there if your issue has already been
|
||||||
|
reported. If you spotted it first, help us smashing it by providing a
|
||||||
|
detailed and welcomed feedback.
|
||||||
|
|
||||||
|
Credits
|
||||||
|
=======
|
||||||
|
|
||||||
|
Contributors
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Laetitia Da Costa
|
||||||
|
|
||||||
|
Funders
|
||||||
|
-------
|
||||||
|
|
||||||
|
The development of this module has been financially supported by:
|
||||||
|
* Elabore (https://elabore.coop)
|
||||||
|
|
||||||
|
|
||||||
|
Maintainer
|
||||||
|
----------
|
||||||
|
|
||||||
|
This module is maintained by Elabore.
|
3
partner_bank_account_portal/__init__.py
Normal file
3
partner_bank_account_portal/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
from . import controllers
|
||||||
|
from . import models
|
48
partner_bank_account_portal/__manifest__.py
Normal file
48
partner_bank_account_portal/__manifest__.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# Copyright 2022 Stéphan Sainléger (Elabore)
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Mandates and bank accounts portal",
|
||||||
|
"version": "16.0.1.0.0",
|
||||||
|
"author": "Elabore",
|
||||||
|
"website": "https://elabore.coop",
|
||||||
|
"maintainer": "Laetitia Da Costa",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"category": "Tools",
|
||||||
|
"summary": "Provide portal pages and forms to manage partner's bank accounts and mandates from portal home space.",
|
||||||
|
# any module necessary for this one to work correctly
|
||||||
|
"depends": [
|
||||||
|
"base",
|
||||||
|
"account",
|
||||||
|
"portal",
|
||||||
|
"website",
|
||||||
|
"account_banking_mandate",
|
||||||
|
"contract",
|
||||||
|
"account_payment_order",
|
||||||
|
"contract_mandate",
|
||||||
|
],
|
||||||
|
"qweb": [],
|
||||||
|
"external_dependencies": {
|
||||||
|
"python": [],
|
||||||
|
},
|
||||||
|
# always loaded
|
||||||
|
"data": [
|
||||||
|
"security/members_security.xml",
|
||||||
|
"security/ir.model.access.csv",
|
||||||
|
"views/portal_my_home_template.xml",
|
||||||
|
"views/portal_my_bank_accounts_template.xml",
|
||||||
|
"views/portal_my_bank_account_template.xml",
|
||||||
|
"views/portal_my_mandates_template.xml",
|
||||||
|
"views/portal_my_mandate_template.xml",
|
||||||
|
"views/portal_my_contract_template_inherit.xml",
|
||||||
|
],
|
||||||
|
# only loaded in demonstration mode
|
||||||
|
"demo": [],
|
||||||
|
"js": [],
|
||||||
|
"css": [],
|
||||||
|
"installable": True,
|
||||||
|
# Install this module automatically if all dependency have been previously
|
||||||
|
# and independently installed. Used for synergetic or glue modules.
|
||||||
|
"auto_install": False,
|
||||||
|
"application": False,
|
||||||
|
}
|
4
partner_bank_account_portal/controllers/__init__.py
Normal file
4
partner_bank_account_portal/controllers/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from . import portal_my_bank_accounts
|
||||||
|
from . import portal_my_bank_account
|
||||||
|
from . import portal_my_mandates
|
||||||
|
from . import portal_my_mandate
|
@@ -0,0 +1,159 @@
|
|||||||
|
# Copyright 2020 Lokavaluto ()
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
import base64
|
||||||
|
from odoo import http, tools, _
|
||||||
|
from odoo.exceptions import AccessError, MissingError
|
||||||
|
from odoo.http import request
|
||||||
|
from odoo.addons.portal.controllers.portal import CustomerPortal
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerPortalBankAccount(CustomerPortal):
|
||||||
|
|
||||||
|
def _bank_account_get_page_view_values(self, bank_account, access_token, **kwargs):
|
||||||
|
values = {
|
||||||
|
"page_name": "bank_account",
|
||||||
|
"bank_account": bank_account,
|
||||||
|
}
|
||||||
|
return self._get_page_view_values(
|
||||||
|
bank_account, access_token, values, "my_bank_accounts_history", False, **kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
def _details_bank_account_form_validate(self, data, bank_account_id):
|
||||||
|
error = dict()
|
||||||
|
error_message = []
|
||||||
|
# public name uniqueness
|
||||||
|
if data.get("public_name") and request.env["res.partner"].sudo().search(
|
||||||
|
[
|
||||||
|
("name", "=", data.get("public_name")),
|
||||||
|
("is_public_profile", "=", True),
|
||||||
|
("contact_id", "!=", bank_account_id),
|
||||||
|
]
|
||||||
|
):
|
||||||
|
error["public_name"] = "error"
|
||||||
|
error_message.append(
|
||||||
|
_("This public name is already used, please find an other idea.")
|
||||||
|
)
|
||||||
|
|
||||||
|
# email validation
|
||||||
|
if data.get("email") and not tools.single_email_re.match(data.get("email")):
|
||||||
|
error["email"] = "error"
|
||||||
|
error_message.append(
|
||||||
|
_("Invalid Email! Please enter a valid email address.")
|
||||||
|
)
|
||||||
|
return error, error_message
|
||||||
|
|
||||||
|
def _get_bank_account_fields(self):
|
||||||
|
fields = [
|
||||||
|
"acc_number",
|
||||||
|
"acc_holder_name",
|
||||||
|
]
|
||||||
|
return fields
|
||||||
|
|
||||||
|
def _get_id_fields(self):
|
||||||
|
fields = [
|
||||||
|
"bank_id",
|
||||||
|
]
|
||||||
|
return fields
|
||||||
|
|
||||||
|
def _get_main_boolean_bank_account_fields(self):
|
||||||
|
'''Provides the fields for which we must check the presence
|
||||||
|
in form's kw to know the value to save in the partner field.
|
||||||
|
All of them MUST start with "main_".'''
|
||||||
|
fields = []
|
||||||
|
return fields
|
||||||
|
|
||||||
|
def _transform_res_partner_fields(self, kw, bank_account_fields, prefix=""):
|
||||||
|
'''Transforms kw's values in res_partner fields and values'''
|
||||||
|
return {key[len(prefix):]: kw[key] for key in bank_account_fields if key in kw}
|
||||||
|
|
||||||
|
def _cast_id_fields(self, kw, id_fields):
|
||||||
|
'''Cast ids fields in kw's values into a integer'''
|
||||||
|
result = {}
|
||||||
|
for key in id_fields:
|
||||||
|
if key in kw:
|
||||||
|
if kw[key] == '':
|
||||||
|
result[key] = None
|
||||||
|
elif not isinstance(kw[key], int):
|
||||||
|
result[key] = int(kw[key])
|
||||||
|
else:
|
||||||
|
result[key] = kw[key]
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _add_boolean_values(self, values, kw, boolean_fields, prefix=""):
|
||||||
|
for key in boolean_fields:
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
key[len(prefix):]: kw.get(key, "off") == "on",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return values
|
||||||
|
|
||||||
|
def _get_page_saving_bank_account_values(self, kw):
|
||||||
|
bank_account_fields = self._get_bank_account_fields()
|
||||||
|
values = self._transform_res_partner_fields(kw, bank_account_fields)
|
||||||
|
if kw["bank_id"] == '':
|
||||||
|
bank_id = None
|
||||||
|
else:
|
||||||
|
bank_id = int(kw["bank_id"])
|
||||||
|
values.update({"bank_id":bank_id})
|
||||||
|
return values
|
||||||
|
|
||||||
|
@http.route(
|
||||||
|
["/my/bank_account/<int:bank_account_id>", "/my/bank_account/save"],
|
||||||
|
type="http",
|
||||||
|
auth="user",
|
||||||
|
website=True,
|
||||||
|
)
|
||||||
|
def portal_my_bank_account(
|
||||||
|
self,bank_account_id=None, access_token=None, redirect=None, **kw
|
||||||
|
):
|
||||||
|
# The following condition is to transform profile_id to an int, as it is sent as a string from the templace "portal_my_profile"
|
||||||
|
# TODO: find a better way to retrieve the profile_id at form submit step
|
||||||
|
if not isinstance(bank_account_id, int):
|
||||||
|
bank_account_id = int(bank_account_id)
|
||||||
|
|
||||||
|
# Check that the user has the right to see this profile
|
||||||
|
try:
|
||||||
|
bank_account_sudo = self._document_check_access(
|
||||||
|
"res.partner.bank", bank_account_id, access_token
|
||||||
|
)
|
||||||
|
except (AccessError, MissingError):
|
||||||
|
return request.redirect("/my/bank_accounts")
|
||||||
|
|
||||||
|
PartnerBankAccount = request.env["res.partner.bank"]
|
||||||
|
user = request.env.user
|
||||||
|
bank_account = PartnerBankAccount.browse(bank_account_id)
|
||||||
|
|
||||||
|
values = self._bank_account_get_page_view_values(bank_account_sudo, access_token, **kw)
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"error": {},
|
||||||
|
"error_message": [],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if kw and request.httprequest.method == "POST":
|
||||||
|
# the user has clicked in the Save button to save new data
|
||||||
|
error, error_message = self._details_bank_account_form_validate(kw, bank_account_id)
|
||||||
|
values.update({"error": error, "error_message": error_message})
|
||||||
|
values.update(kw)
|
||||||
|
if not error:
|
||||||
|
# Update main profile
|
||||||
|
new_values = self._get_page_saving_bank_account_values(kw)
|
||||||
|
bank_account.sudo().write(new_values)
|
||||||
|
if redirect:
|
||||||
|
return request.redirect(redirect)
|
||||||
|
return request.redirect("/my/bank_accounts")
|
||||||
|
|
||||||
|
# This is just the form page opening. We send all the data needed for the form fields
|
||||||
|
can_edit_bank_account = user.partner_id == bank_account.partner_id
|
||||||
|
banks = request.env["res.bank"].sudo().search([])
|
||||||
|
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"bank_account_id": bank_account_id, # Sent in order to retrieve it at submit time
|
||||||
|
"can_edit_bank_account": can_edit_bank_account,
|
||||||
|
"banks": banks,
|
||||||
|
"redirect": "/my/bank_account/" + str(bank_account_id) + "?success=True"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return request.render("partner_bank_account_portal.portal_my_bank_account", values) #TODO créer le template portal_my_bank_account.xml
|
@@ -0,0 +1,92 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from odoo import http, _
|
||||||
|
from odoo.osv import expression
|
||||||
|
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
|
||||||
|
from odoo.exceptions import AccessError, MissingError
|
||||||
|
from collections import OrderedDict
|
||||||
|
from odoo.http import request
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerPortalBankAccounts(CustomerPortal):
|
||||||
|
|
||||||
|
def _prepare_home_portal_values(self, counters):
|
||||||
|
values = super()._prepare_home_portal_values(counters)
|
||||||
|
if 'bank_account_count' in counters:
|
||||||
|
bank_account_count = request.env['res.partner.bank'].search_count([])
|
||||||
|
values['bank_account_count'] = bank_account_count
|
||||||
|
return values
|
||||||
|
|
||||||
|
def _get_account_searchbar_sortings(self):
|
||||||
|
res = super()._get_account_searchbar_sortings()
|
||||||
|
res['acc_number'] = {'label': _('IBAN'), 'order': 'acc_number'}
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@http.route(['/my/bank_accounts', '/my/bank_accounts/page/<int:page>'], type='http', auth="user", website=True)
|
||||||
|
def portal_my_bank_accounts(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, **kw):
|
||||||
|
values = self._prepare_my_bank_accounts_values(page, date_begin, date_end, sortby, filterby)
|
||||||
|
|
||||||
|
# pager
|
||||||
|
pager = portal_pager(**values['pager'])
|
||||||
|
|
||||||
|
# content according to pager and archive selected
|
||||||
|
bank_accounts = values['bank_accounts'](pager['offset'])
|
||||||
|
request.session['bank_accounts_history'] = bank_accounts.ids[:100]
|
||||||
|
|
||||||
|
values.update({
|
||||||
|
'bank_accounts': bank_accounts,
|
||||||
|
'pager': pager,
|
||||||
|
})
|
||||||
|
return request.render("partner_bank_account_portal.portal_my_bank_accounts", values)
|
||||||
|
|
||||||
|
def _get_bank_accounts_domain(self):
|
||||||
|
return [('active', '=', True)]
|
||||||
|
|
||||||
|
|
||||||
|
def _prepare_my_bank_accounts_values(self, page, date_begin, date_end, sortby, filterby, domain=None, url="/my/bank_accounts"):
|
||||||
|
values = self._prepare_portal_layout_values()
|
||||||
|
res_partner_bank = request.env['res.partner.bank']
|
||||||
|
|
||||||
|
domain = expression.AND([
|
||||||
|
domain or [],
|
||||||
|
self._get_bank_accounts_domain(),
|
||||||
|
])
|
||||||
|
|
||||||
|
searchbar_sortings = self._get_account_searchbar_sortings()
|
||||||
|
# default sort by order
|
||||||
|
if not sortby:
|
||||||
|
sortby = 'acc_number'
|
||||||
|
order = searchbar_sortings[sortby]['order']
|
||||||
|
|
||||||
|
# default filter by value
|
||||||
|
if not filterby:
|
||||||
|
filterby = 'all'
|
||||||
|
|
||||||
|
if date_begin and date_end:
|
||||||
|
domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]
|
||||||
|
|
||||||
|
values.update({
|
||||||
|
'date': date_begin,
|
||||||
|
# content according to pager and archive selected
|
||||||
|
# lambda function to get the invoices recordset when the pager will be defined in the main method of a route
|
||||||
|
'bank_accounts': lambda pager_offset: (
|
||||||
|
res_partner_bank.search(domain, order=order, limit=self._items_per_page, offset=pager_offset)
|
||||||
|
if res_partner_bank.check_access_rights('read', raise_exception=False) else
|
||||||
|
res_partner_bank
|
||||||
|
),
|
||||||
|
'page_name': 'bank_accounts',
|
||||||
|
'pager': { # vals to define the pager.
|
||||||
|
"url": url,
|
||||||
|
"url_args": {'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby},
|
||||||
|
"total": res_partner_bank.search_count(domain) if res_partner_bank.check_access_rights('read', raise_exception=False) else 0,
|
||||||
|
"page": page,
|
||||||
|
"step": self._items_per_page,
|
||||||
|
},
|
||||||
|
'default_url': url,
|
||||||
|
'sortby': sortby,
|
||||||
|
'filterby': filterby,
|
||||||
|
})
|
||||||
|
return values
|
152
partner_bank_account_portal/controllers/portal_my_mandate.py
Normal file
152
partner_bank_account_portal/controllers/portal_my_mandate.py
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
# Copyright 2020 Lokavaluto ()
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
import base64
|
||||||
|
from odoo import http, tools, _
|
||||||
|
from odoo.exceptions import AccessError, MissingError
|
||||||
|
from odoo.http import request
|
||||||
|
from odoo.addons.portal.controllers.portal import CustomerPortal
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerPortalMandate(CustomerPortal):
|
||||||
|
|
||||||
|
def _mandate_get_page_view_values(self, mandate, access_token, **kwargs):
|
||||||
|
values = {
|
||||||
|
"page_name": "mandate",
|
||||||
|
"mandate": mandate,
|
||||||
|
}
|
||||||
|
return self._get_page_view_values(
|
||||||
|
mandate, access_token, values, "my_mandates_history", False, **kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
def _details_mandate_form_validate(self, data, mandate_id):
|
||||||
|
error = dict()
|
||||||
|
error_message = []
|
||||||
|
# public name uniqueness
|
||||||
|
if data.get("public_name") and request.env["res.partner"].sudo().search(
|
||||||
|
[
|
||||||
|
("name", "=", data.get("public_name")),
|
||||||
|
("is_public_profile", "=", True),
|
||||||
|
("contact_id", "!=", mandate_id),
|
||||||
|
]
|
||||||
|
):
|
||||||
|
error["public_name"] = "error"
|
||||||
|
error_message.append(
|
||||||
|
_("This public name is already used, please find an other idea.")
|
||||||
|
)
|
||||||
|
|
||||||
|
# email validation
|
||||||
|
if data.get("email") and not tools.single_email_re.match(data.get("email")):
|
||||||
|
error["email"] = "error"
|
||||||
|
error_message.append(
|
||||||
|
_("Invalid Email! Please enter a valid email address.")
|
||||||
|
)
|
||||||
|
return error, error_message
|
||||||
|
|
||||||
|
def _get_mandate_fields(self):
|
||||||
|
fields = [
|
||||||
|
"unique_mandate_reference",
|
||||||
|
"signature_date",
|
||||||
|
"last_debit_date",
|
||||||
|
"state",
|
||||||
|
]
|
||||||
|
return fields
|
||||||
|
|
||||||
|
def _get_main_boolean_mandate_fields(self):
|
||||||
|
'''Provides the fields for which we must check the presence
|
||||||
|
in form's kw to know the value to save in the partner field.
|
||||||
|
All of them MUST start with "main_".'''
|
||||||
|
fields = []
|
||||||
|
return fields
|
||||||
|
|
||||||
|
def _transform_in_res_partner_fields(self, kw, mandate_fields, prefix=""):
|
||||||
|
'''Transforms kw's values in res_partner fields and values'''
|
||||||
|
return {key[len(prefix):]: kw[key] for key in mandate_fields if key in kw}
|
||||||
|
|
||||||
|
def _add_boolean_values(self, values, kw, boolean_fields, prefix=""):
|
||||||
|
for key in boolean_fields:
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
key[len(prefix):]: kw.get(key, "off") == "on",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return values
|
||||||
|
|
||||||
|
def _get_page_saving_mandate_values(self, kw):
|
||||||
|
mandate_fields = self._get_mandate_fields()
|
||||||
|
values = self._transform_in_res_partner_fields(kw, mandate_fields)
|
||||||
|
# boolean_fields = self._get_main_boolean_bank_account_fields()
|
||||||
|
# values = self._add_boolean_values(values, kw, boolean_fields)
|
||||||
|
return values
|
||||||
|
|
||||||
|
def _get_page_opening_values(self):
|
||||||
|
# Just retrieve the values to display for Selection fields
|
||||||
|
countries = request.env["res.country"].sudo().search([])
|
||||||
|
values = {
|
||||||
|
"countries": countries,
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
|
||||||
|
@http.route(
|
||||||
|
["/my/mandate/<int:mandate_id>", "/my/mandate/save"],
|
||||||
|
type="http",
|
||||||
|
auth="user",
|
||||||
|
website=True,
|
||||||
|
)
|
||||||
|
def portal_my_mandate(
|
||||||
|
self,mandate_id=None, access_token=None, redirect=None, **kw
|
||||||
|
):
|
||||||
|
# The following condition is to transform profile_id to an int, as it is sent as a string from the templace "portal_my_profile"
|
||||||
|
# TODO: find a better way to retrieve the profile_id at form submit step
|
||||||
|
if not isinstance(mandate_id, int):
|
||||||
|
mandate_id = int(mandate_id)
|
||||||
|
|
||||||
|
# Check that the user has the right to see this profile
|
||||||
|
try:
|
||||||
|
mandate_sudo = self._document_check_access(
|
||||||
|
"account.banking.mandate", mandate_id, access_token
|
||||||
|
)
|
||||||
|
except (AccessError, MissingError):
|
||||||
|
return request.redirect("/my/mandates")
|
||||||
|
|
||||||
|
Mandate = request.env["account.banking.mandate"]
|
||||||
|
user = request.env.user
|
||||||
|
mandate = Mandate.browse(mandate_id)
|
||||||
|
|
||||||
|
values = self._mandate_get_page_view_values(mandate_sudo, access_token, **kw)
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"error": {},
|
||||||
|
"error_message": [],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if kw and request.httprequest.method == "POST":
|
||||||
|
# the user has clicked in the Save button to save new data
|
||||||
|
error, error_message = self._details_mandate_form_validate(kw, mandate_id)
|
||||||
|
values.update({"error": error, "error_message": error_message})
|
||||||
|
values.update(kw)
|
||||||
|
if not error:
|
||||||
|
# Update main profile
|
||||||
|
new_values = self._get_page_saving_mandate_values(kw)
|
||||||
|
mandate.sudo().write(new_values)
|
||||||
|
# Update public profile
|
||||||
|
# new_values = self._get_page_saving_public_structure_values(kw)
|
||||||
|
# public_profile.sudo().write(new_values)
|
||||||
|
# Update position profile
|
||||||
|
# new_values = self._get_page_saving_position_structure_values(kw)
|
||||||
|
# position_profile.sudo().write(new_values)
|
||||||
|
# End of updates
|
||||||
|
if redirect:
|
||||||
|
return request.redirect(redirect)
|
||||||
|
return request.redirect("/my/mandates")
|
||||||
|
|
||||||
|
# This is just the form page opening. We send all the data needed for the form fields
|
||||||
|
can_edit_mandate = user.partner_id == mandate.partner_id
|
||||||
|
values.update(self._get_page_opening_values())
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"mandate_id": mandate_id, # Sent in order to retrieve it at submit time
|
||||||
|
"can_edit_mandate": can_edit_mandate,
|
||||||
|
"redirect": "/my/mandate/" + str(mandate_id) + "?success=True"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return request.render("partner_bank_account_portal.portal_my_mandate", values) #TODO créer le template portal_my_bank_account.xml
|
@@ -0,0 +1,72 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from odoo import http, _
|
||||||
|
from odoo.osv import expression
|
||||||
|
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
|
||||||
|
from odoo.exceptions import AccessError, MissingError
|
||||||
|
from collections import OrderedDict
|
||||||
|
from odoo.http import request
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerPortalMandates(CustomerPortal):
|
||||||
|
|
||||||
|
def _prepare_home_portal_values(self, counters):
|
||||||
|
values = super()._prepare_home_portal_values(counters)
|
||||||
|
if 'mandate_count' in counters:
|
||||||
|
mandate_count = request.env['account.banking.mandate'].search_count([])
|
||||||
|
values['mandate_count'] = mandate_count
|
||||||
|
return values
|
||||||
|
|
||||||
|
@http.route(['/my/mandates', '/my/mandates/page/<int:page>'], type='http', auth="user", website=True)
|
||||||
|
def portal_mandates(self, page=1, date_begin=None, date_end=None, filterby=None, **kw):
|
||||||
|
values = self._prepare_my_mandates_values(page, date_begin, date_end)
|
||||||
|
|
||||||
|
# pager
|
||||||
|
pager = portal_pager(**values['pager'])
|
||||||
|
|
||||||
|
# content according to pager and archive selected
|
||||||
|
mandates = values['mandates'](pager['offset'])
|
||||||
|
request.session['mandates_history'] = mandates.ids[:100]
|
||||||
|
|
||||||
|
values.update({
|
||||||
|
'mandates': mandates,
|
||||||
|
'pager': pager,
|
||||||
|
})
|
||||||
|
return request.render("partner_bank_account_portal.portal_my_mandates", values)
|
||||||
|
|
||||||
|
def _get_mandate_domain(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def _prepare_my_mandates_values(self, page, date_begin, date_end, domain=None, url="/my/mandates"):
|
||||||
|
values = self._prepare_portal_layout_values()
|
||||||
|
Mandate = request.env['account.banking.mandate']
|
||||||
|
|
||||||
|
domain = expression.AND([
|
||||||
|
domain or [],
|
||||||
|
self._get_mandate_domain(),
|
||||||
|
])
|
||||||
|
|
||||||
|
if date_begin and date_end:
|
||||||
|
domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]
|
||||||
|
|
||||||
|
values.update({
|
||||||
|
'date': date_begin,
|
||||||
|
# content according to pager and archive selected
|
||||||
|
# lambda function to get the invoices recordset when the pager will be defined in the main method of a route
|
||||||
|
'mandates': lambda pager_offset: (
|
||||||
|
Mandate.search(domain, limit=self._items_per_page, offset=pager_offset)
|
||||||
|
if Mandate.check_access_rights('read', raise_exception=False) else
|
||||||
|
Mandate
|
||||||
|
),
|
||||||
|
'page_name': 'mandates',
|
||||||
|
'pager': { # vals to define the pager.
|
||||||
|
"url": url,
|
||||||
|
"url_args": {'date_begin': date_begin, 'date_end': date_end},
|
||||||
|
"total": Mandate.search_count(domain) if Mandate.check_access_rights('read', raise_exception=False) else 0,
|
||||||
|
"page": page,
|
||||||
|
"step": self._items_per_page,
|
||||||
|
},
|
||||||
|
'default_url': url,
|
||||||
|
})
|
||||||
|
return values
|
192
partner_bank_account_portal/i18n/fr.po
Normal file
192
partner_bank_account_portal/i18n/fr.po
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * partner_bank_account_portal
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 16.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2024-08-05 13:58+0000\n"
|
||||||
|
"PO-Revision-Date: 2024-08-05 13:58+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_accounts
|
||||||
|
msgid "1 registration"
|
||||||
|
msgstr "1 enregistrement"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_account
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandate
|
||||||
|
msgid "<i class=\"fa fa-fw fa-check-circle\"/> Data saved!"
|
||||||
|
msgstr "Données enregistrées!"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_account
|
||||||
|
msgid "<span class=\"fa fa-arrow-left\"/> Back to my bank accounts list"
|
||||||
|
msgstr "<span class=\"fa fa-arrow-left\"/> Retour à la liste des comptes bancaires"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandate
|
||||||
|
msgid "<span class=\"fa fa-arrow-left\"/> Back to my mandates list"
|
||||||
|
msgstr "<span class=\"fa fa-arrow-left\"/> Retour à la liste des mandats"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandates
|
||||||
|
msgid "Associed IBAN"
|
||||||
|
msgstr "IBAN associé"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model:ir.model.fields,field_description:partner_bank_account_portal.field_account_setup_bank_manual_config__associated_mandate_count
|
||||||
|
#: model:ir.model.fields,field_description:partner_bank_account_portal.field_res_partner_bank__associated_mandate_count
|
||||||
|
msgid "Associated mandate count"
|
||||||
|
msgstr "Décompte de mandats associés au compte bancaire"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model:ir.model,name:partner_bank_account_portal.model_res_partner_bank
|
||||||
|
msgid "Bank Accounts"
|
||||||
|
msgstr "Comptes bancaires"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_accounts
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_home_bank_accounts
|
||||||
|
msgid "Bank accounts"
|
||||||
|
msgstr "Comptes bancaires"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_accounts
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandates
|
||||||
|
msgid "Contact name"
|
||||||
|
msgstr "Nom du contact"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_account
|
||||||
|
msgid "Contact name:"
|
||||||
|
msgstr "Nom du contact : "
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandates
|
||||||
|
msgid "Format"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandate
|
||||||
|
msgid "Format :"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/partner_bank_account_portal/controllers/portal_my_bank_accounts.py:0
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_accounts
|
||||||
|
#, python-format
|
||||||
|
msgid "IBAN"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_account
|
||||||
|
msgid "IBAN :"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/partner_bank_account_portal/controllers/portal_my_bank_account.py:0
|
||||||
|
#: code:addons/partner_bank_account_portal/controllers/portal_my_mandate.py:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Invalid Email! Please enter a valid email address."
|
||||||
|
msgstr "Email invalide ! Entrez une adresse email valide."
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandates
|
||||||
|
msgid "Last debit date"
|
||||||
|
msgstr "Date du dernier débit"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_home_bank_accounts
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_home_menu_contract
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandates
|
||||||
|
msgid "Mandates"
|
||||||
|
msgstr "Mandats"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_account
|
||||||
|
msgid "My bank account Details"
|
||||||
|
msgstr "Détails du compte bancaire"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandate
|
||||||
|
msgid "My mandate details"
|
||||||
|
msgstr "Details du mandat"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_accounts
|
||||||
|
msgid "Name of IBAN holder if different"
|
||||||
|
msgstr "Nom du titulaire de l'IBAN si différent :"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_account
|
||||||
|
msgid "Name of IBAN holder if different :"
|
||||||
|
msgstr "Nom du titulaire de l'IBAN si différent :"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_accounts
|
||||||
|
msgid "No registrations"
|
||||||
|
msgstr "Pas d'enregistrement"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_accounts
|
||||||
|
msgid "Number of associated mandates"
|
||||||
|
msgstr "Nombre de mandats associés"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandates
|
||||||
|
msgid "Reference"
|
||||||
|
msgstr "Référence"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandate
|
||||||
|
msgid "Reference :"
|
||||||
|
msgstr "Référence :"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_account
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandate
|
||||||
|
msgid "Save"
|
||||||
|
msgstr "Enregistrer"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandates
|
||||||
|
msgid "Signature date"
|
||||||
|
msgstr "Date de signature"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandates
|
||||||
|
msgid "Status"
|
||||||
|
msgstr "Statut"
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_accounts
|
||||||
|
msgid "There are currently no bank accounts for your account."
|
||||||
|
msgstr "Aucun compte bancaire n'est accessible depuis votre compte."
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_mandates
|
||||||
|
msgid "There are currently no mandates for your account."
|
||||||
|
msgstr "Aucun mandat n'est accessible depuis votre compte."
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/partner_bank_account_portal/controllers/portal_my_bank_account.py:0
|
||||||
|
#: code:addons/partner_bank_account_portal/controllers/portal_my_mandate.py:0
|
||||||
|
#, python-format
|
||||||
|
msgid "This public name is already used, please find an other idea."
|
||||||
|
msgstr "Ce nom est déjà utilisé, veuillez trouver un autre nom."
|
||||||
|
|
||||||
|
#. module: partner_bank_account_portal
|
||||||
|
#: model_terms:ir.ui.view,arch_db:partner_bank_account_portal.portal_my_bank_accounts
|
||||||
|
msgid "records"
|
||||||
|
msgstr "enregistrements"
|
2
partner_bank_account_portal/models/__init__.py
Normal file
2
partner_bank_account_portal/models/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
from . import res_partner_bank
|
17
partner_bank_account_portal/models/res_partner_bank.py
Normal file
17
partner_bank_account_portal/models/res_partner_bank.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Copyright 2022 Elabore (https://elabore.coop)
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import fields, models
|
||||||
|
|
||||||
|
class res_partner_bank(models.Model):
|
||||||
|
_inherit = "res.partner.bank"
|
||||||
|
|
||||||
|
#count all mandate linked to the IBAN, even draft or canceled mandates
|
||||||
|
associated_mandate_count = fields.Integer("Associated mandate count", compute="_compute_associated_mandate_count")
|
||||||
|
|
||||||
|
def _compute_associated_mandate_count(self):
|
||||||
|
for record in self:
|
||||||
|
count = self.env["account.banking.mandate"].search_count(
|
||||||
|
[("partner_bank_id", "=", record.id)]
|
||||||
|
)
|
||||||
|
record.associated_mandate_count = count
|
4
partner_bank_account_portal/security/ir.model.access.csv
Normal file
4
partner_bank_account_portal/security/ir.model.access.csv
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
"access_res_partner_bank_group_portal","res_partner_bank group_portal","base.model_res_partner_bank","base.group_portal",1,0,0,0
|
||||||
|
"access_res_bank_group_portal","res_bank group_portal","base.model_res_bank","base.group_portal",1,0,0,0
|
||||||
|
"access_account_banking_mandate_group_portal","account_banking_mandate group_portal","account_banking_mandate.model_account_banking_mandate","base.group_portal",1,0,0,0
|
|
34
partner_bank_account_portal/security/members_security.xml
Normal file
34
partner_bank_account_portal/security/members_security.xml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record model="ir.rule" id="res_partner_portal_members_bank_accounts_read_rule">
|
||||||
|
<field name="name">res_partner: portal: read access on my bank accounts</field>
|
||||||
|
<field name="model_id" ref="base.model_res_partner_bank" />
|
||||||
|
<field name="domain_force">[('partner_id', '=', user.partner_id.id)]</field>
|
||||||
|
<field name="groups" eval="[(4, ref('base.group_portal'))]" />
|
||||||
|
<field name="perm_read" eval="True" />
|
||||||
|
<field name="perm_write" eval="False" />
|
||||||
|
<field name="perm_create" eval="False" />
|
||||||
|
<field name="perm_unlink" eval="False" />
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.rule" id="res_partner_portal_bank_read_rule">
|
||||||
|
<field name="name">res_partner: portal: read access on my banks</field>
|
||||||
|
<field name="model_id" ref="base.model_res_bank" />
|
||||||
|
<field name="groups" eval="[(4, ref('base.group_portal'))]" />
|
||||||
|
<field name="perm_read" eval="True" />
|
||||||
|
<field name="perm_write" eval="False" />
|
||||||
|
<field name="perm_create" eval="False" />
|
||||||
|
<field name="perm_unlink" eval="False" />
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.rule" id="res_partner_portal_mandate_read_rule">
|
||||||
|
<field name="name">res_partner: portal: read access on my mandates</field>
|
||||||
|
<field name="model_id" ref="account_banking_mandate.model_account_banking_mandate" />
|
||||||
|
<field name="domain_force">[('partner_id', '=', user.partner_id.id)]</field>
|
||||||
|
<field name="groups" eval="[(4, ref('base.group_portal'))]" />
|
||||||
|
<field name="perm_read" eval="True" />
|
||||||
|
<field name="perm_write" eval="False" />
|
||||||
|
<field name="perm_create" eval="False" />
|
||||||
|
<field name="perm_unlink" eval="False" />
|
||||||
|
</record>
|
||||||
|
</odoo>
|
@@ -0,0 +1,82 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<template id="portal_my_bank_account" name="Bank account details">
|
||||||
|
<t t-call="portal.portal_layout">
|
||||||
|
<t t-set="additional_title">My bank account Details</t>
|
||||||
|
<form action="/my/bank_account/save" method="post" enctype="multipart/form-data">
|
||||||
|
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
|
||||||
|
<div class="row o_portal_details">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<br />
|
||||||
|
<div t-if="success" class="alert alert-success py-1 mb-2">
|
||||||
|
<i class="fa fa-fw fa-check-circle" /> Data saved! </div>
|
||||||
|
<div t-if="error_message" role="alert" class="col-lg-12 alert alert-danger">
|
||||||
|
<t t-foreach="error_message" t-as="err">
|
||||||
|
<t t-out="err" />
|
||||||
|
<br />
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div id="iban"
|
||||||
|
t-attf-class="form-group #{error.get('acc_number') and 'o_has_error' or ''} col-xl-12">
|
||||||
|
<label class="col-form-label" for="acc_number">IBAN : </label>
|
||||||
|
<label class="text-danger"> *</label>
|
||||||
|
<input t-if="can_edit_bank_account" type="text" name="acc_number"
|
||||||
|
required="True"
|
||||||
|
t-attf-class="form-control #{error.get('acc_number') and 'is-invalid' or ''}"
|
||||||
|
t-att-value="acc_number or bank_account.acc_number" />
|
||||||
|
<span t-if="not can_edit_bank_account" t-field="bank_account.acc_number" />
|
||||||
|
</div>
|
||||||
|
<div id="partner_id"
|
||||||
|
t-attf-class="form-group #{error.get('partner_id') and 'o_has_error' or ''} col-xl-12">
|
||||||
|
<label class="col-form-label" for="partner_id">Contact name: </label>
|
||||||
|
<input t-if="can_edit_bank_account" type="text" name="partner_id"
|
||||||
|
required="False"
|
||||||
|
readonly="True"
|
||||||
|
t-attf-class="form-control #{error.get('partner_id') and 'is-invalid' or ''}"
|
||||||
|
t-att-value="partner_id or bank_account.partner_id.name" />
|
||||||
|
<span t-if="not can_edit_bank_account" t-field="bank_account.partner_id.name" />
|
||||||
|
</div>
|
||||||
|
<div id="iban_holder_name_if_different"
|
||||||
|
t-attf-class="form-group #{error.get('acc_holder_name') and 'o_has_error' or ''} col-xl-12">
|
||||||
|
<label class="col-form-label" for="bank_id">Name of IBAN holder if different : </label>
|
||||||
|
<input t-if="can_edit_bank_account" type="text" name="acc_holder_name"
|
||||||
|
t-attf-class="form-control #{error.get('acc_holder_name') and 'is-invalid' or ''}"
|
||||||
|
t-att-value="acc_holder_name or bank_account.acc_holder_name" />
|
||||||
|
<span t-if="not can_edit_bank_account" t-field="bank_account.acc_holder_name" />
|
||||||
|
</div>
|
||||||
|
<div id="bank_id"
|
||||||
|
t-attf-class="form-group #{error.get('bank_id') and 'o_has_error' or ''} col-xl-12">
|
||||||
|
<label class="col-form-label" for="bank_id">Banque name : </label>
|
||||||
|
<select t-if="can_edit_bank_account" type="text" name="bank_id"
|
||||||
|
t-attf-class="form-control #{error.get('bank_id') and 'is-invalid' or ''}">
|
||||||
|
<option value="">My bank is not in the list</option>
|
||||||
|
<t t-foreach="banks or []" t-as="bank">
|
||||||
|
<option t-att-value="bank.id" t-att-selected="bank.id == bank_account.bank_id.id">
|
||||||
|
<t t-esc="bank.name" />
|
||||||
|
</option>
|
||||||
|
</t>
|
||||||
|
</select>
|
||||||
|
<span t-if="not can_edit_bank_account" t-field="bank_account.acc_holder_name" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<input type="hidden" name="bank_account_id" t-att-value="bank_account_id" />
|
||||||
|
<input type="hidden" name="redirect" t-att-value="redirect" />
|
||||||
|
<div style="text-align:right;">
|
||||||
|
<button type="submit"
|
||||||
|
class="btn btn-primary ">Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div style="text-align:right">
|
||||||
|
<br />
|
||||||
|
<a href="/my/bank_accounts">
|
||||||
|
<span class="fa fa-arrow-left" /> Back to my bank accounts list </a>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
</odoo>
|
@@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<template id="portal_my_bank_accounts" name="My bank accounts">
|
||||||
|
<t t-call="portal.portal_layout">
|
||||||
|
<t t-set="breadcrumbs_searchbar" t-value="True" />
|
||||||
|
|
||||||
|
<t t-call="portal.portal_searchbar">
|
||||||
|
<t t-set="title">Bank accounts</t>
|
||||||
|
</t>
|
||||||
|
<t t-if="not bank_accounts">
|
||||||
|
<p>There are currently no bank accounts for your account.</p>
|
||||||
|
</t>
|
||||||
|
<t t-if="bank_accounts" t-call="portal.portal_table">
|
||||||
|
<thead>
|
||||||
|
<tr class="active">
|
||||||
|
<th>IBAN</th>
|
||||||
|
<th>Contact name</th>
|
||||||
|
<th>Name of IBAN holder if different</th>
|
||||||
|
<th>Number of associated mandates</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<t t-foreach="bank_accounts" t-as="bank_account">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a
|
||||||
|
t-attf-href="/my/bank_account/#{bank_account.id}?{{ keep_query() }}">
|
||||||
|
<span t-field="bank_account.acc_number" />
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-field="bank_account.partner_id.name" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-field="bank_account.acc_holder_name" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<t t-if="bank_account.associated_mandate_count == 0">
|
||||||
|
No registrations
|
||||||
|
</t>
|
||||||
|
<t t-if="bank_account.associated_mandate_count == 1">
|
||||||
|
1 registration
|
||||||
|
</t>
|
||||||
|
<t t-if="bank_account.associated_mandate_count > 1">
|
||||||
|
<t t-esc="bank_account.associated_mandate_count" />
|
||||||
|
records </t>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</t>
|
||||||
|
</tbody>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
</odoo>
|
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<template id="portal_contract_page_inherit_mandate" name="My Contract inherit mandate"
|
||||||
|
inherit_id="contract.portal_contract_page" customize_show="True" priority="100">
|
||||||
|
<xpath expr="//div[@id='product_information']/div" position="inside">
|
||||||
|
<div t-if="contract.mandate_id" class="row mb-2 mb-sm-1">
|
||||||
|
<div class="col-12 col-sm-4">
|
||||||
|
<strong>Direct Debit Mandate</strong>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-sm-8">
|
||||||
|
<span
|
||||||
|
t-field="contract.mandate_id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
</odoo>
|
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<template
|
||||||
|
id="portal_my_home_menu_contract"
|
||||||
|
name="Portal layout : Mandate menu entries"
|
||||||
|
inherit_id="portal.portal_breadcrumbs"
|
||||||
|
priority="35"
|
||||||
|
>
|
||||||
|
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
|
||||||
|
<li
|
||||||
|
t-if="page_name == 'Mandates'"
|
||||||
|
t-attf-class="breadcrumb-item #{'active ' if not contract else ''}"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
t-if="mandate"
|
||||||
|
t-attf-href="/my/mandates?{{ keep_query() }}"
|
||||||
|
>Mandates</a>
|
||||||
|
<t t-else="">Mandates</t>
|
||||||
|
</li>
|
||||||
|
<li t-if="mandate" class="breadcrumb-item active">
|
||||||
|
<t t-esc="mandate.reference" />
|
||||||
|
</li>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
<template id="portal_my_home_bank_accounts" name="Bank accounts"
|
||||||
|
inherit_id="portal.portal_my_home" customize_show="True" priority="100">
|
||||||
|
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
|
||||||
|
<t t-call="portal.portal_docs_entry">
|
||||||
|
<t t-set="title">Bank accounts</t>
|
||||||
|
<t t-set="url" t-value="'/my/bank_accounts'" />
|
||||||
|
<t t-set="placeholder_count" t-value="'bank_account_count'" />
|
||||||
|
</t>
|
||||||
|
<t t-call="portal.portal_docs_entry">
|
||||||
|
<t t-set="title">Mandates</t>
|
||||||
|
<t t-set="url" t-value="'/my/mandates'" />
|
||||||
|
<t t-set="placeholder_count" t-value="'mandate_count'"/>
|
||||||
|
</t>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</odoo>
|
@@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<template id="portal_my_mandate" name="Mandate details">
|
||||||
|
<t t-call="portal.portal_layout">
|
||||||
|
<t t-set="additional_title">My mandate details</t>
|
||||||
|
<form action="/my/mandate/save" method="post" enctype="multipart/form-data">
|
||||||
|
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
|
||||||
|
<div class="row o_portal_details">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<br />
|
||||||
|
<div t-if="success" class="alert alert-success py-1 mb-2">
|
||||||
|
<i class="fa fa-fw fa-check-circle" /> Data saved! </div>
|
||||||
|
<div t-if="error_message" role="alert" class="col-lg-12 alert alert-danger">
|
||||||
|
<t t-foreach="error_message" t-as="err">
|
||||||
|
<t t-out="err" />
|
||||||
|
<br />
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div id="reference"
|
||||||
|
t-attf-class="form-group #{error.get('unique_mandate_reference') and 'o_has_error' or ''} col-xl-12">
|
||||||
|
<label class="col-form-label" for="unique_mandate_reference">Reference : </label>
|
||||||
|
<label class="text-danger"> *</label>
|
||||||
|
<input t-if="can_edit_mandate" type="text" name="unique_mandate_reference"
|
||||||
|
required="True"
|
||||||
|
t-attf-class="form-control #{error.get('unique_mandate_reference') and 'is-invalid' or ''}"
|
||||||
|
t-att-value="unique_mandate_reference or mandate.unique_mandate_reference" />
|
||||||
|
<span t-if="not can_edit_mandate" t-field="mandate.unique_mandate_reference" />
|
||||||
|
</div>
|
||||||
|
<div id="format"
|
||||||
|
t-attf-class="form-group #{error.get('format') and 'o_has_error' or ''} col-xl-12">
|
||||||
|
<label class="col-form-label" for="format">Format : </label>
|
||||||
|
<label class="text-danger"> *</label>
|
||||||
|
<input t-if="can_edit_mandate" type="text" name="format"
|
||||||
|
required="True"
|
||||||
|
t-attf-class="form-control #{error.get('format') and 'is-invalid' or ''}"
|
||||||
|
t-att-value="format or mandate.format" />
|
||||||
|
<span t-if="not can_edit_mandate" t-field="mandate.format" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<input type="hidden" name="mandate_id" t-att-value="mandate_id" />
|
||||||
|
<input type="hidden" name="redirect" t-att-value="redirect" />
|
||||||
|
<div style="text-align:right;">
|
||||||
|
<button type="submit"
|
||||||
|
class="btn btn-primary ">Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div style="text-align:right">
|
||||||
|
<br />
|
||||||
|
<a href="/my/mandates">
|
||||||
|
<span class="fa fa-arrow-left" /> Back to my mandates list </a>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
</odoo>
|
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<template id="portal_my_mandates" name="My mandates">
|
||||||
|
<t t-call="portal.portal_layout">
|
||||||
|
<t t-set="breadcrumbs_searchbar" t-value="True" />
|
||||||
|
|
||||||
|
<t t-call="portal.portal_searchbar">
|
||||||
|
<t t-set="title">Mandates</t>
|
||||||
|
</t>
|
||||||
|
<t t-if="not mandates">
|
||||||
|
<p>There are currently no mandates for your account.</p>
|
||||||
|
</t>
|
||||||
|
<t t-if="mandates" t-call="portal.portal_table">
|
||||||
|
<thead>
|
||||||
|
<tr class="active">
|
||||||
|
<th>Reference</th>
|
||||||
|
<th>Format</th>
|
||||||
|
<th>Contact name</th>
|
||||||
|
<th>Signature date</th>
|
||||||
|
<th>Last debit date</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Associed IBAN</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<t t-foreach="mandates" t-as="mandate">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span t-field="mandate.unique_mandate_reference" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-field="mandate.format" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-field="mandate.partner_id" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-field="mandate.last_debit_date" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-field="mandate.signature_date" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-field="mandate.state" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a t-attf-href="/my/bank_account/#{mandate.partner_bank_id.id}?{{ keep_query() }}">
|
||||||
|
<span t-field="mandate.partner_bank_id.acc_number" />
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</t>
|
||||||
|
</tbody>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
</odoo>
|
Reference in New Issue
Block a user