false, 'error' => 'Não autenticado']); exit; } $input = json_decode(file_get_contents('php://input'), true); if (!isset($input['obra_id']) || !isset($input['bc_tipo']) || !isset($input['dados'])) { http_response_code(400); echo json_encode(['success' => false, 'error' => 'Parâmetros em falta']); exit; } $obra_id = intval($input['obra_id']); $bc_tipo = preg_replace('/[^a-z_]/', '', strtolower($input['bc_tipo'])); $bc_index = intval($input['bc_index'] ?? 1); $dados = $input['dados']; $tiposValidos = ['portail', 'pergola', 'porte_garage', 'clotures', 'garde_corps']; if (!in_array($bc_tipo, $tiposValidos)) { http_response_code(400); echo json_encode(['success' => false, 'error' => 'Tipo de BC inválido']); exit; } try { $pdo = new PDO( 'mysql:host=localhost;dbname=metalpt_producao;charset=utf8mb4', 'metalpt_admin', 'PVC_gab2', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] ); // Verificar acesso do cliente à obra $stmtClientes = $pdo->prepare(" SELECT cliente FROM users_clientes_acesso WHERE user_id = ? AND ativo = 1 "); $stmtClientes->execute([$_SESSION['cliente_id']]); $clientesAssociados = $stmtClientes->fetchAll(PDO::FETCH_COLUMN); if (empty($clientesAssociados)) { echo json_encode(['success' => false, 'error' => 'Sem acesso']); exit; } $placeholders = implode(',', array_fill(0, count($clientesAssociados), '?')); $paramsObra = array_merge([$obra_id, 'S/ BC'], $clientesAssociados); $stmtObra = $pdo->prepare(" SELECT ga.id, ga.cliente, ga.referencia, ga.po, ga.pon, ga.pg, ga.clo, ga.gc, ga.per, ga.carp FROM gestao_admi ga WHERE ga.id = ? AND ga.est_orca = ? AND ga.cliente IN ($placeholders) "); $stmtObra->execute($paramsObra); $obra = $stmtObra->fetch(PDO::FETCH_ASSOC); if (!$obra) { echo json_encode(['success' => false, 'error' => 'Obra não encontrada ou já processada']); exit; } // Guardar ou atualizar BC $stmtCheck = $pdo->prepare(" SELECT id FROM bcs_submetidos WHERE obra_id = ? AND bc_tipo = ? AND bc_index = ? "); $stmtCheck->execute([$obra_id, $bc_tipo, $bc_index]); $existente = $stmtCheck->fetch(); $dadosJson = json_encode($dados, JSON_UNESCAPED_UNICODE); if ($existente) { $pdo->prepare(" UPDATE bcs_submetidos SET dados_json = ?, data_submissao = NOW() WHERE id = ? ")->execute([$dadosJson, $existente['id']]); } else { $pdo->prepare(" INSERT INTO bcs_submetidos (obra_id, bc_tipo, bc_index, dados_json, cliente, referencia) VALUES (?, ?, ?, ?, ?, ?) ")->execute([$obra_id, $bc_tipo, $bc_index, $dadosJson, $obra['cliente'], $obra['referencia']]); } // Calcular BCs necessários e verificar se todos estão prontos $bcsNecessarios = calcularBCsNecessarios($obra); $totalBCs = count($bcsNecessarios); $stmtSubmetidos = $pdo->prepare("SELECT bc_tipo, bc_index FROM bcs_submetidos WHERE obra_id = ?"); $stmtSubmetidos->execute([$obra_id]); $submetidos = $stmtSubmetidos->fetchAll(PDO::FETCH_ASSOC); $submetidosMap = []; foreach ($submetidos as $s) { $submetidosMap[$s['bc_tipo'] . '_' . $s['bc_index']] = true; } $todosProntos = true; foreach ($bcsNecessarios as $bc) { if (!isset($submetidosMap[$bc['tipo'] . '_' . $bc['index']])) { $todosProntos = false; break; } } $prontos = count($submetidos); $restantes = max(0, $totalBCs - $prontos); if (!$todosProntos) { echo json_encode([ 'success' => true, 'completo' => false, 'prontos' => $prontos, 'total' => $totalBCs, 'restantes' => $restantes, 'message' => "BC enregistré ({$prontos}/{$totalBCs}). Il reste {$restantes} BC(s) à remplir." ]); exit; } // ===== TODOS OS BCS PRONTOS ===== // Gerar tokens de acesso para ver BCs online $baseUrl = 'https://alu.metal13.pt'; $links = []; $pdfPaths = []; $nomesTipo = [ 'portail' => 'BC Portail', 'pergola' => 'BC Pergola', 'porte_garage' => 'BC Porte de Garage', 'clotures' => 'BC Clôtures', 'garde_corps' => 'BC Garde-Corps', ]; // Apagar tokens antigos $pdo->prepare("DELETE FROM bc_tokens_acesso WHERE obra_id = ?")->execute([$obra_id]); // Criar pasta da obra para BCs $clienteLimpo = preg_replace('/[^A-Za-z0-9_\-]/', '_', iconv('UTF-8', 'ASCII//TRANSLIT', $obra['cliente'])); $refLimpa = preg_replace('/[^A-Za-z0-9_\-]/', '_', iconv('UTF-8', 'ASCII//TRANSLIT', $obra['referencia'])); $pastaBCs = __DIR__ . '/../uploads/encomendas/' . $clienteLimpo . '/' . $refLimpa . '/bcs/'; if (!is_dir($pastaBCs)) { mkdir($pastaBCs, 0755, true); } foreach ($bcsNecessarios as $bc) { $token = bin2hex(random_bytes(32)); $pdo->prepare(" INSERT INTO bc_tokens_acesso (token, obra_id, bc_tipo, bc_index) VALUES (?, ?, ?, ?) ")->execute([$token, $obra_id, $bc['tipo'], $bc['index']]); $urlVer = $baseUrl . '/bc_ver_preenchido.php' . '?token=' . urlencode($token) . '&obra_id=' . $obra_id . '&bc_tipo=' . urlencode($bc['tipo']) . '&bc_index=' . $bc['index']; $label = $nomesTipo[$bc['tipo']] ?? $bc['tipo']; if (count(array_filter($bcsNecessarios, fn($b) => $b['tipo'] === $bc['tipo'])) > 1) { $label .= ' n°' . $bc['index']; } $links[] = ['label' => $label, 'url' => $urlVer, 'token' => $token, 'tipo' => $bc['tipo'], 'index' => $bc['index']]; } // Gerar PDFs com Puppeteer $nodePath = 'node'; $scriptPath = __DIR__ . '/../gerar_pdf_bc.js'; foreach ($links as &$link) { $nomePDF = 'BC_' . strtoupper($link['tipo']) . '_' . $link['index'] . '_' . $refLimpa . '.pdf'; $pathPDF = $pastaBCs . $nomePDF; $cmd = escapeshellcmd($nodePath) . ' ' . escapeshellarg($scriptPath) . ' ' . escapeshellarg($link['url']) . ' ' . escapeshellarg($pathPDF) . ' 2>&1'; $output = shell_exec($cmd); if (file_exists($pathPDF) && filesize($pathPDF) > 0) { $link['pdf_path'] = $pathPDF; $link['pdf_nome'] = $nomePDF; } else { error_log('Puppeteer falhou para ' . $link['tipo'] . ': ' . $output); $link['pdf_path'] = null; } } unset($link); // Mudar estatuto para S/ OR $pdo->prepare("UPDATE gestao_admi SET est_orca = 'S/ OR' WHERE id = ?")->execute([$obra_id]); // Enviar email enviarEmailBC($obra, $links, $mailDisponivel); echo json_encode([ 'success' => true, 'completo' => true, 'message' => 'Tous les BCs ont été envoyés avec succès!' ]); } catch (Throwable $e) { http_response_code(500); echo json_encode(['success' => false, 'error' => $e->getMessage()]); } // ============================================================ function calcularBCsNecessarios($obra) { $bcs = []; $qtdPO = intval($obra['po'] ?? 0); $qtdPON = intval($obra['pon'] ?? 0); if ($qtdPO > 0 || $qtdPON > 0) { $idx = 1; $poR = $qtdPO; $ponR = $qtdPON; while ($poR > 0 || $ponR > 0) { $bc = ['tipo' => 'portail', 'index' => $idx]; if ($poR > 0) { $bc['tem_po'] = true; $poR--; } if ($ponR > 0) { $bc['tem_pon'] = true; $ponR--; } $bcs[] = $bc; $idx++; } } $total = intval($obra['per'] ?? 0) + intval($obra['carp'] ?? 0); for ($i = 1; $i <= $total; $i++) $bcs[] = ['tipo' => 'pergola', 'index' => $i]; $qtdPG = intval($obra['pg'] ?? 0); for ($i = 1; $i <= $qtdPG; $i++) $bcs[] = ['tipo' => 'porte_garage', 'index' => $i]; if (intval($obra['clo'] ?? 0) > 0) $bcs[] = ['tipo' => 'clotures', 'index' => 1]; if (intval($obra['gc'] ?? 0) > 0) $bcs[] = ['tipo' => 'garde_corps', 'index' => 1]; return $bcs; } function enviarEmailBC($obra, $links, $mailDisponivel) { if (!$mailDisponivel) { error_log('PHPMailer não disponível — email não enviado'); return; } $mail = new PHPMailer(true); try { $mail->CharSet = 'UTF-8'; $mail->isSMTP(); $mail->Host = 'mail.metal13.pt'; $mail->SMTPAuth = true; $mail->Username = 'noreply@metal13.pt'; $mail->Password = 'PVC_gab2'; $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; $mail->Port = 465; $mail->setFrom('noreply@metal13.pt', 'METAL13 - Portal Cliente'); $mail->addAddress('producao@metal13.pt', 'METAL13'); $ref = htmlspecialchars($obra['referencia'] ?? ''); $cliente = htmlspecialchars($obra['cliente'] ?? ''); $mail->Subject = 'Bons de Commande submetidos - ' . $ref . ' - ' . $cliente; $mail->isHTML(true); // Anexar PDFs $temPDFs = false; foreach ($links as $l) { if (!empty($l['pdf_path']) && file_exists($l['pdf_path'])) { $mail->addAttachment($l['pdf_path'], $l['pdf_nome']); $temPDFs = true; } } $linksHtml = ''; foreach ($links as $l) { $linksHtml .= ' ' . htmlspecialchars($l['label']) . ' Ver online '; } $pdfInfo = $temPDFs ? '

✅ Os PDFs estão em anexo neste email.

' : '

⚠️ Não foi possível gerar os PDFs automaticamente. Use os links abaixo.

'; $mail->Body = "

Bons de Commande Submetidos

O cliente {$cliente} submeteu os Bons de Commande para a referência {$ref}.

{$pdfInfo}

Links para ver online:

{$linksHtml}
Documento Ação

O estatuto da obra foi atualizado para S/ OR.

METALGEST - " . date('d/m/Y H:i') . "
"; $mail->send(); } catch (Throwable $e) { error_log('Email BC erro: ' . $e->getMessage()); } } ?>