534 lines
18 KiB
JavaScript
534 lines
18 KiB
JavaScript
import { api } from "../lib/api.js";
|
|
|
|
// Datos aleatorios para generar usuarios de prueba
|
|
const NOMBRES = ["Juan", "María", "Carlos", "Ana", "Pedro", "Laura", "Diego", "Sofía"];
|
|
const APELLIDOS = ["García", "Rodríguez", "Martínez", "López", "González", "Fernández", "Pérez"];
|
|
const CALLES = ["Av. Corrientes", "Av. Santa Fe", "Calle Florida", "Av. Rivadavia", "Av. Cabildo", "Av. Libertador"];
|
|
|
|
function randomItem(arr) {
|
|
return arr[Math.floor(Math.random() * arr.length)];
|
|
}
|
|
|
|
function randomInt(min, max) {
|
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
}
|
|
|
|
function generateTestUser() {
|
|
const randomPhone = `549${randomInt(1000000000, 9999999999)}`;
|
|
const wa_chat_id = `${randomPhone}@s.whatsapp.net`;
|
|
const nombre = randomItem(NOMBRES);
|
|
const apellido = randomItem(APELLIDOS);
|
|
|
|
return {
|
|
wa_chat_id,
|
|
phone: randomPhone,
|
|
name: `${nombre} ${apellido}`,
|
|
address: {
|
|
first_name: nombre,
|
|
last_name: apellido,
|
|
address_1: `${randomItem(CALLES)} ${randomInt(100, 9000)}`,
|
|
city: "CABA",
|
|
state: "Buenos Aires",
|
|
postcode: `${randomInt(1000, 1999)}`,
|
|
country: "AR",
|
|
phone: randomPhone,
|
|
email: `${randomPhone}@no-email.local`,
|
|
},
|
|
};
|
|
}
|
|
|
|
class TestPanel extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
this.attachShadow({ mode: "open" });
|
|
this.products = [];
|
|
this.selectedProducts = [];
|
|
this.testUser = null;
|
|
this.lastOrder = null;
|
|
this.lastPaymentLink = null;
|
|
this.loading = false;
|
|
|
|
this.shadowRoot.innerHTML = `
|
|
<style>
|
|
:host {
|
|
--bg: #0b0f14;
|
|
--panel: #121823;
|
|
--muted: #8aa0b5;
|
|
--text: #e7eef7;
|
|
--line: #1e2a3a;
|
|
--blue: #1f6feb;
|
|
--green: #238636;
|
|
--red: #da3633;
|
|
}
|
|
* { box-sizing: border-box; font-family: system-ui, Segoe UI, Roboto, Arial; }
|
|
.container {
|
|
height: 100%;
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 16px;
|
|
padding: 16px;
|
|
overflow: auto;
|
|
}
|
|
.panel {
|
|
background: var(--panel);
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
.panel-title {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: var(--muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
border-bottom: 1px solid var(--line);
|
|
padding-bottom: 8px;
|
|
}
|
|
.section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
.section-title {
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
color: var(--blue);
|
|
}
|
|
button {
|
|
background: var(--blue);
|
|
border: none;
|
|
color: white;
|
|
padding: 8px 16px;
|
|
border-radius: 6px;
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
transition: opacity 0.15s;
|
|
}
|
|
button:hover { opacity: 0.9; }
|
|
button:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
button.secondary {
|
|
background: transparent;
|
|
border: 1px solid var(--line);
|
|
color: var(--muted);
|
|
}
|
|
button.secondary:hover { border-color: var(--blue); color: var(--text); }
|
|
button.success { background: var(--green); }
|
|
input, select {
|
|
background: var(--bg);
|
|
border: 1px solid var(--line);
|
|
color: var(--text);
|
|
padding: 8px 12px;
|
|
border-radius: 6px;
|
|
font-size: 12px;
|
|
}
|
|
input:focus, select:focus {
|
|
outline: none;
|
|
border-color: var(--blue);
|
|
}
|
|
.product-list {
|
|
max-height: 200px;
|
|
overflow-y: auto;
|
|
border: 1px solid var(--line);
|
|
border-radius: 6px;
|
|
}
|
|
.product-item {
|
|
display: grid;
|
|
grid-template-columns: 1fr 80px 60px 30px;
|
|
gap: 8px;
|
|
padding: 8px;
|
|
border-bottom: 1px solid var(--line);
|
|
align-items: center;
|
|
font-size: 12px;
|
|
}
|
|
.product-item:last-child { border-bottom: none; }
|
|
.product-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.product-qty { text-align: right; }
|
|
.product-unit { color: var(--muted); }
|
|
.remove-btn {
|
|
background: var(--red);
|
|
padding: 4px 8px;
|
|
font-size: 10px;
|
|
}
|
|
.user-info {
|
|
background: var(--bg);
|
|
border: 1px solid var(--line);
|
|
border-radius: 6px;
|
|
padding: 12px;
|
|
font-size: 12px;
|
|
}
|
|
.user-info div { margin-bottom: 4px; }
|
|
.user-info span { color: var(--muted); }
|
|
.result {
|
|
background: var(--bg);
|
|
border: 1px solid var(--line);
|
|
border-radius: 6px;
|
|
padding: 12px;
|
|
font-size: 12px;
|
|
}
|
|
.result.success { border-color: var(--green); }
|
|
.result.error { border-color: var(--red); }
|
|
.result-label { color: var(--muted); font-size: 10px; text-transform: uppercase; }
|
|
.result-value { font-weight: 600; margin-top: 4px; }
|
|
.result-value.big { font-size: 18px; }
|
|
.result-link {
|
|
color: var(--blue);
|
|
text-decoration: underline;
|
|
cursor: pointer;
|
|
word-break: break-all;
|
|
}
|
|
.row { display: flex; gap: 8px; align-items: center; }
|
|
.flex-1 { flex: 1; }
|
|
.loading { opacity: 0.5; pointer-events: none; }
|
|
.empty { color: var(--muted); font-size: 12px; text-align: center; padding: 20px; }
|
|
</style>
|
|
|
|
<div class="container">
|
|
<div class="panel">
|
|
<div class="panel-title">1. Generar Orden de Prueba</div>
|
|
|
|
<div class="section">
|
|
<div class="row">
|
|
<button id="btnGenerate">Generar Orden Aleatoria</button>
|
|
<button id="btnClear" class="secondary">Limpiar</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title">Productos seleccionados</div>
|
|
<div class="product-list" id="productList">
|
|
<div class="empty">Click "Generar Orden Aleatoria" para comenzar</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title">Datos del usuario</div>
|
|
<div class="user-info" id="userInfo">
|
|
<div class="empty">Se generarán automáticamente</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<button id="btnCreateOrder" class="success" disabled>Crear Orden en WooCommerce</button>
|
|
</div>
|
|
|
|
<div class="section" id="orderResult" style="display:none;">
|
|
<div class="result success">
|
|
<div class="result-label">Orden creada</div>
|
|
<div class="result-value big" id="orderIdValue">—</div>
|
|
<div style="margin-top:8px;">
|
|
<span class="result-label">Total:</span>
|
|
<span id="orderTotalValue">—</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<div class="panel-title">2. Link de Pago (MercadoPago)</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title">Monto</div>
|
|
<div class="row">
|
|
<input type="number" id="inputAmount" placeholder="Monto en ARS" class="flex-1" />
|
|
<button id="btnPaymentLink" disabled>Generar Link de Pago</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section" id="paymentResult" style="display:none;">
|
|
<div class="result success">
|
|
<div class="result-label">Link de pago</div>
|
|
<a class="result-link" id="paymentLinkValue" href="#" target="_blank">—</a>
|
|
<div style="margin-top:8px;">
|
|
<span class="result-label">Preference ID:</span>
|
|
<span id="preferenceIdValue">—</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel-title" style="margin-top:24px;">3. Simular Pago Exitoso</div>
|
|
|
|
<div class="section">
|
|
<p style="font-size:12px;color:var(--muted);margin:0;">
|
|
Simula el webhook de MercadoPago con status "approved".
|
|
Esto actualiza la orden en WooCommerce a "processing".
|
|
</p>
|
|
<button id="btnSimulateWebhook" disabled>Simular Pago Exitoso</button>
|
|
</div>
|
|
|
|
<div class="section" id="webhookResult" style="display:none;">
|
|
<div class="result success">
|
|
<div class="result-label">Pago simulado</div>
|
|
<div class="result-value" id="webhookStatusValue">—</div>
|
|
<div style="margin-top:8px;">
|
|
<span class="result-label">Orden status:</span>
|
|
<span id="webhookOrderStatusValue">—</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
connectedCallback() {
|
|
this.shadowRoot.getElementById("btnGenerate").onclick = () => this.generateRandomOrder();
|
|
this.shadowRoot.getElementById("btnClear").onclick = () => this.clearAll();
|
|
this.shadowRoot.getElementById("btnCreateOrder").onclick = () => this.createOrder();
|
|
this.shadowRoot.getElementById("btnPaymentLink").onclick = () => this.createPaymentLink();
|
|
this.shadowRoot.getElementById("btnSimulateWebhook").onclick = () => this.simulateWebhook();
|
|
|
|
this.loadProducts();
|
|
}
|
|
|
|
async loadProducts() {
|
|
try {
|
|
const result = await api.getProductsWithStock();
|
|
this.products = result.items || [];
|
|
console.log(`[test-panel] Loaded ${this.products.length} products with stock`);
|
|
} catch (e) {
|
|
console.error("[test-panel] Error loading products:", e);
|
|
}
|
|
}
|
|
|
|
async generateRandomOrder() {
|
|
if (this.products.length === 0) {
|
|
await this.loadProducts();
|
|
}
|
|
|
|
if (this.products.length === 0) {
|
|
alert("No hay productos con stock disponible");
|
|
return;
|
|
}
|
|
|
|
// Generar usuario aleatorio
|
|
this.testUser = generateTestUser();
|
|
|
|
// Seleccionar 1-3 productos aleatorios
|
|
const numProducts = randomInt(1, Math.min(3, this.products.length));
|
|
const shuffled = [...this.products].sort(() => Math.random() - 0.5);
|
|
this.selectedProducts = [];
|
|
|
|
for (let i = 0; i < numProducts; i++) {
|
|
const product = shuffled[i];
|
|
const isKg = product.sell_unit === "kg";
|
|
const quantity = isKg ? randomInt(200, 2000) : randomInt(1, 5);
|
|
|
|
this.selectedProducts.push({
|
|
product_id: product.woo_product_id,
|
|
name: product.name,
|
|
quantity,
|
|
unit: isKg ? "kg" : "unit",
|
|
price: product.price,
|
|
});
|
|
}
|
|
|
|
this.renderProductList();
|
|
this.renderUserInfo();
|
|
this.updateButtonStates();
|
|
}
|
|
|
|
renderProductList() {
|
|
const container = this.shadowRoot.getElementById("productList");
|
|
|
|
if (this.selectedProducts.length === 0) {
|
|
container.innerHTML = `<div class="empty">Click "Generar Orden Aleatoria" para comenzar</div>`;
|
|
return;
|
|
}
|
|
|
|
container.innerHTML = this.selectedProducts.map((p, i) => `
|
|
<div class="product-item">
|
|
<div class="product-name" title="${p.name}">${p.name}</div>
|
|
<div class="product-qty">${p.unit === "kg" ? `${p.quantity}g` : `${p.quantity}u`}</div>
|
|
<div class="product-unit">$${Number(p.price || 0).toFixed(0)}</div>
|
|
<button class="remove-btn" data-index="${i}">X</button>
|
|
</div>
|
|
`).join("");
|
|
|
|
container.querySelectorAll(".remove-btn").forEach(btn => {
|
|
btn.onclick = (e) => {
|
|
const idx = parseInt(e.target.dataset.index);
|
|
this.selectedProducts.splice(idx, 1);
|
|
this.renderProductList();
|
|
this.updateButtonStates();
|
|
};
|
|
});
|
|
}
|
|
|
|
renderUserInfo() {
|
|
const container = this.shadowRoot.getElementById("userInfo");
|
|
|
|
if (!this.testUser) {
|
|
container.innerHTML = `<div class="empty">Se generarán automáticamente</div>`;
|
|
return;
|
|
}
|
|
|
|
const addr = this.testUser.address;
|
|
container.innerHTML = `
|
|
<div><span>Nombre:</span> ${addr.first_name} ${addr.last_name}</div>
|
|
<div><span>Dirección:</span> ${addr.address_1}</div>
|
|
<div><span>Ciudad:</span> ${addr.city}, ${addr.state}</div>
|
|
<div><span>Teléfono:</span> ${addr.phone}</div>
|
|
<div><span>Email:</span> ${addr.email}</div>
|
|
`;
|
|
}
|
|
|
|
updateButtonStates() {
|
|
const hasProducts = this.selectedProducts.length > 0;
|
|
const hasOrder = this.lastOrder?.woo_order_id;
|
|
const hasPaymentLink = this.lastPaymentLink?.init_point;
|
|
|
|
this.shadowRoot.getElementById("btnCreateOrder").disabled = !hasProducts;
|
|
this.shadowRoot.getElementById("btnPaymentLink").disabled = !hasOrder;
|
|
this.shadowRoot.getElementById("btnSimulateWebhook").disabled = !hasOrder;
|
|
|
|
if (hasOrder) {
|
|
this.shadowRoot.getElementById("inputAmount").value = this.lastOrder.total || "";
|
|
}
|
|
}
|
|
|
|
async createOrder() {
|
|
if (this.loading) return;
|
|
this.loading = true;
|
|
|
|
const btn = this.shadowRoot.getElementById("btnCreateOrder");
|
|
btn.disabled = true;
|
|
btn.textContent = "Creando...";
|
|
|
|
try {
|
|
const basket = {
|
|
items: this.selectedProducts.map(p => ({
|
|
product_id: p.product_id,
|
|
quantity: p.quantity,
|
|
unit: p.unit,
|
|
})),
|
|
};
|
|
|
|
const result = await api.createTestOrder({
|
|
basket,
|
|
address: this.testUser?.address || null,
|
|
wa_chat_id: this.testUser?.wa_chat_id || null,
|
|
});
|
|
|
|
if (result.ok) {
|
|
this.lastOrder = result;
|
|
this.shadowRoot.getElementById("orderIdValue").textContent = `#${result.woo_order_id}`;
|
|
this.shadowRoot.getElementById("orderTotalValue").textContent = `$${Number(result.total || 0).toFixed(2)}`;
|
|
this.shadowRoot.getElementById("orderResult").style.display = "block";
|
|
this.shadowRoot.getElementById("inputAmount").value = result.total || "";
|
|
} else {
|
|
alert("Error: " + (result.error || "Error desconocido"));
|
|
}
|
|
} catch (e) {
|
|
console.error("[test-panel] createOrder error:", e);
|
|
alert("Error creando orden: " + e.message);
|
|
} finally {
|
|
this.loading = false;
|
|
btn.textContent = "Crear Orden en WooCommerce";
|
|
this.updateButtonStates();
|
|
}
|
|
}
|
|
|
|
async createPaymentLink() {
|
|
if (this.loading) return;
|
|
if (!this.lastOrder?.woo_order_id) {
|
|
alert("Primero creá una orden");
|
|
return;
|
|
}
|
|
|
|
const amount = parseFloat(this.shadowRoot.getElementById("inputAmount").value);
|
|
if (!amount || amount <= 0) {
|
|
alert("Ingresá un monto válido");
|
|
return;
|
|
}
|
|
|
|
this.loading = true;
|
|
const btn = this.shadowRoot.getElementById("btnPaymentLink");
|
|
btn.disabled = true;
|
|
btn.textContent = "Generando...";
|
|
|
|
try {
|
|
const result = await api.createPaymentLink({
|
|
woo_order_id: this.lastOrder.woo_order_id,
|
|
amount,
|
|
});
|
|
|
|
if (result.ok) {
|
|
this.lastPaymentLink = result;
|
|
const linkEl = this.shadowRoot.getElementById("paymentLinkValue");
|
|
linkEl.href = result.init_point || result.sandbox_init_point || "#";
|
|
linkEl.textContent = result.init_point || result.sandbox_init_point || "—";
|
|
this.shadowRoot.getElementById("preferenceIdValue").textContent = result.preference_id || "—";
|
|
this.shadowRoot.getElementById("paymentResult").style.display = "block";
|
|
} else {
|
|
alert("Error: " + (result.error || "Error desconocido"));
|
|
}
|
|
} catch (e) {
|
|
console.error("[test-panel] createPaymentLink error:", e);
|
|
alert("Error generando link: " + e.message);
|
|
} finally {
|
|
this.loading = false;
|
|
btn.textContent = "Generar Link de Pago";
|
|
this.updateButtonStates();
|
|
}
|
|
}
|
|
|
|
async simulateWebhook() {
|
|
if (this.loading) return;
|
|
if (!this.lastOrder?.woo_order_id) {
|
|
alert("Primero creá una orden");
|
|
return;
|
|
}
|
|
|
|
this.loading = true;
|
|
const btn = this.shadowRoot.getElementById("btnSimulateWebhook");
|
|
btn.disabled = true;
|
|
btn.textContent = "Simulando...";
|
|
|
|
try {
|
|
const amount = parseFloat(this.shadowRoot.getElementById("inputAmount").value) || this.lastOrder.total || 0;
|
|
|
|
const result = await api.simulateMpWebhook({
|
|
woo_order_id: this.lastOrder.woo_order_id,
|
|
amount,
|
|
});
|
|
|
|
if (result.ok) {
|
|
this.shadowRoot.getElementById("webhookStatusValue").textContent = `Payment ${result.payment_id} - ${result.status}`;
|
|
this.shadowRoot.getElementById("webhookOrderStatusValue").textContent = result.order_status || "processing";
|
|
this.shadowRoot.getElementById("webhookResult").style.display = "block";
|
|
} else {
|
|
alert("Error: " + (result.error || "Error desconocido"));
|
|
}
|
|
} catch (e) {
|
|
console.error("[test-panel] simulateWebhook error:", e);
|
|
alert("Error simulando webhook: " + e.message);
|
|
} finally {
|
|
this.loading = false;
|
|
btn.textContent = "Simular Pago Exitoso";
|
|
this.updateButtonStates();
|
|
}
|
|
}
|
|
|
|
clearAll() {
|
|
this.selectedProducts = [];
|
|
this.testUser = null;
|
|
this.lastOrder = null;
|
|
this.lastPaymentLink = null;
|
|
|
|
this.renderProductList();
|
|
this.renderUserInfo();
|
|
this.updateButtonStates();
|
|
|
|
this.shadowRoot.getElementById("orderResult").style.display = "none";
|
|
this.shadowRoot.getElementById("paymentResult").style.display = "none";
|
|
this.shadowRoot.getElementById("webhookResult").style.display = "none";
|
|
this.shadowRoot.getElementById("inputAmount").value = "";
|
|
}
|
|
}
|
|
|
|
customElements.define("test-panel", TestPanel);
|