Migración de Compras de WooCommerce a Strapi
Esta consulta SQL ha sido diseñada para extraer y organizar los datos de todas las compras realizadas por los usuarios en un proyecto WordPress que utiliza WooCommerce como plataforma de comercio electrónico. La query recopila información detallada de los pedidos completados, como:
- Datos del cliente: nombre, correo electrónico, teléfono y NIF.
- Productos adquiridos: nombre, precio, cantidad, descuentos aplicados y SKU.
- Cupones utilizados: cupones aplicados y los montos de descuento correspondientes.
- Estado del pedido: estado de pago y método de pago.
Query para obtener todas las compras totales
SELECT p.ID AS order_id, pm1.meta_value AS client, pm3.meta_value AS email, p.post_date AS date, pm7.meta_value AS phone, 'complete' AS state_order, order_stats.status AS state_payment, 'wordpress' AS method_payment, COALESCE(NULLIF(pm2.meta_value + pm5.meta_value, null), '0') AS total_price, COALESCE(NULLIF(pm2.meta_value, null), '0') AS stripe_net, COALESCE(NULLIF(pm5.meta_value, null), '0') AS stripe_fee, "" AS idInvoice, GROUP_CONCAT( CONCAT( '{ "coupon_name": "', oi5.order_item_name, '", "discount_amount": "', oim5.meta_value, '" }' ) SEPARATOR ', ' ) AS coupons_used, GROUP_CONCAT( CONCAT( '[{ "id_product": ', oi.order_item_id, ', "name_product": "', REPLACE(oi.order_item_name, ':', '-'), '"', ', "price": ', pmi2.meta_value, ', "quantity": ', pmi3.meta_value, ', "percent_discount": 10', ', "discount_price": 0', ', "SKU": "', pm_sku.meta_value, '"', ', "id_laab": ', COALESCE(NULLIF(pm_igl.meta_value, ''), '0'), ' }]' ) SEPARATOR ', ' ) AS product, pm6.meta_value AS address, pm8.meta_value AS nifFROM wp_posts AS pLEFT JOIN wp_postmeta pm1 ON (pm1.post_id = p.ID AND pm1.meta_key = '_billing_first_name')LEFT JOIN wp_postmeta pm3 ON (pm3.post_id = p.ID AND pm3.meta_key = '_billing_email')LEFT JOIN wp_postmeta pm7 ON (pm7.post_id = p.ID AND pm7.meta_key = '_billing_phone')LEFT JOIN wp_postmeta pm2 ON (pm2.post_id = p.ID AND pm2.meta_key = '_stripe_net')LEFT JOIN wp_postmeta pm5 ON (pm5.post_id = p.ID AND pm5.meta_key = '_stripe_fee')LEFT JOIN wp_postmeta pm6 ON (pm6.post_id = p.ID AND pm6.meta_key = '_billing_address_1')LEFT JOIN wp_postmeta pm8 ON (pm8.post_id = p.ID AND pm8.meta_key = '_billing_nif')INNER JOIN wp_wc_order_stats AS order_stats ON (order_stats.order_id = p.ID)INNER JOIN wp_woocommerce_order_items oi ON oi.order_id = p.IDINNER JOIN wp_woocommerce_order_itemmeta pmi2 ON pmi2.order_item_id = oi.order_item_id AND pmi2.meta_key = '_line_subtotal'INNER JOIN wp_woocommerce_order_itemmeta pmi3 ON pmi3.order_item_id = oi.order_item_id AND pmi3.meta_key = '_qty'INNER JOIN wp_woocommerce_order_itemmeta pmi ON pmi.order_item_id = oi.order_item_id AND pmi.meta_key = '_product_id'LEFT JOIN wp_postmeta AS pm_sku ON pmi.meta_value = pm_sku.post_id AND pm_sku.meta_key = '_sku'LEFT JOIN wp_postmeta AS pm_igl ON pmi.meta_value = pm_igl.post_id AND pm_igl.meta_key = 'id_grupo_laab2'LEFT JOIN wp_woocommerce_order_items oi5 ON oi5.order_id = p.ID AND oi5.order_item_type = 'coupon'LEFT JOIN wp_woocommerce_order_itemmeta oim5 ON oi5.order_item_id = oim5.order_item_id AND oim5.meta_key = 'discount_amount'WHERE p.post_status = 'wc-completed' AND p.post_type = 'shop_order'
GROUP BY p.IDORDER BY p.post_date ASC;Desglose de la Query
La query se organiza en varias secciones, que extraen los datos de las siguientes tablas principales:
wp_posts: Pedidos realizados (estado, fecha, tipo).wp_postmeta: Metadatos de los pedidos (cliente, correo, teléfono, dirección, NIF).wp_wc_order_stats: Estado de pago del pedido.wp_woocommerce_order_items: Productos y cupones del pedido.wp_woocommerce_order_itemmeta: Metadatos de los productos adquiridos (precio, cantidad, descuentos).
Relaciones entre Tablas
Las tablas están conectadas principalmente a través del ID del pedido (p.ID) y el ID de los artículos del pedido (oi.order_item_id), permitiendo unir información sobre los clientes, productos y cupones.
Query para obtener las compras completadas sin el uso de un cupón
SELECT pm1.meta_value AS client, pm3.meta_value AS email, SUBSTRING(p.post_date, 1, LENGTH(p.post_date) - 3) AS date, CONCAT(p.ID) AS number_order, CONCAT(users.ID) AS id_client, pm7.meta_value AS phone, 'completed' AS state_order, order_stats.status AS state_payment, 'wordpress' AS method_payment, CONCAT( '[{ "id_product": ', oi.order_item_id, ', "name_product": "', REPLACE(oi.order_item_name, ':', '-'), '"', ', "price": ', pmi2.meta_value, ', "quantity": ', pmi3.meta_value, ', "percent_discount": 10', ', "discount_price": 0', ', "SKU": "', pm_sku.meta_value, '"', ', "id_laab": ', pm_igl.meta_value, '}]' ) AS product, pmi2.meta_value AS total_price, pm5.meta_value AS stripe_fee, CONCAT( '[{ "state": "', order_stats.status, '", "date": "', order_stats.date_created, '", "method_payment": "', pa.type, '", "message": "', '', '", "card": "', '', '", "last_card_number": 0, "coupon_applied": [{', ( SELECT CONCAT( '"coupon_name": "', REPLACE(oi5.order_item_name, ':', '-'), '", "coupon_id_stripe": "', '', '", "coupon_discount": "', oim5.meta_value, '", "coupon_percent_discount": "', '', '", "products": "', '', '", "promotional_code_name": "', '', '", "promotional_code_id_stripe": "', '', '", "coupon_available_strapi": "', 'false', '"' ) FROM wp_woocommerce_order_items oi5 INNER JOIN wp_woocommerce_order_itemmeta oim5 ON (oim5.order_item_id = oi5.order_item_id AND oim5.meta_key = 'discount_amount') WHERE oi5.order_id = p.ID ), '}]' ) AS payment_intents, pm4.meta_value AS address, pm2.meta_value AS stripe_net, "" AS idInvoice, pm8.meta_value AS nifFROM wp_posts AS pINNER JOIN wp_postmeta pm1 ON (pm1.post_id = p.ID AND pm1.meta_key = '_billing_first_name')INNER JOIN wp_postmeta pm2 ON (pm2.post_id = p.ID AND pm2.meta_key = '_stripe_net')INNER JOIN wp_postmeta pm5 ON(pm5.post_id = p.ID AND pm5.meta_key = '_stripe_fee')INNER JOIN wp_postmeta pm3 ON (pm3.post_id = p.ID AND pm3.meta_key = '_billing_email')INNER JOIN wp_postmeta pm4 ON (pm4.post_id = p.ID AND pm4.meta_key = '_billing_address_1')INNER JOIN wp_postmeta pm7 ON (pm7.post_id = p.ID AND pm7.meta_key = '_billing_phone')INNER JOIN wp_postmeta pm8 ON (pm8.post_id = p.ID AND pm8.meta_key = '_billing_nif')INNER JOIN wp_woocommerce_order_items oi ON oi.order_id = p.IDINNER JOIN wp_woocommerce_order_itemmeta pmi ON pmi.order_item_id = oi.order_item_id AND pmi.meta_key = '_product_id'LEFT JOIN wp_postmeta AS pm_sku ON pmi.meta_value = pm_sku.post_id AND pm_sku.meta_key = '_sku'LEFT JOIN wp_postmeta AS pm_igl ON pmi.meta_value = pm_igl.post_id AND pm_igl.meta_key = 'id_grupo_laab2'INNER JOIN wp_posts productos ON pmi.meta_value = productos.ID AND productos.post_type = 'product'INNER JOIN wp_woocommerce_order_itemmeta pmi2 ON pmi2.order_item_id = oi.order_item_id AND pmi2.meta_key = '_line_subtotal'INNER JOIN wp_woocommerce_order_itemmeta pmi3 ON pmi3.order_item_id = oi.order_item_id AND pmi3.meta_key = '_qty'INNER JOIN wp_wc_order_stats ON (wp_wc_order_stats.order_id = p.ID)INNER JOIN wp_users AS users ON (users.user_email = pm3.meta_value)INNER JOIN wp_wc_order_stats AS order_stats ON (order_stats.order_id = p.ID), wp_usersINNER JOIN wp_woocommerce_payment_tokens pa ON (pa.user_id = wp_users.ID)WHERE users.user_email = pm3.meta_value AND p.post_status = 'wc-completed' AND p.post_type = 'shop_order' AND pm_igl.meta_value IS NOT NULL AND pm_igl.meta_value != ''GROUP BY p.IDORDER BY p.post_date, client ASC;Desglose de la Query
-
wp_posts: Contiene información general del pedido, como el ID del pedido, la fecha de creación y el estado del pedido.p.post_date: La fecha de creación del pedido.p.ID: El identificador único del pedido.
-
wp_postmeta: Almacena metadatos relacionados con los pedidos, como información del cliente, datos de pago y el NIF del cliente._billing_first_name: El nombre del cliente._billing_email: El correo electrónico del cliente._billing_phone: El número de teléfono del cliente._stripe_net: El monto neto procesado por Stripe._stripe_fee: La comisión que Stripe aplica._billing_address_1: La dirección de facturación del cliente._billing_nif: El NIF del cliente._sku: El código SKU de los productos.id_grupo_laab2: Un campo personalizado relacionado con un grupo de productos específico (en este caso, relacionado con un sistema “Laab”).
-
wp_woocommerce_order_items: Contiene los artículos (productos) y cupones asociados a cada pedido.oi.order_item_id: El identificador único del producto en el pedido.oi.order_item_name: El nombre del producto o del cupón.
-
wp_woocommerce_order_itemmeta: Almacena metadatos específicos de los artículos, como el precio y la cantidad comprada._line_subtotal: El precio total del artículo._qty: La cantidad de productos adquiridos._product_id: El identificador del producto.
-
wp_wc_order_stats: Almacena información sobre el estado del pedido, como su estado de pago y la fecha de creación del estado de pago.order_stats.status: El estado actual del pago.order_stats.date_created: La fecha en la que se creó el estado de pago.
-
wp_users: Almacena la información de los usuarios registrados en WordPress. En este caso, se usa para relacionar al cliente del pedido mediante su correo electrónico.users.user_email: El correo electrónico del usuario (cliente).
-
wp_woocommerce_payment_tokens: Almacena información sobre los métodos de pago utilizados.pa.type: Tipo de método de pago utilizado (por ejemplo, tarjeta de crédito, Stripe, etc.).
Script de Python para reestructurar los datos en un formato que Strapi acepte
import jsonimport refrom datetime import datetime
# Leer datos desde un archivo JSON con la codificación correctawith open('data.json', 'r', encoding='utf-8') as file: rows = json.load(file)
laab = {}componentsProducts = {}orders = {}address = {}date_validation = {}contract_validation = {}
# Función para corregir el formato del campo productdef correct_product_format(product_str): # Reemplazar claves sin comillas por claves con comillas dobles product_str = re.sub(r'(\w+):', r'"\1":', product_str) # Reemplazar valores con comillas simples por valores con comillas dobles product_str = re.sub(r"'([^']*)'", r'"\1"', product_str)
return product_str
def process_laab(products, incremental_id): if not products[0]["id_laab"]: products[0]["id_laab"] = None
connection = { "id": incremental_id, "id_group_laab": products[0]["id_laab"], "id_course_laabpro": None } laab[incremental_id] = connection
def process_product(products, incremental_id): prod = { "id": incremental_id, "id_product": None, "name_product": products[0]['name_product'], "price": float(products[0]['price']), "quantity": products[0]['quantity'], "percent_discount": products[0].get('percent_discount'), "discount_price": products[0].get('discount_price', 0), "SKU": products[0]['SKU'], "contract": None, "laab_connection": [incremental_id], "date_validation": [incremental_id], "contract": [incremental_id] } componentsProducts[incremental_id] = prod
def process_address(row, incremental_id): purchaseAddress = { "id": incremental_id, "line1": row['address'], "city": None, "country": None, "postal_code": None, "dni_nif": None } address[incremental_id] = purchaseAddress
def process_date_validation(incremental_id): validation = { "id": incremental_id, "exists_date": False, "starting_date": None } date_validation[incremental_id] = validation print(validation)
def process_contract_validation(incremental_id): validation = { "id": incremental_id, "exists_contract": False, "contract_signature": False } contract_validation[incremental_id] = validation
def process_order(row, incremental_id): order = { "id": incremental_id, "client": row['client'], "email": row['email'], "date": datetime.strptime(row['date'], '%Y-%m-%d %H:%M:%S').isoformat(), "number_order": None, "id_client": None, "phone": row['phone'], "state_order": row['state_order'], "state_payment": row['state_payment'], "method_payment": row['method_payment'], "stripe_fee": row['stripe_fee'], "address": [incremental_id], "stripe_net": row['stripe_net'], "createdAt": datetime.now().isoformat(), "updatedAt": datetime.now().isoformat(), "id_invoice": row['idInvoice'], "nif": row['nif'], "Payments_intents": [] } if row["product"] is not None: order["Product"] = [incremental_id] if row["total_price"] is None: row["total_price"] = 0 order["total_price"] = row["total_price"]
orders[incremental_id] = order
# Función para procesar una filadef process_row(row, incremental_id): # Corregir el formato del campo 'product' if row["product"] is not None: corrected_product_str = correct_product_format(row["product"]) products = json.loads(corrected_product_str) process_laab(products, incremental_id) process_product(products, incremental_id) process_order(row, incremental_id) process_address(row, incremental_id) process_date_validation(incremental_id) process_contract_validation(incremental_id)
all_data = [process_row(row, idx + 1) for idx, row in enumerate(rows)]all_data = { "version": 2, "data": { "api::order.order": orders, "products.products": componentsProducts, "products.laab-connection": laab, "payment-intents.payments": {}, "address.user-address": address, "products.date-validation": date_validation, "products.contract": contract_validation }}
# Convertir a JSONjson_data = json.dumps(all_data, indent=4)
# Guardar el resultado en un nuevo archivo JSONwith open('processed_data.json', 'w', encoding='utf-8') as file: file.write(json_data)
print("Datos procesados y guardados en 'processed_data.json'")Esto devolverá un json nuevo que es el que tenemos que usar para meterlo en el strapi e importar las compras de los usuarios que vienen de wordpress