{ "cells": [ { "cell_type": "markdown", "id": "07306d98", "metadata": {}, "source": [ "# 01 — Exploración: quotes ↔ call_center ↔ factura\n", "\n", "Mapa de tablas y joins en `psql_dcpublic` (BigQuery `autingo-159109`).\n", "\n", "## Cadena de joins\n", "\n", "```\n", "tpv_authorization_tpvuser_centers (dccenter_id ∈ {159 CALL_CENTER_AURGI, 162 CALL_CENTER})\n", " │ tpvuser_id\n", " ▼\n", "tpv_orders_quote.created_by_id ──► quote por agente call_center\n", " │ order_id\n", " ▼\n", "tpv_orders_order ─► terminal_id ─► tpv_terminals.center_id ─► centers (centro real de facturación)\n", " │ │ customer_id │ vehicle_id\n", " ▼ ▼ ▼\n", "tpv_orders_invoice (status convertido) tpv_customers (tlf) tpv_vehicles_vehicle (matrícula)\n", "```\n", "\n", "Identidad cliente = `(customer_id, vehicle_id)` o (tlf, matrícula) según necesite normalización." ] }, { "cell_type": "code", "execution_count": null, "id": "d2b6d545", "metadata": {}, "outputs": [], "source": [ "import os, sys\n", "from google.cloud import bigquery\n", "import pandas as pd\n", "\n", "PROJECT = \"autingo-159109\"\n", "DATASET = \"psql_dcpublic\"\n", "bq = bigquery.Client(project=PROJECT)\n", "\n", "def q(sql):\n", " return bq.query(sql).to_dataframe()" ] }, { "cell_type": "markdown", "id": "3238b92e", "metadata": {}, "source": [ "## 1. Usuarios call_center" ] }, { "cell_type": "code", "execution_count": null, "id": "34d656ad", "metadata": {}, "outputs": [], "source": [ "cc_users = q(f\"\"\"\n", "SELECT u.id, u.name, u.email, u.is_active, u.role_id,\n", " STRING_AGG(CAST(uc.dccenter_id AS STRING)) AS centers\n", "FROM `{PROJECT}.{DATASET}.tpv_authorization_tpvuser` u\n", "JOIN `{PROJECT}.{DATASET}.tpv_authorization_tpvuser_centers` uc\n", " ON u.id = uc.tpvuser_id\n", "WHERE uc.dccenter_id IN (159, 162)\n", "GROUP BY 1,2,3,4,5\n", "ORDER BY u.is_active DESC, u.id\n", "\"\"\")\n", "print(f\"Total usuarios call_center: {len(cc_users)} (activos: {cc_users.is_active.sum()})\")\n", "cc_users.head(20)" ] }, { "cell_type": "markdown", "id": "9ec102fb", "metadata": {}, "source": [ "## 2. Schema quote — campos clave" ] }, { "cell_type": "code", "execution_count": null, "id": "e5f94b52", "metadata": {}, "outputs": [], "source": [ "q(f\"\"\"\n", "SELECT column_name, data_type\n", "FROM `{PROJECT}.{DATASET}.INFORMATION_SCHEMA.COLUMNS`\n", "WHERE table_name='tpv_orders_quote'\n", "ORDER BY ordinal_position\n", "\"\"\")" ] }, { "cell_type": "markdown", "id": "32ffc1d2", "metadata": {}, "source": [ "## 3. Distribución `status` y `accepted` (últimos 90d)" ] }, { "cell_type": "code", "execution_count": null, "id": "609022a9", "metadata": {}, "outputs": [], "source": [ "q(f\"\"\"\n", "SELECT status, accepted, COUNT(*) n\n", "FROM `{PROJECT}.{DATASET}.tpv_orders_quote`\n", "WHERE created_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 90 DAY)\n", " AND deleted_at IS NULL\n", "GROUP BY status, accepted\n", "ORDER BY n DESC\n", "\"\"\")" ] }, { "cell_type": "markdown", "id": "73c85198", "metadata": {}, "source": [ "## 4. Conversion quote → invoice (mismo order_id)\n", "\n", "Una quote convierte cuando existe `tpv_orders_invoice` con el mismo `order_id`. Ese invoice fija la facturación real (NAV-sync via `nav_id`)." ] }, { "cell_type": "code", "execution_count": null, "id": "46378f84", "metadata": {}, "outputs": [], "source": [ "q(f\"\"\"\n", "SELECT\n", " COUNT(*) AS quotes,\n", " COUNT(DISTINCT q.order_id) AS distinct_orders,\n", " SUM(CASE WHEN i.id IS NOT NULL THEN 1 ELSE 0 END) AS quotes_con_invoice,\n", " SAFE_DIVIDE(SUM(CASE WHEN i.id IS NOT NULL THEN 1 ELSE 0 END), COUNT(*)) AS conversion_rate\n", "FROM `{PROJECT}.{DATASET}.tpv_orders_quote` q\n", "LEFT JOIN `{PROJECT}.{DATASET}.tpv_orders_invoice` i\n", " ON q.order_id = i.order_id\n", "WHERE q.created_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 90 DAY)\n", " AND q.deleted_at IS NULL\n", "\"\"\")" ] }, { "cell_type": "markdown", "id": "df8b402c", "metadata": {}, "source": [ "## 5. Sanity: quote por call_center vs otro\n" ] }, { "cell_type": "code", "execution_count": null, "id": "506744d3", "metadata": {}, "outputs": [], "source": [ "q(f\"\"\"\n", "WITH cc_users AS (\n", " SELECT DISTINCT tpvuser_id AS user_id\n", " FROM `{PROJECT}.{DATASET}.tpv_authorization_tpvuser_centers`\n", " WHERE dccenter_id IN (159, 162)\n", ")\n", "SELECT\n", " CASE WHEN cc.user_id IS NOT NULL THEN 'call_center' ELSE 'otro' END AS origen_user,\n", " COUNT(*) AS quotes,\n", " SUM(CASE WHEN i.id IS NOT NULL THEN 1 ELSE 0 END) AS convertidos,\n", " ROUND(SAFE_DIVIDE(SUM(CASE WHEN i.id IS NOT NULL THEN 1 ELSE 0 END), COUNT(*)), 3) AS conv_rate\n", "FROM `{PROJECT}.{DATASET}.tpv_orders_quote` q\n", "LEFT JOIN cc_users cc ON q.created_by_id = cc.user_id\n", "LEFT JOIN `{PROJECT}.{DATASET}.tpv_orders_invoice` i ON q.order_id = i.order_id\n", "WHERE q.created_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 90 DAY)\n", " AND q.deleted_at IS NULL\n", "GROUP BY 1\n", "\"\"\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.5" } }, "nbformat": 4, "nbformat_minor": 5 }