orders->findDetails($orderId); if ($details === null) { return ['success' => false, 'error' => 'Zamowienie nie znalezione', 'log_id' => 0]; } $order = is_array($details['order'] ?? null) ? $details['order'] : []; $addresses = is_array($details['addresses'] ?? null) ? $details['addresses'] : []; $template = $this->templates->findById($templateId); if ($template === null) { return ['success' => false, 'error' => 'Szablon nie znaleziony', 'log_id' => 0]; } $mailbox = $this->resolveMailbox($mailboxId, $template); if ($mailbox === null) { return ['success' => false, 'error' => 'Brak skonfigurowanej skrzynki SMTP', 'log_id' => 0]; } $recipientEmail = $recipientEmailOverride !== null && $recipientEmailOverride !== '' ? $recipientEmailOverride : $this->findRecipientEmail($addresses); if ($recipientEmail === '') { return ['success' => false, 'error' => 'Brak adresu e-mail odbiorcy', 'log_id' => 0]; } $recipientName = $recipientNameOverride !== null && $recipientNameOverride !== '' ? $recipientNameOverride : $this->findRecipientName($addresses); $companySettings = $this->loadCompanySettings(); $variableMap = $this->variableResolver->buildVariableMap($order, $addresses, $companySettings); $resolvedSubject = $this->variableResolver->resolve((string) ($template['subject'] ?? ''), $variableMap); $resolvedBody = $this->variableResolver->resolve((string) ($template['body_html'] ?? ''), $variableMap); $resolvedBody = $this->composeBody($resolvedBody, $mailbox, $variableMap); $attachments = []; $attachmentType = (string) ($template['attachment_1'] ?? ''); if ($attachmentType !== '') { $attachment = $this->attachmentGenerator->generate($attachmentType, $order); if ($attachment !== null) { $attachments[] = $attachment; } } $status = 'sent'; $errorMessage = null; $sentAt = null; try { $this->sendViaSMTP($mailbox, $recipientEmail, $recipientName, $resolvedSubject, $resolvedBody, $attachments); $sentAt = date('Y-m-d H:i:s'); } catch (Throwable $e) { $status = 'failed'; $errorMessage = $e->getMessage(); } $logId = $this->logEmail( $templateId, (int) ($mailbox['id'] ?? 0), $orderId, $recipientEmail, $recipientName, $resolvedSubject, $resolvedBody, $attachments, $status, $errorMessage, $sentAt ); $templateName = (string) ($template['name'] ?? ''); $activitySummary = $status === 'sent' ? 'Wyslano e-mail "' . $resolvedSubject . '" do ' . $recipientEmail : 'Blad wysylki e-mail "' . $resolvedSubject . '" do ' . $recipientEmail . ': ' . ($errorMessage ?? ''); $this->orders->recordActivity( $orderId, 'email_' . $status, $activitySummary, ['template' => $templateName, 'recipient' => $recipientEmail, 'log_id' => $logId], 'user', $actorName ); return [ 'success' => $status === 'sent', 'error' => $errorMessage, 'log_id' => $logId, ]; } /** * @return array{subject: string, body_html: string, attachments: list} */ public function preview(int $orderId, int $templateId): array { $details = $this->orders->findDetails($orderId); if ($details === null) { return ['subject' => '', 'body_html' => '

Zamowienie nie znalezione

', 'attachments' => []]; } $order = is_array($details['order'] ?? null) ? $details['order'] : []; $addresses = is_array($details['addresses'] ?? null) ? $details['addresses'] : []; $template = $this->templates->findById($templateId); if ($template === null) { return ['subject' => '', 'body_html' => '

Szablon nie znaleziony

', 'attachments' => []]; } $companySettings = $this->loadCompanySettings(); $variableMap = $this->variableResolver->buildVariableMap($order, $addresses, $companySettings); $resolvedSubject = $this->variableResolver->resolve((string) ($template['subject'] ?? ''), $variableMap); $resolvedBody = $this->variableResolver->resolve((string) ($template['body_html'] ?? ''), $variableMap); $mailbox = $this->resolveMailbox(null, $template); $resolvedBody = $this->composeBody($resolvedBody, $mailbox, $variableMap); $attachmentNames = []; $attachmentType = (string) ($template['attachment_1'] ?? ''); if ($attachmentType !== '') { $attachment = $this->attachmentGenerator->generate($attachmentType, $order); if ($attachment !== null) { $attachmentNames[] = $attachment['filename']; } } return [ 'subject' => $resolvedSubject, 'body_html' => $resolvedBody, 'attachments' => $attachmentNames, ]; } /** * @param array|null $mailbox * @param array $variableMap */ private function composeBody(string $resolvedBody, ?array $mailbox, array $variableMap): string { if ($mailbox === null) { return $resolvedBody; } $header = trim((string) ($mailbox['header_html'] ?? '')); $footer = trim((string) ($mailbox['footer_html'] ?? '')); if ($header !== '') { $header = $this->variableResolver->resolve($header, $variableMap); } if ($footer !== '') { $footer = $this->variableResolver->resolve($footer, $variableMap); } $parts = []; if ($header !== '') { $parts[] = $header; } $parts[] = $resolvedBody; if ($footer !== '') { $parts[] = $footer; } return implode("\n", $parts); } /** * @param array|null $template * @return array|null */ private function resolveMailbox(?int $mailboxId, ?array $template): ?array { if ($mailboxId !== null && $mailboxId > 0) { $mailbox = $this->mailboxes->findById($mailboxId); if ($mailbox !== null && (int) ($mailbox['is_active'] ?? 0) === 1) { return $mailbox; } } $templateMailboxId = (int) ($template['mailbox_id'] ?? 0); if ($templateMailboxId > 0) { $mailbox = $this->mailboxes->findById($templateMailboxId); if ($mailbox !== null && (int) ($mailbox['is_active'] ?? 0) === 1) { return $mailbox; } } $active = $this->mailboxes->listActive(); foreach ($active as $m) { if ((int) ($m['is_default'] ?? 0) === 1) { return $this->mailboxes->findById((int) $m['id']); } } return $active !== [] ? $this->mailboxes->findById((int) $active[0]['id']) : null; } /** * @param array> $addresses */ private function findRecipientEmail(array $addresses): string { foreach (['customer', 'delivery', 'invoice'] as $type) { foreach ($addresses as $addr) { if (($addr['address_type'] ?? '') === $type) { $email = trim((string) ($addr['email'] ?? '')); if ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL) !== false) { return $email; } } } } return ''; } /** * @param array> $addresses */ private function findRecipientName(array $addresses): string { foreach (['customer', 'delivery'] as $type) { foreach ($addresses as $addr) { if (($addr['address_type'] ?? '') === $type) { $name = trim((string) ($addr['name'] ?? '')); if ($name !== '') { return $name; } } } } return ''; } /** * @return array */ private function loadCompanySettings(): array { $stmt = $this->pdo->prepare('SELECT * FROM company_settings LIMIT 1'); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); return is_array($row) ? $row : []; } /** * @param array $mailbox * @param list $attachments */ private function sendViaSMTP( array $mailbox, string $recipientEmail, string $recipientName, string $subject, string $body, array $attachments ): void { $mail = new PHPMailer(true); $mail->isSMTP(); $mail->Host = (string) ($mailbox['smtp_host'] ?? ''); $mail->Port = (int) ($mailbox['smtp_port'] ?? 587); $mail->SMTPAuth = true; $mail->Username = (string) ($mailbox['smtp_username'] ?? ''); $mail->Password = (string) ($mailbox['smtp_password_decrypted'] ?? ''); $mail->CharSet = PHPMailer::CHARSET_UTF8; $encryption = (string) ($mailbox['smtp_encryption'] ?? 'tls'); if ($encryption === 'tls') { $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; } elseif ($encryption === 'ssl') { $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; } else { $mail->SMTPSecure = ''; $mail->SMTPAutoTLS = false; } $senderEmail = (string) ($mailbox['sender_email'] ?? $mailbox['smtp_username'] ?? ''); $senderName = (string) ($mailbox['sender_name'] ?? ''); $mail->setFrom($senderEmail, $senderName); $mail->addAddress($recipientEmail, $recipientName); $mail->isHTML(true); $mail->Subject = $subject; $mail->Body = $body; foreach ($attachments as $att) { $mail->addStringAttachment($att['content'], $att['filename'], PHPMailer::ENCODING_BASE64, $att['mime']); } $mail->send(); } /** * @param list $attachments */ private function logEmail( int $templateId, int $mailboxId, int $orderId, string $recipientEmail, string $recipientName, string $subject, string $bodyHtml, array $attachments, string $status, ?string $errorMessage, ?string $sentAt ): int { $attachmentsJson = []; foreach ($attachments as $att) { $attachmentsJson[] = [ 'name' => $att['filename'], 'type' => $att['mime'], ]; } $stmt = $this->pdo->prepare( 'INSERT INTO email_logs ( template_id, mailbox_id, order_id, recipient_email, recipient_name, subject, body_html, attachments_json, status, error_message, sent_at, created_at ) VALUES ( :template_id, :mailbox_id, :order_id, :recipient_email, :recipient_name, :subject, :body_html, :attachments_json, :status, :error_message, :sent_at, NOW() )' ); $stmt->execute([ 'template_id' => $templateId, 'mailbox_id' => $mailboxId, 'order_id' => $orderId, 'recipient_email' => $recipientEmail, 'recipient_name' => $recipientName, 'subject' => $subject, 'body_html' => $bodyHtml, 'attachments_json' => json_encode($attachmentsJson, JSON_UNESCAPED_UNICODE), 'status' => $status, 'error_message' => $errorMessage, 'sent_at' => $sentAt, ]); return (int) $this->pdo->lastInsertId(); } }