This commit is contained in:
root
2025-12-22 06:43:19 +01:00
parent a940d51475
commit 6f4ca75faf
25 changed files with 1350 additions and 221 deletions

View File

@@ -3,6 +3,8 @@ import { cookies } from 'next/headers'
import pool from '@/lib/db'
import { getNowPaymentsConfig } from '@/lib/nowpayments'
import { ALLOWED_PAYMENT_CURRENCIES, isAllowedCurrency } from '@/lib/payment-currencies'
import { getCountryFromIp, calculateShippingFee } from '@/lib/geolocation'
import { getCurrencyForCountry, convertPriceForCountry } from '@/lib/currency'
// POST /api/payments/create-invoice - Create a NOWPayments payment
// Note: Endpoint name kept as "create-invoice" for backward compatibility
@@ -129,23 +131,38 @@ export async function POST(request: NextRequest) {
)
}
// Check if user has unlocked wholesale prices
const [referralRows] = await pool.execute(
'SELECT COUNT(*) as count FROM referrals WHERE referrer = ?',
[buyer_id]
)
const referralCount = (referralRows as any[])[0]?.count || 0
const isWholesaleUnlocked = referralCount >= 3
// Check if user has unlocked wholesale prices (use transaction connection to avoid connection leak)
const [referralRows] = await connection.execute(
'SELECT COUNT(*) as count FROM referrals WHERE referrer = ?',
[buyer_id]
)
const referralCount = (referralRows as any[])[0]?.count || 0
const isWholesaleUnlocked = referralCount >= 3
// Calculate price
// ppu is stored as integer where 1000 = $1.00, so divide by 1000 to get actual price
// Get country from IP to determine currency
const countryCode = await getCountryFromIp(request)
const currency = getCurrencyForCountry(countryCode)
// Calculate price in EUR (database stores prices in EUR)
// ppu is stored as integer where 1000 = 1.00 EUR, so divide by 1000 to get actual price
// Assuming ppu is per gram
const pricePerGram = drop.ppu / 1000
const priceToUse = isWholesaleUnlocked ? pricePerGram * 0.76 : pricePerGram
const priceAmount = size * priceToUse
const pricePerGramEur = drop.ppu / 1000
const priceToUseEur = isWholesaleUnlocked ? pricePerGramEur * 0.76 : pricePerGramEur
const priceAmountEur = size * priceToUseEur
// Convert price to user's currency (CHF for Swiss, EUR for others)
const priceAmount = convertPriceForCountry(priceAmountEur, countryCode)
// Calculate shipping fee (already in correct currency: CHF for CH, EUR for others)
const shippingFee = calculateShippingFee(countryCode)
// Add shipping fee to total price
const totalPriceAmount = priceAmount + shippingFee
// Round to 2 decimal places
const roundedPriceAmount = Math.round(priceAmount * 100) / 100
const roundedPriceAmount = Math.round(totalPriceAmount * 100) / 100
const roundedShippingFee = Math.round(shippingFee * 100) / 100
const roundedSubtotal = Math.round(priceAmount * 100) / 100
// Generate order ID
const orderId = `SALE-${Date.now()}-${drop_id}-${buyer_id}`
@@ -158,6 +175,10 @@ export async function POST(request: NextRequest) {
// Get NOWPayments config (testnet or production)
const nowPaymentsConfig = getNowPaymentsConfig()
// Use currency based on user location (CHF for Swiss, EUR for others)
// Override the default currency from config with user's currency
const priceCurrency = currency.toLowerCase()
// Calculate expiration time (10 minutes from now)
const expiresAt = new Date()
expiresAt.setMinutes(expiresAt.getMinutes() + 10)
@@ -180,7 +201,7 @@ export async function POST(request: NextRequest) {
},
body: JSON.stringify({
price_amount: roundedPriceAmount,
price_currency: nowPaymentsConfig.currency,
price_currency: priceCurrency, // CHF for Swiss users, EUR for others
pay_currency: payCurrency, // Required: crypto currency (btc, eth, etc)
order_id: orderId,
order_description: `${drop.item} - ${size}g`,
@@ -206,7 +227,7 @@ export async function POST(request: NextRequest) {
// payment.payment_id is the NOWPayments payment ID
await connection.execute(
'INSERT INTO pending_orders (payment_id, order_id, drop_id, buyer_id, buyer_data_id, size, price_amount, price_currency, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
[payment.payment_id, orderId, drop_id, buyer_id, buyer_data_id, size, roundedPriceAmount, nowPaymentsConfig.currency, expiresAt]
[payment.payment_id, orderId, drop_id, buyer_id, buyer_data_id, size, roundedPriceAmount, priceCurrency, expiresAt]
)
// Commit transaction - inventory is now reserved
@@ -220,8 +241,10 @@ export async function POST(request: NextRequest) {
pay_address: payment.pay_address, // Address where customer sends payment
pay_amount: payment.pay_amount, // Amount in crypto to pay
pay_currency: payment.pay_currency, // Crypto currency
price_amount: payment.price_amount, // Price in fiat
price_currency: payment.price_currency, // Fiat currency
price_amount: payment.price_amount, // Total price in fiat (includes shipping)
price_currency: payment.price_currency, // Fiat currency (CHF or EUR)
shipping_fee: roundedShippingFee, // Shipping fee in user's currency
subtotal: roundedSubtotal, // Product price without shipping in user's currency
order_id: orderId,
payin_extra_id: payment.payin_extra_id, // Memo/tag for certain currencies (XRP, XLM, etc)
expiration_estimate_date: payment.expiration_estimate_date, // When payment expires