Fix init script

This commit is contained in:
2025-11-06 16:29:41 +00:00
parent 28815d3b25
commit 01780d90e5
+55 -55
View File
@@ -126,14 +126,6 @@ CREATE TABLE user_social_logins (
CREATE INDEX idx_users_email_lower ON users (LOWER(email)); CREATE INDEX idx_users_email_lower ON users (LOWER(email));
CREATE INDEX idx_users_account_role ON users (account_role); CREATE INDEX idx_users_account_role ON users (account_role);
CREATE TABLE user_referrals (
referrer_id CHAR(12) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
referred_id CHAR(12) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
referred_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
claimed_booking_id CHAR(12) REFERENCES bookings(id) ON DELETE SET NULL,
PRIMARY KEY (referrer_id, referred_id)
);
-- ======================================= -- =======================================
-- SERVICES TABLE -- SERVICES TABLE
-- ======================================= -- =======================================
@@ -196,6 +188,14 @@ CREATE TABLE booking_services (
PRIMARY KEY (booking_id, service_id) PRIMARY KEY (booking_id, service_id)
); );
CREATE TABLE user_referrals (
referrer_id CHAR(12) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
referred_id CHAR(12) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
referred_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
claimed_booking_id CHAR(12) REFERENCES bookings(id) ON DELETE SET NULL,
PRIMARY KEY (referrer_id, referred_id)
);
-- ======================================= -- =======================================
-- DEFAULT WORKING HOURS TABLE -- DEFAULT WORKING HOURS TABLE
-- ======================================= -- =======================================
@@ -484,8 +484,8 @@ BEGIN
'updated_by', p.updated_by 'updated_by', p.updated_by
) )
), '[]'::json) ), '[]'::json)
FROM payments p FROM payments p
JOIN bookings b ON p.booking_id = b.id JOIN bookings b ON p.booking_id = b.id
WHERE b.user_id = target_user_id WHERE b.user_id = target_user_id
), ),
'export_metadata', json_build_object( 'export_metadata', json_build_object(
@@ -495,7 +495,7 @@ BEGIN
'format_version', '1.0' 'format_version', '1.0'
) )
) INTO result; ) INTO result;
RETURN result; RETURN result;
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
@@ -531,7 +531,7 @@ RETURNS TABLE (
) AS $$ ) AS $$
BEGIN BEGIN
RETURN QUERY RETURN QUERY
SELECT SELECT
start_date as period_start, start_date as period_start,
end_date as period_end, end_date as period_end,
COALESCE(SUM(p.amount), 0) as total_sales, COALESCE(SUM(p.amount), 0) as total_sales,
@@ -540,20 +540,20 @@ BEGIN
-- If VAT is explicitly stored, use it -- If VAT is explicitly stored, use it
WHEN p.vat_amount IS NOT NULL THEN p.vat_amount WHEN p.vat_amount IS NOT NULL THEN p.vat_amount
-- If business is VAT registered but no VAT breakdown, calculate it -- If business is VAT registered but no VAT breakdown, calculate it
WHEN (SELECT is_vat_registered FROM business_settings WHERE id = 1) THEN WHEN (SELECT is_vat_registered FROM business_settings WHERE id = 1) THEN
ROUND(p.amount - (p.amount / (1 + COALESCE(p.vat_rate, ROUND(p.amount - (p.amount / (1 + COALESCE(p.vat_rate,
(SELECT default_vat_rate FROM business_settings WHERE id = 1))/100)), 2) (SELECT default_vat_rate FROM business_settings WHERE id = 1))/100), 2)
-- Business not VAT registered = no VAT charged -- Business not VAT registered = no VAT charged
ELSE 0 ELSE 0
END END
), 0) as total_vat_charged, ), 0) as total_vat_charged,
COALESCE(SUM( COALESCE(SUM(
CASE CASE
-- If net amount is explicitly stored, use it -- If net amount is explicitly stored, use it
WHEN p.net_amount IS NOT NULL THEN p.net_amount WHEN p.net_amount IS NOT NULL THEN p.net_amount
-- If business is VAT registered but no net amount, calculate it -- If business is VAT registered but no net amount, calculate it
WHEN (SELECT is_vat_registered FROM business_settings WHERE id = 1) THEN WHEN (SELECT is_vat_registered FROM business_settings WHERE id = 1) THEN
ROUND(p.amount / (1 + COALESCE(p.vat_rate, ROUND(p.amount / (1 + COALESCE(p.vat_rate,
(SELECT default_vat_rate FROM business_settings WHERE id = 1))/100), 2) (SELECT default_vat_rate FROM business_settings WHERE id = 1))/100), 2)
-- Business not VAT registered = gross amount is net amount -- Business not VAT registered = gross amount is net amount
ELSE p.amount ELSE p.amount
@@ -595,7 +595,7 @@ RETURNS TABLE (
) AS $$ ) AS $$
BEGIN BEGIN
RETURN QUERY RETURN QUERY
SELECT SELECT
p.created_at::date as transaction_date, p.created_at::date as transaction_date,
p.invoice_number::text AS invoice_number, p.invoice_number::text AS invoice_number,
COALESCE(u.fn, 'Walk-in Customer') as customer_name, COALESCE(u.fn, 'Walk-in Customer') as customer_name,
@@ -603,17 +603,17 @@ BEGIN
string_agg(s.name, ', ') as service_description, string_agg(s.name, ', ') as service_description,
p.payment_method::text as payment_method, p.payment_method::text as payment_method,
p.amount as gross_amount, p.amount as gross_amount,
CASE CASE
WHEN include_vat AND p.net_amount IS NOT NULL THEN p.net_amount WHEN include_vat AND p.net_amount IS NOT NULL THEN p.net_amount
WHEN include_vat THEN ROUND(p.amount / 1.20, 2) WHEN include_vat THEN ROUND(p.amount / 1.20, 2)
ELSE p.amount ELSE p.amount
END as net_amount, END as net_amount,
CASE CASE
WHEN include_vat AND p.vat_amount IS NOT NULL THEN p.vat_amount WHEN include_vat AND p.vat_amount IS NOT NULL THEN p.vat_amount
WHEN include_vat THEN ROUND(p.amount - (p.amount / 1.20), 2) WHEN include_vat THEN ROUND(p.amount - (p.amount / 1.20), 2)
ELSE 0 ELSE 0
END as vat_amount, END as vat_amount,
CASE CASE
WHEN include_vat THEN COALESCE(p.vat_rate, 20.00) WHEN include_vat THEN COALESCE(p.vat_rate, 20.00)
ELSE NULL ELSE NULL
END as vat_rate, END as vat_rate,
@@ -653,7 +653,7 @@ RETURNS TABLE (
) AS $$ ) AS $$
BEGIN BEGIN
RETURN QUERY RETURN QUERY
SELECT SELECT
TO_CHAR(p.created_at, 'YYYY-MM') as month_year, TO_CHAR(p.created_at, 'YYYY-MM') as month_year,
COUNT(DISTINCT b.id) as total_bookings, COUNT(DISTINCT b.id) as total_bookings,
SUM(p.amount) as total_revenue, SUM(p.amount) as total_revenue,
@@ -689,7 +689,7 @@ RETURNS TABLE (
) AS $$ ) AS $$
BEGIN BEGIN
RETURN QUERY RETURN QUERY
SELECT SELECT
COALESCE(SUM(p.amount), 0) as total_sales, COALESCE(SUM(p.amount), 0) as total_sales,
COUNT(*) as total_transactions, COUNT(*) as total_transactions,
COALESCE(SUM(CASE WHEN p.payment_method = 'cash' THEN p.amount ELSE 0 END), 0) as cash_total, COALESCE(SUM(CASE WHEN p.payment_method = 'cash' THEN p.amount ELSE 0 END), 0) as cash_total,
@@ -740,8 +740,8 @@ DECLARE
settings_ok BOOLEAN := FALSE; settings_ok BOOLEAN := FALSE;
BEGIN BEGIN
-- Update all existing completed payments with VAT breakdown -- Update all existing completed payments with VAT breakdown
UPDATE payments UPDATE payments
SET SET
vat_rate = enable_vat_registration.vat_rate, vat_rate = enable_vat_registration.vat_rate,
vat_amount = ROUND(amount - (amount / (1 + enable_vat_registration.vat_rate/100)), 2), vat_amount = ROUND(amount - (amount / (1 + enable_vat_registration.vat_rate/100)), 2),
net_amount = ROUND(amount / (1 + enable_vat_registration.vat_rate/100), 2), net_amount = ROUND(amount / (1 + enable_vat_registration.vat_rate/100), 2),
@@ -750,33 +750,33 @@ BEGIN
WHERE status = 'completed' WHERE status = 'completed'
AND created_at::date >= registration_date AND created_at::date >= registration_date
AND vat_amount IS NULL; AND vat_amount IS NULL;
GET DIAGNOSTICS updated_count = ROW_COUNT; GET DIAGNOSTICS updated_count = ROW_COUNT;
-- Calculate totals -- Calculate totals
SELECT SELECT
COALESCE(SUM(vat_amount), 0), COALESCE(SUM(vat_amount), 0),
COALESCE(SUM(net_amount), 0) COALESCE(SUM(net_amount), 0)
INTO total_vat, total_net INTO total_vat, total_net
FROM payments FROM payments
WHERE status = 'completed' WHERE status = 'completed'
AND created_at::date >= registration_date AND created_at::date >= registration_date
AND vat_amount IS NOT NULL; AND vat_amount IS NOT NULL;
-- Update business_settings to reflect VAT registration -- Update business_settings to reflect VAT registration
UPDATE business_settings UPDATE business_settings
SET SET
is_vat_registered = TRUE, is_vat_registered = TRUE,
vat_registration_number = COALESCE(vat_reg_number, vat_registration_number), vat_registration_number = COALESCE(vat_reg_number, vat_registration_number),
default_vat_rate = enable_vat_registration.vat_rate, default_vat_rate = enable_vat_registration.vat_rate,
updated_at = NOW() updated_at = NOW()
WHERE id = 1; WHERE id = 1;
IF FOUND THEN IF FOUND THEN
settings_ok := TRUE; settings_ok := TRUE;
END IF; END IF;
RETURN QUERY SELECT RETURN QUERY SELECT
updated_count, updated_count,
total_vat, total_vat,
total_net, total_net,
@@ -821,7 +821,7 @@ BEGIN
-- Update payment with VAT amounts -- Update payment with VAT amounts
UPDATE payments UPDATE payments
SET SET
vat_rate = effective_rate, vat_rate = effective_rate,
vat_amount = ROUND(amount - (amount / (1 + effective_rate/100)), 2), vat_amount = ROUND(amount - (amount / (1 + effective_rate/100)), 2),
net_amount = ROUND(amount / (1 + effective_rate/100), 2), net_amount = ROUND(amount / (1 + effective_rate/100), 2),
@@ -865,7 +865,7 @@ BEGIN
-- Return net and VAT -- Return net and VAT
RETURN QUERY RETURN QUERY
SELECT SELECT
ROUND(gross_amount / (1 + effective_rate/100), 2) AS net, ROUND(gross_amount / (1 + effective_rate/100), 2) AS net,
gross_amount - ROUND(gross_amount / (1 + effective_rate/100), 2) AS vat; gross_amount - ROUND(gross_amount / (1 + effective_rate/100), 2) AS vat;
END; END;
@@ -909,36 +909,36 @@ RETURNS TABLE (
business_email TEXT, business_email TEXT,
vat_registration_number TEXT, vat_registration_number TEXT,
is_vat_registered BOOLEAN, is_vat_registered BOOLEAN,
-- Payment Information -- Payment Information
payment_id CHAR(12), payment_id CHAR(12),
invoice_number TEXT, invoice_number TEXT,
transaction_date TIMESTAMPTZ, transaction_date TIMESTAMPTZ,
payment_method TEXT, payment_method TEXT,
payment_status TEXT, payment_status TEXT,
-- Customer Information -- Customer Information
customer_id CHAR(12), customer_id CHAR(12),
customer_name TEXT, customer_name TEXT,
customer_email TEXT, customer_email TEXT,
customer_phone TEXT, customer_phone TEXT,
-- Booking Information -- Booking Information
booking_id CHAR(12), booking_id CHAR(12),
appointment_date TIMESTAMPTZ, appointment_date TIMESTAMPTZ,
booking_status TEXT, booking_status TEXT,
-- Service Details -- Service Details
services JSON, services JSON,
total_duration_minutes INT, total_duration_minutes INT,
-- Financial Information -- Financial Information
gross_amount NUMERIC(10,2), gross_amount NUMERIC(10,2),
net_amount NUMERIC(10,2), net_amount NUMERIC(10,2),
vat_amount NUMERIC(10,2), vat_amount NUMERIC(10,2),
vat_rate NUMERIC(5,2), vat_rate NUMERIC(5,2),
is_vat_applicable BOOLEAN, is_vat_applicable BOOLEAN,
-- Receipt Metadata -- Receipt Metadata
receipt_generated_at TIMESTAMPTZ, receipt_generated_at TIMESTAMPTZ,
currency_code TEXT currency_code TEXT
@@ -959,7 +959,7 @@ BEGIN
WHERE id = 1; WHERE id = 1;
RETURN QUERY RETURN QUERY
SELECT SELECT
-- Business Info -- Business Info
bs.business_name, bs.business_name,
bs.business_address, bs.business_address,
@@ -967,34 +967,34 @@ BEGIN
bs.business_email, bs.business_email,
bs.vat_registration_number, bs.vat_registration_number,
bs.is_vat_registered, bs.is_vat_registered,
-- Payment Info -- Payment Info
p.id as payment_id, p.id as payment_id,
COALESCE('INV-' || p.invoice_number::text, 'INV-' || p.id) as invoice_number, COALESCE('INV-' || p.invoice_number::text, 'INV-' || p.id) as invoice_number,
p.created_at as transaction_date, p.created_at as transaction_date,
p.payment_method::text as payment_method, p.payment_method::text as payment_method,
p.status::text as payment_status, p.status::text as payment_status,
-- Customer Info -- Customer Info
u.id as customer_id, u.id as customer_id,
CASE CASE
WHEN u.account_role = 'guest' OR u.fn = 'Deleted User' THEN 'Walk-in Customer' WHEN u.account_role = 'guest' OR u.fn = 'Deleted User' THEN 'Walk-in Customer'
ELSE u.fn ELSE u.fn
END as customer_name, END as customer_name,
CASE CASE
WHEN u.account_role = 'guest' OR u.fn = 'Deleted User' THEN NULL WHEN u.account_role = 'guest' OR u.fn = 'Deleted User' THEN NULL
ELSE u.email ELSE u.email
END as customer_email, END as customer_email,
CASE CASE
WHEN u.account_role = 'guest' OR u.fn = 'Deleted User' THEN NULL WHEN u.account_role = 'guest' OR u.fn = 'Deleted User' THEN NULL
ELSE u.phone ELSE u.phone
END as customer_phone, END as customer_phone,
-- Booking Info -- Booking Info
b.id as booking_id, b.id as booking_id,
b.start_time as appointment_date, b.start_time as appointment_date,
b.status::text as booking_status, b.status::text as booking_status,
-- Service Details -- Service Details
COALESCE(( COALESCE((
SELECT json_agg( SELECT json_agg(
@@ -1011,7 +1011,7 @@ BEGIN
JOIN services s ON bs_inner.service_id = s.id JOIN services s ON bs_inner.service_id = s.id
WHERE bs_inner.booking_id = b.id WHERE bs_inner.booking_id = b.id
), '[]'::json) as services, ), '[]'::json) as services,
-- Total service duration -- Total service duration
COALESCE(( COALESCE((
SELECT SUM(s.duration_minutes) SELECT SUM(s.duration_minutes)
@@ -1019,18 +1019,18 @@ BEGIN
JOIN services s ON bs_inner.service_id = s.id JOIN services s ON bs_inner.service_id = s.id
WHERE bs_inner.booking_id = b.id WHERE bs_inner.booking_id = b.id
), 0) as total_duration_minutes, ), 0) as total_duration_minutes,
-- Financial Info -- Financial Info
p.amount as gross_amount, p.amount as gross_amount,
COALESCE(p.net_amount, p.amount) as net_amount, COALESCE(p.net_amount, p.amount) as net_amount,
COALESCE(p.vat_amount, 0.00) as vat_amount, COALESCE(p.vat_amount, 0.00) as vat_amount,
p.vat_rate as vat_rate, p.vat_rate as vat_rate,
p.is_vat_applicable as is_vat_applicable, p.is_vat_applicable as is_vat_applicable,
-- Receipt Metadata -- Receipt Metadata
NOW() as receipt_generated_at, NOW() as receipt_generated_at,
bs.currency_code as currency_code bs.currency_code as currency_code
FROM payments p FROM payments p
JOIN bookings b ON p.booking_id = b.id JOIN bookings b ON p.booking_id = b.id
LEFT JOIN users u ON b.user_id = u.id LEFT JOIN users u ON b.user_id = u.id
@@ -1111,4 +1111,4 @@ INTEGRATION QUICK REFERENCE
• Monthly close → export_sales_transactions(..., include_vat := [true/false]) • Monthly close → export_sales_transactions(..., include_vat := [true/false])
• VAT registration day → enable_vat_registration() once, then apply_vat_to_payment() • VAT registration day → enable_vat_registration() once, then apply_vat_to_payment()
• Dashboard load → get_sales_totals() + get_monthly_business_summary() • Dashboard load → get_sales_totals() + get_monthly_business_summary()
*/ */