flectra/addons/sale/controllers/portal.py

232 lines
9.3 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
import base64
from flectra import http, _
from flectra.exceptions import AccessError
from flectra.http import request
from flectra.tools import consteq
from flectra.addons.portal.controllers.mail import _message_post_helper
from flectra.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager, get_records_pager
class CustomerPortal(CustomerPortal):
def _prepare_portal_layout_values(self):
values = super(CustomerPortal, self)._prepare_portal_layout_values()
partner = request.env.user.partner_id
SaleOrder = request.env['sale.order']
quotation_count = SaleOrder.search_count([
('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
('state', 'in', ['sent', 'cancel'])
])
order_count = SaleOrder.search_count([
('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
('state', 'in', ['sale', 'done'])
])
values.update({
'quotation_count': quotation_count,
'order_count': order_count,
})
return values
#
# Quotations and Sales Orders
#
def _order_check_access(self, order_id, access_token=None):
order = request.env['sale.order'].browse([order_id])
order_sudo = order.sudo()
try:
order.check_access_rights('read')
order.check_access_rule('read')
except AccessError:
if not access_token or not consteq(order_sudo.access_token, access_token):
raise
return order_sudo
def _order_get_page_view_values(self, order, access_token, **kwargs):
order_invoice_lines = {il.product_id.id: il.invoice_id for il in order.invoice_ids.mapped('invoice_line_ids')}
values = {
'order': order,
'order_invoice_lines': order_invoice_lines,
}
if access_token:
values['no_breadcrumbs'] = True
values['access_token'] = access_token
values['portal_confirmation'] = order.get_portal_confirmation_action()
if kwargs.get('error'):
values['error'] = kwargs['error']
if kwargs.get('warning'):
values['warning'] = kwargs['warning']
if kwargs.get('success'):
values['success'] = kwargs['success']
history = request.session.get('my_orders_history', [])
values.update(get_records_pager(history, order))
return values
@http.route(['/my/quotes', '/my/quotes/page/<int:page>'], type='http', auth="user", website=True)
def portal_my_quotes(self, page=1, date_begin=None, date_end=None, sortby=None, **kw):
values = self._prepare_portal_layout_values()
partner = request.env.user.partner_id
SaleOrder = request.env['sale.order']
domain = [
('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
('state', 'in', ['sent', 'cancel'])
]
searchbar_sortings = {
'date': {'label': _('Order Date'), 'order': 'date_order desc'},
'name': {'label': _('Reference'), 'order': 'name'},
'stage': {'label': _('Stage'), 'order': 'state'},
}
# default sortby order
if not sortby:
sortby = 'date'
sort_order = searchbar_sortings[sortby]['order']
archive_groups = self._get_archive_groups('sale.order', domain)
if date_begin and date_end:
domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]
# count for pager
quotation_count = SaleOrder.search_count(domain)
# make pager
pager = portal_pager(
url="/my/quotes",
url_args={'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby},
total=quotation_count,
page=page,
step=self._items_per_page
)
# search the count to display, according to the pager data
quotations = SaleOrder.search(domain, order=sort_order, limit=self._items_per_page, offset=pager['offset'])
request.session['my_quotes_history'] = quotations.ids[:100]
values.update({
'date': date_begin,
'quotations': quotations.sudo(),
'page_name': 'quote',
'pager': pager,
'archive_groups': archive_groups,
'default_url': '/my/quotes',
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
})
return request.render("sale.portal_my_quotations", values)
@http.route(['/my/orders', '/my/orders/page/<int:page>'], type='http', auth="user", website=True)
def portal_my_orders(self, page=1, date_begin=None, date_end=None, sortby=None, **kw):
values = self._prepare_portal_layout_values()
partner = request.env.user.partner_id
SaleOrder = request.env['sale.order']
domain = [
('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
('state', 'in', ['sale', 'done'])
]
searchbar_sortings = {
'date': {'label': _('Order Date'), 'order': 'date_order desc'},
'name': {'label': _('Reference'), 'order': 'name'},
'stage': {'label': _('Stage'), 'order': 'state'},
}
# default sortby order
if not sortby:
sortby = 'date'
sort_order = searchbar_sortings[sortby]['order']
archive_groups = self._get_archive_groups('sale.order', domain)
if date_begin and date_end:
domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]
# count for pager
order_count = SaleOrder.search_count(domain)
# pager
pager = portal_pager(
url="/my/orders",
url_args={'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby},
total=order_count,
page=page,
step=self._items_per_page
)
# content according to pager and archive selected
orders = SaleOrder.search(domain, order=sort_order, limit=self._items_per_page, offset=pager['offset'])
request.session['my_orders_history'] = orders.ids[:100]
values.update({
'date': date_begin,
'orders': orders.sudo(),
'page_name': 'order',
'pager': pager,
'archive_groups': archive_groups,
'default_url': '/my/orders',
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
})
return request.render("sale.portal_my_orders", values)
@http.route(['/my/orders/<int:order>'], type='http', auth="public", website=True)
def portal_order_page(self, order=None, access_token=None, **kw):
try:
order_sudo = self._order_check_access(order, access_token=access_token)
except AccessError:
return request.redirect('/my')
values = self._order_get_page_view_values(order_sudo, access_token, **kw)
return request.render("sale.portal_order_page", values)
@http.route(['/my/orders/pdf/<int:order_id>'], type='http', auth="public", website=True)
def portal_order_report(self, order_id, access_token=None, **kw):
try:
order_sudo = self._order_check_access(order_id, access_token)
except AccessError:
return request.redirect('/my')
# print report as sudo, since it require access to taxes, payment term, ... and portal
# does not have those access rights.
pdf = request.env.ref('sale.action_report_saleorder').sudo().render_qweb_pdf([order_sudo.id])[0]
pdfhttpheaders = [
('Content-Type', 'application/pdf'),
('Content-Length', len(pdf)),
]
return request.make_response(pdf, headers=pdfhttpheaders)
def _portal_quote_user_can_accept(self, order_id):
return request.env['ir.config_parameter'].sudo().get_param('sale.sale_portal_confirmation_options', default='none') in ('pay', 'sign')
@http.route(['/my/quotes/accept'], type='json', auth="public", website=True)
def portal_quote_accept(self, res_id, access_token=None, partner_name=None, signature=None):
if not self._portal_quote_user_can_accept(res_id):
return {'error': _('Operation not allowed')}
if not signature:
return {'error': _('Signature is missing.')}
try:
order_sudo = self._order_check_access(res_id, access_token=access_token)
except AccessError:
return {'error': _('Invalid order')}
if order_sudo.state != 'sent':
return {'error': _('Order is not in a state requiring customer validation.')}
order_sudo.action_confirm()
_message_post_helper(
res_model='sale.order',
res_id=order_sudo.id,
message=_('Order signed by %s') % (partner_name,),
attachments=[('signature.png', base64.b64decode(signature))] if signature else [],
**({'token': access_token} if access_token else {}))
return {
'success': _('Your Order has been confirmed.'),
'redirect_url': '/my/orders/%s?%s' % (order_sudo.id, access_token and 'access_token=%s' % order_sudo.access_token or ''),
}