'use strict' const { log, erpFetch } = require('./helpers') const { otpEmailHtml } = require('./email-templates') const otpStore = new Map() function generateOTP () { return String(Math.floor(100000 + Math.random() * 900000)) } function erpQuery (doctype, filters, fields, limit) { let url = `/api/resource/${encodeURIComponent(doctype)}?filters=${encodeURIComponent(JSON.stringify(filters))}&fields=${encodeURIComponent(JSON.stringify(fields))}` if (limit) url += `&limit_page_length=${limit}` return erpFetch(url) } async function sendOTP (identifier) { const isEmail = identifier.includes('@') const code = generateOTP() const expires = Date.now() + 10 * 60 * 1000 let customer = null if (isEmail) { const res = await erpQuery('Customer', [['email_id', '=', identifier]], ['name', 'customer_name', 'cell_phone', 'email_id'], 1) if (res.status === 200 && res.data?.data?.length) customer = res.data.data[0] } else { const { lookupCustomerByPhone } = require('./helpers') customer = await lookupCustomerByPhone(identifier) } if (!customer) return { found: false } otpStore.set(identifier, { code, expires, customerId: customer.name, customerName: customer.customer_name }) if (isEmail) { const { sendEmail } = require('./email') await sendEmail({ to: identifier, subject: 'Code de vérification Gigafibre', html: otpEmailHtml(code), }) } else { try { const { sendSmsInternal } = require('./twilio') await sendSmsInternal(identifier, `Gigafibre — Votre code de vérification : ${code}\nExpire dans 10 min.`) } catch (e) { log('OTP SMS failed:', e.message) } } log(`OTP sent to ${identifier} for customer ${customer.name}`) return { found: true, sent: true, channel: isEmail ? 'email' : 'sms' } } async function verifyOTP (identifier, code) { const entry = otpStore.get(identifier) if (!entry) return { valid: false, reason: 'no_otp' } if (Date.now() > entry.expires) { otpStore.delete(identifier); return { valid: false, reason: 'expired' } } if (entry.code !== code) return { valid: false, reason: 'wrong_code' } otpStore.delete(identifier) const result = { valid: true, customer_id: entry.customerId, customer_name: entry.customerName } try { const custRes = await erpFetch(`/api/resource/Customer/${encodeURIComponent(entry.customerId)}?fields=${encodeURIComponent(JSON.stringify(['name', 'customer_name', 'cell_phone', 'email_id', 'tel_home']))}`) if (custRes.status === 200 && custRes.data?.data) { const c = custRes.data.data result.phone = c.cell_phone || c.tel_home || '' result.email = c.email_id || '' } if (!result.email) { try { const contRes = await erpQuery('Contact', [['Dynamic Link', 'link_doctype', '=', 'Customer'], ['Dynamic Link', 'link_name', '=', entry.customerId]], ['email_id'], 1) if (contRes.status === 200 && contRes.data?.data?.[0]?.email_id) { result.email = contRes.data.data[0].email_id } } catch (e) { log('OTP - Contact email fallback error:', e.message) } } const locRes = await erpQuery('Service Location', [['customer', '=', entry.customerId]], ['name', 'address_line', 'city', 'postal_code', 'location_name', 'latitude', 'longitude'], 20) if (locRes.status === 200 && locRes.data?.data?.length) { result.addresses = locRes.data.data.map(l => ({ name: l.name, address: l.address_line || l.location_name || l.name, city: l.city || '', postal_code: l.postal_code || '', latitude: l.latitude || null, longitude: l.longitude || null, })) } } catch (e) { log('OTP verify - customer details fetch error:', e.message) } return result } module.exports = { otpStore, generateOTP, sendOTP, verifyOTP }