mirror of
https://github.com/myronblair/tomsjavajive-app
synced 2026-06-30 17:50:56 -05:00
439 lines
14 KiB
PHP
439 lines
14 KiB
PHP
<?php
|
|
/**
|
|
* Tom's Java Jive - Customer Loyalty Program
|
|
*
|
|
* Handles loyalty tiers, points, and rewards
|
|
*/
|
|
|
|
class LoyaltyProgram {
|
|
|
|
// Loyalty tier definitions
|
|
private array $tiers = [
|
|
'bronze' => [
|
|
'name' => 'Bronze Bean',
|
|
'min_points' => 0,
|
|
'multiplier' => 1.0,
|
|
'benefits' => [
|
|
'Earn 1 point per $1 spent',
|
|
'Birthday reward',
|
|
'Member-only offers'
|
|
],
|
|
'color' => '#CD7F32',
|
|
'icon' => 'fa-coffee'
|
|
],
|
|
'silver' => [
|
|
'name' => 'Silver Roast',
|
|
'min_points' => 500,
|
|
'multiplier' => 1.25,
|
|
'benefits' => [
|
|
'Earn 1.25 points per $1 spent',
|
|
'Free shipping on orders $25+',
|
|
'Early access to new products',
|
|
'Double points weekends'
|
|
],
|
|
'color' => '#C0C0C0',
|
|
'icon' => 'fa-mug-hot'
|
|
],
|
|
'gold' => [
|
|
'name' => 'Gold Blend',
|
|
'min_points' => 1500,
|
|
'multiplier' => 1.5,
|
|
'benefits' => [
|
|
'Earn 1.5 points per $1 spent',
|
|
'Free shipping on all orders',
|
|
'Exclusive Gold-only products',
|
|
'Priority customer support',
|
|
'Quarterly free coffee sample'
|
|
],
|
|
'color' => '#FFD700',
|
|
'icon' => 'fa-crown'
|
|
],
|
|
'platinum' => [
|
|
'name' => 'Platinum Reserve',
|
|
'min_points' => 5000,
|
|
'multiplier' => 2.0,
|
|
'benefits' => [
|
|
'Earn 2 points per $1 spent',
|
|
'Free express shipping',
|
|
'VIP early access to everything',
|
|
'Annual free bag of premium coffee',
|
|
'Dedicated account manager',
|
|
'Exclusive tasting events'
|
|
],
|
|
'color' => '#E5E4E2',
|
|
'icon' => 'fa-gem'
|
|
]
|
|
];
|
|
|
|
// Points redemption rates
|
|
private float $pointsToValue = 0.01; // 1 point = $0.01 (100 points = $1)
|
|
|
|
/**
|
|
* Get all tier definitions
|
|
*/
|
|
public function getTiers(): array {
|
|
return $this->tiers;
|
|
}
|
|
|
|
/**
|
|
* Get a specific tier
|
|
*/
|
|
public function getTier(string $tierKey): ?array {
|
|
return $this->tiers[$tierKey] ?? null;
|
|
}
|
|
|
|
/**
|
|
* Determine customer's tier based on total points earned (lifetime)
|
|
*/
|
|
public function calculateTier(int $lifetimePoints): string {
|
|
$currentTier = 'bronze';
|
|
|
|
foreach ($this->tiers as $key => $tier) {
|
|
if ($lifetimePoints >= $tier['min_points']) {
|
|
$currentTier = $key;
|
|
}
|
|
}
|
|
|
|
return $currentTier;
|
|
}
|
|
|
|
/**
|
|
* Get customer's current tier info
|
|
*/
|
|
public function getCustomerTier(string $customerId): array {
|
|
$customer = db()->fetch(
|
|
"SELECT reward_points, lifetime_points, loyalty_tier FROM customers WHERE customer_id = :id",
|
|
['id' => $customerId]
|
|
);
|
|
|
|
if (!$customer) {
|
|
return ['tier' => 'bronze', 'info' => $this->tiers['bronze'], 'points' => 0];
|
|
}
|
|
|
|
$lifetimePoints = $customer['lifetime_points'] ?? $customer['reward_points'] ?? 0;
|
|
$tierKey = $this->calculateTier($lifetimePoints);
|
|
$tier = $this->tiers[$tierKey];
|
|
|
|
// Calculate progress to next tier
|
|
$nextTierKey = $this->getNextTier($tierKey);
|
|
$nextTier = $nextTierKey ? $this->tiers[$nextTierKey] : null;
|
|
|
|
$progress = 100;
|
|
$pointsToNext = 0;
|
|
|
|
if ($nextTier) {
|
|
$currentMin = $tier['min_points'];
|
|
$nextMin = $nextTier['min_points'];
|
|
$pointsToNext = $nextMin - $lifetimePoints;
|
|
$progress = min(100, (($lifetimePoints - $currentMin) / ($nextMin - $currentMin)) * 100);
|
|
}
|
|
|
|
return [
|
|
'tier' => $tierKey,
|
|
'info' => $tier,
|
|
'points' => $customer['reward_points'] ?? 0,
|
|
'lifetime_points' => $lifetimePoints,
|
|
'next_tier' => $nextTierKey,
|
|
'next_tier_info' => $nextTier,
|
|
'points_to_next' => $pointsToNext,
|
|
'progress_percent' => round($progress, 1)
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get next tier key
|
|
*/
|
|
private function getNextTier(string $currentTier): ?string {
|
|
$keys = array_keys($this->tiers);
|
|
$index = array_search($currentTier, $keys);
|
|
|
|
return isset($keys[$index + 1]) ? $keys[$index + 1] : null;
|
|
}
|
|
|
|
/**
|
|
* Award points for a purchase
|
|
*/
|
|
public function awardPoints(string $customerId, float $amount, string $description = 'Purchase'): array {
|
|
$customerTier = $this->getCustomerTier($customerId);
|
|
$multiplier = $customerTier['info']['multiplier'];
|
|
|
|
// Calculate points (base: 1 point per dollar)
|
|
$basePoints = floor($amount);
|
|
$bonusPoints = floor($basePoints * ($multiplier - 1));
|
|
$totalPoints = $basePoints + $bonusPoints;
|
|
|
|
// Update customer points
|
|
db()->query(
|
|
"UPDATE customers SET
|
|
reward_points = reward_points + :points,
|
|
lifetime_points = COALESCE(lifetime_points, 0) + :points,
|
|
updated_at = NOW()
|
|
WHERE customer_id = :id",
|
|
['points' => $totalPoints, 'id' => $customerId]
|
|
);
|
|
|
|
// Log the transaction
|
|
db()->insert('loyalty_transactions', [
|
|
'transaction_id' => generateId('lt_'),
|
|
'customer_id' => $customerId,
|
|
'points' => $totalPoints,
|
|
'type' => 'earn',
|
|
'description' => $description . ($bonusPoints > 0 ? " (+{$bonusPoints} bonus)" : ''),
|
|
'reference_amount' => $amount
|
|
]);
|
|
|
|
// Check for tier upgrade
|
|
$newTier = $this->checkTierUpgrade($customerId, $customerTier['tier']);
|
|
|
|
return [
|
|
'points_earned' => $totalPoints,
|
|
'base_points' => $basePoints,
|
|
'bonus_points' => $bonusPoints,
|
|
'multiplier' => $multiplier,
|
|
'tier_upgraded' => $newTier !== null,
|
|
'new_tier' => $newTier
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Redeem points for credit
|
|
*/
|
|
public function redeemPoints(string $customerId, int $points): array {
|
|
$customer = db()->fetch(
|
|
"SELECT reward_points FROM customers WHERE customer_id = :id",
|
|
['id' => $customerId]
|
|
);
|
|
|
|
if (!$customer || $customer['reward_points'] < $points) {
|
|
return ['success' => false, 'error' => 'Insufficient points'];
|
|
}
|
|
|
|
$creditValue = $points * $this->pointsToValue;
|
|
|
|
// Deduct points
|
|
db()->query(
|
|
"UPDATE customers SET reward_points = reward_points - :points, updated_at = NOW() WHERE customer_id = :id",
|
|
['points' => $points, 'id' => $customerId]
|
|
);
|
|
|
|
// Log the redemption
|
|
db()->insert('loyalty_transactions', [
|
|
'transaction_id' => generateId('lt_'),
|
|
'customer_id' => $customerId,
|
|
'points' => -$points,
|
|
'type' => 'redeem',
|
|
'description' => "Redeemed for " . formatCurrency($creditValue) . " credit",
|
|
'reference_amount' => $creditValue
|
|
]);
|
|
|
|
// Add to wallet
|
|
$newBalance = db()->fetch(
|
|
"SELECT wallet_balance FROM customers WHERE customer_id = :id",
|
|
['id' => $customerId]
|
|
)['wallet_balance'] ?? 0;
|
|
|
|
$newBalance += $creditValue;
|
|
|
|
db()->query(
|
|
"UPDATE customers SET wallet_balance = :balance WHERE customer_id = :id",
|
|
['balance' => $newBalance, 'id' => $customerId]
|
|
);
|
|
|
|
// Log wallet transaction
|
|
db()->insert('wallet_transactions', [
|
|
'transaction_id' => generateId('wt_'),
|
|
'customer_id' => $customerId,
|
|
'amount' => $creditValue,
|
|
'balance_after' => $newBalance,
|
|
'type' => 'loyalty_redemption',
|
|
'description' => "Redeemed {$points} loyalty points"
|
|
]);
|
|
|
|
return [
|
|
'success' => true,
|
|
'points_redeemed' => $points,
|
|
'credit_value' => $creditValue,
|
|
'new_points_balance' => $customer['reward_points'] - $points,
|
|
'new_wallet_balance' => $newBalance
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Check and process tier upgrade
|
|
*/
|
|
public function checkTierUpgrade(string $customerId, string $currentTier): ?string {
|
|
$customer = db()->fetch(
|
|
"SELECT lifetime_points, loyalty_tier FROM customers WHERE customer_id = :id",
|
|
['id' => $customerId]
|
|
);
|
|
|
|
if (!$customer) {
|
|
return null;
|
|
}
|
|
|
|
$calculatedTier = $this->calculateTier($customer['lifetime_points'] ?? 0);
|
|
$storedTier = $customer['loyalty_tier'] ?? 'bronze';
|
|
|
|
// Compare tier levels
|
|
$tierOrder = ['bronze', 'silver', 'gold', 'platinum'];
|
|
$calculatedIndex = array_search($calculatedTier, $tierOrder);
|
|
$storedIndex = array_search($storedTier, $tierOrder);
|
|
|
|
if ($calculatedIndex > $storedIndex) {
|
|
// Upgrade!
|
|
db()->query(
|
|
"UPDATE customers SET loyalty_tier = :tier, updated_at = NOW() WHERE customer_id = :id",
|
|
['tier' => $calculatedTier, 'id' => $customerId]
|
|
);
|
|
|
|
// Log the upgrade
|
|
db()->insert('loyalty_transactions', [
|
|
'transaction_id' => generateId('lt_'),
|
|
'customer_id' => $customerId,
|
|
'points' => 0,
|
|
'type' => 'tier_upgrade',
|
|
'description' => "Upgraded from {$this->tiers[$storedTier]['name']} to {$this->tiers[$calculatedTier]['name']}"
|
|
]);
|
|
|
|
// Send notifications
|
|
$this->sendTierUpgradeNotifications($customerId, $calculatedTier);
|
|
|
|
return $calculatedTier;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Send tier upgrade notifications
|
|
*/
|
|
private function sendTierUpgradeNotifications(string $customerId, string $newTier): void {
|
|
$customer = db()->fetch(
|
|
"SELECT email, phone, name FROM customers WHERE customer_id = :id",
|
|
['id' => $customerId]
|
|
);
|
|
|
|
if (!$customer) return;
|
|
|
|
$tierInfo = $this->tiers[$newTier];
|
|
|
|
// Send email notification
|
|
if (!empty($customer['email'])) {
|
|
require_once __DIR__ . '/email.php';
|
|
// Custom email for tier upgrade would go here
|
|
}
|
|
|
|
// Send SMS notification
|
|
if (!empty($customer['phone'])) {
|
|
require_once __DIR__ . '/sms.php';
|
|
sendSMS()->sendTierUpgrade($customer['phone'], $tierInfo['name']);
|
|
}
|
|
|
|
// Send push notification
|
|
require_once __DIR__ . '/push.php';
|
|
pushNotify()->sendTierNotification($customerId, $tierInfo['name'], $tierInfo['benefits']);
|
|
}
|
|
|
|
/**
|
|
* Get points conversion info
|
|
*/
|
|
public function getConversionInfo(): array {
|
|
return [
|
|
'points_per_dollar' => 1,
|
|
'points_value' => $this->pointsToValue,
|
|
'points_for_one_dollar' => intval(1 / $this->pointsToValue),
|
|
'description' => 'Earn 1 point for every $1 spent. Redeem 100 points for $1 credit.'
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get customer's loyalty history
|
|
*/
|
|
public function getHistory(string $customerId, int $limit = 20): array {
|
|
return db()->fetchAll(
|
|
"SELECT * FROM loyalty_transactions WHERE customer_id = :id ORDER BY created_at DESC LIMIT :limit",
|
|
['id' => $customerId, 'limit' => $limit]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Award birthday bonus
|
|
*/
|
|
public function awardBirthdayBonus(string $customerId): array {
|
|
$customerTier = $this->getCustomerTier($customerId);
|
|
|
|
// Bonus points based on tier
|
|
$bonusPoints = match($customerTier['tier']) {
|
|
'platinum' => 500,
|
|
'gold' => 300,
|
|
'silver' => 200,
|
|
default => 100
|
|
};
|
|
|
|
db()->query(
|
|
"UPDATE customers SET reward_points = reward_points + :points WHERE customer_id = :id",
|
|
['points' => $bonusPoints, 'id' => $customerId]
|
|
);
|
|
|
|
db()->insert('loyalty_transactions', [
|
|
'transaction_id' => generateId('lt_'),
|
|
'customer_id' => $customerId,
|
|
'points' => $bonusPoints,
|
|
'type' => 'birthday_bonus',
|
|
'description' => "Birthday reward - Happy Birthday!"
|
|
]);
|
|
|
|
return ['success' => true, 'points' => $bonusPoints];
|
|
}
|
|
|
|
/**
|
|
* Award referral bonus
|
|
*/
|
|
public function awardReferralBonus(string $referrerId, string $newCustomerId): array {
|
|
$referrerBonus = 100;
|
|
$newCustomerBonus = 50;
|
|
|
|
// Award to referrer
|
|
db()->query(
|
|
"UPDATE customers SET reward_points = reward_points + :points WHERE customer_id = :id",
|
|
['points' => $referrerBonus, 'id' => $referrerId]
|
|
);
|
|
|
|
db()->insert('loyalty_transactions', [
|
|
'transaction_id' => generateId('lt_'),
|
|
'customer_id' => $referrerId,
|
|
'points' => $referrerBonus,
|
|
'type' => 'referral_bonus',
|
|
'description' => "Referral bonus - Thank you for spreading the word!"
|
|
]);
|
|
|
|
// Award to new customer
|
|
db()->query(
|
|
"UPDATE customers SET reward_points = reward_points + :points WHERE customer_id = :id",
|
|
['points' => $newCustomerBonus, 'id' => $newCustomerId]
|
|
);
|
|
|
|
db()->insert('loyalty_transactions', [
|
|
'transaction_id' => generateId('lt_'),
|
|
'customer_id' => $newCustomerId,
|
|
'points' => $newCustomerBonus,
|
|
'type' => 'referral_welcome',
|
|
'description' => "Welcome bonus from referral"
|
|
]);
|
|
|
|
return [
|
|
'referrer_bonus' => $referrerBonus,
|
|
'new_customer_bonus' => $newCustomerBonus
|
|
];
|
|
}
|
|
}
|
|
|
|
// Helper function
|
|
function loyalty(): LoyaltyProgram {
|
|
static $instance = null;
|
|
if ($instance === null) {
|
|
$instance = new LoyaltyProgram();
|
|
}
|
|
return $instance;
|
|
}
|