diff --git a/frontend/src/routes/book/+page.svelte b/frontend/src/routes/book/+page.svelte
index eb90d35..762aa23 100644
--- a/frontend/src/routes/book/+page.svelte
+++ b/frontend/src/routes/book/+page.svelte
@@ -636,6 +636,24 @@
}
}
+ function getDayWithOrdinal(date: CalendarDate): string {
+ const monthName = new Date(date.year, date.month - 1, date.day).toLocaleDateString('en-GB', {
+ month: 'long'
+ });
+ const day = date.day;
+ if (day > 3 && day < 21) return monthName + ' ' + day + 'th';
+ switch (day % 10) {
+ case 1:
+ return monthName + ' ' + day + 'st';
+ case 2:
+ return monthName + ' ' + day + 'nd';
+ case 3:
+ return monthName + ' ' + day + 'rd';
+ default:
+ return monthName + ' ' + day + 'th';
+ }
+ }
+
// Use the formatted duration everywhere
const formattedTotalDuration = $derived(formatDuration(getTotalDuration()));
@@ -823,6 +841,9 @@
{#if (loadingWorkingHours || loadingAvailableHours) && selectedDate}
Loading available times...
{:else if groupedTimeSlots.length > 0}
+ {#if selectedDate}
+ {getDayWithOrdinal(selectedDate)}
+ {/if}
{#each groupedTimeSlots as slot (slot.startTime)}
diff --git a/init-scripts/init-script.sql b/init-scripts/init-script.sql
index efbb328..20f95d2 100644
--- a/init-scripts/init-script.sql
+++ b/init-scripts/init-script.sql
@@ -327,14 +327,19 @@ INSERT INTO business_settings (
'Crussell Nail Art Studio',
'Address',
'+44 131 123 4567',
- 'Email',
- NULL, -- Set this when you register for VAT
- FALSE, -- Set to TRUE when you register for VAT
+ 'crussellnails@gmail.com',
+ NULL, -- Set this when we register for VAT
+ FALSE, -- Set to TRUE when we register for VAT
20.00,
'GBP',
'https://www.website.co.uk'
);
+CREATE INDEX idx_payments_booking_id_status ON payments(booking_id, status);
+CREATE INDEX idx_bookings_start_time_status ON bookings(start_time, status);
+CREATE INDEX idx_users_created_at ON users(created_at);
+CREATE INDEX idx_payments_created_at_status ON payments(created_at, status);
+
-- =======================================
-- GDPR COMPLIANCE FUNCTIONS
-- =======================================
@@ -425,7 +430,7 @@ BEGIN
'account_role', account_role,
'loyalty_stamps', loyalty_stamps,
'data_retention_consent', data_retention_consent,
- 'data_consent_updated_at', consent_updated_at,
+ 'data_consent_updated_at', data_consent_updated_at,
'created_at', created_at,
'updated_at', updated_at
)
@@ -528,14 +533,26 @@ BEGIN
COALESCE(SUM(p.amount), 0) as total_sales,
COALESCE(SUM(
CASE
- WHEN p.vat_rate IS NOT NULL THEN p.vat_amount
- ELSE ROUND(p.amount - (p.amount / (1 + COALESCE(p.vat_rate, 20.00)/100)), 2)
+ -- If VAT is explicitly stored, use it
+ WHEN p.vat_amount IS NOT NULL THEN p.vat_amount
+ -- If business is VAT registered but no VAT breakdown, calculate it
+ WHEN (SELECT is_vat_registered FROM business_settings WHERE id = 1) THEN
+ ROUND(p.amount - (p.amount / (1 + COALESCE(p.vat_rate,
+ (SELECT default_vat_rate FROM business_settings WHERE id = 1))/100)), 2)
+ -- Business not VAT registered = no VAT charged
+ ELSE 0
END
), 0) as total_vat_charged,
COALESCE(SUM(
CASE
+ -- If net amount is explicitly stored, use it
WHEN p.net_amount IS NOT NULL THEN p.net_amount
- ELSE ROUND(p.amount / 1.20, 2) -- Calculate net if not stored
+ -- If business is VAT registered but no net amount, calculate it
+ WHEN (SELECT is_vat_registered FROM business_settings WHERE id = 1) THEN
+ ROUND(p.amount / (1 + COALESCE(p.vat_rate,
+ (SELECT default_vat_rate FROM business_settings WHERE id = 1))/100), 2)
+ -- Business not VAT registered = gross amount is net amount
+ ELSE p.amount
END
), 0) as net_sales,
COUNT(*) as transaction_count
@@ -543,7 +560,7 @@ BEGIN
JOIN bookings b ON p.booking_id = b.id
WHERE p.status = 'completed'
AND p.created_at::date BETWEEN start_date AND end_date
- AND p.payment_type IN ('full', 'partial', 'balance'); -- Exclude deposits and tips for main sales
+ AND p.payment_type IN ('full', 'partial', 'balance');
END;
$$ LANGUAGE plpgsql;
@@ -690,7 +707,7 @@ $$ LANGUAGE plpgsql;
-- WHY: When crossing £90k threshold, must register for VAT and backfill existing data
-- WHEN: One-time use when VAT registration becomes mandatory
-- OUTPUT: Updates all historical payments with VAT breakdown + sets new defaults
--- USE: Call once when you register for VAT - transforms business from non-VAT to VAT
+-- USE: Call once when we register for VAT - transforms business from non-VAT to VAT
-- =======================================
-- UTILITY FUNCTIONS
-- =======================================
@@ -699,7 +716,7 @@ $$ LANGUAGE plpgsql;
-- WHY: When crossing £90k threshold, must register for VAT and backfill existing data
-- WHEN: One-time use when VAT registration becomes mandatory
-- OUTPUT: Updates all historical payments with VAT breakdown + sets new defaults
--- USE: Call once when you register for VAT - transforms business from non-VAT to VAT
+-- USE: Call once when we register for VAT - transforms business from non-VAT to VAT
CREATE OR REPLACE FUNCTION enable_vat_registration(
registration_date DATE DEFAULT CURRENT_DATE,
vat_rate NUMERIC(5,2) DEFAULT 20.00,
@@ -1022,7 +1039,7 @@ $$ LANGUAGE plpgsql;
-- =======================================
/*
This summary organizes all database functions by their primary purpose, legal basis, and expected usage frequency—
-providing a clear guide for integration into your application, compliance workflows, and business operations.
+providing a clear guide for integration into our application, compliance workflows, and business operations.
--------------------------------------------------------------------------------
1. FINANCIAL & TAX COMPLIANCE