Skip to content

Commit cb3274d

Browse files
committed
fix: Super Admin access denied + role resolution from users table + Razorpay migration + contact page B2B SaaS repositioning
- Fixed Super Admin 'Access Denied': admin handler functions were already defined but hidden by literal \r encoding corruption in billing section - Fixed verifyViaSupabase role resolution: now checks app_metadata -> user_metadata -> employees table -> users table (auth_id + email fallback) - Removed duplicate admin handler functions that were accidentally inserted - Fixed literal \r encoding corruption in Razorpay billing handlers (lines 6542-6611) - Fixed duplicate JSDoc comment opener in billing section - Razorpay payment gateway migration (removed Cashfree/Paddle) - Contact page repositioned for B2B SaaS Enterprise AI-Powered ATS
1 parent abf893d commit cb3274d

9 files changed

Lines changed: 324 additions & 406 deletions

File tree

backend/simpatico-ats.js

Lines changed: 146 additions & 190 deletions
Large diffs are not rendered by default.

contact.html

Lines changed: 83 additions & 93 deletions
Large diffs are not rendered by default.

js/hr-config.js

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,9 @@ window.SIMPATICO_CONFIG = {
2929
},
3030
appVersion: '5.0.0-Industrial',
3131

32-
// 5. PAYMENT GATEWAYS
33-
// Cashfree config is server-side only (env secrets in worker)
34-
// Paddle client-side config:
35-
paddleClientToken: '', // Set your Paddle client-side token here
36-
paddleEnv: 'sandbox', // 'sandbox' or 'production'
37-
paddlePriceIds: {
38-
// Map plan+cycle to Paddle Price IDs from your Paddle dashboard
39-
// starter_monthly: 'pri_XXXXXXXXXXXXXXX',
40-
// starter_annual: 'pri_XXXXXXXXXXXXXXX',
41-
// professional_monthly: 'pri_XXXXXXXXXXXXXXX',
42-
// professional_annual: 'pri_XXXXXXXXXXXXXXX',
43-
},
32+
// 5. PAYMENT GATEWAY — Razorpay (Test Mode)
33+
razorpayKeyId: 'rzp_test_yourtestkeyhere', // Replace with your Razorpay Test Key ID
34+
razorpayEnv: 'test', // 'test' or 'live'
4435

4536
// Helper to generate Trace IDs for debugging (crypto-safe)
4637
generateTraceId: () => {

platform/payment-success.html

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@
4949
display: inline-block; font-size: 11px; font-weight: 600; padding: 3px 10px;
5050
border-radius: 100px; margin-top: 6px;
5151
}
52-
.gateway-cashfree { background: #EEF2FF; color: #4F46E5; }
53-
.gateway-paddle { background: #F0FDF4; color: #059669; }
52+
.gateway-razorpay { background: #EEF2FF; color: #4F46E5; }
5453
.cta-btn {
5554
display: inline-block; padding: 14px 32px; background: linear-gradient(135deg, #4F46E5, #7C3AED);
5655
color: white; border-radius: 12px; text-decoration: none;
@@ -80,11 +79,10 @@ <h1>Payment Successful! 🎉</h1>
8079
// Parse params
8180
const params = new URLSearchParams(window.location.search);
8281
const plan = params.get('plan') || 'professional';
83-
const gateway = params.get('gateway') || 'cashfree';
8482

8583
document.getElementById('planName').textContent = plan.charAt(0).toUpperCase() + plan.slice(1);
8684
const tag = document.getElementById('gatewayTag');
87-
tag.innerHTML = `<span class="gateway-tag gateway-${gateway}"><i class="fas ${gateway === 'cashfree' ? 'fa-indian-rupee-sign' : 'fa-globe'}"></i> Paid via ${gateway === 'cashfree' ? 'Cashfree' : 'Paddle'}</span>`;
85+
tag.innerHTML = `<span class="gateway-tag gateway-razorpay"><i class="fas fa-indian-rupee-sign"></i> Paid via Razorpay</span>`;
8886

8987
// Mini confetti effect
9088
const canvas = document.getElementById('confetti');

platform/pricing.html

Lines changed: 79 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
66
<title>Pricing — Simpatico HR</title>
7-
<meta name="description" content="Simple pricing for AI-powered HR & recruitment. Cashfree for India, Paddle for international.">
7+
<meta name="description" content="Simple pricing for AI-powered HR & recruitment. Secure payments via Razorpay.">
88
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
99
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
1010
<script src="../js/hr-config.js"></script>
11-
<!-- Cashfree JS SDK -->
12-
<script src="https://sdk.cashfree.com/js/v3/cashfree.js"></script>
13-
<!-- Paddle JS SDK -->
14-
<script src="https://cdn.paddle.com/paddle/v2/paddle.js"></script>
11+
<!-- Razorpay Checkout JS SDK -->
12+
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
1513
<style>
1614
:root {
1715
--primary: #4F46E5; --primary-hover: #4338CA;
@@ -206,7 +204,7 @@ <h1>Choose Your Plan</h1>
206204
<button class="plan-btn plan-btn-outline" id="btn-starter" onclick="subscribe('starter')">
207205
<i class="fas fa-bolt" style="margin-right:6px"></i>Get Started
208206
</button>
209-
<div class="gateway-row"><i class="fas fa-lock" style="font-size:10px"></i> Secured by Cashfree & Paddle</div>
207+
<div class="gateway-row"><i class="fas fa-lock" style="font-size:10px"></i> Secured by Razorpay</div>
210208
</div>
211209

212210
<!-- Professional -->
@@ -261,7 +259,7 @@ <h1>Choose Your Plan</h1>
261259
<h2>Frequently Asked Questions</h2>
262260
<div class="faq-item" onclick="this.classList.toggle('open')">
263261
<div class="faq-q">Which payment methods do you support? <i class="fas fa-chevron-down" style="font-size:12px;color:#94a3b8"></i></div>
264-
<div class="faq-a"><strong>India:</strong> UPI, credit/debit cards, netbanking, wallets via Cashfree.<br><strong>International:</strong> Visa, Mastercard, American Express, and more via Paddle. Tax compliance handled automatically.</div>
262+
<div class="faq-a">We accept UPI, credit/debit cards, netbanking, wallets, and more via Razorpay — our secure PCI DSS Level 1 certified payment partner.</div>
265263
</div>
266264
<div class="faq-item" onclick="this.classList.toggle('open')">
267265
<div class="faq-q">How does the 2-day free trial work? <i class="fas fa-chevron-down" style="font-size:12px;color:#94a3b8"></i></div>
@@ -277,7 +275,7 @@ <h2>Frequently Asked Questions</h2>
277275
</div>
278276
<div class="faq-item" onclick="this.classList.toggle('open')">
279277
<div class="faq-q">Is my payment data secure? <i class="fas fa-chevron-down" style="font-size:12px;color:#94a3b8"></i></div>
280-
<div class="faq-a">Absolutely. We never store your card details. Cashfree (PCI DSS Level 1) handles Indian payments and Paddle (Merchant of Record) handles international payments with full tax compliance.</div>
278+
<div class="faq-a">Absolutely. We never store your card details. Razorpay (PCI DSS Level 1) handles all payment processing with bank-grade security.</div>
281279
</div>
282280
</div>
283281

@@ -295,6 +293,7 @@ <h2>Frequently Asked Questions</h2>
295293
const token = localStorage.getItem('simpatico_token') || sessionStorage.getItem('simpatico_token');
296294
const user = JSON.parse(localStorage.getItem('simpatico_user') || sessionStorage.getItem('simpatico_user') || '{}');
297295
const TENANT_ID = user.company_id || user.tenant_id || window.SIMPATICO_CONFIG?.tenantId || '';
296+
const RZP_KEY = window.SIMPATICO_CONFIG?.razorpayKeyId || '';
298297

299298
let billingCycle = 'monthly';
300299
let currentPlan = null;
@@ -304,7 +303,7 @@ <h2>Frequently Asked Questions</h2>
304303
professional: { monthly: { inr: 14999, usd: 179 }, annual: { inr: 149990, usd: 1790 } },
305304
};
306305

307-
// ── Detect region ──
306+
// ── Detect region (for price display only) ──
308307
function isIndianUser() {
309308
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone || '';
310309
return tz.includes('Kolkata') || tz.includes('Calcutta') || tz.includes('Asia/Colombo') ||
@@ -314,17 +313,6 @@ <h2>Frequently Asked Questions</h2>
314313

315314
const isDomestic = isIndianUser();
316315

317-
// ── Initialize Paddle (international) ──
318-
if (typeof Paddle !== 'undefined' && window.SIMPATICO_CONFIG?.paddleClientToken) {
319-
try {
320-
const paddleEnv = window.SIMPATICO_CONFIG?.paddleEnv || 'sandbox';
321-
Paddle.Initialize({
322-
token: window.SIMPATICO_CONFIG.paddleClientToken,
323-
environment: paddleEnv,
324-
});
325-
} catch(e) { console.warn('[Paddle] Init failed:', e.message); }
326-
}
327-
328316
// ── Billing toggle ──
329317
function toggleBilling() {
330318
setBilling(billingCycle === 'monthly' ? 'annual' : 'monthly');
@@ -387,29 +375,21 @@ <h2>Frequently Asked Questions</h2>
387375
} catch(e) { console.warn('Could not load subscription:', e.message); }
388376
}
389377

390-
// ── Subscribe ──
378+
// ── Subscribe via Razorpay ──
391379
async function subscribe(plan) {
392380
if (!token) {
393381
alert('Please log in first to subscribe.');
394382
window.location.href = '/platform/login.html';
395383
return;
396384
}
397385

398-
if (isDomestic) {
399-
await subscribeCashfree(plan);
400-
} else {
401-
subscribePaddle(plan);
402-
}
403-
}
404-
405-
// ── Cashfree (Domestic INR) ──
406-
async function subscribeCashfree(plan) {
407386
const btn = document.getElementById(`btn-${plan}`);
408387
const origText = btn.innerHTML;
409388
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Creating order...';
410389
btn.disabled = true;
411390

412391
try {
392+
// 1. Create Razorpay order on backend
413393
const res = await fetch(`${WORKER_URL}/billing/create-order`, {
414394
method: 'POST',
415395
headers: {
@@ -430,79 +410,82 @@ <h2>Frequently Asked Questions</h2>
430410
if (!res.ok) throw new Error(json?.error?.message || 'Order creation failed');
431411

432412
const orderData = json.data || json;
433-
const cfEnv = orderData.environment === 'production' ? 'production' : 'sandbox';
434-
435-
// Open Cashfree checkout
436-
const cashfree = Cashfree({ mode: cfEnv });
437-
const result = await cashfree.checkout({
438-
paymentSessionId: orderData.payment_session_id,
439-
redirectTarget: '_modal',
440-
});
441-
442-
if (result.error) {
443-
console.error('[Cashfree]', result.error);
444-
alert('Payment was cancelled or failed. Please try again.');
445-
} else if (result.paymentDetails) {
446-
// Verify payment
447-
document.getElementById('payOverlay').classList.add('active');
448-
const verifyRes = await fetch(`${WORKER_URL}/billing/verify-payment`, {
449-
method: 'POST',
450-
headers: {
451-
'Content-Type': 'application/json',
452-
'Authorization': `Bearer ${token}`,
453-
'X-Tenant-ID': TENANT_ID,
454-
},
455-
body: JSON.stringify({ order_id: orderData.order_id }),
456-
});
457-
const verifyData = await verifyRes.json();
458-
document.getElementById('payOverlay').classList.remove('active');
459-
460-
if (verifyData.data?.paid || verifyData.paid) {
461-
// Update local user
462-
user.subscription_plan = plan;
463-
localStorage.setItem('simpatico_user', JSON.stringify(user));
464-
window.location.href = `/platform/payment-success.html?plan=${plan}&gateway=cashfree`;
465-
} else {
466-
alert('Payment verification pending. Please check your dashboard.');
467-
}
468-
}
469-
} catch(e) {
470-
alert('Error: ' + e.message);
471-
} finally {
472-
btn.innerHTML = origText;
473-
btn.disabled = false;
474-
}
475-
}
476-
477-
// ── Paddle (International) ──
478-
function subscribePaddle(plan) {
479-
const priceIds = window.SIMPATICO_CONFIG?.paddlePriceIds || {};
480-
const priceKey = `${plan}_${billingCycle}`;
481-
const priceId = priceIds[priceKey];
482413

483-
if (!priceId) {
484-
alert(`Paddle price not configured for ${plan} (${billingCycle}). Please contact sales.`);
485-
return;
486-
}
487-
488-
try {
489-
Paddle.Checkout.open({
490-
items: [{ priceId: priceId, quantity: 1 }],
491-
customer: { email: user.email },
492-
customData: {
493-
company_id: TENANT_ID,
414+
// 2. Open Razorpay Checkout
415+
const options = {
416+
key: RZP_KEY,
417+
amount: orderData.order_amount * 100, // Razorpay expects paise
418+
currency: orderData.order_currency || 'INR',
419+
name: 'Simpatico HR',
420+
description: `${plan.charAt(0).toUpperCase() + plan.slice(1)} Plan (${billingCycle})`,
421+
order_id: orderData.razorpay_order_id,
422+
prefill: {
423+
name: user.full_name || user.name || '',
424+
email: user.email || '',
425+
contact: user.phone || '',
426+
},
427+
notes: {
494428
plan: plan,
495429
billing_cycle: billingCycle,
430+
company_id: TENANT_ID,
431+
internal_order_id: orderData.order_id,
432+
},
433+
theme: {
434+
color: '#4F46E5',
496435
},
497-
settings: {
498-
successUrl: `${window.location.origin}/platform/payment-success.html?plan=${plan}&gateway=paddle`,
499-
displayMode: 'overlay',
500-
theme: 'light',
501-
locale: 'en',
436+
handler: async function(response) {
437+
// 3. Payment successful — verify on backend
438+
document.getElementById('payOverlay').classList.add('active');
439+
try {
440+
const verifyRes = await fetch(`${WORKER_URL}/billing/verify-payment`, {
441+
method: 'POST',
442+
headers: {
443+
'Content-Type': 'application/json',
444+
'Authorization': `Bearer ${token}`,
445+
'X-Tenant-ID': TENANT_ID,
446+
},
447+
body: JSON.stringify({
448+
order_id: orderData.order_id,
449+
razorpay_order_id: response.razorpay_order_id,
450+
razorpay_payment_id: response.razorpay_payment_id,
451+
razorpay_signature: response.razorpay_signature,
452+
}),
453+
});
454+
const verifyData = await verifyRes.json();
455+
document.getElementById('payOverlay').classList.remove('active');
456+
457+
if (verifyData.data?.paid || verifyData.paid) {
458+
user.subscription_plan = plan;
459+
localStorage.setItem('simpatico_user', JSON.stringify(user));
460+
window.location.href = `/platform/payment-success.html?plan=${plan}&gateway=razorpay`;
461+
} else {
462+
alert('Payment verification pending. Please check your dashboard.');
463+
}
464+
} catch(e) {
465+
document.getElementById('payOverlay').classList.remove('active');
466+
alert('Verification error: ' + e.message);
467+
}
502468
},
469+
modal: {
470+
ondismiss: function() {
471+
btn.innerHTML = origText;
472+
btn.disabled = false;
473+
},
474+
},
475+
};
476+
477+
const rzp = new Razorpay(options);
478+
rzp.on('payment.failed', function(response) {
479+
alert('Payment failed: ' + (response.error?.description || 'Unknown error'));
480+
btn.innerHTML = origText;
481+
btn.disabled = false;
503482
});
483+
rzp.open();
484+
504485
} catch(e) {
505-
alert('Paddle checkout error: ' + e.message);
486+
alert('Error: ' + e.message);
487+
btn.innerHTML = origText;
488+
btn.disabled = false;
506489
}
507490
}
508491

pricing.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
66
<title>Pricing — Simpatico HR | AI SaaS Enterprise Platform</title>
7-
<meta name="description" content="Simple, transparent pricing for Simpatico HR's AI-powered HRMS & ATS platform. Start free, upgrade anytime. Secure payments via Paddle.">
7+
<meta name="description" content="Simple, transparent pricing for Simpatico HR's AI-powered HRMS & ATS platform. Start free, upgrade anytime. Secure payments via Razorpay.">
88
<link rel="icon" type="image/png" sizes="96x96" href="favicon-96x96.png">
99
<link rel="canonical" href="https://simpaticohrconsultancy.com/pricing.html">
1010
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
@@ -174,7 +174,7 @@ <h1>Choose the Right <span class="hl">Plan</span> for Your Team</h1>
174174
<li><i class="fas fa-times"></i> WhatsApp automation</li>
175175
</ul>
176176
<a href="platform/register-company.html?plan=starter" class="plan-btn btn-out"><i class="fas fa-bolt" style="margin-right:6px"></i>Get Started</a>
177-
<div class="gateway"><i class="fas fa-lock" style="font-size:10px"></i> Secured by Paddle</div>
177+
<div class="gateway"><i class="fas fa-lock" style="font-size:10px"></i> Secured by Razorpay</div>
178178
</div>
179179

180180
<!-- Professional -->
@@ -234,7 +234,7 @@ <h1>Choose the Right <span class="hl">Plan</span> for Your Team</h1>
234234
<h2>Frequently Asked Questions</h2>
235235
<div class="faq-item" onclick="this.classList.toggle('open')">
236236
<div class="faq-q">Which payment methods do you support? <i class="fas fa-chevron-down" style="font-size:12px;color:#94a3b8"></i></div>
237-
<div class="faq-a">We accept Visa, Mastercard, American Express, UPI, and more via Paddle — our secure payment partner and Merchant of Record. Tax compliance is handled automatically for all regions.</div>
237+
<div class="faq-a">We accept Visa, Mastercard, American Express, UPI, Netbanking, and Wallets via Razorpay — our secure payment partner. All payments are PCI DSS Level 1 compliant.</div>
238238
</div>
239239
<div class="faq-item" onclick="this.classList.toggle('open')">
240240
<div class="faq-q">How does the 2-day free trial work? <i class="fas fa-chevron-down" style="font-size:12px;color:#94a3b8"></i></div>
@@ -250,7 +250,7 @@ <h2>Frequently Asked Questions</h2>
250250
</div>
251251
<div class="faq-item" onclick="this.classList.toggle('open')">
252252
<div class="faq-q">Is my payment data secure? <i class="fas fa-chevron-down" style="font-size:12px;color:#94a3b8"></i></div>
253-
<div class="faq-a">Absolutely. We never store your card details. All payments are processed by Paddle (Merchant of Record) with PCI DSS compliance and full tax handling.</div>
253+
<div class="faq-a">Absolutely. We never store your card details. All payments are processed by Razorpay with PCI DSS Level 1 compliance and bank-grade security.</div>
254254
</div>
255255
</div>
256256

privacy.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ <h2>2. Information We Collect</h2>
8282
<p><strong>Account Information:</strong> Name, email address, phone number, company name, and role when you register.</p>
8383
<p><strong>Employee Data:</strong> Information you upload about your employees, including names, contact details, salary information, attendance records, and documents. You are the data controller for this information.</p>
8484
<p><strong>Candidate Data:</strong> Resumes, application details, assessment results, and interview recordings submitted through the recruitment process.</p>
85-
<p><strong>Payment Information:</strong> Billing details are processed securely by Paddle, our Merchant of Record. We do not store credit card numbers on our servers.</p>
85+
<p><strong>Payment Information:</strong> Billing details are processed securely by Razorpay, our PCI DSS Level 1 certified payment gateway. We do not store credit card numbers on our servers.</p>
8686
<p><strong>Usage Data:</strong> Log data, browser type, device information, and feature usage analytics to improve the Service.</p>
8787

8888
<h2>3. How We Use Your Information</h2>
@@ -115,7 +115,7 @@ <h2>5. AI & Data Processing</h2>
115115
<h2>6. Data Sharing</h2>
116116
<p>We do not sell your data. We share information only with:</p>
117117
<ul>
118-
<li><strong>Payment Processors:</strong> Paddle (Merchant of Record), for billing purposes</li>
118+
<li><strong>Payment Processors:</strong> Razorpay (PCI DSS Level 1 Certified), for billing purposes</li>
119119
<li><strong>Infrastructure Providers:</strong> Supabase, Cloudflare (under strict data processing agreements)</li>
120120
<li><strong>Email Services:</strong> Resend, for transactional emails you initiate</li>
121121
<li><strong>Legal Requirements:</strong> When required by law or to protect our rights</li>
@@ -138,7 +138,7 @@ <h2>9. Cookies</h2>
138138
<p>We use essential cookies for authentication and session management. We do not use third-party tracking cookies. Local storage is used for session tokens and user preferences.</p>
139139

140140
<h2>10. International Transfers</h2>
141-
<p>Your data may be processed in regions where our infrastructure providers operate. We ensure appropriate safeguards are in place for all international data transfers, including Paddle's Merchant of Record service which handles international payment compliance.</p>
141+
<p>Your data may be processed in regions where our infrastructure providers operate. We ensure appropriate safeguards are in place for all international data transfers, including Razorpay's payment processing service which handles payment compliance.</p>
142142

143143
<h2>11. Children's Privacy</h2>
144144
<p>The Service is not intended for individuals under 18 years of age. We do not knowingly collect information from children.</p>

0 commit comments

Comments
 (0)