tenantIntegrationService = $tenantIntegrationService; $this->paymentProviderFactory = $paymentProviderFactory; } public function processCheckout(Tenant $tenant, int $userId, array $purchaseData, string $integrationCode, array $paymentData): Purchase { // 1. Obtener configuración del tenant $tenantIntegration = $this->tenantIntegrationService->getTenantIntegration($tenant->codigo, $integrationCode); if (!$tenantIntegration) { throw ValidationException::withMessages([ 'integration_code' => "El tenant no tiene configurada la integración: {$integrationCode}", ]); } // 2. Instanciar el proveedor de pago $provider = $this->paymentProviderFactory->make($integrationCode); // 3. Procesar el pago con las credenciales desencriptadas $paymentResult = $provider->process($paymentData, $tenantIntegration->integration_data); // 4. Preparar items de la compra $items = $purchaseData['items']; unset($purchaseData['items']); $variants = $this->resolveTenantVariants($tenant, $items); $purchaseItemsPayload = $this->buildPurchaseItemsPayload($items, $variants); // 5. Crear la orden de compra return DB::transaction(function () use ($tenant, $userId, $purchaseData, $purchaseItemsPayload, $paymentResult): Purchase { /** @var Purchase $purchase */ $purchase = Purchase::query()->create([ ...$purchaseData, 'tenant_codigo' => $tenant->codigo, 'user_id' => $userId, // TODO: En un futuro se puede guardar info de $paymentResult en la base de datos (ej: payment_id, status) ]); $purchase->items()->createMany($purchaseItemsPayload); return $purchase->load(['items.variant.product', 'items.variant.definitions.productAttribute.attribute']); }); } /** * @param array> $items * @return \Illuminate\Support\Collection */ protected function resolveTenantVariants(Tenant $tenant, array $items) { $variantIds = collect($items) ->pluck('producto_variante_id') ->filter() ->map(static fn (mixed $id): int => (int) $id) ->unique() ->values(); $variants = ProductVariant::query() ->with('product') ->whereIn('id', $variantIds) ->whereHas('product', fn ($query) => $query->where('tenant_codigo', $tenant->codigo)) ->get() ->keyBy('id'); if ($variants->count() !== $variantIds->count()) { throw ValidationException::withMessages([ 'items' => 'One or more product variants do not belong to the tenant.', ]); } return $variants; } /** * @param array> $items * @param \Illuminate\Support\Collection $variants * @return array> */ protected function buildPurchaseItemsPayload(array $items, $variants): array { return collect($items) ->map(function (array $item) use ($variants): array { /** @var ProductVariant $variant */ $variant = $variants->get((int) $item['producto_variante_id']); $quantity = (int) $item['cantidad']; $unitPrice = (float) ($variant->product?->precio ?? 0); return [ 'producto_variante_id' => $variant->getKey(), 'cantidad' => $quantity, 'precio_unitario' => $unitPrice, 'discount_total' => null, 'tax_total' => null, 'total' => $unitPrice * $quantity, ]; }) ->all(); } }