Files
blackcanyontickets/supabase/migrations/005_add_fee_payment_model.sql
2025-07-08 12:31:31 -06:00

184 lines
7.0 KiB
PL/PgSQL

-- Add fee payment model options to organizations table
-- This determines whether customers pay the platform fee on top of the ticket price
-- or if the fee is absorbed into the ticket price
ALTER TABLE organizations
ADD COLUMN platform_fee_model VARCHAR(20) DEFAULT 'customer_pays',
ADD COLUMN absorb_fee_in_price BOOLEAN DEFAULT false;
-- Update fee_structures table to include the fee model
ALTER TABLE fee_structures
ADD COLUMN fee_model VARCHAR(20) DEFAULT 'customer_pays',
ADD COLUMN absorb_fee_in_price BOOLEAN DEFAULT false;
-- Add comments for clarity
COMMENT ON COLUMN organizations.platform_fee_model IS 'Fee payment model: customer_pays, absorbed_in_price';
COMMENT ON COLUMN organizations.absorb_fee_in_price IS 'Whether to hide fee by including it in the displayed ticket price';
COMMENT ON COLUMN fee_structures.fee_model IS 'Fee payment model: customer_pays, absorbed_in_price';
COMMENT ON COLUMN fee_structures.absorb_fee_in_price IS 'Whether to hide fee by including it in the displayed ticket price';
-- Update existing organizations with default fee model and actual BCT rates
UPDATE organizations
SET
platform_fee_model = 'customer_pays',
absorb_fee_in_price = false,
platform_fee_percentage = 0.025, -- 2.5% BCT platform fee
platform_fee_fixed = 150 -- $1.50 BCT platform fee
WHERE platform_fee_model IS NULL;
-- Update existing fee structure templates with actual rates
UPDATE fee_structures
SET
fee_model = 'customer_pays',
absorb_fee_in_price = false
WHERE fee_model IS NULL;
-- Update the default template to reflect actual BCT rates
UPDATE fee_structures
SET
fee_percentage = 0.025,
fee_fixed = 150,
description = 'BCT platform fee: 2.5% + $1.50 per transaction'
WHERE name = 'Standard Platform Fee' AND is_template = true;
-- Add new fee structure templates with absorbed fee model and correct BCT rates
INSERT INTO fee_structures (name, description, fee_type, fee_percentage, fee_fixed, fee_model, absorb_fee_in_price, is_template) VALUES
('All-Inclusive BCT Standard', 'BCT platform fee 2.5% + $1.50 included in ticket price', 'percentage_plus_fixed', 0.025, 150, 'absorbed_in_price', true, true),
('All-Inclusive Percentage Only', '2.5% fee included in ticket price', 'percentage', 0.025, 0, 'absorbed_in_price', true, true),
('All-Inclusive Fixed Only', '$1.50 fee included in ticket price', 'fixed', 0.0000, 150, 'absorbed_in_price', true, true),
('Premium All-Inclusive', 'Premium 3% + $2.00 fee included in ticket price', 'percentage_plus_fixed', 0.030, 200, 'absorbed_in_price', true, true);
-- Add template for Stripe fee structure (for reference/calculation)
INSERT INTO fee_structures (name, description, fee_type, fee_percentage, fee_fixed, fee_model, absorb_fee_in_price, is_template) VALUES
('Stripe Processing Fee', 'Stripe credit card processing: 2.99% + $0.30', 'percentage_plus_fixed', 0.0299, 30, 'customer_pays', false, true);
-- Add function to calculate the display price based on fee model
CREATE OR REPLACE FUNCTION calculate_display_price(
base_price DECIMAL,
fee_percentage DECIMAL DEFAULT 0.03,
fee_fixed INTEGER DEFAULT 30,
fee_type VARCHAR DEFAULT 'percentage_plus_fixed',
fee_model VARCHAR DEFAULT 'customer_pays'
) RETURNS DECIMAL AS $$
DECLARE
platform_fee DECIMAL;
display_price DECIMAL;
BEGIN
-- Calculate platform fee based on fee type
CASE fee_type
WHEN 'percentage' THEN
platform_fee := base_price * fee_percentage;
WHEN 'fixed' THEN
platform_fee := fee_fixed / 100.0; -- Convert cents to dollars
WHEN 'percentage_plus_fixed' THEN
platform_fee := (base_price * fee_percentage) + (fee_fixed / 100.0);
ELSE
platform_fee := (base_price * fee_percentage) + (fee_fixed / 100.0);
END CASE;
-- Calculate display price based on fee model
CASE fee_model
WHEN 'customer_pays' THEN
-- Customer pays base price + platform fee
display_price := base_price;
WHEN 'absorbed_in_price' THEN
-- Platform fee is absorbed into the display price
-- To maintain the same net revenue for organizer,
-- we need to increase the display price to cover the fee
display_price := base_price + platform_fee;
ELSE
display_price := base_price;
END CASE;
RETURN ROUND(display_price, 2);
END;
$$ LANGUAGE plpgsql;
-- Add function to calculate the total amount customer pays
CREATE OR REPLACE FUNCTION calculate_customer_total(
base_price DECIMAL,
fee_percentage DECIMAL DEFAULT 0.03,
fee_fixed INTEGER DEFAULT 30,
fee_type VARCHAR DEFAULT 'percentage_plus_fixed',
fee_model VARCHAR DEFAULT 'customer_pays'
) RETURNS DECIMAL AS $$
DECLARE
platform_fee DECIMAL;
customer_total DECIMAL;
BEGIN
-- Calculate platform fee based on fee type
CASE fee_type
WHEN 'percentage' THEN
platform_fee := base_price * fee_percentage;
WHEN 'fixed' THEN
platform_fee := fee_fixed / 100.0; -- Convert cents to dollars
WHEN 'percentage_plus_fixed' THEN
platform_fee := (base_price * fee_percentage) + (fee_fixed / 100.0);
ELSE
platform_fee := (base_price * fee_percentage) + (fee_fixed / 100.0);
END CASE;
-- Calculate total amount customer pays
CASE fee_model
WHEN 'customer_pays' THEN
-- Customer pays base price + platform fee separately
customer_total := base_price + platform_fee;
WHEN 'absorbed_in_price' THEN
-- Customer pays only the display price (fee is included)
customer_total := base_price;
ELSE
customer_total := base_price + platform_fee;
END CASE;
RETURN ROUND(customer_total, 2);
END;
$$ LANGUAGE plpgsql;
-- Add function to calculate organizer net with fee model
CREATE OR REPLACE FUNCTION calculate_organizer_net(
base_price DECIMAL,
fee_percentage DECIMAL DEFAULT 0.03,
fee_fixed INTEGER DEFAULT 30,
fee_type VARCHAR DEFAULT 'percentage_plus_fixed',
fee_model VARCHAR DEFAULT 'customer_pays'
) RETURNS DECIMAL AS $$
DECLARE
platform_fee DECIMAL;
organizer_net DECIMAL;
BEGIN
-- Calculate platform fee based on fee type
CASE fee_type
WHEN 'percentage' THEN
platform_fee := base_price * fee_percentage;
WHEN 'fixed' THEN
platform_fee := fee_fixed / 100.0; -- Convert cents to dollars
WHEN 'percentage_plus_fixed' THEN
platform_fee := (base_price * fee_percentage) + (fee_fixed / 100.0);
ELSE
platform_fee := (base_price * fee_percentage) + (fee_fixed / 100.0);
END CASE;
-- Calculate organizer net (what they receive)
organizer_net := base_price - platform_fee;
-- Ensure organizer net is never negative
IF organizer_net < 0 THEN
organizer_net := 0;
END IF;
RETURN ROUND(organizer_net, 2);
END;
$$ LANGUAGE plpgsql;
-- Add indexes for performance
CREATE INDEX idx_organizations_platform_fee_model ON organizations(platform_fee_model);
CREATE INDEX idx_fee_structures_fee_model ON fee_structures(fee_model);
-- Add check constraints to ensure valid fee models
ALTER TABLE organizations
ADD CONSTRAINT check_platform_fee_model
CHECK (platform_fee_model IN ('customer_pays', 'absorbed_in_price'));
ALTER TABLE fee_structures
ADD CONSTRAINT check_fee_model
CHECK (fee_model IN ('customer_pays', 'absorbed_in_price'));