final
This commit is contained in:
@@ -71,7 +71,7 @@ export async function PUT(
|
||||
}
|
||||
|
||||
const body = await request.json()
|
||||
const { item, size, unit, ppu, imageUrl, startTime } = body
|
||||
const { item, description, size, unit, ppu, priceChf, priceEur, wholesalePriceChf, wholesalePriceEur, imageUrl, startTime } = body
|
||||
|
||||
// Check if drop exists
|
||||
const [existingRows] = await pool.execute(
|
||||
@@ -95,6 +95,11 @@ export async function PUT(
|
||||
values.push(item)
|
||||
}
|
||||
|
||||
if (description !== undefined) {
|
||||
updates.push('description = ?')
|
||||
values.push(description || null)
|
||||
}
|
||||
|
||||
if (size !== undefined) {
|
||||
if (size <= 0) {
|
||||
return NextResponse.json(
|
||||
@@ -122,6 +127,50 @@ export async function PUT(
|
||||
values.push(ppu)
|
||||
}
|
||||
|
||||
if (priceChf !== undefined) {
|
||||
if (priceChf !== null && priceChf < 0) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Price CHF must be greater than or equal to 0' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
updates.push('price_chf = ?')
|
||||
values.push(priceChf !== null && priceChf !== '' ? priceChf : null)
|
||||
}
|
||||
|
||||
if (priceEur !== undefined) {
|
||||
if (priceEur !== null && priceEur < 0) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Price EUR must be greater than or equal to 0' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
updates.push('price_eur = ?')
|
||||
values.push(priceEur !== null && priceEur !== '' ? priceEur : null)
|
||||
}
|
||||
|
||||
if (wholesalePriceChf !== undefined) {
|
||||
if (wholesalePriceChf !== null && wholesalePriceChf < 0) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Wholesale price CHF must be greater than or equal to 0' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
updates.push('wholesale_price_chf = ?')
|
||||
values.push(wholesalePriceChf !== null && wholesalePriceChf !== '' ? wholesalePriceChf : null)
|
||||
}
|
||||
|
||||
if (wholesalePriceEur !== undefined) {
|
||||
if (wholesalePriceEur !== null && wholesalePriceEur < 0) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Wholesale price EUR must be greater than or equal to 0' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
updates.push('wholesale_price_eur = ?')
|
||||
values.push(wholesalePriceEur !== null && wholesalePriceEur !== '' ? wholesalePriceEur : null)
|
||||
}
|
||||
|
||||
if (imageUrl !== undefined) {
|
||||
updates.push('image_url = ?')
|
||||
values.push(imageUrl || null)
|
||||
|
||||
@@ -56,7 +56,7 @@ export async function GET(request: NextRequest) {
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { item, size, unit = 'g', ppu, imageUrl, startTime } = body
|
||||
const { item, description, size, unit = 'g', ppu, priceChf, priceEur, wholesalePriceChf, wholesalePriceEur, imageUrl, startTime } = body
|
||||
|
||||
// Validate required fields
|
||||
if (!item || !size || !ppu) {
|
||||
@@ -71,8 +71,8 @@ export async function POST(request: NextRequest) {
|
||||
// ALTER TABLE drops ADD COLUMN image_url VARCHAR(255) DEFAULT NULL AFTER unit;
|
||||
// Note: fill is no longer stored, it's calculated from sales
|
||||
const [result] = await pool.execute(
|
||||
'INSERT INTO drops (item, size, unit, ppu, image_url, start_time) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[item, size, unit, ppu, imageUrl || null, startTime || null]
|
||||
'INSERT INTO drops (item, description, size, unit, ppu, price_chf, price_eur, wholesale_price_chf, wholesale_price_eur, image_url, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[item, description || null, size, unit, ppu, priceChf || null, priceEur || null, wholesalePriceChf || null, wholesalePriceEur || null, imageUrl || null, startTime || null]
|
||||
)
|
||||
|
||||
const insertId = (result as any).insertId
|
||||
|
||||
@@ -192,23 +192,35 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
// Get points_to_chf setting
|
||||
// Get points_to_eur setting (fallback to points_to_chf for backward compatibility)
|
||||
const [settingsRows] = await connection.execute(
|
||||
'SELECT setting_value FROM referral_settings WHERE setting_key = ?',
|
||||
['points_to_chf']
|
||||
'SELECT setting_key, setting_value FROM referral_settings WHERE setting_key IN (?, ?)',
|
||||
['points_to_eur', 'points_to_chf']
|
||||
)
|
||||
const settings = settingsRows as any[]
|
||||
const pointsToChf = parseFloat(settings[0]?.setting_value || '100')
|
||||
|
||||
// Calculate discount in CHF, then convert to user's currency
|
||||
const discountChf = pointsToUse / pointsToChf
|
||||
let pointsToEur = parseFloat(settings.find(s => s.setting_key === 'points_to_eur')?.setting_value || '0')
|
||||
|
||||
// Convert discount based on user's currency
|
||||
// If points_to_eur not found, use points_to_chf and convert
|
||||
if (pointsToEur === 0) {
|
||||
const pointsToChf = parseFloat(settings.find(s => s.setting_key === 'points_to_chf')?.setting_value || '100')
|
||||
// Convert CHF-based points to EUR-based (1 CHF ≈ 1.0309 EUR)
|
||||
pointsToEur = pointsToChf / 1.030927835
|
||||
}
|
||||
|
||||
if (pointsToEur === 0) {
|
||||
pointsToEur = 100 // Default fallback
|
||||
}
|
||||
|
||||
// Calculate discount in EUR first (universal base currency)
|
||||
const discountEur = pointsToUse / pointsToEur
|
||||
|
||||
// Convert discount to user's currency
|
||||
if (currency === 'CHF') {
|
||||
pointsDiscount = discountChf
|
||||
// Convert EUR to CHF (1 EUR = 0.97 CHF)
|
||||
pointsDiscount = discountEur * 0.97
|
||||
} else {
|
||||
// Convert CHF to EUR (1 CHF ≈ 1.03 EUR)
|
||||
pointsDiscount = discountChf * 1.03
|
||||
// Already in EUR
|
||||
pointsDiscount = discountEur
|
||||
}
|
||||
|
||||
// Don't allow discount to exceed the product price (before shipping)
|
||||
|
||||
@@ -43,10 +43,10 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
// Validate crypto currency
|
||||
if (!isAllowedCurrency(normalizedCryptoCurrency)) {
|
||||
// Validate crypto currency - only USDT (SOL) is allowed for redemption
|
||||
if (normalizedCryptoCurrency !== 'usdtsol') {
|
||||
return NextResponse.json(
|
||||
{ error: `Unsupported cryptocurrency. Allowed: ${ALLOWED_PAYMENT_CURRENCIES.join(', ')}` },
|
||||
{ error: 'Only USDT (SOL) is supported for point redemption' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
@@ -205,6 +205,7 @@ async function getCryptoExchangeRate(crypto: string, fiat: string): Promise<numb
|
||||
'xrp': 0.6,
|
||||
'bnbbsc': 300,
|
||||
'usdterc20': 0.9, // Approximate CHF per USDT
|
||||
'usdtsol': 0.9, // Approximate CHF per USDT on Solana
|
||||
}
|
||||
|
||||
return mockRates[crypto.toLowerCase()] || null
|
||||
|
||||
@@ -38,12 +38,31 @@ export async function GET(request: NextRequest) {
|
||||
)
|
||||
const settings = settingsRows as any[]
|
||||
|
||||
// Get EUR-based settings (preferred)
|
||||
let pointsToEur = parseFloat(
|
||||
settings.find(s => s.setting_key === 'points_to_eur')?.setting_value || '0'
|
||||
)
|
||||
let pointsPerEur = parseFloat(
|
||||
settings.find(s => s.setting_key === 'points_per_eur')?.setting_value || '0'
|
||||
)
|
||||
|
||||
// Get CHF-based settings (for backward compatibility)
|
||||
const pointsToChf = parseFloat(
|
||||
settings.find(s => s.setting_key === 'points_to_chf')?.setting_value || '100'
|
||||
)
|
||||
const pointsPerChf = parseFloat(
|
||||
settings.find(s => s.setting_key === 'points_per_chf')?.setting_value || '10'
|
||||
)
|
||||
|
||||
// If EUR settings not found, convert from CHF (1 CHF ≈ 1.0309 EUR)
|
||||
const chfToEurRate = 1.030927835
|
||||
if (pointsToEur === 0) {
|
||||
pointsToEur = pointsToChf / chfToEurRate
|
||||
}
|
||||
if (pointsPerEur === 0) {
|
||||
pointsPerEur = pointsPerChf * chfToEurRate
|
||||
}
|
||||
|
||||
const pointsToCryptoChf = parseFloat(
|
||||
settings.find(s => s.setting_key === 'points_to_crypto_chf')?.setting_value || '100'
|
||||
)
|
||||
@@ -51,15 +70,19 @@ export async function GET(request: NextRequest) {
|
||||
settings.find(s => s.setting_key === 'min_redemption_points')?.setting_value || '1000'
|
||||
)
|
||||
|
||||
// Calculate maximum discount available
|
||||
const maxDiscountChf = referralPoints / pointsToChf
|
||||
// Calculate maximum discount available (in EUR, then convert to CHF for display)
|
||||
const maxDiscountEur = referralPoints / pointsToEur
|
||||
const maxDiscountChf = maxDiscountEur * 0.97 // Convert EUR to CHF
|
||||
|
||||
return NextResponse.json({
|
||||
referral_points: referralPoints,
|
||||
points_to_chf: pointsToChf,
|
||||
points_per_chf: pointsPerChf,
|
||||
points_to_eur: pointsToEur,
|
||||
points_per_eur: pointsPerEur,
|
||||
points_to_chf: pointsToChf, // Keep for backward compatibility
|
||||
points_per_chf: pointsPerChf, // Keep for backward compatibility
|
||||
points_to_crypto_chf: pointsToCryptoChf,
|
||||
min_redemption_points: minRedemptionPoints,
|
||||
max_discount_eur: maxDiscountEur,
|
||||
max_discount_chf: maxDiscountChf,
|
||||
})
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user