ADR 0009 ya había decidido PayU LatAm como proveedor (única opción que no exige cuenta Bancolombia/Nequi) y confirmado que no existe ningún plugin real de Medusa para su API -- los paquetes que aparecen buscando "PayU" son para PayU Polonia/CEE, API completamente distinta (clientId/posId/secondKey vs. apiLogin/apiKey/merchantId/accountId). Este commit implementa esa decisión: módulo de pago custom (AbstractPaymentProvider) para PSE (transferencia bancaria), primer alcance del método de pago -- Nequi/Daviplata quedan fuera por ahora. Backend (commerce-backend): - src/modules/payu-pse/: initiatePayment arma y postea SUBMIT_TRANSACTION contra la API real de PayU LatAm; authorizePayment devuelve "pending_authorization" (PSE es async, la confirmación real llega por webhook, no en el momento de completar el carrito); getWebhookActionAndData valida la firma MD5 del webhook antes de confiar en cualquier confirmación de pago -- falla cerrado si no matchea. refundPayment/ retrievePayment tiran error explícito en vez de simular éxito: esos endpoints de PayU no quedaron verificados en vivo y hay dinero real de por medio. - No hace falta un subscriber propio para completar la orden -- el subscriber nativo de Medusa (payment-webhook + process-payment-workflow) ya hace ese trabajo con los métodos de arriba bien implementados (confirmado leyendo el código fuente instalado de @medusajs/medusa 2.18.0, no la documentación). - Correlación webhook↔sesión: Medusa inyecta su propio session_id en `data` antes de initiatePayment; se usa ese mismo valor como referenceCode de PayU, así el reference_sale que vuelve en el webhook ya es directamente el session_id de Medusa. - src/lib/payu.ts: cliente HTTP + firmas (orden y webhook, fórmulas distintas, confirmadas contra el SDK PHP oficial de PayU). - src/api/store/payments/pse-banks/route.ts: lista de bancos PSE, cacheada en memoria. - medusa-config.ts, Dockerfile, configmap/secrets.template: 7 env vars nuevas (PAYU_API_LOGIN/API_KEY/MERCHANT_ID/ACCOUNT_ID/ENV/RESPONSE_URL/ NOTIFY_URL), dummies de build agregados, secrets con placeholder "CAMBIAR". Frontend (ecommerce): - Nuevo step "payment" en components/checkout/checkout-client.tsx (reemplaza al step "review" que solo ofrecía WhatsApp): selector de banco, tipo de persona (N/J), tipo/número de documento, botón "Pagar con PSE" que crea la sesión de pago, completa el carrito y redirige al banco (navegación completa, no iframe -- así lo exige PayU). WhatsApp queda como respaldo manual si falla la iniciación del pago. - lib/headless/providers/medusa-payment.ts + 3 rutas proxy nuevas bajo app/api/cart/, mismo patrón que el resto del carrito (medusaCartFetch, ahora exportado desde medusa-cart.ts). - app/checkout/pse/return/: página de vuelta del banco -- nunca afirma éxito, la confirmación real es el webhook async. Arranca contra las credenciales de sandbox genéricas y públicas de PayU (developers.payulatam.com) mientras el usuario termina su propio registro de comercio -- swap de las 4 credenciales via secret cuando estén listas, sin cambios de código. Verificado: build real de Medusa con las env vars dummy (no solo tsc), tipos de AbstractPaymentProvider/WebhookActionResult/PaymentActions confirmados contra @medusajs/utils y @medusajs/types instalados (node_modules limpiado después), typecheck + lint + build completo del frontend, páginas nuevas renderizando sin error. Pendiente: prueba end-to-end contra el sandbox real de PayU (necesita el backend desplegado) y habilitar el provider en la región Colombia desde el Admin. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
117 lines
3.9 KiB
Docker
117 lines
3.9 KiB
Docker
# syntax=docker/dockerfile:1.7
|
|
|
|
#############################################################
|
|
# Builder
|
|
#############################################################
|
|
FROM node:22.18.0-bookworm-slim AS builder
|
|
|
|
WORKDIR /app
|
|
|
|
ENV CI=true \
|
|
NODE_ENV=development \
|
|
NPM_CONFIG_UPDATE_NOTIFIER=false \
|
|
DATABASE_URL=postgres://medusa:[email protected]:5432/medusa \
|
|
REDIS_URL=redis://127.0.0.1:6379 \
|
|
STORE_CORS=http://localhost:8000 \
|
|
ADMIN_CORS=http://localhost:7001 \
|
|
AUTH_CORS=http://localhost:7001 \
|
|
JWT_SECRET=build-only-jwt-secret \
|
|
COOKIE_SECRET=build-only-cookie-secret \
|
|
S3_FILE_URL=http://localhost:9000/ari-shopping \
|
|
S3_ACCESS_KEY_ID=build-access-key \
|
|
S3_SECRET_ACCESS_KEY=build-secret-key \
|
|
S3_BUCKET=ari-shopping \
|
|
S3_ENDPOINT=http://127.0.0.1:9000 \
|
|
MEILISEARCH_HOST=http://127.0.0.1:7700 \
|
|
MEILISEARCH_API_KEY=build-only-meili-key \
|
|
GOOGLE_CLIENT_ID=build-only-google-client-id \
|
|
GOOGLE_CLIENT_SECRET=build-only-google-client-secret \
|
|
GOOGLE_CALLBACK_URL=http://localhost:9000/auth/customer/google/callback \
|
|
PAYU_API_LOGIN=build-only-payu-login \
|
|
PAYU_API_KEY=build-only-payu-key \
|
|
PAYU_MERCHANT_ID=999999 \
|
|
PAYU_ACCOUNT_ID=999999 \
|
|
PAYU_ENV=sandbox \
|
|
PAYU_RESPONSE_URL=http://localhost:8000/checkout/pse/return \
|
|
PAYU_NOTIFY_URL=http://localhost:9000/hooks/payment/payu_pse
|
|
|
|
COPY package.json package-lock.json .npmrc ./
|
|
|
|
RUN --mount=type=cache,id=medusa-npm-cache,target=/root/.npm \
|
|
npm ci \
|
|
--legacy-peer-deps \
|
|
--prefer-offline \
|
|
--no-audit \
|
|
--no-fund
|
|
|
|
COPY tsconfig.json ./
|
|
COPY medusa-config.ts ./
|
|
COPY src ./src
|
|
|
|
RUN npm run build
|
|
|
|
#
|
|
# Elimina todas las dependencias de desarrollo
|
|
#
|
|
RUN npm prune --omit=dev
|
|
|
|
#
|
|
# Limpia cache de npm
|
|
#
|
|
RUN npm cache clean --force
|
|
|
|
#############################################################
|
|
# Runtime
|
|
#############################################################
|
|
FROM node:22.18.0-bookworm-slim
|
|
|
|
WORKDIR /app
|
|
|
|
ENV NODE_ENV=production \
|
|
PORT=9000 \
|
|
NPM_CONFIG_UPDATE_NOTIFIER=false
|
|
|
|
#
|
|
# libgnutls30 en la base node:22.18.0-bookworm-slim trae dos CVE
|
|
# CRITICAL con fix ya publicado por Debian (CVE-2026-33845,
|
|
# CVE-2026-42010) -- detectado por el gate de Trivy imagen del
|
|
# pipeline (run 138). Solo se actualiza este paquete puntual, no toda
|
|
# la imagen, para minimizar el diff de superficie de la base.
|
|
RUN apt-get update \
|
|
&& apt-get upgrade -y libgnutls30 \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# El CLI global de npm que trae la imagen base node:*-slim arrastra su
|
|
# propia copia vendorizada de `tar` con un CVE CRITICAL
|
|
# (CVE-2026-59873, detectado por Trivy en
|
|
# usr/local/lib/node_modules/npm/node_modules/tar). Se elimina npm
|
|
# entero -- no alcanza con borrar solo el tar vendorizado: el propio
|
|
# `npx` depende de ese tar internamente (pacote/arborist) incluso para
|
|
# ejecutar un binario ya instalado localmente, así que queda roto igual
|
|
# si el paquete tar desaparece pero npm sigue ahí (confirmado
|
|
# probando "npx medusa --version" contra la imagen: falla con
|
|
# "Cannot find module 'tar'").
|
|
#
|
|
# OJO con este cambio: el init container "migrations" de
|
|
# workloads/ecommerce/commerce/medusa.yaml corría "npx medusa
|
|
# db:migrate" contra esta misma imagen -- un primer intento de este
|
|
# fix borraba npm sin ajustar ese comando y rompió el init container
|
|
# en producción ("npx: executable file not found in $PATH",
|
|
# medusa-deploy atascado en Init:CrashLoopBackOff, detectado revisando
|
|
# el estado real del cluster después del deploy). El fix completo
|
|
# incluye cambiar ese comando a invocar el CLI directo con `node`, sin
|
|
# pasar por npm/npx -- mismo patrón que ya usa el CMD de este
|
|
# Dockerfile más abajo.
|
|
RUN rm -rf /usr/local/lib/node_modules/npm
|
|
|
|
#
|
|
# Solo lo necesario para ejecutar Medusa
|
|
#
|
|
COPY --from=builder --chown=node:node /app/node_modules ./node_modules
|
|
COPY --from=builder --chown=node:node /app/.medusa/server ./
|
|
|
|
USER node
|
|
|
|
EXPOSE 9000
|
|
|
|
CMD ["node","node_modules/@medusajs/cli/dist/index.js","start"] |