mirror of
https://github.com/marcogll/AnchorOS.git
synced 2026-03-15 14:24:27 +00:00
fix: Correct calendar offset and fix business hours showing only 22:00-23:00
FIX 1 - Calendar Day Offset (already fixed in previous commit): - Corrected DatePicker component to calculate proper day offset - Added padding cells for correct weekday alignment - January 1, 2026 now correctly shows as Thursday instead of Monday FIX 2 - Business Hours Only Showing 22:00-23:00: PROBLEM: - Time slots API only returned 22:00 and 23:00 as available hours - Incorrect business hours in database (likely 22:00-23:00 instead of 10:00-19:00) - Poor timezone conversion in get_detailed_availability function ROOT CAUSES: 1. Location business_hours stored incorrect hours (22:00-23:00) 2. get_detailed_availability had timezone concatenation issues - Used string concatenation for timestamp construction - Didn't properly handle timezone conversion 3. Fallback to defaults was using wrong values SOLUTIONS: 1. Migration 20260118080000_fix_business_hours_default.sql: - Update default business hours to normal salon hours - Mon-Fri: 10:00-19:00 - Saturday: 10:00-18:00 - Sunday: Closed 2. Migration 20260118090000_fix_get_detailed_availability_timezone.sql: - Rewrite get_detailed_availability function - Use make_timestamp() instead of string concatenation - Proper timezone handling with AT TIME ZONE - Better NULL handling for business_hours - Fix is_available_for_booking COALESCE to default true CHANGES: - components/booking/date-picker.tsx: Added day offset calculation - supabase/migrations/20260118080000.sql: Fix default business hours - supabase/migrations/20260118090000.sql: Fix timezone in availability function
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
-- ============================================
|
||||||
|
-- FIX: Corregir horarios de negocio por defecto
|
||||||
|
-- Date: 20260118
|
||||||
|
-- Description: Fix business hours that only show 22:00-23:00
|
||||||
|
-- ============================================
|
||||||
|
|
||||||
|
-- Verificar horarios actuales
|
||||||
|
SELECT id, name, timezone, business_hours FROM locations;
|
||||||
|
|
||||||
|
-- Actualizar horarios de negocio a horarios normales
|
||||||
|
UPDATE locations
|
||||||
|
SET business_hours = '{
|
||||||
|
"monday": {"open": "10:00", "close": "19:00", "is_closed": false},
|
||||||
|
"tuesday": {"open": "10:00", "close": "19:00", "is_closed": false},
|
||||||
|
"wednesday": {"open": "10:00", "close": "19:00", "is_closed": false},
|
||||||
|
"thursday": {"open": "10:00", "close": "19:00", "is_closed": false},
|
||||||
|
"friday": {"open": "10:00", "close": "19:00", "is_closed": false},
|
||||||
|
"saturday": {"open": "10:00", "close": "18:00", "is_closed": false},
|
||||||
|
"sunday": {"is_closed": true}
|
||||||
|
}'::jsonb
|
||||||
|
WHERE business_hours IS NULL
|
||||||
|
OR business_hours = '{}'::jsonb;
|
||||||
|
|
||||||
|
-- Verificar que los horarios se actualizaron correctamente
|
||||||
|
SELECT id, name, timezone, business_hours FROM locations;
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
-- ============================================
|
||||||
|
-- FIX: Mejorar get_detailed_availability para corregir problema de timezone
|
||||||
|
-- Date: 20260118
|
||||||
|
-- Description: Fix timezone conversion in availability function
|
||||||
|
-- ============================================
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS get_detailed_availability(p_location_id UUID, p_service_id UUID, p_date DATE, p_time_slot_duration_minutes INTEGER) CASCADE;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION get_detailed_availability(
|
||||||
|
p_location_id UUID,
|
||||||
|
p_service_id UUID,
|
||||||
|
p_date DATE,
|
||||||
|
p_time_slot_duration_minutes INTEGER DEFAULT 60
|
||||||
|
)
|
||||||
|
RETURNS JSONB AS $$
|
||||||
|
DECLARE
|
||||||
|
v_service_duration INTEGER;
|
||||||
|
v_location_timezone TEXT;
|
||||||
|
v_business_hours JSONB;
|
||||||
|
v_day_of_week TEXT;
|
||||||
|
v_day_hours JSONB;
|
||||||
|
v_open_time_text TEXT;
|
||||||
|
v_close_time_text TEXT;
|
||||||
|
v_start_time TIME;
|
||||||
|
v_end_time TIME;
|
||||||
|
v_time_slots JSONB := '[]'::JSONB;
|
||||||
|
v_slot_start TIMESTAMPTZ;
|
||||||
|
v_slot_end TIMESTAMPTZ;
|
||||||
|
v_available_staff_count INTEGER;
|
||||||
|
v_day_names TEXT[] := ARRAY['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
|
||||||
|
BEGIN
|
||||||
|
-- Obtener duración del servicio
|
||||||
|
SELECT duration_minutes INTO v_service_duration
|
||||||
|
FROM services
|
||||||
|
WHERE id = p_service_id;
|
||||||
|
|
||||||
|
IF v_service_duration IS NULL THEN
|
||||||
|
RETURN '[]'::JSONB;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Obtener zona horaria y horarios de la ubicación
|
||||||
|
SELECT
|
||||||
|
timezone,
|
||||||
|
COALESCE(business_hours, '{}'::jsonb)
|
||||||
|
INTO
|
||||||
|
v_location_timezone,
|
||||||
|
v_business_hours
|
||||||
|
FROM locations
|
||||||
|
WHERE id = p_location_id;
|
||||||
|
|
||||||
|
IF v_location_timezone IS NULL THEN
|
||||||
|
RETURN '[]'::JSONB;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Obtener día de la semana (0 = Domingo, 1 = Lunes, etc.)
|
||||||
|
v_day_of_week := v_day_names[EXTRACT(DOW FROM p_date) + 1];
|
||||||
|
|
||||||
|
-- Obtener horarios para este día desde JSONB
|
||||||
|
v_day_hours := v_business_hours -> v_day_of_week;
|
||||||
|
|
||||||
|
-- Verificar si el lugar está cerrado este día
|
||||||
|
IF v_day_hours IS NULL OR v_day_hours->>'is_closed' = 'true' THEN
|
||||||
|
RETURN '[]'::JSONB;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Extraer horas de apertura y cierre como TEXT primero
|
||||||
|
v_open_time_text := v_day_hours->>'open';
|
||||||
|
v_close_time_text := v_day_hours->>'close';
|
||||||
|
|
||||||
|
-- Convertir a TIME, usar defaults si están NULL
|
||||||
|
v_start_time := COALESCE(v_open_time_text::TIME, '10:00'::TIME);
|
||||||
|
v_end_time := COALESCE(v_close_time_text::TIME, '19:00'::TIME);
|
||||||
|
|
||||||
|
-- Generar slots de tiempo para el día
|
||||||
|
-- Construir timestamp en la timezone correcta
|
||||||
|
v_slot_start := make_timestamp(
|
||||||
|
EXTRACT(YEAR FROM p_date)::INTEGER,
|
||||||
|
EXTRACT(MONTH FROM p_date)::INTEGER,
|
||||||
|
EXTRACT(DAY FROM p_date)::INTEGER,
|
||||||
|
EXTRACT(HOUR FROM v_start_time)::INTEGER,
|
||||||
|
EXTRACT(MINUTE FROM v_start_time)::INTEGER,
|
||||||
|
0
|
||||||
|
)::TIMESTAMPTZ AT TIME ZONE v_location_timezone;
|
||||||
|
|
||||||
|
v_slot_end := make_timestamp(
|
||||||
|
EXTRACT(YEAR FROM p_date)::INTEGER,
|
||||||
|
EXTRACT(MONTH FROM p_date)::INTEGER,
|
||||||
|
EXTRACT(DAY FROM p_date)::INTEGER,
|
||||||
|
EXTRACT(HOUR FROM v_end_time)::INTEGER,
|
||||||
|
EXTRACT(MINUTE FROM v_end_time)::INTEGER,
|
||||||
|
0
|
||||||
|
)::TIMESTAMPTZ AT TIME ZONE v_location_timezone;
|
||||||
|
|
||||||
|
-- Iterar por cada slot
|
||||||
|
WHILE v_slot_start < v_slot_end LOOP
|
||||||
|
-- Verificar staff disponible para este slot
|
||||||
|
SELECT COUNT(*) INTO v_available_staff_count
|
||||||
|
FROM (
|
||||||
|
SELECT 1
|
||||||
|
FROM staff s
|
||||||
|
WHERE s.location_id = p_location_id
|
||||||
|
AND s.is_active = true
|
||||||
|
AND COALESCE(s.is_available_for_booking, true) = true
|
||||||
|
AND s.role IN ('artist', 'staff', 'manager')
|
||||||
|
AND check_staff_availability(s.id, v_slot_start, v_slot_start + (v_service_duration || ' minutes')::INTERVAL)
|
||||||
|
) AS available_staff;
|
||||||
|
|
||||||
|
-- Agregar slot al resultado
|
||||||
|
IF v_available_staff_count > 0 THEN
|
||||||
|
v_time_slots := v_time_slots || jsonb_build_object(
|
||||||
|
'start_time', v_slot_start::TEXT,
|
||||||
|
'end_time', (v_slot_start + (p_time_slot_duration_minutes || ' minutes')::INTERVAL)::TEXT,
|
||||||
|
'available', true,
|
||||||
|
'available_staff_count', v_available_staff_count
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Avanzar al siguiente slot
|
||||||
|
v_slot_start := v_slot_start + (p_time_slot_duration_minutes || ' minutes')::INTERVAL;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
RETURN v_time_slots;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||||
|
|
||||||
|
GRANT EXECUTE ON FUNCTION get_detailed_availability TO authenticated, service_role;
|
||||||
|
|
||||||
|
COMMENT ON FUNCTION get_detailed_availability IS 'Returns available time slots for booking with correct timezone handling';
|
||||||
Reference in New Issue
Block a user