Skip to content

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 nif
FROM
wp_posts AS p
LEFT 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.ID
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_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.ID
ORDER 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 nif
FROM
wp_posts AS p
INNER 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.ID
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'
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_users
INNER 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.ID
ORDER 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 json
import re
from datetime import datetime
# Leer datos desde un archivo JSON con la codificación correcta
with 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 product
def 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 fila
def 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 JSON
json_data = json.dumps(all_data, indent=4)
# Guardar el resultado en un nuevo archivo JSON
with 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