viewData['pageTitle'] = lang('Importador.listingPage'); $this->viewData['usingSweetAlert'] = true; // Breadcrumbs (IMN) $this->viewData['breadcrumb'] = [ ['title' => lang("App.menu_importadores"), 'route' => "javascript:void(0);", 'active' => false], ['title' => lang("App.menu_importadores_bubok"), 'route' => route_to('importadorBubokTool'), 'active' => true] ]; parent::initController($request, $response, $logger); } public function index() { $viewData = [ 'pageSubTitle' => lang('Basic.global.ManageAllRecords', [lang('Importador.importadorCatalogoTitle')]), ]; $viewData = array_merge($this->viewData, $viewData); // merge any possible values from the parent controller class return view(static::$viewPath . 'viewImportadorBubokTool', $viewData); } public function validarFila() { $json = $this->request->getJSON(); if (!$json || empty($json->producto) || empty($json->pedido)) { return $this->response->setJSON([ 'apto' => false, 'reason' => 'Datos incompletos' ]); } $producto = $json->producto; $pedido = $json->pedido; // Validar existencia de ID de producto if (empty($producto->id)) { return $this->response->setJSON([ 'apto' => false, 'reason' => 'ID de producto no proporcionado' ]); } $refCliente = $pedido->orderNumber . '-' . $producto->id; // Validar formato Ref. Cliente if (strpos($refCliente, '-') === false || strlen($refCliente) < 5) { return $this->response->setJSON([ 'apto' => false, 'reason' => 'Ref. cliente inválido' ]); } // 1. Verificar si ya fue importado $presupuestoModel = new PresupuestoModel(); $yaExiste = $presupuestoModel->where('referencia_cliente', $refCliente)->first(); if ($yaExiste) { return $this->response->setJSON([ 'apto' => false, 'reason' => 'Referencia ya importada' ]); } // 2. Validación básica del producto (puedes expandir con más reglas si lo necesitas) $errores = []; if (empty($producto->title)) $errores[] = 'Falta título'; if (empty($producto->body->pages)) $errores[] = 'Faltan páginas'; if (empty($producto->amount)) $errores[] = 'Falta tirada'; if (!empty($errores)) { return $this->response->setJSON([ 'apto' => false, 'reason' => implode(', ', $errores) ]); } // 3. Producto considerado apto return $this->response->setJSON([ 'apto' => true ]); } public function importarFila() { $json = $this->request->getJSON(); // Validación mínima de datos comunes $pedido = $json->pedido ?? null; if (!$pedido || !isset($pedido->orderNumber)) { return $this->respond([ 'status' => 400, 'message' => 'Datos comunes del pedido ausentes o inválidos.' ]); } // Validación mínima de existencia del producto en la linea if (!$json || !isset($json->producto)) { return $this->respond([ 'status' => 400, 'message' => 'Producto no proporcionado o inválido.' ]); } $producto = $json->producto; // 1. Datos básicos: // Referencia del cliente $orderNumber = $pedido->orderNumber ?? null; $productId = $producto->id ?? null; if (is_null($orderNumber) || is_null($productId)) { return $this->respond([ 'status' => 400, 'message' => 'Número de orden o ID del producto no reconocidos.' ]); } $refCliente = "$orderNumber-$productId"; // Titulo $titulo = $producto->title ?? null; if (is_null($titulo)) { return $this->respond([ 'status' => 400, 'message' => 'Título del libro no reconocido.' ]); } // Validación de páginas y tirada $paginas = isset($producto->body->pages) ? (int) $producto->body->pages : 0; $tirada = isset($producto->amount) ? (int) $producto->amount : 0; if ($paginas <= 0 || $tirada <= 0) { $errores = []; if ($paginas <= 0) { $errores[] = 'Número de páginas inválido.'; } if ($tirada <= 0) { $errores[] = 'Tirada inválida.'; } return $this->respond([ 'status' => 400, 'message' => implode(' ', $errores) ]); } // Ancho y alto $ancho = null; $alto = null; foreach ($producto->size as $key => $val) { if ($val == 1) { // ejemplo: size170x235 $size = str_replace('size', '', $key); [$ancho, $alto] = explode('x', $size); $ancho = (int) $ancho; $alto = (int) $alto; break; } } if (!$ancho || !$alto) { return $this->respond([ 'status' => 400, 'message' => 'Tamaño del libro no reconocido.' ]); } /*$numGuardaPages = 4; $hasGuarda = !empty($producto->cover->guarda); if ($hasGuarda) $paginas += $numGuardaPages;*/ // 2. Interior: color o negro // Determinar tipo de impresión interior $interiorTipo = null; if (isset($producto->body->color->CMYK) && $producto->body->color->CMYK == '1') { $interiorTipo = 'color'; } elseif (isset($producto->body->color->Monochrome) && $producto->body->color->Monochrome == '1') { $interiorTipo = 'negro'; } elseif (isset($producto->body->color->Semicolor) && $producto->body->color->Semicolor == '1') { return $this->respond([ 'status' => 400, 'message' => 'Tipo de impresión "Semicolor" no soportado.' ]); } if (is_null($interiorTipo)) { return $this->respond([ 'status' => 400, 'message' => 'No se pudo determinar si el interior es en color o blanco y negro.' ]); } // Determinar tipo de papel interior $papelInteriorId = null; if (isset($producto->body->paperColor->white) && $producto->body->paperColor->white == '1') { $papelInteriorId = 3; // Offset blanco 'OFF1' } elseif (isset($producto->body->paperColor->cream) && $producto->body->paperColor->cream == '1') { $papelInteriorId = 4; // Offset ahuesado 'OFF2' } else { return $this->respond([ 'status' => 400, 'message' => 'Tipo de papel interior no definido.' ]); } // Determinar el gramaje del papel $gramajePapelInterior = null; foreach ($producto->body->paperWeight as $key => $val) { if ($val == 1) { $gramajePapelInterior = (int) str_replace(['weight', 'gr'], '', $key); break; } } if (!$gramajePapelInterior) { return $this->respond([ 'status' => 400, 'message' => 'Gramaje del papel no válido.' ]); } // 3. Encuadernación // Tapa dura $tapaDura = isset($producto->cover->type->tapadura) && $producto->cover->type->tapadura == '1'; // Solapas $solapas = isset($producto->cover->type->consolapas) && $producto->cover->type->consolapas == '1'; // Doble cara (a veces se activa con tapa dura) una cara => 2; dos caras => 4 $doscara = false; // Tipo de encuadernado $encuadernadoId = null; if (isset($producto->cover->coverType->SoftCover) && $producto->cover->coverType->SoftCover == '1') { if ($tapaDura) { $encuadernadoId = 1; // Libro fresado tapa dura $doscara = true; } else { $encuadernadoId = 2; // Libro fresado tapa blanda } } elseif (isset($producto->cover->coverType->SaddleStitch) && $producto->cover->coverType->SaddleStitch == '1') { if ($tapaDura) { $encuadernadoId = 3; // Libro cosido tapa dura $doscara = true; } else { $encuadernadoId = $solapas ? 20 : 4; // Libro cosido tapa blanda (solapas) : (sin solapas) } } elseif (isset($producto->cover->coverType->CoilBinding) && $producto->cover->coverType->CoilBinding == '1') { if ($tapaDura) { $encuadernadoId = 5; // Libro espiral tapa dura $doscara = true; } else { $encuadernadoId = 6; // Libro espiral tapa blanda } } if (!$encuadernadoId) { return $this->respond([ 'status' => 400, 'message' => 'Tipo de encuadernación no identificado.' ]); } // Determinar el acabado de la cubierta $acabadoId = null; if (isset($producto->cover->acabado->brillo) && $producto->cover->acabado->brillo == '1') { $acabadoId = 1; // Plastificado brillo 1/c } elseif (isset($producto->cover->acabado->mate) && $producto->cover->acabado->mate == '1') { $acabadoId = 2; // Plastificado mate 1/c } else { return $this->respond([ 'status' => 400, 'message' => 'Tipo de acabado de cubierta no definido.' ]); } // 4. ENVÍO: recuperamos la primera dirección del cliente BUBOK (ID 40) $clienteDireccionModel = model('App\Models\Clientes\ClienteDireccionesModel'); $direccionCliente = $clienteDireccionModel ->where('cliente_id', 40) ->orderBy('id', 'asc') ->first(); if (!$direccionCliente) { return $this->respond([ 'status' => 400, 'message' => 'El cliente Bubok no tiene direcciones asociadas.' ]); } $direcciones = [ [ 'direccion' => [ 'id' => (int) $direccionCliente->id, 'cliente_id' => (int) $direccionCliente->cliente_id, 'cliente_nombre' => $direccionCliente->clienteNombre, 'att' => $direccionCliente->persona_contacto ?? '', 'alias' => $direccionCliente->alias ?? '', 'email' => $direccionCliente->email ?? '', 'direccion' => $direccionCliente->direccion, 'pais_id' => (int) $direccionCliente->pais_id, 'pais' => $direccionCliente->paisNombre, 'municipio' => $direccionCliente->municipio, 'provincia' => $direccionCliente->provincia, 'cp' => $direccionCliente->cp, 'telefono' => $direccionCliente->telefono, ], 'unidades' => $tirada, 'entregaPalets' => false ] ]; // Recalcular calidad (isColor y isHq) en funcion del cliente [$isColor, $isHq] = PresupuestoService::getCalidad( 'importador-bubok', null, ((trim(strtolower($interiorTipo)) === 'color') ? 1 : 0), 0, intval($tirada ?? 0) ); // Generamos el objeto a importar $dataToImport = [ 'selectedTirada' => $tirada, 'datosCabecera' => [ 'titulo' => $titulo, 'autor' => null, 'isbn' => null, 'coleccion' => null, 'referenciaCliente' => $refCliente ], 'tirada' => [$tirada], 'tamanio' => [ 'ancho' => $ancho, 'alto' => $alto ], 'tipo' => '', 'tipo_presupuesto_id' => $encuadernadoId, 'clienteId' => 40, // BUBOK ID 'isColor' => $isColor, 'isHq' => $isHq, 'paginas' => $paginas, 'paginasColor' => ($interiorTipo === 'color') ? $paginas : 0, 'paginasCuadernillo' => 32, 'interior' => [ 'papelInterior' => $papelInteriorId, 'gramajeInterior' => $gramajePapelInterior ], 'cubierta' => [ 'papelCubierta' => 2, // 'EST2' 'carasCubierta' => $doscara ? 2 : 4, 'gramajeCubierta' => in_array($encuadernadoId, [1, 3]) ? 150 : 300, // 150 gramos para "fresado tapa dura" y "cosido tapa dura" 'solapas' => !empty($producto->cover->type->consolapas) ? 80 : 0, 'acabado' => $acabadoId, 'cabezada' => 'WHI', 'lomoRedondo' => 0 ], 'guardas' => [], 'sobrecubierta' => [], 'faja' => null, 'direcciones' => $direcciones, 'ivaReducido' => 1, ]; /*return $this->respond([ 'status' => 400, 'message' => $dataToImport, 'interiorTipo' => $interiorTipo, 'isColor' => $isColor ]);*/ // 5. Guardar try { $presupuestocliente = new Presupuestocliente(); $response = $presupuestocliente->guardar($dataToImport); // Guardar la URL de la portada y el cuerpo en los comentarios del presupuesto $presupuestoModel = model('App\Models\Presupuestos\PresupuestoModel'); $presupuestoModel->update($response['sk_id'], [ 'comentarios_safekat' => 'URL COVER: ' . $producto->cover->file . "\nURL BODY: " . $producto->body->file, ]); // Ajuste del precio $precio_compra = $json->producto->prices->unitPrice ?? null; if ($precio_compra != null && $precio_compra > 0) { $respuesta_ajuste = PresupuestoService::ajustarPresupuesto( $response['sk_id'], $precio_compra, $tirada, null, true ); if ($respuesta_ajuste['warning'] == true) { $response['price_warning'] = [ 'new_precio_unidad' => $respuesta_ajuste['new_precio_unidad'], 'new_total' => $respuesta_ajuste['new_total'], ]; } } // confirmar y crear pedido y ot $presupuestoModel->confirmarPresupuesto($response['sk_id']); PresupuestoService::crearPedido($response['sk_id'], isImported: true); if (!isset($response['sk_id'])) { return $this->respond([ 'status' => 400, 'error' => 'Missing sk_id', 'message' => 'No se pudo crear el presupuesto.' ], 400); } return $this->respond([ 'status' => 200, 'data' => [ 'sk_id' => $response['sk_id'], 'sk_url' => $response['sk_url'] ?? null ] ]); } catch (\Throwable $e) { return $this->respond([ 'status' => 500, 'error' => 'Server error', 'message' => 'Error inesperado', 'debug' => $e->getMessage() ]); } } }