Path: C:\
<?php
header('Content-Type: application/json; charset=utf-8');
// Tenta requerer o autoload (se rodaram composer install localmente)
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
require __DIR__ . '/vendor/autoload.php';
} else {
// Se não encontrou, confiar que o servidor carrega globalmente ou lançar aviso claro
if (!class_exists('\PhpOffice\PhpSpreadsheet\IOFactory')) {
echo json_encode(['status' => 'error', 'message' => "ERRO DO SERVIDOR: PhpSpreadsheet não foi carregado.\nRode 'composer install' na pasta Transvoyant-manual ou verifique a instalação global."]);
exit;
}
}
use PhpOffice\PhpSpreadsheet\IOFactory;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Requisição inválida.']);
exit;
}
if (!isset($_FILES['csv_file']) || $_FILES['csv_file']['error'] !== UPLOAD_ERR_OK) {
echo json_encode(['status' => 'error', 'message' => 'Erro no upload do arquivo.']);
exit;
}
$tempPath = $_FILES['csv_file']['tmp_name'];
$originalName = $_FILES['csv_file']['name'];
try {
// 1. LÊ as linhas do CSV manualmente para ter mais controle igual ao Pandas
$fileData = file_get_contents($tempPath);
// Tenta arrumar encoding se vier em ANSI (Windows-1252/latin1)
if (!mb_check_encoding($fileData, 'UTF-8')) {
$fileData = utf8_encode($fileData); // Fallback legado suportado
}
// Identificar Delimitador pela primeira linha
$lines = explode("\n", str_replace("\r", "", trim($fileData)));
if (count($lines) == 0) {
throw new Exception("O arquivo CSV está vazio.");
}
$headerLine = $lines[0];
$delimiter = ';';
if (substr_count($headerLine, ';') < substr_count($headerLine, ',')) {
$delimiter = ',';
}
$headers = str_getcsv($headerLine, $delimiter);
// Mapeamento de índices do cabeçalho
$idx = [];
foreach ($headers as $i => $col) {
$idx[trim($col)] = $i;
}
// Regras e verificações de colunas vitais
$hasCte = isset($idx['Tomador CT-e']);
$hasMin = isset($idx['Tomador Minuta']);
if (!$hasCte && !$hasMin) {
throw new Exception("Nenhuma das colunas de Tomador ('Tomador CT-e' ou 'Tomador Minuta') foi encontrada no CSV.");
}
// Processamento linha a linha
$linhasValidas = [];
$notasDescartadas = 0;
for ($i = 1; $i < count($lines); $i++) {
if (trim($lines[$i]) === '')
continue; // linha em branco
$row = str_getcsv($lines[$i], $delimiter);
// Completa as colunas faltantes com vazio se a linha estiver quebrada
while (count($row) < count($headers)) {
$row[] = '';
}
$passouFirmenich = false;
$temDSM = false;
// Verifica FIRMENICH
if ($hasCte && stripos($row[$idx['Tomador CT-e']], 'FIRMENICH') !== false)
$passouFirmenich = true;
if ($hasMin && stripos($row[$idx['Tomador Minuta']], 'FIRMENICH') !== false)
$passouFirmenich = true;
// Verifica se possui DSM
if ($hasCte && stripos($row[$idx['Tomador CT-e']], 'DSM') !== false)
$temDSM = true;
if ($hasMin && stripos($row[$idx['Tomador Minuta']], 'DSM') !== false)
$temDSM = true;
if ($passouFirmenich) {
// Verifica as Datas
$dtSaidaCte = isset($idx['Dt. Saída - CTE']) ? trim($row[$idx['Dt. Saída - CTE']]) : '';
$dtSaidaMin = isset($idx['Dt. Saída - Minuta']) ? trim($row[$idx['Dt. Saída - Minuta']]) : '';
$validCteDate = ($dtSaidaCte !== '' && strtolower($dtSaidaCte) !== 'nan');
$validMinDate = ($dtSaidaMin !== '' && strtolower($dtSaidaMin) !== 'nan');
if (!$validCteDate && !$validMinDate && (isset($idx['Dt. Saída - CTE']) || isset($idx['Dt. Saída - Minuta']))) {
$notasDescartadas++;
continue; // Linha descartada
}
// Monta o objeto que vai pro excel
$linhasValidas[] = [
'Numero_pedido' => isset($idx['Número do pedido']) ? trim($row[$idx['Número do pedido']]) : '',
'Saida_CTE' => $dtSaidaCte,
'Saida_Minuta' => $dtSaidaMin,
'Entrega_CTE' => isset($idx['Dt. Entrega - CTE']) ? trim($row[$idx['Dt. Entrega - CTE']]) : '',
'Entrega_Minuta' => isset($idx['Dt. Entrega - Minuta']) ? trim($row[$idx['Dt. Entrega - Minuta']]) : '',
'Copia_Pedido_Remessa' => !$temDSM
];
}
}
// Checa se há dados
if (count($linhasValidas) === 0) {
$msg = "Nenhuma linha atendeu a todos os critérios (Tomador com Firmenich e possuir Data).";
if ($notasDescartadas > 0)
$msg .= "\n\nNota: Foram descartadas $notasDescartadas linhas com Firmenich por não terem Data de Saída.";
echo json_encode(['status' => 'warning', 'message' => $msg]);
exit;
}
// 2. ABRIR E PREENCHER O FORMATO DO TRANSVOYANT
$modeloPath = __DIR__ . '/Modelo-Transvoyant.xlsx';
if (!file_exists($modeloPath)) {
throw new Exception("Arquivo modelo não encontrado: Modelo-Transvoyant.xlsx não está na pasta no servidor.");
}
$spreadsheet = IOFactory::load($modeloPath);
$sheet = $spreadsheet->getActiveSheet();
// Limpa linhas após o cabeçalho se houver (o original já costumava vir limpo, max_row no phpSpreadsheet éHighestRow)
$highestRow = $sheet->getHighestRow();
if ($highestRow > 2) {
// Remover linhas seria complexo para as formatações nativas, então sobrescrevemos
// Nesse caso de uso prático, o openpyxl deletava. PhpSpreadsheet deleteRow:
$sheet->removeRow(3, $highestRow - 2);
}
$linhaDestino = 3;
$linhasEscritas = 0;
foreach ($linhasValidas as $dado) {
// A: Compañía
$sheet->setCellValue('A' . $linhaDestino, 'TRANS WAR TRANSPORTES LTDA');
// B: Número de entrega
$pedido = $dado['Numero_pedido'];
if (substr($pedido, -2) === '.0') {
$pedido = substr($pedido, 0, -2);
}
$pedidoFormatado = '';
if ($pedido !== '') {
// Preenche com zeros à esquerda até 10 dígitos
$pedidoFormatado = str_pad($pedido, 10, "0", STR_PAD_LEFT);
// Salva como texto explícito para o Excel manter os zeros
$sheet->setCellValueExplicit('B' . $linhaDestino, $pedidoFormatado, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);
}
// D: Numero de Remessa (Shipment Number)
if ($dado['Copia_Pedido_Remessa'] && $pedidoFormatado !== '') {
$sheet->setCellValueExplicit('D' . $linhaDestino, $pedidoFormatado, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);
}
// M: Momento da Coleta (Dt Saída - Minuta ou CTE)
$saida = ($dado['Saida_Minuta'] !== '' && strtolower($dado['Saida_Minuta']) !== 'nan') ? $dado['Saida_Minuta'] : $dado['Saida_CTE'];
if ($saida !== '' && strtolower($saida) !== 'nan')
$sheet->setCellValue('M' . $linhaDestino, $saida);
// U: Finalização (Dt Entrega - Minuta ou CTE)
$entrega = ($dado['Entrega_Minuta'] !== '' && strtolower($dado['Entrega_Minuta']) !== 'nan') ? $dado['Entrega_Minuta'] : $dado['Entrega_CTE'];
if ($entrega !== '' && strtolower($entrega) !== 'nan')
$sheet->setCellValue('U' . $linhaDestino, $entrega);
$linhaDestino++;
$linhasEscritas++;
}
// Gerar arquivo final formatado
$dataAtual = date("d-m-Y_H\hi");
$outputName = "Envio_Transvoyant_$dataAtual.xlsx";
$outputPath = __DIR__ . '/' . $outputName;
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save($outputPath);
// 3. ENVIO DO E-MAIL VIA SMTP DE ACORDO COM O CÓDIGO PYTHON
$emailSucesso = false;
$emailErroMsg = "";
try {
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtplw.com.br';
$mail->SMTPAuth = true;
$mail->Username = 'transwartransportes'; // Conforme o python original
$mail->Password = 'zvtsyiJL8214'; // Conforme o python original
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // Equivalente a .starttls() na porta 587
$mail->Port = 587;
$mail->CharSet = 'UTF-8';
$mail->setFrom('envioautomatico@transwar.com.br', 'Automação Transwar');
// Destinatários baseados no original
$destinatarios = [
// 'andressa.marozi@transwar.com.br',
// 'eliane.rodrigues@transwar.com.br',
'danilo.faria@transwar.com.br'
];
foreach ($destinatarios as $dest) {
$mail->addAddress($dest);
}
$mail->Subject = 'Relatório Transvoyant Processado';
$mail->Body = "Olá,\n\nSegue em anexo o arquivo para integração Transvoyant.\n\nAtenciosamente,\nAutomação Transwar";
// Anexo Excel
$mail->addAttachment($outputPath, $outputName);
$mail->send();
$emailSucesso = true;
} catch (Exception $e) {
$emailErroMsg = $mail->ErrorInfo ?: $e->getMessage();
}
// Retorno do resultado Final
$sucesso_msg = "SISTEMA CONCLUÍDO COM SUCESSO!\n\nArquivo configurado: $outputName\nLinhas Preenchidas: $linhasEscritas.\n";
if ($notasDescartadas > 0) {
$sucesso_msg .= "Aviso: $notasDescartadas Notas foram detectadas porém descartadas devido à falta de Data de Saída.\n";
}
if ($emailSucesso) {
$sucesso_msg .= "\n[✓] O E-MAIL FOI ENVIADO para os destinatários cadastrados!";
} else {
$sucesso_msg .= "\n[x] ALERTA DE E-MAIL: O Excel foi criado e salvo no servidor, mas falhamos ao enviar o e-mail.\nErro: $emailErroMsg";
}
echo json_encode(['status' => 'success', 'message' => $sucesso_msg]);
} catch (Exception $e) {
echo json_encode(['status' => 'error', 'message' => 'Erro Crítico no Servidor: ' . $e->getMessage()]);
}
?>