CHANGES
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import json
|
||||
import hashlib
|
||||
import logging
|
||||
import secrets
|
||||
|
||||
@@ -796,12 +795,12 @@ class PortalSchedule(CustomerPortal):
|
||||
if not event.exists() or partner not in event.partner_ids:
|
||||
return {'success': False, 'error': 'Event not found or access denied.'}
|
||||
|
||||
tz = self._get_user_timezone()
|
||||
# The slot datetime sent by the client is already UTC (the slot
|
||||
# generator emits UTC); parse it directly — do NOT re-localize, which
|
||||
# would double-shift the appointment by the user's UTC offset.
|
||||
try:
|
||||
start_naive = datetime.strptime(new_datetime, '%Y-%m-%d %H:%M:%S')
|
||||
start_local = tz.localize(start_naive)
|
||||
start_utc = start_local.astimezone(pytz.utc).replace(tzinfo=None)
|
||||
except (ValueError, Exception) as e:
|
||||
start_utc = datetime.strptime(new_datetime, '%Y-%m-%d %H:%M:%S')
|
||||
except (ValueError, Exception):
|
||||
return {'success': False, 'error': 'Invalid date/time format.'}
|
||||
|
||||
duration = float(new_duration) if new_duration else event.duration
|
||||
@@ -883,12 +882,10 @@ class PortalSchedule(CustomerPortal):
|
||||
if not slot_datetime:
|
||||
return request.redirect('/schedule/manage/%s?error=Please+select+a+new+time+slot' % token)
|
||||
|
||||
tz = self._resolve_timezone(event.user_id)
|
||||
|
||||
# The slot datetime is already UTC (the slot generator emits UTC); parse
|
||||
# directly — do NOT re-localize (that double-shifts by the tz offset).
|
||||
try:
|
||||
start_naive = datetime.strptime(slot_datetime, '%Y-%m-%d %H:%M:%S')
|
||||
start_local = tz.localize(start_naive)
|
||||
start_utc = start_local.astimezone(pytz.utc).replace(tzinfo=None)
|
||||
start_utc = datetime.strptime(slot_datetime, '%Y-%m-%d %H:%M:%S')
|
||||
except (ValueError, Exception):
|
||||
return request.redirect('/schedule/manage/%s?error=Invalid+time+slot' % token)
|
||||
|
||||
@@ -1499,12 +1496,10 @@ class PortalSchedule(CustomerPortal):
|
||||
'/schedule/%s?error=Name,+email,+and+time+slot+are+required' % slug
|
||||
)
|
||||
|
||||
tz = self._resolve_timezone(user)
|
||||
|
||||
# The slot datetime is already UTC (the slot generator emits UTC); parse
|
||||
# directly — do NOT re-localize (that double-shifts by the tz offset).
|
||||
try:
|
||||
start_dt_naive = datetime.strptime(slot_datetime, '%Y-%m-%d %H:%M:%S')
|
||||
start_dt_local = tz.localize(start_dt_naive)
|
||||
start_dt_utc = start_dt_local.astimezone(pytz.utc).replace(tzinfo=None)
|
||||
start_dt_utc = datetime.strptime(slot_datetime, '%Y-%m-%d %H:%M:%S')
|
||||
except (ValueError, Exception) as e:
|
||||
_logger.error("Failed to parse slot datetime %s: %s", slot_datetime, e)
|
||||
return request.redirect('/schedule/%s?error=Invalid+time+slot' % slug)
|
||||
@@ -1512,17 +1507,22 @@ class PortalSchedule(CustomerPortal):
|
||||
duration = float(slot_duration)
|
||||
stop_dt_utc = start_dt_utc + timedelta(hours=duration)
|
||||
|
||||
# Find or create partner for the visitor
|
||||
# Find or create a contact for the visitor. SECURITY: this is an
|
||||
# unauthenticated endpoint and visitor_email is attacker-controlled, so
|
||||
# never reuse/attach a partner that backs a login user (staff/internal),
|
||||
# and never write onto an existing contact. Reuse only a plain non-user
|
||||
# contact (avoids duplicates for genuine repeat visitors).
|
||||
Partner = request.env['res.partner'].sudo()
|
||||
partner = Partner.search([('email', '=ilike', visitor_email)], limit=1)
|
||||
partner = Partner.search([
|
||||
('email', '=ilike', visitor_email),
|
||||
('user_ids', '=', False),
|
||||
], limit=1)
|
||||
if not partner:
|
||||
partner = Partner.create({
|
||||
'name': visitor_name,
|
||||
'email': visitor_email,
|
||||
'phone': visitor_phone,
|
||||
'phone': visitor_phone or False,
|
||||
})
|
||||
elif visitor_phone and not partner.phone:
|
||||
partner.phone = visitor_phone
|
||||
|
||||
address_parts = [p for p in [visitor_street, visitor_city, visitor_province, visitor_postal] if p]
|
||||
location = ', '.join(address_parts)
|
||||
|
||||
Reference in New Issue
Block a user