264 lines
11 KiB
Python

# -*- coding: utf-8 -*-
import base64
import logging
from datetime import datetime
from odoo import http, fields, _, exceptions
from odoo.http import request
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
_logger = logging.getLogger(__name__)
def parse_html_datetime(dt_str):
if not dt_str:
return None
for fmt in (
"%Y-%m-%dT%H:%M", "%Y-%m-%dT%H:%M:%S",
"%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M", "%Y-%m-%d",
"%m/%d/%Y %I:%M %p", "%d/%m/%Y %I:%M %p",
"%m/%d/%Y %H:%M", "%d/%m/%Y %H:%M",
"%m/%d/%Y", "%d/%m/%Y"
):
try:
return datetime.strptime(dt_str.strip(), fmt)
except ValueError:
continue
try:
return fields.Datetime.to_datetime(dt_str)
except Exception:
return None
class EventRentalController(http.Controller):
@http.route('/rentals', type='http', auth='public', website=True)
def rental_catalog(self, search='', category=None, **post):
domain = [('is_rental', '=', True)]
if search:
domain.append(('name', 'ilike', search))
# Fetch products matching domain
products = request.env['product.template'].sudo().search(domain)
# Extract categories represented by these products to display in the filter sidebar
categories = products.mapped('categ_id')
if category:
domain.append(('categ_id', '=', int(category)))
products = request.env['product.template'].sudo().search(domain)
values = {
'products': products,
'categories': categories,
'search': search,
'current_category': int(category) if category else None,
}
return request.render('event_rental.rental_catalog_template', values)
@http.route('/rentals/<string:product_slug>', type='http', auth='public', website=True)
def rental_product_detail(self, product_slug, **post):
try:
if '-' in product_slug:
product_id = int(product_slug.split('-')[-1])
else:
product_id = int(product_slug)
except (ValueError, IndexError):
return request.not_found()
product = request.env['product.template'].sudo().browse(product_id)
if not product or not product.exists() or not product.is_rental:
return request.not_found()
return request.render('event_rental.rental_product_detail_template', {'product': product})
@http.route('/rental/request', type='http', auth='public', website=True, methods=['GET', 'POST'])
def rental_request(self, product_id=None, **post):
if request.httprequest.method == 'GET':
selected_product = None
if product_id:
# Browse product product variant
product_tmpl = request.env['product.template'].sudo().browse(int(product_id))
selected_product = product_tmpl.product_variant_id
all_products = request.env['product.product'].sudo().search([('is_rental', '=', True)])
return request.render('event_rental.rental_request_form_template', {
'all_products': all_products,
'selected_product': selected_product,
'error_message': None,
'post': post
})
# Process POST request
try:
_logger.info("RENTAL REQUEST POST PARAMS (product_id=%s): %s", product_id, post)
customer_name = post.get('customer_name')
customer_email = post.get('customer_email')
customer_phone = post.get('customer_phone')
company_name = post.get('company_name')
customer_address = post.get('customer_address')
start_date_str = post.get('start_date')
end_date_str = post.get('end_date')
location = post.get('location')
event_type = post.get('event_type')
req_product_id = int(product_id or post.get('product_id') or 0)
quantity = float(post.get('quantity') or 1.0)
doc_type = post.get('doc_type', 'aadhaar')
id_proof_file = request.httprequest.files.get('id_proof')
# Simple UI checks
if not customer_name or not customer_email or not customer_phone or not start_date_str or not end_date_str or not location or not req_product_id:
raise ValueError(_("All required fields must be filled."))
if not id_proof_file or id_proof_file.filename == '':
raise ValueError(_("Please upload a valid Government ID Proof document."))
start_date = parse_html_datetime(start_date_str)
end_date = parse_html_datetime(end_date_str)
if not start_date or not end_date:
raise ValueError(_("Invalid start or end date format."))
if start_date >= end_date:
raise ValueError(_("Event Start Date must be earlier than End Date."))
product = request.env['product.product'].sudo().browse(req_product_id)
if not product:
raise ValueError(_("Invalid rental product selected."))
# Availability checking bypassed per request
# dummy_request = request.env['event.rental.request'].sudo()
# available_qty = dummy_request.check_availability(start_date, end_date, product)
#
# if available_qty < quantity:
# raise ValueError(_("Product '%s' is not available in the quantity requested (%s) for the selected dates. Only %s units are currently available.") % (
# product.name, quantity, available_qty
# ))
# Find or create partner
partner = request.env['res.partner'].sudo().search([('email', '=', customer_email)], limit=1)
if not partner:
partner = request.env['res.partner'].sudo().create({
'name': customer_name,
'email': customer_email,
'phone': customer_phone,
'company_name': company_name,
'street': customer_address,
})
# Create rental request record
rental_request = request.env['event.rental.request'].sudo().create({
'partner_id': partner.id,
'customer_name': customer_name,
'customer_email': customer_email,
'customer_phone': customer_phone,
'company_name': company_name,
'customer_address': customer_address,
'start_date': start_date,
'end_date': end_date,
'location': location,
'event_type': event_type,
'status': 'under_review',
})
# Create request line
request.env['event.rental.line'].sudo().create({
'request_id': rental_request.id,
'product_id': product.id,
'quantity': quantity,
})
# Store ID proof attachment
file_content = id_proof_file.read()
file_base64 = base64.b64encode(file_content)
attachment = request.env['ir.attachment'].sudo().create({
'name': id_proof_file.filename,
'type': 'binary',
'datas': file_base64,
'res_model': 'event.rental.request',
'res_id': rental_request.id,
})
# Create document record
request.env['event.document'].sudo().create({
'request_id': rental_request.id,
'partner_id': partner.id,
'doc_type': doc_type,
'attachment_id': attachment.id,
'verification_status': 'pending',
})
# Post submission trace
rental_request.message_post(body=_("Rental request submitted successfully from public website."))
return request.redirect(f'/rental/request/success?name={rental_request.name}')
except Exception as e:
selected_product = None
if post.get('product_id'):
selected_product = request.env['product.product'].sudo().browse(int(post.get('product_id')))
all_products = request.env['product.product'].sudo().search([('is_rental', '=', True)])
return request.render('event_rental.rental_request_form_template', {
'all_products': all_products,
'selected_product': selected_product,
'error_message': str(e),
'post': post
})
@http.route('/rental/request/success', type='http', auth='public', website=True)
def rental_request_success(self, name, **post):
return request.render('event_rental.rental_request_success_template', {'name': name})
class CustomerPortalRental(CustomerPortal):
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
if 'rental_count' in counters:
partner = request.env.user.partner_id
rental_count = request.env['event.rental.request'].search_count([
('partner_id', '=', partner.id)
])
values['rental_count'] = rental_count
return values
@http.route(['/my/rentals', '/my/rentals/page/<int:page>'], type='http', auth="user", website=True)
def portal_my_rentals(self, page=1, date_begin=None, date_end=None, sortby=None, **kw):
values = self._prepare_portal_layout_values()
partner = request.env.user.partner_id
RentalRequest = request.env['event.rental.request']
domain = [('partner_id', '=', partner.id)]
# Count for pagination
rental_count = RentalRequest.search_count(domain)
pager = portal_pager(
url="/my/rentals",
total=rental_count,
page=page,
step=10
)
requests = RentalRequest.search(domain, limit=10, offset=pager['offset'])
values.update({
'requests': requests,
'page_name': 'rental_requests',
'pager': pager,
'default_url': '/my/rentals',
})
return request.render("event_rental.portal_my_rental_requests", values)
@http.route(['/my/rentals/<int:request_id>'], type='http', auth="user", website=True)
def portal_rental_request_detail(self, request_id, **kw):
rental_request = request.env['event.rental.request'].browse(request_id)
try:
# Enforce native record rules / access rights
rental_request.check_access_rights('read')
rental_request.check_access_rule('read')
except exceptions.AccessError:
return request.redirect('/my')
values = {
'rental_request': rental_request,
'page_name': 'rental_request_detail',
}
return request.render("event_rental.portal_rental_request_detail_template", values)