final
This commit is contained in:
23
.env.local
Normal file
23
.env.local
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# NOWPayments IPN Secret Key
|
||||||
|
# Get this from your NOWPayments dashboard -> Store Settings -> IPN Secret Key
|
||||||
|
NOWPAYMENTS_IPN_SECRET_KEY=PpzD3PupiX7CdXN5+ZAs5xYFe0zBFh//
|
||||||
|
|
||||||
|
# Server Port (optional, defaults to 3000)
|
||||||
|
PORT=3421
|
||||||
|
|
||||||
|
# Node Environment
|
||||||
|
NODE_ENV=development
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_USER=cbd420
|
||||||
|
DB_PASSWORD=76HkE-mQ1HeH-PLk
|
||||||
|
DB_NAME=cbd420
|
||||||
|
|
||||||
|
SMTP_HOST=mail.playpoolstudios.com
|
||||||
|
SMTP_PORT=465
|
||||||
|
SMTP_USER=sewmina@playpoolstudios.com
|
||||||
|
SMTP_PASSWORD=TcSp419603
|
||||||
|
SMTP_FROM_EMAIL=sewmina@playpoolstudios.com
|
||||||
|
SMTP_FROM_NAME=CBD420
|
||||||
291
cbd420(1).sql
291
cbd420(1).sql
@@ -3,7 +3,7 @@
|
|||||||
-- https://www.phpmyadmin.net/
|
-- https://www.phpmyadmin.net/
|
||||||
--
|
--
|
||||||
-- Host: localhost:3306
|
-- Host: localhost:3306
|
||||||
-- Generation Time: Dec 21, 2025 at 09:44 AM
|
-- Generation Time: Dec 28, 2025 at 01:36 AM
|
||||||
-- Server version: 10.11.14-MariaDB-0+deb12u2
|
-- Server version: 10.11.14-MariaDB-0+deb12u2
|
||||||
-- PHP Version: 8.2.29
|
-- PHP Version: 8.2.29
|
||||||
|
|
||||||
@@ -32,6 +32,7 @@ CREATE TABLE `buyers` (
|
|||||||
`username` varchar(255) NOT NULL,
|
`username` varchar(255) NOT NULL,
|
||||||
`password` varchar(255) NOT NULL,
|
`password` varchar(255) NOT NULL,
|
||||||
`email` varchar(255) NOT NULL,
|
`email` varchar(255) NOT NULL,
|
||||||
|
`referral_points` decimal(10,2) NOT NULL DEFAULT 0.00,
|
||||||
`created_at` datetime NOT NULL DEFAULT current_timestamp()
|
`created_at` datetime NOT NULL DEFAULT current_timestamp()
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
@@ -82,6 +83,32 @@ CREATE TABLE `drops` (
|
|||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `drop_images`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `drop_images` (
|
||||||
|
`id` int(11) NOT NULL,
|
||||||
|
`drop_id` int(11) NOT NULL,
|
||||||
|
`image_url` varchar(255) NOT NULL,
|
||||||
|
`display_order` int(11) NOT NULL DEFAULT 0,
|
||||||
|
`created_at` datetime NOT NULL DEFAULT current_timestamp()
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `notification_subscribers`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `notification_subscribers` (
|
||||||
|
`address` varchar(100) NOT NULL,
|
||||||
|
`type` text NOT NULL DEFAULT '\'email\'',
|
||||||
|
`buyer_id` int(11) DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `pending_orders`
|
-- Table structure for table `pending_orders`
|
||||||
--
|
--
|
||||||
@@ -96,12 +123,44 @@ CREATE TABLE `pending_orders` (
|
|||||||
`size` int(11) NOT NULL,
|
`size` int(11) NOT NULL,
|
||||||
`price_amount` decimal(10,2) NOT NULL,
|
`price_amount` decimal(10,2) NOT NULL,
|
||||||
`price_currency` varchar(10) NOT NULL DEFAULT 'chf',
|
`price_currency` varchar(10) NOT NULL DEFAULT 'chf',
|
||||||
|
`points_used` decimal(10,2) NOT NULL DEFAULT 0.00,
|
||||||
`created_at` datetime NOT NULL DEFAULT current_timestamp(),
|
`created_at` datetime NOT NULL DEFAULT current_timestamp(),
|
||||||
`expires_at` datetime NOT NULL DEFAULT (current_timestamp() + interval 10 minute)
|
`expires_at` datetime NOT NULL DEFAULT (current_timestamp() + interval 10 minute)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `referral_point_transactions`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `referral_point_transactions` (
|
||||||
|
`id` int(11) NOT NULL,
|
||||||
|
`buyer_id` int(11) NOT NULL,
|
||||||
|
`points` decimal(10,2) NOT NULL,
|
||||||
|
`type` enum('earned','spent') NOT NULL,
|
||||||
|
`sale_id` int(11) DEFAULT NULL,
|
||||||
|
`pending_order_id` int(11) DEFAULT NULL,
|
||||||
|
`description` text DEFAULT NULL,
|
||||||
|
`created_at` datetime NOT NULL DEFAULT current_timestamp()
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `referral_settings`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `referral_settings` (
|
||||||
|
`id` int(11) NOT NULL,
|
||||||
|
`setting_key` varchar(100) NOT NULL,
|
||||||
|
`setting_value` varchar(255) NOT NULL,
|
||||||
|
`description` text DEFAULT NULL,
|
||||||
|
`updated_at` datetime NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `referrals`
|
-- Table structure for table `referrals`
|
||||||
--
|
--
|
||||||
@@ -125,6 +184,9 @@ CREATE TABLE `sales` (
|
|||||||
`buyer_data_id` int(11) NOT NULL,
|
`buyer_data_id` int(11) NOT NULL,
|
||||||
`size` int(11) NOT NULL DEFAULT 1,
|
`size` int(11) NOT NULL DEFAULT 1,
|
||||||
`payment_id` text NOT NULL DEFAULT '',
|
`payment_id` text NOT NULL DEFAULT '',
|
||||||
|
`price_amount` decimal(10,2) DEFAULT NULL,
|
||||||
|
`price_currency` varchar(10) NOT NULL DEFAULT 'chf',
|
||||||
|
`points_used` decimal(10,2) NOT NULL DEFAULT 0.00,
|
||||||
`created_at` datetime NOT NULL DEFAULT current_timestamp()
|
`created_at` datetime NOT NULL DEFAULT current_timestamp()
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
@@ -142,7 +204,8 @@ ALTER TABLE `buyers`
|
|||||||
-- Indexes for table `buyer_data`
|
-- Indexes for table `buyer_data`
|
||||||
--
|
--
|
||||||
ALTER TABLE `buyer_data`
|
ALTER TABLE `buyer_data`
|
||||||
ADD PRIMARY KEY (`id`);
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD KEY `buyer_id` (`buyer_id`);
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Indexes for table `deliveries`
|
-- Indexes for table `deliveries`
|
||||||
@@ -157,6 +220,21 @@ ALTER TABLE `deliveries`
|
|||||||
ALTER TABLE `drops`
|
ALTER TABLE `drops`
|
||||||
ADD PRIMARY KEY (`id`);
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for table `drop_images`
|
||||||
|
--
|
||||||
|
ALTER TABLE `drop_images`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD KEY `drop_id` (`drop_id`),
|
||||||
|
ADD KEY `idx_drop_images_drop_order` (`drop_id`,`display_order`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for table `notification_subscribers`
|
||||||
|
--
|
||||||
|
ALTER TABLE `notification_subscribers`
|
||||||
|
ADD PRIMARY KEY (`address`),
|
||||||
|
ADD KEY `buyer_id` (`buyer_id`);
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Indexes for table `pending_orders`
|
-- Indexes for table `pending_orders`
|
||||||
--
|
--
|
||||||
@@ -169,6 +247,22 @@ ALTER TABLE `pending_orders`
|
|||||||
ADD KEY `idx_expires_at` (`expires_at`),
|
ADD KEY `idx_expires_at` (`expires_at`),
|
||||||
ADD KEY `buyer_data_id` (`buyer_data_id`);
|
ADD KEY `buyer_data_id` (`buyer_data_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for table `referral_point_transactions`
|
||||||
|
--
|
||||||
|
ALTER TABLE `referral_point_transactions`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD KEY `buyer_id` (`buyer_id`),
|
||||||
|
ADD KEY `sale_id` (`sale_id`),
|
||||||
|
ADD KEY `pending_order_id` (`pending_order_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for table `referral_settings`
|
||||||
|
--
|
||||||
|
ALTER TABLE `referral_settings`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `setting_key` (`setting_key`);
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Indexes for table `referrals`
|
-- Indexes for table `referrals`
|
||||||
--
|
--
|
||||||
@@ -214,12 +308,30 @@ ALTER TABLE `deliveries`
|
|||||||
ALTER TABLE `drops`
|
ALTER TABLE `drops`
|
||||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- AUTO_INCREMENT for table `drop_images`
|
||||||
|
--
|
||||||
|
ALTER TABLE `drop_images`
|
||||||
|
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- AUTO_INCREMENT for table `pending_orders`
|
-- AUTO_INCREMENT for table `pending_orders`
|
||||||
--
|
--
|
||||||
ALTER TABLE `pending_orders`
|
ALTER TABLE `pending_orders`
|
||||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- AUTO_INCREMENT for table `referral_point_transactions`
|
||||||
|
--
|
||||||
|
ALTER TABLE `referral_point_transactions`
|
||||||
|
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- AUTO_INCREMENT for table `referral_settings`
|
||||||
|
--
|
||||||
|
ALTER TABLE `referral_settings`
|
||||||
|
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- AUTO_INCREMENT for table `referrals`
|
-- AUTO_INCREMENT for table `referrals`
|
||||||
--
|
--
|
||||||
@@ -236,12 +348,30 @@ ALTER TABLE `sales`
|
|||||||
-- Constraints for dumped tables
|
-- Constraints for dumped tables
|
||||||
--
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `buyer_data`
|
||||||
|
--
|
||||||
|
ALTER TABLE `buyer_data`
|
||||||
|
ADD CONSTRAINT `buyer_data_ibfk_1` FOREIGN KEY (`buyer_id`) REFERENCES `buyers` (`id`);
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Constraints for table `deliveries`
|
-- Constraints for table `deliveries`
|
||||||
--
|
--
|
||||||
ALTER TABLE `deliveries`
|
ALTER TABLE `deliveries`
|
||||||
ADD CONSTRAINT `deliveries_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `sales` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
ADD CONSTRAINT `deliveries_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `sales` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `drop_images`
|
||||||
|
--
|
||||||
|
ALTER TABLE `drop_images`
|
||||||
|
ADD CONSTRAINT `drop_images_ibfk_1` FOREIGN KEY (`drop_id`) REFERENCES `drops` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `notification_subscribers`
|
||||||
|
--
|
||||||
|
ALTER TABLE `notification_subscribers`
|
||||||
|
ADD CONSTRAINT `notification_subscribers_ibfk_1` FOREIGN KEY (`buyer_id`) REFERENCES `buyers` (`id`);
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Constraints for table `pending_orders`
|
-- Constraints for table `pending_orders`
|
||||||
--
|
--
|
||||||
@@ -250,6 +380,14 @@ ALTER TABLE `pending_orders`
|
|||||||
ADD CONSTRAINT `pending_orders_ibfk_2` FOREIGN KEY (`buyer_id`) REFERENCES `buyers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
ADD CONSTRAINT `pending_orders_ibfk_2` FOREIGN KEY (`buyer_id`) REFERENCES `buyers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
ADD CONSTRAINT `pending_orders_ibfk_3` FOREIGN KEY (`buyer_data_id`) REFERENCES `buyer_data` (`id`);
|
ADD CONSTRAINT `pending_orders_ibfk_3` FOREIGN KEY (`buyer_data_id`) REFERENCES `buyer_data` (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `referral_point_transactions`
|
||||||
|
--
|
||||||
|
ALTER TABLE `referral_point_transactions`
|
||||||
|
ADD CONSTRAINT `referral_point_transactions_ibfk_1` FOREIGN KEY (`buyer_id`) REFERENCES `buyers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT `referral_point_transactions_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `sales` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT `referral_point_transactions_ibfk_3` FOREIGN KEY (`pending_order_id`) REFERENCES `pending_orders` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Constraints for table `referrals`
|
-- Constraints for table `referrals`
|
||||||
--
|
--
|
||||||
@@ -264,6 +402,155 @@ ALTER TABLE `sales`
|
|||||||
ADD CONSTRAINT `sales_ibfk_1` FOREIGN KEY (`drop_id`) REFERENCES `drops` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
ADD CONSTRAINT `sales_ibfk_1` FOREIGN KEY (`drop_id`) REFERENCES `drops` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
ADD CONSTRAINT `sales_ibfk_2` FOREIGN KEY (`buyer_id`) REFERENCES `buyers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
ADD CONSTRAINT `sales_ibfk_2` FOREIGN KEY (`buyer_id`) REFERENCES `buyers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
ADD CONSTRAINT `sales_ibfk_3` FOREIGN KEY (`buyer_data_id`) REFERENCES `buyer_data` (`id`);
|
ADD CONSTRAINT `sales_ibfk_3` FOREIGN KEY (`buyer_data_id`) REFERENCES `buyer_data` (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Insert default referral settings
|
||||||
|
--
|
||||||
|
INSERT INTO `referral_settings` (`setting_key`, `setting_value`, `description`) VALUES
|
||||||
|
('points_per_chf', '10', 'Number of referral points earned per 1 CHF purchase by referred user'),
|
||||||
|
('points_to_chf', '100', 'Number of referral points required to redeem 1 CHF discount');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Stored procedure to award referral points when a sale is completed
|
||||||
|
-- This procedure should be called after a sale is created
|
||||||
|
-- Parameters: sale_id - The ID of the sale that was just created
|
||||||
|
--
|
||||||
|
DELIMITER $$
|
||||||
|
|
||||||
|
CREATE PROCEDURE `award_referral_points`(IN p_sale_id INT)
|
||||||
|
BEGIN
|
||||||
|
DECLARE v_buyer_id INT;
|
||||||
|
DECLARE v_referrer_id INT;
|
||||||
|
DECLARE v_price_amount DECIMAL(10,2);
|
||||||
|
DECLARE v_points_per_chf DECIMAL(10,2);
|
||||||
|
DECLARE v_points_earned DECIMAL(10,2);
|
||||||
|
DECLARE v_drop_id INT;
|
||||||
|
DECLARE v_size INT;
|
||||||
|
DECLARE v_ppu DECIMAL(10,2);
|
||||||
|
DECLARE v_currency VARCHAR(10);
|
||||||
|
|
||||||
|
-- Get sale details
|
||||||
|
SELECT buyer_id, drop_id, size, COALESCE(price_amount, 0), price_currency
|
||||||
|
INTO v_buyer_id, v_drop_id, v_size, v_price_amount, v_currency
|
||||||
|
FROM sales
|
||||||
|
WHERE id = p_sale_id;
|
||||||
|
|
||||||
|
-- If price_amount is not set, calculate it from drop's ppu
|
||||||
|
IF v_price_amount = 0 OR v_price_amount IS NULL THEN
|
||||||
|
SELECT ppu INTO v_ppu FROM drops WHERE id = v_drop_id;
|
||||||
|
SET v_price_amount = v_ppu * v_size;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Get the referrer for this buyer (if any)
|
||||||
|
SELECT referrer INTO v_referrer_id
|
||||||
|
FROM referrals
|
||||||
|
WHERE referree = v_buyer_id
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- If there's a referrer, award points
|
||||||
|
IF v_referrer_id IS NOT NULL THEN
|
||||||
|
-- Get points_per_chf setting
|
||||||
|
SELECT CAST(setting_value AS DECIMAL(10,2)) INTO v_points_per_chf
|
||||||
|
FROM referral_settings
|
||||||
|
WHERE setting_key = 'points_per_chf'
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- Default to 10 if setting not found
|
||||||
|
IF v_points_per_chf IS NULL THEN
|
||||||
|
SET v_points_per_chf = 10;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Calculate points earned (based on actual purchase amount in CHF)
|
||||||
|
-- Note: This assumes price_amount is already in CHF, or convert if needed
|
||||||
|
SET v_points_earned = v_price_amount * v_points_per_chf;
|
||||||
|
|
||||||
|
-- Update referrer's points balance
|
||||||
|
UPDATE buyers
|
||||||
|
SET referral_points = referral_points + v_points_earned
|
||||||
|
WHERE id = v_referrer_id;
|
||||||
|
|
||||||
|
-- Record the transaction
|
||||||
|
INSERT INTO referral_point_transactions (
|
||||||
|
buyer_id,
|
||||||
|
points,
|
||||||
|
type,
|
||||||
|
sale_id,
|
||||||
|
description
|
||||||
|
) VALUES (
|
||||||
|
v_referrer_id,
|
||||||
|
v_points_earned,
|
||||||
|
'earned',
|
||||||
|
p_sale_id,
|
||||||
|
CONCAT('Points earned from referral purchase (Sale #', p_sale_id, ', Amount: ', v_price_amount, ' ', v_currency, ')')
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Stored procedure to spend referral points for a purchase
|
||||||
|
-- This procedure deducts points from buyer's balance and records the transaction
|
||||||
|
-- Parameters:
|
||||||
|
-- p_buyer_id - The ID of the buyer spending points
|
||||||
|
-- p_points_to_spend - Amount of points to spend
|
||||||
|
-- p_pending_order_id - Optional: ID of pending order if spending for pending order
|
||||||
|
-- p_sale_id - Optional: ID of sale if spending for completed sale
|
||||||
|
-- Returns: 1 if successful, 0 if insufficient points
|
||||||
|
--
|
||||||
|
DELIMITER $$
|
||||||
|
|
||||||
|
CREATE PROCEDURE `spend_referral_points`(
|
||||||
|
IN p_buyer_id INT,
|
||||||
|
IN p_points_to_spend DECIMAL(10,2),
|
||||||
|
IN p_pending_order_id INT,
|
||||||
|
IN p_sale_id INT,
|
||||||
|
OUT p_success INT
|
||||||
|
)
|
||||||
|
BEGIN
|
||||||
|
DECLARE v_current_points DECIMAL(10,2);
|
||||||
|
DECLARE v_new_balance DECIMAL(10,2);
|
||||||
|
|
||||||
|
-- Get current points balance
|
||||||
|
SELECT referral_points INTO v_current_points
|
||||||
|
FROM buyers
|
||||||
|
WHERE id = p_buyer_id;
|
||||||
|
|
||||||
|
-- Check if buyer has enough points
|
||||||
|
IF v_current_points IS NULL OR v_current_points < p_points_to_spend THEN
|
||||||
|
SET p_success = 0;
|
||||||
|
ELSE
|
||||||
|
-- Deduct points
|
||||||
|
SET v_new_balance = v_current_points - p_points_to_spend;
|
||||||
|
|
||||||
|
UPDATE buyers
|
||||||
|
SET referral_points = v_new_balance
|
||||||
|
WHERE id = p_buyer_id;
|
||||||
|
|
||||||
|
-- Record the transaction
|
||||||
|
INSERT INTO referral_point_transactions (
|
||||||
|
buyer_id,
|
||||||
|
points,
|
||||||
|
type,
|
||||||
|
sale_id,
|
||||||
|
pending_order_id,
|
||||||
|
description
|
||||||
|
) VALUES (
|
||||||
|
p_buyer_id,
|
||||||
|
p_points_to_spend,
|
||||||
|
'spent',
|
||||||
|
p_sale_id,
|
||||||
|
p_pending_order_id,
|
||||||
|
CONCAT('Points spent for purchase',
|
||||||
|
IF(p_sale_id IS NOT NULL, CONCAT(' (Sale #', p_sale_id, ')'), ''),
|
||||||
|
IF(p_pending_order_id IS NOT NULL, CONCAT(' (Pending Order #', p_pending_order_id, ')'), '')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
SET p_success = 1;
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
||||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
|||||||
@@ -364,14 +364,18 @@ export async function movePaymentToSalesWithInventoryCheck(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create sale record (Step 5 from guide)
|
// Create sale record (Step 5 from guide)
|
||||||
|
// Include price_amount, price_currency, and points_used from pending order
|
||||||
const [insertResult] = await connection.execute(
|
const [insertResult] = await connection.execute(
|
||||||
'INSERT INTO sales (drop_id, buyer_id, buyer_data_id, size, payment_id, created_at) VALUES (?, ?, ?, ?, ?, NOW())',
|
'INSERT INTO sales (drop_id, buyer_id, buyer_data_id, size, payment_id, price_amount, price_currency, points_used, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW())',
|
||||||
[
|
[
|
||||||
pendingOrder.drop_id,
|
pendingOrder.drop_id,
|
||||||
pendingOrder.buyer_id,
|
pendingOrder.buyer_id,
|
||||||
pendingOrder.buyer_data_id,
|
pendingOrder.buyer_data_id,
|
||||||
pendingOrder.size,
|
pendingOrder.size,
|
||||||
paymentId
|
paymentId,
|
||||||
|
pendingOrder.price_amount,
|
||||||
|
pendingOrder.price_currency,
|
||||||
|
pendingOrder.points_used || 0
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -558,3 +562,20 @@ export async function getBuyerDataById(buyerDataId: number): Promise<BuyerDataIn
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Award referral points to the referrer when a sale is completed
|
||||||
|
* Calls the stored procedure award_referral_points
|
||||||
|
*/
|
||||||
|
export async function awardReferralPoints(saleId: number): Promise<void> {
|
||||||
|
try {
|
||||||
|
await pool.execute('CALL award_referral_points(?)', [saleId]);
|
||||||
|
console.log(`✅ Referral points awarded for sale ${saleId}`);
|
||||||
|
} catch (error) {
|
||||||
|
// Log error but don't throw - referral points failure shouldn't break the payment flow
|
||||||
|
console.error(`❌ Error awarding referral points for sale ${saleId}:`, error);
|
||||||
|
if (error instanceof Error) {
|
||||||
|
console.error(`❌ Error details: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export interface PendingOrder {
|
|||||||
size: number;
|
size: number;
|
||||||
price_amount: number;
|
price_amount: number;
|
||||||
price_currency: string;
|
price_currency: string;
|
||||||
|
points_used: number;
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
expires_at: Date;
|
expires_at: Date;
|
||||||
}
|
}
|
||||||
@@ -23,6 +24,9 @@ export interface Sale {
|
|||||||
buyer_data_id: number;
|
buyer_data_id: number;
|
||||||
size: number;
|
size: number;
|
||||||
payment_id: string;
|
payment_id: string;
|
||||||
|
price_amount: number | null;
|
||||||
|
price_currency: string;
|
||||||
|
points_used: number;
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
movePaymentToSalesWithInventoryCheck,
|
movePaymentToSalesWithInventoryCheck,
|
||||||
paymentExistsInSales,
|
paymentExistsInSales,
|
||||||
deletePendingOrderById,
|
deletePendingOrderById,
|
||||||
|
awardReferralPoints,
|
||||||
} from '../database/paymentService';
|
} from '../database/paymentService';
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
@@ -171,6 +172,18 @@ async function handleSuccessfulPayment(pendingOrder: any, paymentId: string): Pr
|
|||||||
const sale = await movePaymentToSalesWithInventoryCheck(pendingOrder.id, paymentId);
|
const sale = await movePaymentToSalesWithInventoryCheck(pendingOrder.id, paymentId);
|
||||||
|
|
||||||
console.log(`✅ Successfully processed payment ${paymentId}. Sale ID: ${sale.id}`);
|
console.log(`✅ Successfully processed payment ${paymentId}. Sale ID: ${sale.id}`);
|
||||||
|
|
||||||
|
// Award referral points to the referrer (if any)
|
||||||
|
// This is done asynchronously to avoid blocking the payment flow
|
||||||
|
// Errors are logged but don't affect the payment processing
|
||||||
|
setImmediate(async () => {
|
||||||
|
try {
|
||||||
|
await awardReferralPoints(sale.id);
|
||||||
|
} catch (error) {
|
||||||
|
// Error is already logged in awardReferralPoints, just log here for context
|
||||||
|
console.error(`Failed to award referral points for sale ${sale.id}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Error handling: if inventory check fails, the pending order is already deleted in the transaction
|
// Error handling: if inventory check fails, the pending order is already deleted in the transaction
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user