Browse Source

Merge pull request #52 from coopiteasy/12.0-migration-emc-website-portal

[MIG] migrate module. comply with new portal.
pull/56/head
Houssine BAKKALI 4 years ago
committed by GitHub
parent
commit
8aedeecd11
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 351
      easy_my_coop/models/partner.py
  2. 13
      easy_my_coop_website/views/subscription_template.xml
  3. 12
      easy_my_coop_website_portal/__manifest__.py
  4. 191
      easy_my_coop_website_portal/controllers/main.py
  5. 218
      easy_my_coop_website_portal/views/easy_my_coop_website_portal_templates.xml
  6. 2
      website_portal_extend/__init__.py
  7. 31
      website_portal_extend/__openerp__.py
  8. 2
      website_portal_extend/controllers/__init__.py
  9. 188
      website_portal_extend/controllers/main.py
  10. 117
      website_portal_extend/views/portal_website_templates.xml

351
easy_my_coop/models/partner.py

@ -1,170 +1,181 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Coop IT Easy SCRL fs
# Houssine Bakkali <houssine@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
@api.multi
def _invoice_total(self):
account_invoice_report = self.env['account.invoice.report']
if not self.ids:
self.total_invoiced = 0.0
return True
all_partners_and_children = {}
all_partner_ids = []
for partner in self:
# price_total is in the company currency
all_partners_and_children[partner] = self.search([('id', 'child_of', partner.id)]).ids
all_partner_ids += all_partners_and_children[partner]
# searching account.invoice.report via the orm is comparatively
# expensive (generates queries "id in []" forcing to build the
# full table).
# In simple cases where all invoices are in the same currency than
# the user's company access directly these elements
# generate where clause to include multicompany rules
where_query = account_invoice_report._where_calc([
('partner_id', 'in', all_partner_ids),
('state', 'not in', ['draft', 'cancel']),
('company_id', '=', self.env.user.company_id.id),
('type', 'in', ('out_invoice', 'out_refund')),
('release_capital_request', '=', False),
])
account_invoice_report._apply_ir_rules(where_query, 'read')
from_clause, where_clause, where_clause_params = where_query.get_sql()
# price_total is in the company currency
query = """
SELECT SUM(price_total) as total, partner_id
FROM account_invoice_report account_invoice_report
WHERE %s
GROUP BY partner_id
""" % where_clause
self.env.cr.execute(query, where_clause_params)
price_totals = self.env.cr.dictfetchall()
for partner, child_ids in all_partners_and_children.items():
partner.total_invoiced = sum(price['total'] for price in price_totals if price['partner_id'] in child_ids)
@api.multi
@api.depends('share_ids')
def _compute_effective_date(self):
# TODO change it to compute it from the share register
for partner in self:
if partner.share_ids:
partner.effective_date = partner.share_ids[0].effective_date
@api.multi
def _get_share_type(self):
shares = (
self.env['product.product']
.search([('is_share', '=', True)])
)
share_types = [(share.default_code, share.short_name) for share in shares]
return [('', '')] + share_types
@api.multi
@api.depends('share_ids')
def _compute_cooperator_type(self):
for partner in self:
share_type = ''
for line in partner.share_ids:
share_type = line.share_product_id.default_code
if share_type:
partner.cooperator_type = share_type
@api.multi
@api.depends('share_ids')
def _compute_share_info(self):
for partner in self:
number_of_share = 0
total_value = 0.0
for line in partner.share_ids:
number_of_share += line.share_number
total_value += line.share_unit_price * line.share_number
partner.number_of_share = number_of_share
partner.total_value = total_value
cooperator = fields.Boolean(string='Cooperator',
help="Check this box if this contact is a"
" cooperator (effective or not).")
member = fields.Boolean(string='Effective cooperator',
help="Check this box if this cooperator"
" is an effective member.")
coop_candidate = fields.Boolean(string="Cooperator candidate",
compute="_compute_coop_candidate",
store=True,
readonly=True)
old_member = fields.Boolean(string='Old cooperator',
help="Check this box if this cooperator is"
" no more an effective member.")
# todo use oca partner_contact_gender
gender = fields.Selection([('male', 'Male'),
('female', 'Female'),
('other', 'Other')],
string='Gender')
share_ids = fields.One2many('share.line',
'partner_id',
string='Share Lines')
cooperator_register_number = fields.Integer(string='Cooperator Number')
number_of_share = fields.Integer(compute="_compute_share_info",
multi='share',
string='Number of share',
readonly=True)
total_value = fields.Float(compute="_compute_share_info",
multi='share',
string='Total value of shares',
readonly=True)
company_register_number = fields.Char(string='Company Register Number')
cooperator_type = fields.Selection(selection='_get_share_type',
compute=_compute_cooperator_type,
string='Cooperator Type',
store=True)
effective_date = fields.Date(sting="Effective Date",
compute=_compute_effective_date,
store=True)
representative = fields.Boolean(string="Legal Representative")
subscription_request_ids = fields.One2many('subscription.request',
'partner_id',
string="Subscription request")
legal_form = fields.Selection([('', '')],
string="Legal form")
data_policy_approved = fields.Boolean(string="Approved Data Policy")
internal_rules_approved = fields.Boolean(string="Approved Internal Rules")
@api.multi
@api.depends('subscription_request_ids.state')
def _compute_coop_candidate(self):
for partner in self:
if partner.member:
is_candidate = False
else:
if len(partner.subscription_request_ids.filtered(lambda record: record.state == 'done')) > 0:
is_candidate = True
else:
is_candidate = False
partner.coop_candidate = is_candidate
def has_representative(self):
if self.child_ids.filtered('representative'):
return True
return False
def get_representative(self):
return self.child_ids.filtered('representative')
def get_cooperator_from_email(self, email):
return self.search([('cooperator', '=', True),
('email', '=', email)])
def get_cooperator_from_crn(self, company_register_number):
return self.search([('cooperator', '=', True),
('company_register_number', '=', company_register_number)])
# -*- coding: utf-8 -*-
# Copyright 2019 Coop IT Easy SCRL fs
# Houssine Bakkali <houssine@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
@api.multi
def _get_report_base_filename(self):
self.ensure_one()
if self.member:
return "Cooperator Certificate - %s" % self.name
else:
return 'unknown'
@api.multi
def _invoice_total(self):
account_invoice_report = self.env['account.invoice.report']
if not self.ids:
self.total_invoiced = 0.0
return True
all_partners_and_children = {}
all_partner_ids = []
for partner in self:
# price_total is in the company currency
all_partners_and_children[partner] = self.search([('id', 'child_of', partner.id)]).ids
all_partner_ids += all_partners_and_children[partner]
# searching account.invoice.report via the orm is comparatively
# expensive (generates queries "id in []" forcing to build the
# full table).
# In simple cases where all invoices are in the same currency than
# the user's company access directly these elements
# generate where clause to include multicompany rules
where_query = account_invoice_report._where_calc([
('partner_id', 'in', all_partner_ids),
('state', 'not in', ['draft', 'cancel']),
('company_id', '=', self.env.user.company_id.id),
('type', 'in', ('out_invoice', 'out_refund')),
('release_capital_request', '=', False),
])
account_invoice_report._apply_ir_rules(where_query, 'read')
from_clause, where_clause, where_clause_params = where_query.get_sql()
# price_total is in the company currency
query = """
SELECT SUM(price_total) as total, partner_id
FROM account_invoice_report account_invoice_report
WHERE %s
GROUP BY partner_id
""" % where_clause
self.env.cr.execute(query, where_clause_params)
price_totals = self.env.cr.dictfetchall()
for partner, child_ids in all_partners_and_children.items():
partner.total_invoiced = sum(price['total'] for price in price_totals if price['partner_id'] in child_ids)
@api.multi
@api.depends('share_ids')
def _compute_effective_date(self):
# TODO change it to compute it from the share register
for partner in self:
if partner.share_ids:
partner.effective_date = partner.share_ids[0].effective_date
@api.multi
def _get_share_type(self):
shares = (
self.env['product.product']
.search([('is_share', '=', True)])
)
share_types = [(share.default_code, share.short_name) for share in shares]
return [('', '')] + share_types
@api.multi
@api.depends('share_ids')
def _compute_cooperator_type(self):
for partner in self:
share_type = ''
for line in partner.share_ids:
share_type = line.share_product_id.default_code
if share_type:
partner.cooperator_type = share_type
@api.multi
@api.depends('share_ids')
def _compute_share_info(self):
for partner in self:
number_of_share = 0
total_value = 0.0
for line in partner.share_ids:
number_of_share += line.share_number
total_value += line.share_unit_price * line.share_number
partner.number_of_share = number_of_share
partner.total_value = total_value
cooperator = fields.Boolean(string='Cooperator',
help="Check this box if this contact is a"
" cooperator (effective or not).")
member = fields.Boolean(string='Effective cooperator',
help="Check this box if this cooperator"
" is an effective member.")
coop_candidate = fields.Boolean(string="Cooperator candidate",
compute="_compute_coop_candidate",
store=True,
readonly=True)
old_member = fields.Boolean(string='Old cooperator',
help="Check this box if this cooperator is"
" no more an effective member.")
# todo use oca partner_contact_gender
gender = fields.Selection([('male', 'Male'),
('female', 'Female'),
('other', 'Other')],
string='Gender')
share_ids = fields.One2many('share.line',
'partner_id',
string='Share Lines')
cooperator_register_number = fields.Integer(string='Cooperator Number')
number_of_share = fields.Integer(compute="_compute_share_info",
multi='share',
string='Number of share',
readonly=True)
total_value = fields.Float(compute="_compute_share_info",
multi='share',
string='Total value of shares',
readonly=True)
company_register_number = fields.Char(string='Company Register Number')
cooperator_type = fields.Selection(selection='_get_share_type',
compute=_compute_cooperator_type,
string='Cooperator Type',
store=True)
effective_date = fields.Date(sting="Effective Date",
compute=_compute_effective_date,
store=True)
representative = fields.Boolean(string="Legal Representative")
subscription_request_ids = fields.One2many('subscription.request',
'partner_id',
string="Subscription request")
legal_form = fields.Selection([('', '')],
string="Legal form")
data_policy_approved = fields.Boolean(string="Approved Data Policy")
internal_rules_approved = fields.Boolean(string="Approved Internal Rules")
@api.multi
@api.depends('subscription_request_ids.state')
def _compute_coop_candidate(self):
for partner in self:
if partner.member:
is_candidate = False
else:
sub_requests = partner.subscription_request_ids.filtered(
lambda record: record.state == 'done')
is_candidate = bool(sub_requests)
partner.coop_candidate = is_candidate
@api.multi
def has_representative(self):
self.ensure_one()
if self.child_ids.filtered('representative'):
return True
return False
@api.multi
def get_representative(self):
self.ensure_one()
return self.child_ids.filtered('representative')
def get_cooperator_from_email(self, email):
return self.env['res.partner'].search([('cooperator', '=', True),
('email', '=', email)])
def get_cooperator_from_crn(self, company_register_number):
return self.env['res.partner'].search([('cooperator', '=', True),
('company_register_number', '=', company_register_number)])

13
easy_my_coop_website/views/subscription_template.xml

@ -57,6 +57,11 @@
<form action="/subscription/subscribe_share" method="post" class="form-horizontal mt32" enctype="multipart/form-data">
<p style="color:red;"><t t-esc="error_msg"/></p>
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div t-attf-class="form-group">
<a class='btn btn-primary' t-if="logged" t-attf-href="/my/account">You want to modify your personnal information ?</a>
<br/>
</div>
<div t-attf-class="form-group">
<a class='btn btn-primary' t-if="not logged" t-attf-href="/web/login?redirect=#{ request.httprequest.url }">You have already an account?</a>
@ -177,8 +182,8 @@
<td>
<input type="text" class="form-control mandatory-field" name="city"
required="True" t-att-readonly="logged"
t-attf-value="#{city or ''}" placeholder="Bruxelles"/>
</td>
t-attf-value="#{city or ''}" placeholder="Bruxelles"/>
</td>
</tr>
</table>
</div>
@ -292,7 +297,7 @@
<table style="margin-left:195px">
<tr>
<td width="80%">
<div class="g-recaptcha" t-att-data-sitekey="website.recaptcha_key_site" data-theme="green"/><br/>
<div class="g-recaptcha" t-att-data-sitekey="website.recaptcha_key_site" data-theme="green"/><br/>
</td>
<td>
<div class="form-group">
@ -300,7 +305,7 @@
<button class="btn btn-primary btn-lg">Send</button>
</div>
</div>
</td>
</td>
</tr>
</table>

12
easy_my_coop_website_portal/__manifest__.py

@ -1,14 +1,15 @@
# Copyright 2018-Coop IT Easy SCRLfs (<http://www.coopiteasy.be>)
# Copyright 2018 Coop IT Easy SCRLfs (<http://www.coopiteasy.be>)
# - Rémy Taymans <remy@coopiteasy.be>
# - Houssine Bakkali <houssine@coopiteasy.be>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Easy My Coop Website Portal',
"version": "12.0.1.0.0",
'depends': [
'website',
'website_portal_v10',
'easy_my_coop',
'report',
'website',
'account',
'portal',
],
'description': """
Show cooperator information in the website portal.
@ -20,6 +21,5 @@
'data': [
'views/easy_my_coop_website_portal_templates.xml',
],
'installable': False,
'application': False,
'installable': True,
}

191
easy_my_coop_website_portal/controllers/main.py

@ -1,66 +1,115 @@
# -*- coding: utf-8 -*-
# Copyright 2015-2016 Odoo S.A.
# Copyright 2016 Jairo Llopis <jairo.llopis@tecnativa.com>
# Copyright 2017-2018 Rémy Taymans <remytaymans@gmail.com>
# Copyright 2017-2018 Rémy Taymans <remy@coopiteasy.be>
# Copyright 2019 Houssine Bakkali <houssine@coopiteasy.be>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from werkzeug.exceptions import Forbidden, NotFound
from openerp import http
from openerp.exceptions import AccessError, MissingError
from openerp.fields import Date
from openerp.http import request
from odoo.exceptions import AccessError, MissingError
from odoo.fields import Date
from odoo.http import request, route
from odoo import _
from openerp.addons.website_portal_v10.controllers.main import WebsiteAccount
from odoo.addons.portal.controllers.portal import CustomerPortal
from odoo.addons.portal.controllers.portal import pager as portal_pager
from odoo.addons.payment.controllers.portal import PaymentProcessing
class CooperatorWebsiteAccount(WebsiteAccount):
class CooperatorPortalAccount(CustomerPortal):
CustomerPortal.MANDATORY_BILLING_FIELDS.extend(["iban",
"birthdate_date",
"gender"])
def _prepare_portal_layout_values(self):
values = super(CooperatorWebsiteAccount,
values = super(CooperatorPortalAccount,
self)._prepare_portal_layout_values()
# We assume that commercial_partner_id always point to the
# partner itself or to the linked partner. So there is no
# need to check if the partner is a "contact" or not.
coop = request.env.user.partner_id.commercial_partner_id
partner = request.env.user.partner_id
coop = partner.commercial_partner_id
partner_obj = request.env['res.partner']
coop_bank = request.env['res.partner.bank'].sudo().search(
[('partner_id', 'in', [coop.id])],
limit=1
)
values.update({
'coop': coop,
'coop_bank': coop_bank,
})
return values
@http.route()
def account(self):
""" Add Release Capital Request to main account page """
response = super(CooperatorWebsiteAccount, self).account()
partner = request.env.user.partner_id
invoice_mgr = request.env['account.invoice']
capital_request_count = invoice_mgr.sudo().search_count([
('partner_id', 'in',
[partner.commercial_partner_id.id]),
capital_request_count = invoice_mgr.search_count([
('state', 'in', ['open', 'paid', 'cancelled']),
# Get only the release capital request
('release_capital_request', '=', True),
])
response.qcontext.update({
invoice_count = invoice_mgr.search_count([
('release_capital_request', '=', False)
])
iban = ''
if partner.bank_ids:
iban = partner.bank_ids[0].acc_number
fields_desc = partner_obj.sudo().fields_get(['gender'])
values.update({
'coop': coop,
'coop_bank': coop_bank,
'capital_request_count': capital_request_count,
'invoice_count': invoice_count,
'iban': iban,
'genders': fields_desc['gender']['selection']
})
return response
return values
@http.route(
def details_form_validate(self, data):
error, error_message = super(CooperatorPortalAccount,
self).details_form_validate(data)
sub_req_obj = request.env['subscription.request']
iban = data.get("iban")
valid = sub_req_obj.check_iban(iban)
if not valid:
error['iban'] = 'error'
error_message.append(_("You iban account number is not valid"))
return error, error_message
@route(['/my/account'], type='http', auth='user', website=True)
def account(self, redirect=None, **post):
res = super(CooperatorPortalAccount, self).account(
redirect, **post)
if not res.qcontext.get('error'):
partner = request.env.user.partner_id
partner_bank = request.env['res.partner.bank']
iban = post.get('iban')
if iban:
if partner.bank_ids:
bank_account = partner.bank_ids[0]
bank_account.acc_number = iban
else:
partner_bank.sudo().create({
'partner_id': partner.id,
'acc_number': iban
})
return res
@route(['/my/invoices', '/my/invoices/page/<int:page>'], type='http',
auth="user", website=True)
def portal_my_invoices(self, page=1, date_begin=None, date_end=None,
sortby=None, **kw):
res = super(CooperatorPortalAccount, self).portal_my_invoices(
page, date_begin, date_end, sortby, **kw)
invoice_obj = request.env['account.invoice']
qcontext = res.qcontext
if qcontext:
invoices = invoice_obj.search([('release_capital_request', '=', False)])
invoice_count = len(invoices)
qcontext['invoices'] = invoices
qcontext['pager']['invoice_count'] = invoice_count
return res
@route(
['/my/release_capital_request',
'/my/release_capital_request/page/<int:page>'],
type='http', auth="user", website=True)
def portal_my_release_capital_request(self, page=1, date_begin=None,
date_end=None, **kw):
date_end=None, sortby=None, **kw):
"""Render a page with the list of release capital request.
A release capital request is an invoice with a flag that tell
if it's a capital request or not.
@ -85,9 +134,10 @@ class CooperatorWebsiteAccount(WebsiteAccount):
# count for pager
capital_request_count = invoice_mgr.sudo().search_count(domain)
# pager
pager = request.website.pager(
pager = portal_pager(
url="/my/release_capital_request",
url_args={'date_begin': date_begin, 'date_end': date_end},
url_args={'date_begin': date_begin, 'date_end': date_end,
'sortby': sortby},
total=capital_request_count,
page=page,
step=self._items_per_page
@ -98,53 +148,54 @@ class CooperatorWebsiteAccount(WebsiteAccount):
values.update({
'date': date_begin,
'capital_requests': invoices,
'page_name': 'invoice',
'page_name': 'Release request',
'pager': pager,
'archive_groups': archive_groups,
'default_url': '/my/release_capital_request',
})
return request.website.render(
return request.render(
"easy_my_coop_website_portal.portal_my_capital_releases",
values
)
@http.route(['/my/release_capital_request/pdf/<int:oid>'],
type='http', auth="user", website=True)
def get_release_capital_request(self, oid=-1, **kw):
"""Render the pdf of the given release capital request"""
# Get the release capital request and raise an error if the user
# is not allowed to access to it or if the object is not found.
partner = request.env.user.partner_id
invoice_mgr = request.env['account.invoice']
capital_request = invoice_mgr.sudo().browse(oid)
@route(['/my/invoices/<int:invoice_id>'],
type='http', auth="public", website=True)
def portal_my_invoice_detail(self, invoice_id, access_token=None,
report_type=None, download=False, **kw):
# override in order to not retrieve release capital request as invoices
try:
if capital_request.partner_id != partner:
raise Forbidden()
except AccessError:
raise Forbidden()
except MissingError:
raise NotFound()
# Get the pdf
report_mgr = request.env['report']
pdf = report_mgr.sudo().get_pdf(
capital_request,
'easy_my_coop.theme_invoice_G002'
)
filename = "Release Capital Request - %d" % capital_request.id
return self._render_pdf(pdf, filename)
@http.route(['/my/cooperator_certificate/pdf'],
type='http', auth="user", website=True)
invoice_sudo = self._document_check_access('account.invoice',
invoice_id,
access_token)
except (AccessError, MissingError):
return request.redirect('/my')
if invoice_sudo.release_capital_request:
report_ref = 'easy_my_coop.action_cooperator_invoices'
else:
report_ref = 'account.account_invoices'
if report_type in ('html', 'pdf', 'text'):
return self._show_report(model=invoice_sudo,
report_type=report_type,
report_ref=report_ref,
download=download)
values = self._invoice_get_page_view_values(invoice_sudo, access_token,
**kw)
PaymentProcessing.remove_payment_transaction(invoice_sudo.transaction_ids)
return request.render("account.portal_invoice_page", values)
@route(['/my/cooperator_certificate/pdf'],
type='http', auth="user", website=True)
def get_cooperator_certificat(self, **kw):
"""Render the cooperator certificate pdf of the current user"""
partner = request.env.user.partner_id
report_mgr = request.env['report']
pdf = report_mgr.sudo().get_pdf(
partner,
'easy_my_coop.cooperator_certificat_G001'
)
filename = "Cooperator Certificate - %s" % partner.name
return self._render_pdf(pdf, filename)
return self._show_report(
model=partner,
report_type='pdf',
report_ref='easy_my_coop.action_cooperator_report_certificat',
download=True
)
def _render_pdf(self, pdf, filename):
"""Render a http response for a pdf"""

218
easy_my_coop_website_portal/views/easy_my_coop_website_portal_templates.xml

@ -1,18 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2016 Odoo S.A.
Copyright 2016 Jairo Llopis <jairo.llopis@tecnativa.com>
Copyright 2018 Rémy Taymans <remytaymans@gmail.com>
Copyright 2018 Rémy Taymans <remy@cooptieasy.be>
Copyright 2019 Houssine Bakkali <houssine@cooptieasy.be>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<odoo>
<template id="portal_my_details_emc" inherit_id="portal.portal_my_details" name="Portal user details">
<input name="name" position="attributes">
<attribute name="t-att-readonly">True</attribute>
</input>
<input name="email" position="attributes">
<attribute name="t-att-readonly">True</attribute>
</input>
<xpath expr="//input[@name='phone']/.." position="after">
<div t-attf-class="form-group #{error.get('gender') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="gender">Gender</label>
<select name="gender" t-attf-class="form-control #{error.get('gender') or ''}">
<option value=""></option>
<t t-foreach="genders or []" t-as="item">
<option t-att-value="item[0]" t-att-selected="item[0] == partner.gender">
<t t-esc="item[1]" />
</option>
</t>
</select>
</div>
<div t-attf-class="form-group #{error.get('birthdate_date') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="birthdate_date">Birthdate</label>
<input type="date" name="birthdate_date" t-attf-class="form-control #{error.get('birthdate_date') or ''}" t-att-value="birthdate_date or partner.birthdate_date" />
</div>
<div t-attf-class="form-group #{error.get('iban') and 'o_has_error' or ''} col-xl-6">
<label class="col-form-label" for="iban">Iban</label>
<input type="input" name="iban" t-attf-class="form-control #{error.get('iban') or ''}" t-att-value="iban" />
</div>
</xpath>
</template>
<!-- Add cooperator information -->
<template
id="website_portal_details_form"
name="Website Portal Details Form"
inherit_id="website_portal_v10.portal_layout">
<xpath expr="//div[@class='o_my_details']" position="after">
inherit_id="portal.portal_layout">
<xpath expr="//div[@class='o_portal_my_details']" position="after">
<div class="o_my_details_coop" t-if="coop.member">
<h3 class="page-header">Your Cooperator Details</h3>
<p class="text-center">
@ -65,9 +94,9 @@
<label>Gender: </label>
<t t-esc="coop.gender"/>
</p>
<p t-if="coop.birthdate">
<p t-if="coop.birthdate_date">
<label>Date of Birth: </label>
<t t-esc="coop.birthdate"/>
<t t-esc="coop.birthdate_date"/>
</p>
<p t-if="coop_bank and coop_bank.acc_number">
<label>Bank Account: </label>
@ -90,110 +119,81 @@
</xpath>
</template>
<!-- Release Capital Requests in the menu -->
<template
id="portal_my_home_menu_capital_release"
name="Portal Menu: Easy My Coop Capital Release"
inherit_id="website_portal_v10.portal_layout"
priority="20">
<xpath expr="//ul[contains(@class,'o_portal_submenu')]"
position="inside">
<li>
<a href="/my/release_capital_request">Capital Releases</a>
</li>
</xpath>
</template>
<template id="portal_my_home_menu_capital_request" name="Portal layout : capital request menu entries" inherit_id="portal.portal_breadcrumbs" priority="30">
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
<li t-if="page_name == 'capital request'" t-attf-class="breadcrumb-item #{'active ' if not capital_requests else ''}">
<a t-if="capital_request" t-attf-href="/my/release_capital_request?{{ keep_query() }}">Capital Request</a>
<t t-else="">Capital Request</t>
</li>
<li t-if="capital_request" class="breadcrumb-item active">
<t t-esc="capital_request.number" t-if="capital_request.number"/>
<t t-else=""><em>Draft Request</em></t>
</li>
</xpath>
</template>
<!-- Release Capital Requests on the main page -->
<template
id="portal_my_home_capital_release"
<template id="portal_my_home_capital_release"
name="Portal My Home : Easy My Coop Capital Release Requests"
inherit_id="website_portal_v10.portal_my_home"
priority="20">
<xpath expr="//div[contains(@class,'o_my_home_content')]"
position="inside">
<h3 class="page-header">
<a href="/my/release_capital_request">
Your Release Capital Requests
<small class="ml8">
<t t-if="capital_request_count">
<span class='badge'>
<t t-esc="capital_request_count"/>
</span>
</t>
<t t-if="not capital_request_count">
There are currently no release capital request for your
account.
inherit_id="portal.portal_my_home" priority="30">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="capital_request_count" t-call="portal.portal_docs_entry">
<t t-set="title">Your Release Capital Requests</t>
<t t-set="url" t-value="'/my/release_capital_request'"/>
<t t-set="count" t-value="capital_request_count"/>
</t>
</small>
</a>
</h3>
</xpath>
</template>
</xpath>
</template>
<!-- Release Capital Request page -->
<template id="portal_my_capital_releases" name="My Capital Releases">
<t t-call="website_portal_v10.portal_layout">
<h3 class="page-header">Your Capital Release Requests</h3>
<t t-if="not capital_requests">
<p>
There are currently no capital release request for your
account.
</p>
</t>
<t t-if="capital_requests">
<table class="table table-hover o_my_status_table">
<thead>
<tr class="active">
<th>Request #</th>
<th>Request Date</th>
<th>Due Date</th>
<th></th>
<th>Amount Due</th>
</tr>
</thead>
<tbody>
<tr t-foreach="capital_requests" t-as="capital_request">
<td>
<a t-att-href="'/my/release_capital_request/pdf/%s' %
capital_request.id">
<t t-esc="capital_request.number"/>
</a>
</td>
<td><span t-field="capital_request.date_invoice"/></td>
<td><span t-field="capital_request.date_due"/></td>
<td>
<t t-if="capital_request.state == 'open'">
<span class="label label-info">
<i class="fa fa-fw fa-clock-o"/> Waiting for Payment
</span>
</t>
<t t-if="capital_request.state == 'paid'">
<span class="label label-default">
<i class="fa fa-fw fa-check"/> Paid
</span>
</t>
<t t-if="capital_request.state == 'cancel'">
<span class="label label-default">
<i class="fa fa-fw fa-remove"/> Cancelled
</span>
<template id="portal_my_capital_releases" name="My Capital Releases">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<t t-set="title">My Capital Releases</t>
</t>
<t t-if="not capital_requests">
<p>There are currently no capital release request for your
account.
</p>
</t>
<t t-if="capital_requests" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>Request #</th>
<th>Request Date</th>
<th class='d-none d-md-table-cell'>Due Date</th>
<th/>
<th class="text-right">Amount Due</th>
</tr>
</thead>
<tbody>
<t t-foreach="capital_requests" t-as="capital_request">
<tr>
<td>
<a t-att-href="capital_request.get_portal_url()" t-att-title="capital_request.number">
<t t-esc="capital_request.number" t-if="capital_request.number"/>
<em t-else="">Draft Request</em>
</a>
</td>
<td><span t-field="capital_request.date_invoice"/></td>
<td class='d-none d-md-table-cell'><span t-field="capital_request.date_due"/></td>
<td class="tx_status">
<t t-if="capital_request.state == 'open'">
<span class="badge badge-pill badge-info"><i class="fa fa-fw fa-clock-o" aria-label="Opened" title="Opened" role="img"></i><span class="d-none d-md-inline"> Waiting for Payment</span></span>
</t>
<t t-if="capital_request.state == 'paid'">
<span class="badge badge-pill badge-success"><i class="fa fa-fw fa-check" aria-label="Paid" title="Paid" role="img"></i><span class="d-none d-md-inline"> Paid</span></span>
</t>
<t t-if="capital_request.state == 'cancel'">
<span class="badge badge-pill badge-warning"><i class="fa fa-fw fa-remove" aria-label="Cancelled" title="Cancelled" role="img"></i><span class="d-none d-md-inline"> Cancelled</span></span>
</t>
</td>
<td class="text-right"><span t-esc="-capital_request.residual if capital_request.type == 'out_refund' else capital_request.residual" t-options='{"widget": "monetary", "display_currency": capital_request.currency_id}'/></td>
</tr>
</t>
</td>
<td>
<span t-field="capital_request.residual"
t-field-options='{
"widget": "monetary",
"display_currency": "capital_request.currency_id"
}'/>
</td>
</tr>
</tbody>
</table>
<div t-if="pager" class="o_portal_pager text-center">
<t t-call="website.pager"/>
</div>
</tbody>
</t>
</t>
</t>
</template>
</openerp>
</template>
</odoo>

2
website_portal_extend/__init__.py

@ -1,2 +0,0 @@
# -*- coding: utf8 -*-
import controllers

31
website_portal_extend/__openerp__.py

@ -1,31 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Rémy Taymans <remytaymans@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Website Portal Extend',
'summary': """
Extension of Website Portal that show correctly information about
companies
""",
'description': """
""",
'author': 'Rémy Taymans',
'license': 'AGPL-3',
'version': '9.0.1.0',
'website': "https://github.com/houssine78/vertical-cooperative",
'category': 'Website',
'depends': [
'website',
'website_portal_v10',
],
'data': [
'views/portal_website_templates.xml',
]
}

2
website_portal_extend/controllers/__init__.py

@ -1,2 +0,0 @@
# -*- coding: utf-8 -*-
from . import main

188
website_portal_extend/controllers/main.py

@ -1,188 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2017-2018 Rémy Taymans <remytaymans@gmail.com>
# Copyright 2018 Odoo SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import fields, models, http
from openerp.http import request
from openerp import tools
from openerp.tools.translate import _
from openerp.addons.website_portal_v10.controllers.main import WebsiteAccount
class ExtendWebsiteAccountController(WebsiteAccount):
mandatory_billing_fields = [
"name",
"phone",
"email",
"city",
"country_id",
"street",
]
optional_billing_fields = [
"zipcode",
"state_id",
"vat",
]
@http.route(['/my/account'], type='http', auth='user', website=True)
def details(self, redirect=None, **post):
partner = request.env['res.users'].browse(request.uid).partner_id
values = {
'error': {},
'error_message': []
}
self._set_mandatory_fields(post)
self._set_optional_fields(post)
all_fields = (
self.mandatory_billing_fields
+ self.optional_billing_fields
)
if post:
error, error_message = self.details_form_validate(post)
values.update({'error': error, 'error_message': error_message})
values.update(post)
if not error:
# Change zipcode to zip as it is stored as zip in the
# partner
if 'zipcode' in all_fields:
post.update({'zip': post.pop('zipcode', '')})
if partner.type == "contact":
address_fields = {}
if 'city' in all_fields:
address_fields.update({
'city': post.pop('city'),
})
if 'street' in all_fields:
address_fields.update({
'street': post.pop('street'),
})
if 'vat' in all_fields:
address_fields.update({
'vat': post['vat'],
})
if 'zipcode' in all_fields:
address_fields.update({
'zip': post.pop('zip'),
})
if 'country_id' in all_fields:
address_fields.update({
'country_id': post.pop('country_id'),
})
if 'state_id' in all_fields:
address_fields.update({
'state_id': post.pop('state_id')
})
company_fields = {}
if 'company_name' in all_fields:
company_fields.update({
'name': post.pop('company_name'),
})
if 'vat' in all_fields:
company_fields.update({
# The VAT must be updated on the company and on
# the partner, so pop is not used.
'vat': post['vat'],
})
partner.commercial_partner_id.sudo().write(address_fields)
partner.commercial_partner_id.sudo().write(company_fields)
# Write the rest of the info in the partner
partner.sudo().write(post)
if redirect:
return request.redirect(redirect)
return request.redirect('/my/home')
countries = request.env['res.country'].sudo().search([])
states = request.env['res.country.state'].sudo().search([])
values.update({
'partner': partner,
'countries': countries,
'states': states,
'has_check_vat': hasattr(request.env['res.partner'], 'check_vat'),
'redirect': redirect,
})
return request.website.render("website_portal.details", values)
def _set_mandatory_fields(self, data):
"""Change mandatory billing fields of the form.
Overwrite this function if mandatory fields must be changed
depending on the value of the data or any other value.
Here it mark the field 'company_name' as need or not depending
on the current user.
"""
partner = request.env['res.users'].browse(request.uid).partner_id
if (partner.parent_id
and 'company_name' not in self.mandatory_billing_fields):
self.mandatory_billing_fields.append('company_name')
if (not partner.parent_id
and 'company_name' in self.mandatory_billing_fields):
self.mandatory_billing_fields.remove('company_name')
def _set_optional_fields(self, data):
"""Same as set_mandatory_fields but for optional ones.
Here this does nothing.
"""
pass
def details_form_validate(self, data):
"""Validate the form"""
error = dict()
error_message = []
all_fields = (
self.mandatory_billing_fields
+ self.optional_billing_fields
)
# Validation
for field_name in self.mandatory_billing_fields:
if not data.get(field_name):
error[field_name] = 'missing'
# email validation
if ('email' in all_fields
and 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.')
)
# vat validation
if ('vat' in all_fields
and data.get("vat")
and hasattr(request.env["res.partner"], "check_vat")):
if request.website.company_id.vat_check_vies:
# force full VIES online check
check_func = request.env["res.partner"].vies_vat_check
else:
# quick and partial off-line checksum validation
check_func = request.env["res.partner"].simple_vat_check
vat_country, vat_number = request.env["res.partner"]._split_vat(
data.get("vat")
)
if not check_func(vat_country, vat_number): # simple_vat_check
error["vat"] = 'error'
# error message for empty required fields
if [err for err in error.values() if err == 'missing']:
error_message.append(_('Some required fields are empty.'))
unknown = [k for k in data.iterkeys() if k not in all_fields]
if unknown:
error['common'] = 'Unknown field'
error_message.append("Unknown field '%s'" % ','.join(unknown))
return error, error_message

117
website_portal_extend/views/portal_website_templates.xml

@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 Rémy Taymans <remytaymans@gmail.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<!-- Modifying the form -->
<template
id="website_portal_details_form"
name="Website Portal Details Form"
inherit_id="website_portal.details">
<xpath expr="//form" position="replace">
<form action="/my/account" method="post">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="row o_website_portal_details">
<div class="col-md-8">
<div class="row">
<div class="col-md-12">
<div t-if="error_message" class="alert alert-danger">
<t t-foreach="error_message" t-as="err"><t t-esc="err"/><br /></t>
</div>
</div>
<div t-attf-class="form-group #{error.get('name') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="name">Your Name</label>
<input type="text" name="name" class="form-control" t-att-value="name or partner.name" />
</div>
<div class="clearfix" />
<div t-attf-class="form-group #{error.get('email') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="email">Email</label>
<input type="email" name="email" class="form-control" t-att-value="email or partner.email" />
</div>
<div t-attf-class="form-group #{error.get('phone') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="phone">Phone</label>
<input type="tel" name="phone" class="form-control" t-att-value="phone or partner.phone" />
</div>
<div class="clearfix" />
<div t-attf-class="form-group #{error.get('company_name') and 'has-error' or ''} col-lg-6" t-if="partner.parent_id">
<label class="control-label" for="company_name">Company Name</label>
<input type="text" name="company_name" class="form-control" t-att-value="company_name or partner.parent_id.name"/>
</div>
<div t-if="has_check_vat" t-attf-class="form-group #{error.get('vat') and 'has-error' or ''} col-lg-6">
<label class="control-label label-optional" for="vat">VAT Number</label>
<input type="text" name="vat" class="form-control" t-att-value="vat or partner.parent_id.vat" t-if="partner.parent_id"/>
<input type="text" name="vat" class="form-control" t-att-value="vat or partner.vat" t-if="not partner.parent_id"/>
</div>
<div class="clearfix" />
<div t-attf-class="form-group #{error.get('street') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="street">Street</label>
<input type="text" name="street" class="form-control" t-att-value="street or partner.street" />
</div>
<div t-attf-class="form-group #{error.get('city') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="city">City</label>
<input type="text" name="city" class="form-control" t-att-value="city or partner.city" />
</div>
<div t-attf-class="form-group #{error.get('zip') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="zipcode">Zip / Postal Code</label>
<input type="text" name="zipcode" class="form-control" t-att-value="zipcode or partner.zip" />
</div>
<div t-attf-class="form-group #{error.get('country_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="country_id">Country</label>
<select name="country_id" class="form-control">
<option value="">Country...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="country.id == partner.country_id.id">
<t t-esc="country.name" />
</option>
</t>
</select>
</div>
<div t-attf-class="form-group #{error.get('state_id') and 'has-error' or ''} col-lg-6">
<label class="control-label label-optional" for="state_id">State / Province</label>
<select name="state_id" class="form-control">
<option value="">select...</option>
<t t-foreach="states or []" t-as="state">
<option t-att-value="state.id" style="display:none;" t-att-data-country_id="state.country_id.id" t-att-selected="state.id == partner.state_id.id">
<t t-esc="state.name" />
</option>
</t>
</select>
</div>
<input type="hidden" name="redirect" t-att-value="redirect"/>
</div> <!-- row -->
<div class="clearfix">
<button type="submit" class="btn btn-default btn-primary pull-right mb32 ">
Confirm
<span class="fa fa-long-arrow-right" />
</button>
</div>
</div>
</div>
</form>
</xpath>
</template>
</openerp>
Loading…
Cancel
Save