Fix init script
This commit is contained in:
@@ -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()
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user