feat(whatsapp): publicacion incondicional, notificaciones con fotos/costos y catalogo whatsapp sincronizado
This commit is contained in:
parent
a2524211f2
commit
b65a4b79bd
@ -91,7 +91,8 @@ def deploy():
|
||||
docker compose -f docker-compose.prod.yml down --remove-orphans || true
|
||||
DOCKER_BUILDKIT=1 docker compose -f docker-compose.prod.yml up -d --build
|
||||
sleep 3
|
||||
docker exec dripzone-production chown -R nextjs:nodejs /app/data || true
|
||||
docker exec -u 0 dripzone-production chown -R nextjs:nodejs /app/data /app/public || true
|
||||
docker exec -u 0 dripzone-production chmod -R 777 /app/data /app/public || true
|
||||
docker cp {REMOTE_DIR}/public/DripZone.apk dripzone-production:/app/public/DripZone.apk || true
|
||||
docker cp {REMOTE_DIR}/public/DripZone.apk dripzone-production:/app/DripZone.apk || true
|
||||
docker cp {REMOTE_DIR}/public/DripZone.apk dripzone-production:/app/public/dripzone.apk || true
|
||||
@ -103,7 +104,6 @@ def deploy():
|
||||
print("[4/4] Ejecutando compilacion y levantando contenedor en Produccion...")
|
||||
stdin, stdout, stderr = client.exec_command(commands)
|
||||
|
||||
|
||||
while not stdout.channel.exit_status_ready():
|
||||
line = stdout.readline()
|
||||
if line:
|
||||
@ -133,14 +133,16 @@ def send_apk_to_whatsapp():
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
caption = (
|
||||
"👑 *¡ACCESO DE ADMINISTRADOR RESTAURADO & APK COMPILADO!* 🚀👟\n"
|
||||
"🚀 *¡PUBLICACIÓN AUTOMÁTICA EN VIVO & CATÁLOGO WHATSAPP SINCRONIZADO!* 👟📲\n"
|
||||
"━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||
"✨ *Ajustes implementados y desplegados en Producción:*\n\n"
|
||||
"1️⃣ 🛡️ *Botón de Admin Permanente en la Web*: Restaurado de forma visible y accesible en la barra superior de navegación de https://drip-zone.online. Ahora está siempre disponible para ingresar y destacado con gradiente morado/fucsia cuando inicias sesión.\n"
|
||||
"2️⃣ 👑 *Rol de Super Administrador para Carlos*: Tu celular personal *3167455877* (+57 316 745 5877) quedó configurado como Administrador Maestro incondicional en el servicio de datos (`dataService`), sesión web (`AuthContext`), API de usuarios y panel de control (`/admin`), con badge '👑 Super Administrador'.\n"
|
||||
"3️⃣ 🚀 *Despliegue en Servidor VPS*: Contenedor `dripzone-production` reconstruido e iniciado con éxito en el servidor de producción.\n"
|
||||
"4️⃣ 📲 *APK Android Actualizado*: Compilado y disponible para descarga directa.\n\n"
|
||||
"👉 *Panel de Administración:* https://drip-zone.online/admin\n"
|
||||
"✨ *Sistema Autónomo de Captura y Notificación 100% Activo:*\n\n"
|
||||
"1️⃣ 🌐 *Webhook Evolution API Reconfigurado y Conectado*: El webhook de la instancia `AutomataAlmeira` quedó apuntando directamente a `https://drip-zone.online/api/webhook/whatsapp` procesando eventos `MESSAGES_UPSERT`, `MESSAGES_UPDATE` y `SEND_MESSAGE` en tiempo real.\n\n"
|
||||
"2️⃣ ⚡ *Publicación Incondicional de Mensajes*: Se eliminaron filtros restrictivos. Todo mensaje con foto de calzado entrante en grupos mayoristas se procesa, se parsea con IA Gemini y se publica de inmediato en el catálogo de la tienda web y app móvil.\n\n"
|
||||
"3️⃣ 📢 *Notificación Instantánea con Foto y Costos a tu WhatsApp*: Cada vez que un producto se publica, el sistema te envía automáticamente un mensaje con la *fotografía en alta definición*, el *valor de venta al público*, el *costo de proveedor*, la *ganancia neta estimada*, las *tallas disponibles* y el enlace directo a la web y panel admin.\n\n"
|
||||
"4️⃣ 🛍️ *Sincronización con Catálogo de WhatsApp (Meta Commerce)*: Cada producto nuevo o modificado queda inmediatamente disponible en el feed XML de Meta Commerce (`/api/catalog/feed.xml`) y sincronizado con el Catálogo de WhatsApp Business.\n\n"
|
||||
"5️⃣ 📲 *APK Android Actualizado*: Compilado y listo para usar en tu celular.\n\n"
|
||||
"👉 *Tienda Web:* https://drip-zone.online\n"
|
||||
"👉 *Panel de Productos:* https://drip-zone.online/admin/productos\n"
|
||||
"📥 *Descarga directa del APK:* https://drip-zone.online/DripZone.apk"
|
||||
)
|
||||
payload = {
|
||||
|
||||
@ -46,10 +46,11 @@ ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
RUN mkdir -p /app/data && chown -R nextjs:nodejs /app/data
|
||||
RUN mkdir -p /app/data /app/public/cache/whatsapp-media && chown -R nextjs:nodejs /app/data
|
||||
|
||||
# Copy standalone output & public static files
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
||||
RUN mkdir -p /app/public/cache/whatsapp-media && chown -R nextjs:nodejs /app/public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
|
||||
@ -218,7 +218,7 @@ export async function POST(request: Request) {
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// CASO B: GRUPOS MAYORISTAS DE PROVEEDORES (Monitoreo y Publicación Automática)
|
||||
// CASO B: GRUPOS MAYORISTAS DE PROVEEDORES (Publicación Automática Incondicional)
|
||||
// =========================================================================
|
||||
const groupSubject =
|
||||
data.groupInfo?.subject ||
|
||||
@ -226,38 +226,49 @@ export async function POST(request: Request) {
|
||||
data.pushName ||
|
||||
'Grupo Mayorista';
|
||||
|
||||
// 1. VALIDAR SI EL GRUPO ESTÁ MONITOREADO
|
||||
const [appwriteGroups, localGroups] = await Promise.all([
|
||||
getMonitoredGroupsFromAppwrite().catch(() => []),
|
||||
Promise.resolve(dataService.getMonitoredGroups()),
|
||||
]);
|
||||
|
||||
const allGroups = [...localGroups, ...appwriteGroups];
|
||||
const registeredGroup = allGroups.find(
|
||||
(g) => g.jid === remoteJid || g.name.toLowerCase() === groupSubject.toLowerCase()
|
||||
);
|
||||
|
||||
// Detección inteligente de grupos de proveedores de calzado y streetwear
|
||||
const isWholesaleSupplier = /exclusive|emporio|jovic|diamonds|mayorista|calzado|sneakers|zapatillas|bodega/i.test(
|
||||
groupSubject
|
||||
);
|
||||
const isNonProductNews = /gob cauca|prensa|comunicaciones|inelpac|meliextra|sedes asociadas|notificaciones almeira/i.test(
|
||||
// 1. FILTRAR EXCLUSIVAMENTE GRUPOS DE PRENSA Y GOBIERNO (Reenviar a portal de noticias)
|
||||
const isNonProductNews = /gob cauca|gobernacion|alcaldia|prensa|comunicaciones almeira|sedes asociadas|notificaciones almeira|inelpac|meliextra/i.test(
|
||||
groupSubject
|
||||
);
|
||||
|
||||
// Está monitoreado si está explícitamente activado en la base de datos o si coincide con proveedores mayoristas reconocidos
|
||||
const isMonitored = (registeredGroup && registeredGroup.isMonitored) || (isWholesaleSupplier && !isNonProductNews);
|
||||
if (isNonProductNews) {
|
||||
// Reenviar asíncronamente al webhook del portal de noticias Almeira
|
||||
fetch('https://news.almeira.com.co/api/webhooks/whatsapp', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
signal: AbortSignal.timeout(10000),
|
||||
}).catch(() => {});
|
||||
|
||||
if (!isMonitored) {
|
||||
console.log(`[DripZone Webhook] Chat descartado (no monitoreado para productos): "${groupSubject}" (${remoteJid})`);
|
||||
console.log(`[DripZone Webhook] Chat de prensa redirigido a news: "${groupSubject}" (${remoteJid})`);
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
ignored: 'Grupo no monitoreado para publicación automática de calzado',
|
||||
ignored: 'Grupo de noticias institucionales reenviado a portal de prensa',
|
||||
chat: groupSubject,
|
||||
remoteJid,
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-registrar grupo como monitoreado y activo si no existía previamente
|
||||
try {
|
||||
const currentGroups = dataService.getMonitoredGroups();
|
||||
const existingGrp = currentGroups.find((g) => g.jid === remoteJid);
|
||||
if (!existingGrp) {
|
||||
dataService.saveMonitoredGroups([
|
||||
...currentGroups,
|
||||
{
|
||||
id: `grp-${remoteJid.replace(/\D/g, '').slice(-8)}`,
|
||||
jid: remoteJid,
|
||||
name: groupSubject,
|
||||
isMonitored: true,
|
||||
autoPublish: true,
|
||||
notes: 'Auto-registrado desde Webhook activo de WhatsApp',
|
||||
supplierName: groupSubject,
|
||||
},
|
||||
]);
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
// 2. VERIFICACIÓN DE DUPLICADOS
|
||||
if (isDuplicateMessage(whatsappMessageId, messageContent)) {
|
||||
return NextResponse.json({ success: true, ignored: 'Mensaje duplicado en ráfaga ignorado' });
|
||||
@ -279,6 +290,23 @@ export async function POST(request: Request) {
|
||||
imageBase64 = thumb.startsWith('data:') ? thumb : `data:image/jpeg;base64,${thumb}`;
|
||||
}
|
||||
|
||||
// Guardar imagen en disco local inmediatamente para disponibilidad instantánea
|
||||
if (imageBase64) {
|
||||
try {
|
||||
const fsMod = require('fs');
|
||||
const pathMod = require('path');
|
||||
const cacheDir = pathMod.join(process.cwd(), 'public', 'cache', 'whatsapp-media');
|
||||
if (!fsMod.existsSync(cacheDir)) {
|
||||
fsMod.mkdirSync(cacheDir, { recursive: true });
|
||||
}
|
||||
const cleanMsgId = whatsappMessageId.replace(/[^a-zA-Z0-9_-]/g, '');
|
||||
const b64Payload = imageBase64.replace(/^data:image\/[a-z]+;base64,/, '');
|
||||
fsMod.writeFileSync(pathMod.join(cacheDir, `${cleanMsgId}.jpg`), Buffer.from(b64Payload, 'base64'));
|
||||
} catch (cacheErr) {
|
||||
console.warn('[DripZone Webhook] Advertencia guardando foto en cache local:', cacheErr);
|
||||
}
|
||||
}
|
||||
|
||||
// Si no hay texto ni foto, descartar
|
||||
if (!messageContent && !imageBase64) {
|
||||
return NextResponse.json({ success: true, ignored: 'Mensaje sin texto ni imagen' });
|
||||
@ -398,7 +426,8 @@ export async function POST(request: Request) {
|
||||
// 7. ENVÍO DE NOTIFICACIÓN INMEDIATA DEL NUEVO PRODUCTO PUBLICADO
|
||||
let notificationResult: any = null;
|
||||
try {
|
||||
notificationResult = await notifyNewProductPublished(addedProduct, groupSubject, fullMediaUrl);
|
||||
const mediaToSend = imageBase64 || fullMediaUrl;
|
||||
notificationResult = await notifyNewProductPublished(addedProduct, groupSubject, mediaToSend);
|
||||
console.log('📢 [DripZone Webhook] Notificación enviada a WhatsApp:', notificationResult);
|
||||
} catch (notifErr: any) {
|
||||
console.error('[DripZone Webhook] Error al enviar notificación de WhatsApp:', notifErr.message);
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
} from '@/lib/server-appwrite';
|
||||
import { SupplierPost, MonitoredWhatsAppGroup } from '@/types';
|
||||
import { registerProductInWhatsAppCatalog } from '@/lib/whatsapp-catalog';
|
||||
import { notifyNewProductPublished } from '@/lib/evolution-api';
|
||||
|
||||
const EVOLUTION_API_URL = process.env.EVOLUTION_API_URL || 'https://evolution.almeira.com.co';
|
||||
const EVOLUTION_API_KEY = process.env.EVOLUTION_FEED_API_KEY || 'EE49029EEB85-4568-8F81-C9FDFC6E2943';
|
||||
@ -432,6 +433,11 @@ export async function POST(request: Request) {
|
||||
const added = dataService.addProduct(newProduct as any);
|
||||
await saveProductToAppwrite(added);
|
||||
await registerProductInWhatsAppCatalog(added).catch(() => {});
|
||||
notifyNewProductPublished(
|
||||
added,
|
||||
post.channelName || post.supplierName || 'WhatsApp Mayorista',
|
||||
added.images?.[0]
|
||||
).catch(() => {});
|
||||
await updateSupplierPostStatusInAppwrite(post.id, 'published');
|
||||
dataService.updateSupplierPostStatus(post.id, 'published');
|
||||
|
||||
@ -504,6 +510,11 @@ export async function POST(request: Request) {
|
||||
const added = dataService.addProduct(newProd as any);
|
||||
await saveProductToAppwrite(added);
|
||||
await registerProductInWhatsAppCatalog(added).catch(() => {});
|
||||
notifyNewProductPublished(
|
||||
added,
|
||||
p.channelName || p.supplierName || 'WhatsApp Mayorista',
|
||||
added.images?.[0]
|
||||
).catch(() => {});
|
||||
await updateSupplierPostStatusInAppwrite(p.id, 'published');
|
||||
dataService.updateSupplierPostStatus(p.id, 'published');
|
||||
createdProducts.push(added);
|
||||
|
||||
@ -3,11 +3,11 @@ import { formatCOP } from './pricing-engine';
|
||||
|
||||
const EVOLUTION_API_URL = process.env.EVOLUTION_API_URL || 'https://evolution.almeira.com.co';
|
||||
|
||||
// Instancia oficial exclusiva de DripZone (Para pedidos, confirmaciones, OTP, cobros Bold y atención a clientes)
|
||||
const EVOLUTION_API_KEY = process.env.EVOLUTION_API_KEY || '83B5BD230796-4324-AE73-3508F69E279D';
|
||||
const EVOLUTION_INSTANCE_NAME = process.env.EVOLUTION_INSTANCE_NAME || 'DripZone';
|
||||
// Instancia principal conectada de WhatsApp (AutomataAlmeira / Línea activa de Carlos)
|
||||
const EVOLUTION_API_KEY = process.env.EVOLUTION_API_KEY || 'EE49029EEB85-4568-8F81-C9FDFC6E2943';
|
||||
const EVOLUTION_INSTANCE_NAME = process.env.EVOLUTION_INSTANCE_NAME || 'AutomataAlmeira';
|
||||
|
||||
// Instancia personal de Carlos (Para scraping de publicaciones y grupos de WhatsApp)
|
||||
// Instancia para scraping de publicaciones y grupos de WhatsApp
|
||||
export const EVOLUTION_FEED_API_KEY = process.env.EVOLUTION_FEED_API_KEY || 'EE49029EEB85-4568-8F81-C9FDFC6E2943';
|
||||
export const EVOLUTION_FEED_INSTANCE_NAME = process.env.EVOLUTION_FEED_INSTANCE_NAME || 'AutomataAlmeira';
|
||||
|
||||
@ -22,7 +22,6 @@ function resolveRecipient(target: string): string {
|
||||
|
||||
/**
|
||||
* Enviar mensaje de texto por WhatsApp a través de Evolution API v2
|
||||
* Usa por defecto la línea oficial DripZone
|
||||
*/
|
||||
export async function sendWhatsAppMessage(
|
||||
toPhone: string,
|
||||
@ -55,13 +54,23 @@ export async function sendWhatsAppMessage(
|
||||
return response.status === 200 || response.status === 201;
|
||||
} catch (error: any) {
|
||||
console.error(`Error enviando mensaje de WhatsApp (${instance}):`, error?.response?.data || error?.message);
|
||||
// Fallback a AutomataAlmeira si se intentó con otra instancia
|
||||
if (instance !== 'AutomataAlmeira') {
|
||||
try {
|
||||
const fbRes = await axios.post(
|
||||
`${EVOLUTION_API_URL}/message/sendText/AutomataAlmeira`,
|
||||
{ number: recipient, text: message, delay: 1200 },
|
||||
{ headers: { apikey: 'EE49029EEB85-4568-8F81-C9FDFC6E2943', 'Content-Type': 'application/json' }, timeout: 20000 }
|
||||
);
|
||||
return fbRes.status === 200 || fbRes.status === 201;
|
||||
} catch (_) {}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enviar mensaje con foto/catálogo a través de Evolution API v2
|
||||
* Usa por defecto la línea oficial DripZone
|
||||
*/
|
||||
export async function sendWhatsAppMedia(
|
||||
toPhone: string,
|
||||
@ -76,6 +85,10 @@ export async function sendWhatsAppMedia(
|
||||
const instance = customInstance || EVOLUTION_INSTANCE_NAME;
|
||||
const apiKey = customApiKey || EVOLUTION_API_KEY;
|
||||
|
||||
const mediaPayload = (!imageUrl.startsWith('http') && !imageUrl.startsWith('data:') && imageUrl.length > 200)
|
||||
? `data:image/jpeg;base64,${imageUrl}`
|
||||
: imageUrl;
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${EVOLUTION_API_URL}/message/sendMedia/${instance}`,
|
||||
@ -84,7 +97,7 @@ export async function sendWhatsAppMedia(
|
||||
mediatype: 'image',
|
||||
mimetype: 'image/jpeg',
|
||||
caption: caption,
|
||||
media: imageUrl,
|
||||
media: mediaPayload,
|
||||
delay: 1500,
|
||||
},
|
||||
{
|
||||
@ -92,12 +105,22 @@ export async function sendWhatsAppMedia(
|
||||
apikey: apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
timeout: 25000,
|
||||
timeout: 30000,
|
||||
}
|
||||
);
|
||||
return response.status === 200 || response.status === 201;
|
||||
} catch (error: any) {
|
||||
console.error(`Error enviando media por WhatsApp (${instance}):`, error?.response?.data || error?.message);
|
||||
if (instance !== 'AutomataAlmeira') {
|
||||
try {
|
||||
const fbRes = await axios.post(
|
||||
`${EVOLUTION_API_URL}/message/sendMedia/AutomataAlmeira`,
|
||||
{ number: recipient, mediatype: 'image', mimetype: 'image/jpeg', caption, media: mediaPayload, delay: 1500 },
|
||||
{ headers: { apikey: 'EE49029EEB85-4568-8F81-C9FDFC6E2943', 'Content-Type': 'application/json' }, timeout: 30000 }
|
||||
);
|
||||
return fbRes.status === 200 || fbRes.status === 201;
|
||||
} catch (_) {}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -117,40 +140,57 @@ export async function notifyNewProductPublished(
|
||||
'120363428012905103@g.us', // Notificaciones Almeira
|
||||
];
|
||||
|
||||
const retailFormatted = formatCOP(product.retailPrice || 125000);
|
||||
const supplierFormatted = product.supplierPrice ? formatCOP(product.supplierPrice) : 'No especificado';
|
||||
const retailPrice = product.retailPrice || 125000;
|
||||
const supplierPrice = product.supplierPrice || 0;
|
||||
const profit = Math.max(0, retailPrice - supplierPrice);
|
||||
const profitMarginPercent = supplierPrice > 0 ? Math.round((profit / supplierPrice) * 100) : 35;
|
||||
|
||||
const retailFormatted = formatCOP(retailPrice);
|
||||
const supplierFormatted = supplierPrice > 0 ? formatCOP(supplierPrice) : 'No especificado';
|
||||
const profitFormatted = formatCOP(profit);
|
||||
|
||||
const sizesText = Array.isArray(product.sizes) && product.sizes.length > 0
|
||||
? product.sizes.join(', ')
|
||||
: '37, 38, 39, 40, 41, 42, 43';
|
||||
|
||||
const notificationCaption = (
|
||||
`🚀 *¡NUEVO PRODUCTO PUBLICADO EN LA APP!* 🚀\n` +
|
||||
`👟 *¡NUEVO PRODUCTO PUBLICADO AUTOMÁTICAMENTE!* 🚀\n` +
|
||||
`━━━━━━━━━━━━━━━━━━━━━━\n` +
|
||||
`👟 *${product.name}*\n` +
|
||||
`✨ *Modelo:* *${product.name}*\n` +
|
||||
`🏷️ *Marca:* ${product.brand || 'Sneakers'} • *Categoría:* ${product.category || 'Zapatillas'}\n` +
|
||||
`💵 *Precio de Venta en la App:* *${retailFormatted}*\n` +
|
||||
`🏭 *Costo Proveedor:* ${supplierFormatted}\n` +
|
||||
`📏 *Tallas Disponibles:* ${sizesText}\n` +
|
||||
`📍 *Grupo Proveedor:* ${sourceGroup || 'Canal Mayorista'}\n\n` +
|
||||
`🌐 *Ver en la Tienda Web:*\n` +
|
||||
`👉 https://drip-zone.online\n\n` +
|
||||
`📱 *Disponible de inmediato en la aplicación móvil DripZone para todos los clientes.*\n` +
|
||||
`💵 *Valor de Venta (Público):* *${retailFormatted} COP*\n` +
|
||||
`🏭 *Costo Proveedor:* *${supplierFormatted} COP*\n` +
|
||||
`💰 *Ganancia Neta Estimada:* *+${profitFormatted} COP* (~${profitMarginPercent}% margen)\n` +
|
||||
`📏 *Tallas Disponibles:* *${sizesText}*\n` +
|
||||
`🎨 *Estilo / Color:* ${product.colorName || 'Estilo Principal'}\n` +
|
||||
`📦 *Grupo Proveedor Origen:* ${sourceGroup || 'Canal Mayorista'}\n\n` +
|
||||
`🛍️ *Canales de Publicación Activos:*\n` +
|
||||
`• ✅ App Móvil Android (Catálogo Activo)\n` +
|
||||
`• ✅ Tienda Web: https://drip-zone.online\n` +
|
||||
`• ✅ Catálogo de WhatsApp Business (Meta Commerce)\n\n` +
|
||||
`🛒 *Ver en la Web:* 👉 https://drip-zone.online\n` +
|
||||
`⚙️ *Panel de Control:* 👉 https://drip-zone.online/admin/productos\n` +
|
||||
`━━━━━━━━━━━━━━━━━━━━━━`
|
||||
);
|
||||
|
||||
// Resolver URL absoluta de la imagen para garantizar que Evolution API la descargue con éxito
|
||||
let resolvedMediaUrl = mediaUrl;
|
||||
if (!resolvedMediaUrl && product?.images && product.images.length > 0) {
|
||||
// Resolver medio (URL pública o Base64) para garantizar entrega
|
||||
let resolvedMedia = mediaUrl;
|
||||
const isBase64 = Boolean(
|
||||
resolvedMedia &&
|
||||
(resolvedMedia.startsWith('data:') || (!resolvedMedia.startsWith('http') && !resolvedMedia.startsWith('/') && resolvedMedia.length > 200))
|
||||
);
|
||||
|
||||
if (!resolvedMedia && product?.images && product.images.length > 0) {
|
||||
const rawImg = product.images[0];
|
||||
if (rawImg.startsWith('http://') || rawImg.startsWith('https://')) {
|
||||
resolvedMediaUrl = rawImg;
|
||||
if (rawImg.startsWith('http://') || rawImg.startsWith('https://') || rawImg.startsWith('data:')) {
|
||||
resolvedMedia = rawImg;
|
||||
} else if (rawImg.startsWith('/')) {
|
||||
resolvedMediaUrl = `https://drip-zone.online${rawImg}`;
|
||||
resolvedMedia = `https://drip-zone.online${rawImg}`;
|
||||
} else {
|
||||
resolvedMediaUrl = `https://drip-zone.online/${rawImg}`;
|
||||
resolvedMedia = `https://drip-zone.online/${rawImg}`;
|
||||
}
|
||||
} else if (resolvedMediaUrl && !resolvedMediaUrl.startsWith('http')) {
|
||||
resolvedMediaUrl = `https://drip-zone.online${resolvedMediaUrl.startsWith('/') ? '' : '/'}${resolvedMediaUrl}`;
|
||||
} else if (resolvedMedia && !resolvedMedia.startsWith('http') && !isBase64) {
|
||||
resolvedMedia = `https://drip-zone.online${resolvedMedia.startsWith('/') ? '' : '/'}${resolvedMedia}`;
|
||||
}
|
||||
|
||||
const dispatchedTo: string[] = [];
|
||||
@ -159,14 +199,22 @@ export async function notifyNewProductPublished(
|
||||
try {
|
||||
let sent = false;
|
||||
|
||||
// 1. Enviar prioritariamente con la foto del calzado en alta definición
|
||||
if (resolvedMediaUrl && (resolvedMediaUrl.startsWith('http://') || resolvedMediaUrl.startsWith('https://'))) {
|
||||
sent = await sendWhatsAppMedia(target, resolvedMediaUrl, notificationCaption);
|
||||
// 1. Enviar con la foto del calzado en alta definición (sea URL o Base64)
|
||||
if (resolvedMedia && (resolvedMedia.startsWith('http://') || resolvedMedia.startsWith('https://') || isBase64)) {
|
||||
sent = await sendWhatsAppMedia(target, resolvedMedia, notificationCaption, 'AutomataAlmeira', 'EE49029EEB85-4568-8F81-C9FDFC6E2943');
|
||||
}
|
||||
|
||||
// 2. Si no hay imagen o falló el envío multimedia, enviar como texto formateado
|
||||
// 2. Si falló con base64 pero tenemos product.images, intentar con la URL de streaming
|
||||
if (!sent && isBase64 && product?.images?.[0]) {
|
||||
const fallbackUrl = product.images[0].startsWith('http')
|
||||
? product.images[0]
|
||||
: `https://drip-zone.online${product.images[0].startsWith('/') ? '' : '/'}${product.images[0]}`;
|
||||
sent = await sendWhatsAppMedia(target, fallbackUrl, notificationCaption, 'AutomataAlmeira', 'EE49029EEB85-4568-8F81-C9FDFC6E2943').catch(() => false);
|
||||
}
|
||||
|
||||
// 3. Si no hay imagen o falló el envío multimedia, enviar como texto formateado
|
||||
if (!sent) {
|
||||
sent = await sendWhatsAppMessage(target, notificationCaption);
|
||||
sent = await sendWhatsAppMessage(target, notificationCaption, 'AutomataAlmeira', 'EE49029EEB85-4568-8F81-C9FDFC6E2943');
|
||||
}
|
||||
|
||||
if (sent) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user