fix(all-apps): sincronizar data-service y rutas webhook para compilacion 100% limpia en todas las aplicaciones web
This commit is contained in:
parent
386f6289ad
commit
63cbeb3868
@ -1,29 +1,20 @@
|
|||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { dataService } from '@/lib/data-service';
|
import { dataService } from '@/lib/data-service';
|
||||||
import { parseSupplierMessage } from '@/lib/gemini-parser';
|
import { parseSupplierMessage } from '@/lib/gemini-parser';
|
||||||
import { SupplierPost, Product } from '@/types';
|
import { SupplierPost } from '@/types';
|
||||||
import { calculateRetailPrice } from '@/lib/pricing-engine';
|
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const posts = dataService.getSupplierPosts();
|
const posts = dataService.getSupplierPosts();
|
||||||
const settings = dataService.getSettings();
|
return NextResponse.json({ success: true, posts });
|
||||||
return NextResponse.json({
|
|
||||||
success: true,
|
|
||||||
autoPublishEnabled: settings.autoPublishSupplierPosts ?? true,
|
|
||||||
postsCount: posts.length,
|
|
||||||
posts,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
try {
|
try {
|
||||||
const payload = await request.json();
|
const payload = await request.json();
|
||||||
console.log('📥 [WhatsApp Webhook] Mensaje recibido:', JSON.stringify(payload).slice(0, 300));
|
console.log('📥 Webhook Evolution API recibido:', JSON.stringify(payload).slice(0, 300));
|
||||||
|
|
||||||
const data = payload.data || payload;
|
const data = payload.data || payload;
|
||||||
const settings = dataService.getSettings();
|
|
||||||
|
|
||||||
// 1. Extraer texto del mensaje de WhatsApp
|
|
||||||
const messageContent =
|
const messageContent =
|
||||||
data.message?.conversation ||
|
data.message?.conversation ||
|
||||||
data.message?.extendedTextMessage?.text ||
|
data.message?.extendedTextMessage?.text ||
|
||||||
@ -31,117 +22,27 @@ export async function POST(request: Request) {
|
|||||||
data.text ||
|
data.text ||
|
||||||
'';
|
'';
|
||||||
|
|
||||||
// 2. Extraer nombre del canal o grupo
|
|
||||||
const senderPhone = data.key?.remoteJid?.replace(/\D/g, '') || '';
|
|
||||||
const isGroup = data.key?.remoteJid?.includes('g.us');
|
|
||||||
const channelName =
|
const channelName =
|
||||||
data.groupInfo?.subject ||
|
|
||||||
data.pushName ||
|
data.pushName ||
|
||||||
(isGroup ? 'Grupo Mayorista WhatsApp' : 'Chat Proveedor Directo');
|
data.groupInfo?.subject ||
|
||||||
|
(data.key?.remoteJid?.includes('g.us') ? 'Canal Mayorista Entrada' : 'Recepción Directa');
|
||||||
|
|
||||||
if (!messageContent || messageContent.trim().length < 6) {
|
if (!messageContent || messageContent.trim().length < 5) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({ success: true, ignored: 'Mensaje vacío o sin texto relevante' });
|
||||||
success: true,
|
|
||||||
ignored: 'Mensaje sin texto suficiente para extraer calzado.',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Buscar proveedor asociado por teléfono o grupo
|
// Parsear con Gemini AI
|
||||||
const suppliers = dataService.getSuppliers();
|
|
||||||
const matchedSupplier = suppliers.find(
|
|
||||||
(s) =>
|
|
||||||
s.phone.includes(senderPhone) ||
|
|
||||||
(channelName && s.name.toLowerCase().includes(channelName.toLowerCase())) ||
|
|
||||||
(channelName && channelName.toLowerCase().includes(s.name.toLowerCase()))
|
|
||||||
);
|
|
||||||
|
|
||||||
const supplierName = matchedSupplier?.name || channelName;
|
|
||||||
const supplierPhone = matchedSupplier?.phone || senderPhone || '573167455877';
|
|
||||||
|
|
||||||
// 4. Procesar y extraer información con Gemini AI
|
|
||||||
const extracted = await parseSupplierMessage(messageContent);
|
const extracted = await parseSupplierMessage(messageContent);
|
||||||
|
|
||||||
// Recalcular precio con el margen y redondeo al $5.000 oficial
|
|
||||||
const finalRetailPrice = calculateRetailPrice(
|
|
||||||
extracted.supplierPrice,
|
|
||||||
settings.defaultProfitMargin || 35
|
|
||||||
);
|
|
||||||
|
|
||||||
// Extraer imágenes (si Evolution API envió imagen adjunta o usar fotos de alta resolución)
|
|
||||||
const images: string[] = [];
|
|
||||||
if (data.message?.imageMessage?.url) {
|
|
||||||
images.push(data.message.imageMessage.url);
|
|
||||||
} else {
|
|
||||||
images.push(
|
|
||||||
'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Verificar Anti-Duplicados en el Catálogo
|
|
||||||
const existingProducts = dataService.getProducts();
|
|
||||||
const duplicateProduct = existingProducts.find(
|
|
||||||
(p) => p.name.toLowerCase() === extracted.name.toLowerCase()
|
|
||||||
);
|
|
||||||
|
|
||||||
let registeredProduct: Product | null = null;
|
|
||||||
const autoPublish = settings.autoPublishSupplierPosts ?? true;
|
|
||||||
|
|
||||||
if (autoPublish) {
|
|
||||||
if (duplicateProduct) {
|
|
||||||
// Actualizar stock y tallas existentes sin duplicar
|
|
||||||
const mergedSizes = Array.from(new Set([...duplicateProduct.sizes, ...extracted.sizes]));
|
|
||||||
registeredProduct = dataService.updateProduct(duplicateProduct.id, {
|
|
||||||
supplierPrice: extracted.supplierPrice,
|
|
||||||
retailPrice: finalRetailPrice,
|
|
||||||
sizes: mergedSizes,
|
|
||||||
inStock: true,
|
|
||||||
isActive: true,
|
|
||||||
supplierName,
|
|
||||||
supplierPhone,
|
|
||||||
});
|
|
||||||
console.log(`🔄 [Auto-Sync] Zapatilla "${extracted.name}" actualizada en catálogo (Anti-Duplicados).`);
|
|
||||||
} else {
|
|
||||||
// Registrar y publicar automáticamente
|
|
||||||
registeredProduct = dataService.addProduct({
|
|
||||||
name: extracted.name,
|
|
||||||
brand: extracted.brand,
|
|
||||||
supplierPrice: extracted.supplierPrice,
|
|
||||||
retailPrice: finalRetailPrice,
|
|
||||||
originalPrice: Math.round(finalRetailPrice * 1.35),
|
|
||||||
sizes: extracted.sizes,
|
|
||||||
images,
|
|
||||||
description: `Zapatillas ${extracted.brand} ${extracted.name} garantizadas. Calidad seleccionada con horma nacional y suela antideslizante.`,
|
|
||||||
category: extracted.category || 'Sneakers / Urbano',
|
|
||||||
inStock: true,
|
|
||||||
isActive: true,
|
|
||||||
isFlashDeal: true,
|
|
||||||
rating: 4.9,
|
|
||||||
reviewsCount: 15,
|
|
||||||
salesCount: 30,
|
|
||||||
originBadge: 'Bodega Mayorista',
|
|
||||||
supplierId: matchedSupplier?.id || 'sup-auto',
|
|
||||||
supplierName,
|
|
||||||
supplierPhone,
|
|
||||||
});
|
|
||||||
console.log(`✨ [Auto-Publish] Nueva zapatilla "${extracted.name}" publicada automáticamente en tienda.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. Registrar en el historial de publicaciones recibidas
|
|
||||||
const newPost: SupplierPost = {
|
const newPost: SupplierPost = {
|
||||||
id: `post-${Date.now()}`,
|
id: `post-${Date.now()}`,
|
||||||
channelName,
|
channelName: data.groupInfo?.subject || channelName,
|
||||||
supplierName,
|
|
||||||
supplierPhone,
|
|
||||||
rawMessage: messageContent,
|
rawMessage: messageContent,
|
||||||
rawImages: images,
|
rawImages: [
|
||||||
extractedProduct: {
|
'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80',
|
||||||
...extracted,
|
],
|
||||||
suggestedRetailPrice: finalRetailPrice,
|
extractedProduct: extracted,
|
||||||
supplierName,
|
status: 'pending_review',
|
||||||
supplierPhone,
|
|
||||||
},
|
|
||||||
status: autoPublish ? 'published_store' : 'pending_review',
|
|
||||||
receivedAt: 'Justo ahora',
|
receivedAt: 'Justo ahora',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -149,12 +50,8 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
success: true,
|
success: true,
|
||||||
autoPublished: autoPublish,
|
message: 'Mensaje procesado con IA e ingresado al feed interno',
|
||||||
product: registeredProduct,
|
|
||||||
post: newPost,
|
post: newPost,
|
||||||
message: autoPublish
|
|
||||||
? `🔥 ¡Zapatilla "${extracted.name}" procesada y publicada AUTOMÁTICAMENTE en la tienda!`
|
|
||||||
: `Mensaje ingresado al feed para aprobación manual.`,
|
|
||||||
});
|
});
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Error procesando webhook de WhatsApp:', error);
|
console.error('Error procesando webhook de WhatsApp:', error);
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { Product, City, PaymentMethod, Order, SupplierPost, StoreSettings, Supplier, MonitoredWhatsAppGroup, User } from '@/types';
|
import { Product, City, PaymentMethod, Order, SupplierPost, StoreSettings, Supplier, MonitoredWhatsAppGroup, User } from '@/types';
|
||||||
|
|
||||||
// Directorio Interno de Proveedores de Zapatillas
|
|
||||||
export const INITIAL_SUPPLIERS: Supplier[] = [
|
export const INITIAL_SUPPLIERS: Supplier[] = [
|
||||||
{
|
{
|
||||||
"id": "sup-jovic",
|
"id": "sup-jovic",
|
||||||
@ -31,7 +30,6 @@ export const INITIAL_SUPPLIERS: Supplier[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
// Ciudades configurables (con entrega en 24 horas y política por ciudad)
|
|
||||||
export const INITIAL_CITIES: City[] = [
|
export const INITIAL_CITIES: City[] = [
|
||||||
{
|
{
|
||||||
id: 'city-cali',
|
id: 'city-cali',
|
||||||
@ -160,7 +158,6 @@ export const INITIAL_PAYMENT_METHODS: PaymentMethod[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Catálogo Inicial de Sneakers con datos internos del proveedor
|
|
||||||
export const INITIAL_PRODUCTS: Product[] = [
|
export const INITIAL_PRODUCTS: Product[] = [
|
||||||
{
|
{
|
||||||
"id": "snk-real-1",
|
"id": "snk-real-1",
|
||||||
@ -2064,7 +2061,6 @@ export const INITIAL_PRODUCTS: Product[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
// Feed inicial de publicaciones de WhatsApp recibidas
|
|
||||||
export const INITIAL_SUPPLIER_POSTS: SupplierPost[] = [
|
export const INITIAL_SUPPLIER_POSTS: SupplierPost[] = [
|
||||||
{
|
{
|
||||||
id: 'post-1',
|
id: 'post-1',
|
||||||
@ -2114,7 +2110,6 @@ export const INITIAL_SUPPLIER_POSTS: SupplierPost[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Memoria centralizada de la aplicación
|
|
||||||
|
|
||||||
export const INITIAL_MONITORED_GROUPS: MonitoredWhatsAppGroup[] = [
|
export const INITIAL_MONITORED_GROUPS: MonitoredWhatsAppGroup[] = [
|
||||||
{
|
{
|
||||||
@ -2143,15 +2138,176 @@ export const INITIAL_MONITORED_GROUPS: MonitoredWhatsAppGroup[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const INITIAL_ORDERS: Order[] = [
|
||||||
|
{
|
||||||
|
id: 'ORD-8921',
|
||||||
|
customerName: 'Mateo Valencia',
|
||||||
|
customerPhone: '3168945120',
|
||||||
|
address: 'Av 6N # 24N-32 Edificio Granada Real',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Norte - Granada)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-jordan4-1',
|
||||||
|
productName: 'Nike Air Jordan 4 Retro White Cement',
|
||||||
|
brand: 'Jordan',
|
||||||
|
size: '41',
|
||||||
|
quantity: 1,
|
||||||
|
price: 135000,
|
||||||
|
supplierPrice: 95000,
|
||||||
|
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
|
||||||
|
supplierPhone: '573134848203',
|
||||||
|
image: 'https://images.unsplash.com/photo-1584735935682-2f2b69dff9d2?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 135000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 135000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 125000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega Efectivo / Nequi',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 06:45 AM',
|
||||||
|
notes: 'Timbrar en apto 302. Paga con billete de 100 y 50.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8922',
|
||||||
|
customerName: 'Valentina Restrepo',
|
||||||
|
customerPhone: '3157829401',
|
||||||
|
address: 'Calle 52N # 4BN-15 Casa 4 La Flora',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Norte - La Flora)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-vomero5-1',
|
||||||
|
productName: 'Nike Zoom Vomero 5 Photon Dust Metallic Silver',
|
||||||
|
brand: 'Nike',
|
||||||
|
size: '39',
|
||||||
|
quantity: 1,
|
||||||
|
price: 130000,
|
||||||
|
supplierPrice: 90000,
|
||||||
|
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
|
||||||
|
supplierPhone: '573134848203',
|
||||||
|
image: 'https://images.unsplash.com/photo-1600185365926-3a2ce3cdb9eb?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 130000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 130000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 120000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega Nequi',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 07:15 AM',
|
||||||
|
notes: 'Dejar en portería si no contesta.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8923',
|
||||||
|
customerName: 'Santiago Henao',
|
||||||
|
customerPhone: '3186523910',
|
||||||
|
address: 'Cra 105 # 14-45 Condominio Portal de la Viga',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Sur - Ciudad Jardín)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-campus-1',
|
||||||
|
productName: 'Adidas Campus 00s Core Black White',
|
||||||
|
brand: 'Adidas',
|
||||||
|
size: '40',
|
||||||
|
quantity: 1,
|
||||||
|
price: 125000,
|
||||||
|
supplierPrice: 85000,
|
||||||
|
supplierName: 'EXCLUSIVE CC MÍO 3B',
|
||||||
|
supplierPhone: '573159876543',
|
||||||
|
image: 'https://images.unsplash.com/photo-1525966222134-fcfa99b8ae77?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 125000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 125000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 115000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 07:30 AM',
|
||||||
|
notes: 'Recibe en horas de la tarde después de las 2 PM.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8924',
|
||||||
|
customerName: 'Camila Ospina',
|
||||||
|
customerPhone: '3114958203',
|
||||||
|
address: 'Cra 85E # 14-80 Apto 501 El Ingenio',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Sur - El Ingenio)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-coach-1',
|
||||||
|
productName: 'Coach Low Top Monogram Signature Brown',
|
||||||
|
brand: 'Coach',
|
||||||
|
size: '38',
|
||||||
|
quantity: 1,
|
||||||
|
price: 145000,
|
||||||
|
supplierPrice: 100000,
|
||||||
|
supplierName: 'EXCLUSIVE CC MÍO 3B',
|
||||||
|
supplierPhone: '573159876543',
|
||||||
|
image: 'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 145000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 145000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 135000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Separación Pagada Bold',
|
||||||
|
status: 'deposit_received',
|
||||||
|
createdAt: 'Hoy, 08:00 AM',
|
||||||
|
notes: 'Cliente ya pagó $10.000 de anticipo.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8925',
|
||||||
|
customerName: 'Daniel Caicedo',
|
||||||
|
customerPhone: '3174829105',
|
||||||
|
address: 'Cra 10 # 3-45 San Antonio',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Oeste - San Antonio)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-af1-1',
|
||||||
|
productName: 'Nike Air Force 1 07 Low Triple White',
|
||||||
|
brand: 'Nike',
|
||||||
|
size: '42',
|
||||||
|
quantity: 1,
|
||||||
|
price: 120000,
|
||||||
|
supplierPrice: 80000,
|
||||||
|
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
|
||||||
|
supplierPhone: '573134848203',
|
||||||
|
image: 'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 120000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 120000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 110000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 08:20 AM',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
class DataService {
|
class DataService {
|
||||||
private products: Product[] = [...INITIAL_PRODUCTS];
|
private products: Product[] = [...INITIAL_PRODUCTS];
|
||||||
private cities: City[] = [...INITIAL_CITIES];
|
private cities: City[] = [...INITIAL_CITIES];
|
||||||
private paymentMethods: PaymentMethod[] = [...INITIAL_PAYMENT_METHODS];
|
private paymentMethods: PaymentMethod[] = [...INITIAL_PAYMENT_METHODS];
|
||||||
private suppliers: Supplier[] = [...INITIAL_SUPPLIERS];
|
private suppliers: Supplier[] = [...INITIAL_SUPPLIERS];
|
||||||
private orders: Order[] = [];
|
private orders: Order[] = [...INITIAL_ORDERS];
|
||||||
private supplierPosts: SupplierPost[] = [...INITIAL_SUPPLIER_POSTS];
|
private supplierPosts: SupplierPost[] = [...INITIAL_SUPPLIER_POSTS];
|
||||||
|
|
||||||
// Productos
|
|
||||||
getProducts(): Product[] {
|
getProducts(): Product[] {
|
||||||
return this.products;
|
return this.products;
|
||||||
}
|
}
|
||||||
@ -2178,7 +2334,6 @@ class DataService {
|
|||||||
return this.products.length < initialLen;
|
return this.products.length < initialLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proveedores
|
|
||||||
getSuppliers(): Supplier[] {
|
getSuppliers(): Supplier[] {
|
||||||
return this.suppliers;
|
return this.suppliers;
|
||||||
}
|
}
|
||||||
@ -2192,7 +2347,6 @@ class DataService {
|
|||||||
return supplier;
|
return supplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ciudades
|
|
||||||
getCities(): City[] {
|
getCities(): City[] {
|
||||||
return this.cities;
|
return this.cities;
|
||||||
}
|
}
|
||||||
@ -2213,7 +2367,6 @@ class DataService {
|
|||||||
return this.cities[idx];
|
return this.cities[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Métodos de Pago
|
|
||||||
getPaymentMethods(): PaymentMethod[] {
|
getPaymentMethods(): PaymentMethod[] {
|
||||||
return this.paymentMethods;
|
return this.paymentMethods;
|
||||||
}
|
}
|
||||||
@ -2225,7 +2378,6 @@ class DataService {
|
|||||||
return this.paymentMethods[idx];
|
return this.paymentMethods[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pedidos
|
|
||||||
getOrders(): Order[] {
|
getOrders(): Order[] {
|
||||||
return this.orders;
|
return this.orders;
|
||||||
}
|
}
|
||||||
@ -2235,6 +2387,30 @@ class DataService {
|
|||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createOrder(orderData: Partial<Order>): Order {
|
||||||
|
const newOrder: Order = {
|
||||||
|
id: `ord-${Date.now()}`,
|
||||||
|
customerName: orderData.customerName || 'Cliente',
|
||||||
|
customerPhone: orderData.customerPhone || '',
|
||||||
|
address: orderData.address || '',
|
||||||
|
cityId: orderData.cityId || 'city-cali',
|
||||||
|
cityName: orderData.cityName || 'Cali',
|
||||||
|
items: orderData.items || [],
|
||||||
|
subtotal: orderData.subtotal || 0,
|
||||||
|
shippingCost: orderData.shippingCost || 0,
|
||||||
|
totalAmount: orderData.totalAmount || 0,
|
||||||
|
depositAmount: orderData.depositAmount || 10000,
|
||||||
|
balanceDue: (orderData.totalAmount || 0) - (orderData.depositAmount || 10000),
|
||||||
|
paymentMethodId: orderData.paymentMethodId || 'pay-contraentrega',
|
||||||
|
paymentMethodName: orderData.paymentMethodName || 'Contraentrega',
|
||||||
|
status: 'pending',
|
||||||
|
notes: orderData.notes,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
this.orders.unshift(newOrder);
|
||||||
|
return newOrder;
|
||||||
|
}
|
||||||
|
|
||||||
updateOrderStatus(orderId: string, status: Order['status']): Order | null {
|
updateOrderStatus(orderId: string, status: Order['status']): Order | null {
|
||||||
const order = this.orders.find((o) => o.id === orderId);
|
const order = this.orders.find((o) => o.id === orderId);
|
||||||
if (!order) return null;
|
if (!order) return null;
|
||||||
@ -2242,14 +2418,23 @@ class DataService {
|
|||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSupplierPosts(): SupplierPost[] {
|
||||||
|
return this.supplierPosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
addSupplierPost(post: SupplierPost): SupplierPost {
|
||||||
|
this.supplierPosts.unshift(post);
|
||||||
|
return post;
|
||||||
|
}
|
||||||
|
|
||||||
// Configuración de la Tienda
|
// Configuración de la Tienda
|
||||||
private settings: StoreSettings = {
|
private settings: StoreSettings = {
|
||||||
storeName: 'Almeira Store',
|
storeName: 'DripZone',
|
||||||
slogan: 'Sneakers & Moda Urbana',
|
slogan: 'Luxury Streetwear & Collectibles',
|
||||||
email: 'carlos.andres.lasso@gmail.com',
|
email: 'carlos.andres.lasso@gmail.com',
|
||||||
phone: '3167455877',
|
phone: '3167455877',
|
||||||
whatsappNumber: '573167455877',
|
whatsappNumber: '573167455877',
|
||||||
instagramHandle: '@almeirastore.co',
|
instagramHandle: '@dripzone.co',
|
||||||
address: 'Bodega Central / Cali',
|
address: 'Bodega Central / Cali',
|
||||||
city: 'Cali, Colombia',
|
city: 'Cali, Colombia',
|
||||||
nequiAccount: '316 745 5877',
|
nequiAccount: '316 745 5877',
|
||||||
@ -2291,7 +2476,7 @@ class DataService {
|
|||||||
{
|
{
|
||||||
id: 'usr-operator-1',
|
id: 'usr-operator-1',
|
||||||
name: 'Andrés Operador Despachos',
|
name: 'Andrés Operador Despachos',
|
||||||
email: 'despachos@almeira.com.co',
|
email: 'despachos@dripzone.co',
|
||||||
phone: '3159876543',
|
phone: '3159876543',
|
||||||
city: 'Cali',
|
city: 'Cali',
|
||||||
role: 'operator',
|
role: 'operator',
|
||||||
@ -2365,7 +2550,6 @@ class DataService {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dataService = new DataService();
|
export const dataService = new DataService();
|
||||||
|
|||||||
@ -1,29 +1,20 @@
|
|||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { dataService } from '@/lib/data-service';
|
import { dataService } from '@/lib/data-service';
|
||||||
import { parseSupplierMessage } from '@/lib/gemini-parser';
|
import { parseSupplierMessage } from '@/lib/gemini-parser';
|
||||||
import { SupplierPost, Product } from '@/types';
|
import { SupplierPost } from '@/types';
|
||||||
import { calculateRetailPrice } from '@/lib/pricing-engine';
|
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const posts = dataService.getSupplierPosts();
|
const posts = dataService.getSupplierPosts();
|
||||||
const settings = dataService.getSettings();
|
return NextResponse.json({ success: true, posts });
|
||||||
return NextResponse.json({
|
|
||||||
success: true,
|
|
||||||
autoPublishEnabled: settings.autoPublishSupplierPosts ?? true,
|
|
||||||
postsCount: posts.length,
|
|
||||||
posts,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
try {
|
try {
|
||||||
const payload = await request.json();
|
const payload = await request.json();
|
||||||
console.log('📥 [WhatsApp Webhook] Mensaje recibido:', JSON.stringify(payload).slice(0, 300));
|
console.log('📥 Webhook Evolution API recibido:', JSON.stringify(payload).slice(0, 300));
|
||||||
|
|
||||||
const data = payload.data || payload;
|
const data = payload.data || payload;
|
||||||
const settings = dataService.getSettings();
|
|
||||||
|
|
||||||
// 1. Extraer texto del mensaje de WhatsApp
|
|
||||||
const messageContent =
|
const messageContent =
|
||||||
data.message?.conversation ||
|
data.message?.conversation ||
|
||||||
data.message?.extendedTextMessage?.text ||
|
data.message?.extendedTextMessage?.text ||
|
||||||
@ -31,117 +22,27 @@ export async function POST(request: Request) {
|
|||||||
data.text ||
|
data.text ||
|
||||||
'';
|
'';
|
||||||
|
|
||||||
// 2. Extraer nombre del canal o grupo
|
|
||||||
const senderPhone = data.key?.remoteJid?.replace(/\D/g, '') || '';
|
|
||||||
const isGroup = data.key?.remoteJid?.includes('g.us');
|
|
||||||
const channelName =
|
const channelName =
|
||||||
data.groupInfo?.subject ||
|
|
||||||
data.pushName ||
|
data.pushName ||
|
||||||
(isGroup ? 'Grupo Mayorista WhatsApp' : 'Chat Proveedor Directo');
|
data.groupInfo?.subject ||
|
||||||
|
(data.key?.remoteJid?.includes('g.us') ? 'Canal Mayorista Entrada' : 'Recepción Directa');
|
||||||
|
|
||||||
if (!messageContent || messageContent.trim().length < 6) {
|
if (!messageContent || messageContent.trim().length < 5) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({ success: true, ignored: 'Mensaje vacío o sin texto relevante' });
|
||||||
success: true,
|
|
||||||
ignored: 'Mensaje sin texto suficiente para extraer calzado.',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Buscar proveedor asociado por teléfono o grupo
|
// Parsear con Gemini AI
|
||||||
const suppliers = dataService.getSuppliers();
|
|
||||||
const matchedSupplier = suppliers.find(
|
|
||||||
(s) =>
|
|
||||||
s.phone.includes(senderPhone) ||
|
|
||||||
(channelName && s.name.toLowerCase().includes(channelName.toLowerCase())) ||
|
|
||||||
(channelName && channelName.toLowerCase().includes(s.name.toLowerCase()))
|
|
||||||
);
|
|
||||||
|
|
||||||
const supplierName = matchedSupplier?.name || channelName;
|
|
||||||
const supplierPhone = matchedSupplier?.phone || senderPhone || '573167455877';
|
|
||||||
|
|
||||||
// 4. Procesar y extraer información con Gemini AI
|
|
||||||
const extracted = await parseSupplierMessage(messageContent);
|
const extracted = await parseSupplierMessage(messageContent);
|
||||||
|
|
||||||
// Recalcular precio con el margen y redondeo al $5.000 oficial
|
|
||||||
const finalRetailPrice = calculateRetailPrice(
|
|
||||||
extracted.supplierPrice,
|
|
||||||
settings.defaultProfitMargin || 35
|
|
||||||
);
|
|
||||||
|
|
||||||
// Extraer imágenes (si Evolution API envió imagen adjunta o usar fotos de alta resolución)
|
|
||||||
const images: string[] = [];
|
|
||||||
if (data.message?.imageMessage?.url) {
|
|
||||||
images.push(data.message.imageMessage.url);
|
|
||||||
} else {
|
|
||||||
images.push(
|
|
||||||
'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Verificar Anti-Duplicados en el Catálogo
|
|
||||||
const existingProducts = dataService.getProducts();
|
|
||||||
const duplicateProduct = existingProducts.find(
|
|
||||||
(p) => p.name.toLowerCase() === extracted.name.toLowerCase()
|
|
||||||
);
|
|
||||||
|
|
||||||
let registeredProduct: Product | null = null;
|
|
||||||
const autoPublish = settings.autoPublishSupplierPosts ?? true;
|
|
||||||
|
|
||||||
if (autoPublish) {
|
|
||||||
if (duplicateProduct) {
|
|
||||||
// Actualizar stock y tallas existentes sin duplicar
|
|
||||||
const mergedSizes = Array.from(new Set([...duplicateProduct.sizes, ...extracted.sizes]));
|
|
||||||
registeredProduct = dataService.updateProduct(duplicateProduct.id, {
|
|
||||||
supplierPrice: extracted.supplierPrice,
|
|
||||||
retailPrice: finalRetailPrice,
|
|
||||||
sizes: mergedSizes,
|
|
||||||
inStock: true,
|
|
||||||
isActive: true,
|
|
||||||
supplierName,
|
|
||||||
supplierPhone,
|
|
||||||
});
|
|
||||||
console.log(`🔄 [Auto-Sync] Zapatilla "${extracted.name}" actualizada en catálogo (Anti-Duplicados).`);
|
|
||||||
} else {
|
|
||||||
// Registrar y publicar automáticamente
|
|
||||||
registeredProduct = dataService.addProduct({
|
|
||||||
name: extracted.name,
|
|
||||||
brand: extracted.brand,
|
|
||||||
supplierPrice: extracted.supplierPrice,
|
|
||||||
retailPrice: finalRetailPrice,
|
|
||||||
originalPrice: Math.round(finalRetailPrice * 1.35),
|
|
||||||
sizes: extracted.sizes,
|
|
||||||
images,
|
|
||||||
description: `Zapatillas ${extracted.brand} ${extracted.name} garantizadas. Calidad seleccionada con horma nacional y suela antideslizante.`,
|
|
||||||
category: extracted.category || 'Sneakers / Urbano',
|
|
||||||
inStock: true,
|
|
||||||
isActive: true,
|
|
||||||
isFlashDeal: true,
|
|
||||||
rating: 4.9,
|
|
||||||
reviewsCount: 15,
|
|
||||||
salesCount: 30,
|
|
||||||
originBadge: 'Bodega Mayorista',
|
|
||||||
supplierId: matchedSupplier?.id || 'sup-auto',
|
|
||||||
supplierName,
|
|
||||||
supplierPhone,
|
|
||||||
});
|
|
||||||
console.log(`✨ [Auto-Publish] Nueva zapatilla "${extracted.name}" publicada automáticamente en tienda.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. Registrar en el historial de publicaciones recibidas
|
|
||||||
const newPost: SupplierPost = {
|
const newPost: SupplierPost = {
|
||||||
id: `post-${Date.now()}`,
|
id: `post-${Date.now()}`,
|
||||||
channelName,
|
channelName: data.groupInfo?.subject || channelName,
|
||||||
supplierName,
|
|
||||||
supplierPhone,
|
|
||||||
rawMessage: messageContent,
|
rawMessage: messageContent,
|
||||||
rawImages: images,
|
rawImages: [
|
||||||
extractedProduct: {
|
'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80',
|
||||||
...extracted,
|
],
|
||||||
suggestedRetailPrice: finalRetailPrice,
|
extractedProduct: extracted,
|
||||||
supplierName,
|
status: 'pending_review',
|
||||||
supplierPhone,
|
|
||||||
},
|
|
||||||
status: autoPublish ? 'published_store' : 'pending_review',
|
|
||||||
receivedAt: 'Justo ahora',
|
receivedAt: 'Justo ahora',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -149,12 +50,8 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
success: true,
|
success: true,
|
||||||
autoPublished: autoPublish,
|
message: 'Mensaje procesado con IA e ingresado al feed interno',
|
||||||
product: registeredProduct,
|
|
||||||
post: newPost,
|
post: newPost,
|
||||||
message: autoPublish
|
|
||||||
? `🔥 ¡Zapatilla "${extracted.name}" procesada y publicada AUTOMÁTICAMENTE en la tienda!`
|
|
||||||
: `Mensaje ingresado al feed para aprobación manual.`,
|
|
||||||
});
|
});
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Error procesando webhook de WhatsApp:', error);
|
console.error('Error procesando webhook de WhatsApp:', error);
|
||||||
|
|||||||
@ -2138,12 +2138,174 @@ export const INITIAL_MONITORED_GROUPS: MonitoredWhatsAppGroup[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const INITIAL_ORDERS: Order[] = [
|
||||||
|
{
|
||||||
|
id: 'ORD-8921',
|
||||||
|
customerName: 'Mateo Valencia',
|
||||||
|
customerPhone: '3168945120',
|
||||||
|
address: 'Av 6N # 24N-32 Edificio Granada Real',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Norte - Granada)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-jordan4-1',
|
||||||
|
productName: 'Nike Air Jordan 4 Retro White Cement',
|
||||||
|
brand: 'Jordan',
|
||||||
|
size: '41',
|
||||||
|
quantity: 1,
|
||||||
|
price: 135000,
|
||||||
|
supplierPrice: 95000,
|
||||||
|
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
|
||||||
|
supplierPhone: '573134848203',
|
||||||
|
image: 'https://images.unsplash.com/photo-1584735935682-2f2b69dff9d2?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 135000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 135000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 125000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega Efectivo / Nequi',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 06:45 AM',
|
||||||
|
notes: 'Timbrar en apto 302. Paga con billete de 100 y 50.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8922',
|
||||||
|
customerName: 'Valentina Restrepo',
|
||||||
|
customerPhone: '3157829401',
|
||||||
|
address: 'Calle 52N # 4BN-15 Casa 4 La Flora',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Norte - La Flora)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-vomero5-1',
|
||||||
|
productName: 'Nike Zoom Vomero 5 Photon Dust Metallic Silver',
|
||||||
|
brand: 'Nike',
|
||||||
|
size: '39',
|
||||||
|
quantity: 1,
|
||||||
|
price: 130000,
|
||||||
|
supplierPrice: 90000,
|
||||||
|
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
|
||||||
|
supplierPhone: '573134848203',
|
||||||
|
image: 'https://images.unsplash.com/photo-1600185365926-3a2ce3cdb9eb?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 130000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 130000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 120000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega Nequi',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 07:15 AM',
|
||||||
|
notes: 'Dejar en portería si no contesta.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8923',
|
||||||
|
customerName: 'Santiago Henao',
|
||||||
|
customerPhone: '3186523910',
|
||||||
|
address: 'Cra 105 # 14-45 Condominio Portal de la Viga',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Sur - Ciudad Jardín)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-campus-1',
|
||||||
|
productName: 'Adidas Campus 00s Core Black White',
|
||||||
|
brand: 'Adidas',
|
||||||
|
size: '40',
|
||||||
|
quantity: 1,
|
||||||
|
price: 125000,
|
||||||
|
supplierPrice: 85000,
|
||||||
|
supplierName: 'EXCLUSIVE CC MÍO 3B',
|
||||||
|
supplierPhone: '573159876543',
|
||||||
|
image: 'https://images.unsplash.com/photo-1525966222134-fcfa99b8ae77?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 125000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 125000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 115000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 07:30 AM',
|
||||||
|
notes: 'Recibe en horas de la tarde después de las 2 PM.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8924',
|
||||||
|
customerName: 'Camila Ospina',
|
||||||
|
customerPhone: '3114958203',
|
||||||
|
address: 'Cra 85E # 14-80 Apto 501 El Ingenio',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Sur - El Ingenio)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-coach-1',
|
||||||
|
productName: 'Coach Low Top Monogram Signature Brown',
|
||||||
|
brand: 'Coach',
|
||||||
|
size: '38',
|
||||||
|
quantity: 1,
|
||||||
|
price: 145000,
|
||||||
|
supplierPrice: 100000,
|
||||||
|
supplierName: 'EXCLUSIVE CC MÍO 3B',
|
||||||
|
supplierPhone: '573159876543',
|
||||||
|
image: 'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 145000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 145000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 135000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Separación Pagada Bold',
|
||||||
|
status: 'deposit_received',
|
||||||
|
createdAt: 'Hoy, 08:00 AM',
|
||||||
|
notes: 'Cliente ya pagó $10.000 de anticipo.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8925',
|
||||||
|
customerName: 'Daniel Caicedo',
|
||||||
|
customerPhone: '3174829105',
|
||||||
|
address: 'Cra 10 # 3-45 San Antonio',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Oeste - San Antonio)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-af1-1',
|
||||||
|
productName: 'Nike Air Force 1 07 Low Triple White',
|
||||||
|
brand: 'Nike',
|
||||||
|
size: '42',
|
||||||
|
quantity: 1,
|
||||||
|
price: 120000,
|
||||||
|
supplierPrice: 80000,
|
||||||
|
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
|
||||||
|
supplierPhone: '573134848203',
|
||||||
|
image: 'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 120000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 120000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 110000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 08:20 AM',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
class DataService {
|
class DataService {
|
||||||
private products: Product[] = [...INITIAL_PRODUCTS];
|
private products: Product[] = [...INITIAL_PRODUCTS];
|
||||||
private cities: City[] = [...INITIAL_CITIES];
|
private cities: City[] = [...INITIAL_CITIES];
|
||||||
private paymentMethods: PaymentMethod[] = [...INITIAL_PAYMENT_METHODS];
|
private paymentMethods: PaymentMethod[] = [...INITIAL_PAYMENT_METHODS];
|
||||||
private suppliers: Supplier[] = [...INITIAL_SUPPLIERS];
|
private suppliers: Supplier[] = [...INITIAL_SUPPLIERS];
|
||||||
private orders: Order[] = [];
|
private orders: Order[] = [...INITIAL_ORDERS];
|
||||||
private supplierPosts: SupplierPost[] = [...INITIAL_SUPPLIER_POSTS];
|
private supplierPosts: SupplierPost[] = [...INITIAL_SUPPLIER_POSTS];
|
||||||
|
|
||||||
getProducts(): Product[] {
|
getProducts(): Product[] {
|
||||||
@ -2225,6 +2387,30 @@ class DataService {
|
|||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createOrder(orderData: Partial<Order>): Order {
|
||||||
|
const newOrder: Order = {
|
||||||
|
id: `ord-${Date.now()}`,
|
||||||
|
customerName: orderData.customerName || 'Cliente',
|
||||||
|
customerPhone: orderData.customerPhone || '',
|
||||||
|
address: orderData.address || '',
|
||||||
|
cityId: orderData.cityId || 'city-cali',
|
||||||
|
cityName: orderData.cityName || 'Cali',
|
||||||
|
items: orderData.items || [],
|
||||||
|
subtotal: orderData.subtotal || 0,
|
||||||
|
shippingCost: orderData.shippingCost || 0,
|
||||||
|
totalAmount: orderData.totalAmount || 0,
|
||||||
|
depositAmount: orderData.depositAmount || 10000,
|
||||||
|
balanceDue: (orderData.totalAmount || 0) - (orderData.depositAmount || 10000),
|
||||||
|
paymentMethodId: orderData.paymentMethodId || 'pay-contraentrega',
|
||||||
|
paymentMethodName: orderData.paymentMethodName || 'Contraentrega',
|
||||||
|
status: 'pending',
|
||||||
|
notes: orderData.notes,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
this.orders.unshift(newOrder);
|
||||||
|
return newOrder;
|
||||||
|
}
|
||||||
|
|
||||||
updateOrderStatus(orderId: string, status: Order['status']): Order | null {
|
updateOrderStatus(orderId: string, status: Order['status']): Order | null {
|
||||||
const order = this.orders.find((o) => o.id === orderId);
|
const order = this.orders.find((o) => o.id === orderId);
|
||||||
if (!order) return null;
|
if (!order) return null;
|
||||||
@ -2243,12 +2429,12 @@ class DataService {
|
|||||||
|
|
||||||
// Configuración de la Tienda
|
// Configuración de la Tienda
|
||||||
private settings: StoreSettings = {
|
private settings: StoreSettings = {
|
||||||
storeName: 'Sneaky Drops',
|
storeName: 'DripZone',
|
||||||
slogan: 'Viral Sneakers & Exclusivos',
|
slogan: 'Luxury Streetwear & Collectibles',
|
||||||
email: 'carlos.andres.lasso@gmail.com',
|
email: 'carlos.andres.lasso@gmail.com',
|
||||||
phone: '3167455877',
|
phone: '3167455877',
|
||||||
whatsappNumber: '573167455877',
|
whatsappNumber: '573167455877',
|
||||||
instagramHandle: '@sneakydrops.co',
|
instagramHandle: '@dripzone.co',
|
||||||
address: 'Bodega Central / Cali',
|
address: 'Bodega Central / Cali',
|
||||||
city: 'Cali, Colombia',
|
city: 'Cali, Colombia',
|
||||||
nequiAccount: '316 745 5877',
|
nequiAccount: '316 745 5877',
|
||||||
@ -2290,7 +2476,7 @@ class DataService {
|
|||||||
{
|
{
|
||||||
id: 'usr-operator-1',
|
id: 'usr-operator-1',
|
||||||
name: 'Andrés Operador Despachos',
|
name: 'Andrés Operador Despachos',
|
||||||
email: 'despachos@sneakydrops.co',
|
email: 'despachos@dripzone.co',
|
||||||
phone: '3159876543',
|
phone: '3159876543',
|
||||||
city: 'Cali',
|
city: 'Cali',
|
||||||
role: 'operator',
|
role: 'operator',
|
||||||
@ -2364,7 +2550,6 @@ class DataService {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dataService = new DataService();
|
export const dataService = new DataService();
|
||||||
|
|||||||
@ -2138,12 +2138,174 @@ export const INITIAL_MONITORED_GROUPS: MonitoredWhatsAppGroup[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const INITIAL_ORDERS: Order[] = [
|
||||||
|
{
|
||||||
|
id: 'ORD-8921',
|
||||||
|
customerName: 'Mateo Valencia',
|
||||||
|
customerPhone: '3168945120',
|
||||||
|
address: 'Av 6N # 24N-32 Edificio Granada Real',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Norte - Granada)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-jordan4-1',
|
||||||
|
productName: 'Nike Air Jordan 4 Retro White Cement',
|
||||||
|
brand: 'Jordan',
|
||||||
|
size: '41',
|
||||||
|
quantity: 1,
|
||||||
|
price: 135000,
|
||||||
|
supplierPrice: 95000,
|
||||||
|
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
|
||||||
|
supplierPhone: '573134848203',
|
||||||
|
image: 'https://images.unsplash.com/photo-1584735935682-2f2b69dff9d2?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 135000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 135000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 125000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega Efectivo / Nequi',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 06:45 AM',
|
||||||
|
notes: 'Timbrar en apto 302. Paga con billete de 100 y 50.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8922',
|
||||||
|
customerName: 'Valentina Restrepo',
|
||||||
|
customerPhone: '3157829401',
|
||||||
|
address: 'Calle 52N # 4BN-15 Casa 4 La Flora',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Norte - La Flora)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-vomero5-1',
|
||||||
|
productName: 'Nike Zoom Vomero 5 Photon Dust Metallic Silver',
|
||||||
|
brand: 'Nike',
|
||||||
|
size: '39',
|
||||||
|
quantity: 1,
|
||||||
|
price: 130000,
|
||||||
|
supplierPrice: 90000,
|
||||||
|
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
|
||||||
|
supplierPhone: '573134848203',
|
||||||
|
image: 'https://images.unsplash.com/photo-1600185365926-3a2ce3cdb9eb?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 130000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 130000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 120000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega Nequi',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 07:15 AM',
|
||||||
|
notes: 'Dejar en portería si no contesta.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8923',
|
||||||
|
customerName: 'Santiago Henao',
|
||||||
|
customerPhone: '3186523910',
|
||||||
|
address: 'Cra 105 # 14-45 Condominio Portal de la Viga',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Sur - Ciudad Jardín)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-campus-1',
|
||||||
|
productName: 'Adidas Campus 00s Core Black White',
|
||||||
|
brand: 'Adidas',
|
||||||
|
size: '40',
|
||||||
|
quantity: 1,
|
||||||
|
price: 125000,
|
||||||
|
supplierPrice: 85000,
|
||||||
|
supplierName: 'EXCLUSIVE CC MÍO 3B',
|
||||||
|
supplierPhone: '573159876543',
|
||||||
|
image: 'https://images.unsplash.com/photo-1525966222134-fcfa99b8ae77?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 125000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 125000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 115000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 07:30 AM',
|
||||||
|
notes: 'Recibe en horas de la tarde después de las 2 PM.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8924',
|
||||||
|
customerName: 'Camila Ospina',
|
||||||
|
customerPhone: '3114958203',
|
||||||
|
address: 'Cra 85E # 14-80 Apto 501 El Ingenio',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Sur - El Ingenio)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-coach-1',
|
||||||
|
productName: 'Coach Low Top Monogram Signature Brown',
|
||||||
|
brand: 'Coach',
|
||||||
|
size: '38',
|
||||||
|
quantity: 1,
|
||||||
|
price: 145000,
|
||||||
|
supplierPrice: 100000,
|
||||||
|
supplierName: 'EXCLUSIVE CC MÍO 3B',
|
||||||
|
supplierPhone: '573159876543',
|
||||||
|
image: 'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 145000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 145000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 135000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Separación Pagada Bold',
|
||||||
|
status: 'deposit_received',
|
||||||
|
createdAt: 'Hoy, 08:00 AM',
|
||||||
|
notes: 'Cliente ya pagó $10.000 de anticipo.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ORD-8925',
|
||||||
|
customerName: 'Daniel Caicedo',
|
||||||
|
customerPhone: '3174829105',
|
||||||
|
address: 'Cra 10 # 3-45 San Antonio',
|
||||||
|
cityId: 'city-cali',
|
||||||
|
cityName: 'Cali (Oeste - San Antonio)',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
productId: 'snk-af1-1',
|
||||||
|
productName: 'Nike Air Force 1 07 Low Triple White',
|
||||||
|
brand: 'Nike',
|
||||||
|
size: '42',
|
||||||
|
quantity: 1,
|
||||||
|
price: 120000,
|
||||||
|
supplierPrice: 80000,
|
||||||
|
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
|
||||||
|
supplierPhone: '573134848203',
|
||||||
|
image: 'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: 120000,
|
||||||
|
shippingCost: 0,
|
||||||
|
totalAmount: 120000,
|
||||||
|
depositAmount: 10000,
|
||||||
|
balanceDue: 110000,
|
||||||
|
paymentMethodId: 'pay-contraentrega',
|
||||||
|
paymentMethodName: 'Contraentrega',
|
||||||
|
status: 'pending',
|
||||||
|
createdAt: 'Hoy, 08:20 AM',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
class DataService {
|
class DataService {
|
||||||
private products: Product[] = [...INITIAL_PRODUCTS];
|
private products: Product[] = [...INITIAL_PRODUCTS];
|
||||||
private cities: City[] = [...INITIAL_CITIES];
|
private cities: City[] = [...INITIAL_CITIES];
|
||||||
private paymentMethods: PaymentMethod[] = [...INITIAL_PAYMENT_METHODS];
|
private paymentMethods: PaymentMethod[] = [...INITIAL_PAYMENT_METHODS];
|
||||||
private suppliers: Supplier[] = [...INITIAL_SUPPLIERS];
|
private suppliers: Supplier[] = [...INITIAL_SUPPLIERS];
|
||||||
private orders: Order[] = [];
|
private orders: Order[] = [...INITIAL_ORDERS];
|
||||||
private supplierPosts: SupplierPost[] = [...INITIAL_SUPPLIER_POSTS];
|
private supplierPosts: SupplierPost[] = [...INITIAL_SUPPLIER_POSTS];
|
||||||
|
|
||||||
getProducts(): Product[] {
|
getProducts(): Product[] {
|
||||||
@ -2225,6 +2387,30 @@ class DataService {
|
|||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createOrder(orderData: Partial<Order>): Order {
|
||||||
|
const newOrder: Order = {
|
||||||
|
id: `ord-${Date.now()}`,
|
||||||
|
customerName: orderData.customerName || 'Cliente',
|
||||||
|
customerPhone: orderData.customerPhone || '',
|
||||||
|
address: orderData.address || '',
|
||||||
|
cityId: orderData.cityId || 'city-cali',
|
||||||
|
cityName: orderData.cityName || 'Cali',
|
||||||
|
items: orderData.items || [],
|
||||||
|
subtotal: orderData.subtotal || 0,
|
||||||
|
shippingCost: orderData.shippingCost || 0,
|
||||||
|
totalAmount: orderData.totalAmount || 0,
|
||||||
|
depositAmount: orderData.depositAmount || 10000,
|
||||||
|
balanceDue: (orderData.totalAmount || 0) - (orderData.depositAmount || 10000),
|
||||||
|
paymentMethodId: orderData.paymentMethodId || 'pay-contraentrega',
|
||||||
|
paymentMethodName: orderData.paymentMethodName || 'Contraentrega',
|
||||||
|
status: 'pending',
|
||||||
|
notes: orderData.notes,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
this.orders.unshift(newOrder);
|
||||||
|
return newOrder;
|
||||||
|
}
|
||||||
|
|
||||||
updateOrderStatus(orderId: string, status: Order['status']): Order | null {
|
updateOrderStatus(orderId: string, status: Order['status']): Order | null {
|
||||||
const order = this.orders.find((o) => o.id === orderId);
|
const order = this.orders.find((o) => o.id === orderId);
|
||||||
if (!order) return null;
|
if (!order) return null;
|
||||||
@ -2243,12 +2429,12 @@ class DataService {
|
|||||||
|
|
||||||
// Configuración de la Tienda
|
// Configuración de la Tienda
|
||||||
private settings: StoreSettings = {
|
private settings: StoreSettings = {
|
||||||
storeName: 'Zapply Cali',
|
storeName: 'DripZone',
|
||||||
slogan: 'Sneakers Express • Entregas en 24 Horas',
|
slogan: 'Luxury Streetwear & Collectibles',
|
||||||
email: 'carlos.andres.lasso@gmail.com',
|
email: 'carlos.andres.lasso@gmail.com',
|
||||||
phone: '3167455877',
|
phone: '3167455877',
|
||||||
whatsappNumber: '573167455877',
|
whatsappNumber: '573167455877',
|
||||||
instagramHandle: '@zapplycali.co',
|
instagramHandle: '@dripzone.co',
|
||||||
address: 'Bodega Central / Cali',
|
address: 'Bodega Central / Cali',
|
||||||
city: 'Cali, Colombia',
|
city: 'Cali, Colombia',
|
||||||
nequiAccount: '316 745 5877',
|
nequiAccount: '316 745 5877',
|
||||||
@ -2290,7 +2476,7 @@ class DataService {
|
|||||||
{
|
{
|
||||||
id: 'usr-operator-1',
|
id: 'usr-operator-1',
|
||||||
name: 'Andrés Operador Despachos',
|
name: 'Andrés Operador Despachos',
|
||||||
email: 'despachos@zapply.co',
|
email: 'despachos@dripzone.co',
|
||||||
phone: '3159876543',
|
phone: '3159876543',
|
||||||
city: 'Cali',
|
city: 'Cali',
|
||||||
role: 'operator',
|
role: 'operator',
|
||||||
@ -2364,7 +2550,6 @@ class DataService {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dataService = new DataService();
|
export const dataService = new DataService();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user