| 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/clients/client1/seaside.pacim.de/web/ |
Upload File : |
<?php
/**
* broker-api.php – API für das Vermittler-/Reisebüro-Portal. Strikt broker-scoped:
* nur eingeloggte Vermittler (is_broker), Daten immer auf den eigenen Account begrenzt.
*
* action=events GET -> { ok, events:[{title,begin,end}] } (kommende, aktive)
* action=products GET -> { ok, products:[{id,title,net,gross}] } (Zusatzleistungen)
* action=quote POST type,begin,end,products[] -> { ok, quote:{...} } (Preis/Provision-Vorschau)
* action=create POST <Buchungsfelder> -> { ok, invoice_id, booking_id, booking_no }
*/
require_once( __DIR__ . '/includes/config.inc.php' );
@ini_set( 'display_errors', '0' );
error_reporting( 0 );
ob_start();
function ba_json( $a ) { while ( ob_get_level() > 0 ) ob_end_clean(); header( 'Content-Type: application/json; charset=utf-8' ); echo json_encode( $a ); exit(); }
if ( ! function_exists( 'is_broker' ) || ! is_broker() ) {
http_response_code( 403 );
ba_json( array( 'ok' => false, 'error' => 'forbidden' ) );
}
$brokerId = current_broker_id();
$action = isset( $_GET['action'] ) ? $_GET['action'] : ( isset( $_POST['action'] ) ? $_POST['action'] : '' );
$db = new MysqliDb( MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB );
/* ---------------- Events (Schiffe/Termine) ---------------- */
if ( $action === 'events' ) {
$rows = $db->rawQuery(
"SELECT event_calendar_title AS title,
DATE_FORMAT(event_calendar_begin, '%Y-%m-%d') AS begin,
DATE_FORMAT(event_calendar_end, '%Y-%m-%d') AS end
FROM pacim_events
WHERE event_calendar_active = 1
AND event_calendar_begin >= CURDATE() - INTERVAL 1 DAY
ORDER BY event_calendar_begin ASC
LIMIT 400"
);
ba_json( array( 'ok' => true, 'events' => $rows ? $rows : array() ) );
}
/* ---------------- Zusatzleistungen ---------------- */
if ( $action === 'products' ) {
$year = (int) date( 'Y' );
// bookbare Zusatzleistungen (ohne reine Parkplatzprodukte 1/2 und ohne 0-Preis-Platzhalter)
$rows = $db->rawQuery(
"SELECT p.product_id AS id, p.product_title AS title,
COALESCE((SELECT pp.price FROM pacim_product_prices pp WHERE pp.product_id=p.product_id AND pp.year=? LIMIT 1), p.product_price) AS net
FROM pacim_products p
WHERE p.product_id NOT IN (1,2)
ORDER BY p.product_id",
array( $year )
);
$out = array();
foreach ( (array) $rows as $r ) {
$net = (float) $r['net'];
if ( $net <= 0 ) continue; // Platzhalter/0-Preis-Produkte ausblenden
$out[] = array( 'id' => (int) $r['id'], 'title' => $r['title'], 'net' => round( $net, 2 ), 'gross' => round( $net * 1.19, 2 ) );
}
ba_json( array( 'ok' => true, 'products' => $out ) );
}
/* ---------------- Preis-/Provisionsvorschau ---------------- */
if ( $action === 'quote' ) {
$q = bookingservice::quote( array(
'type' => (int) ( $_POST['type'] ?? 1 ),
'begin' => (string) ( $_POST['begin'] ?? '' ),
'end' => (string) ( $_POST['end'] ?? '' ),
'products' => isset( $_POST['products'] ) ? (array) $_POST['products'] : array(),
'brokerId' => $brokerId,
) );
ba_json( array( 'ok' => true, 'quote' => $q ) );
}
/* ---------------- Buchung anlegen ---------------- */
if ( $action === 'create' ) {
$res = bookingservice::create( array(
'brokerId' => $brokerId,
'customer' => array(
'gender' => (int) ( $_POST['customer_gender'] ?? 1 ),
'firstname' => (string) ( $_POST['customer_firstname'] ?? '' ),
'lastname' => (string) ( $_POST['customer_lastname'] ?? '' ),
'street' => (string) ( $_POST['customer_street'] ?? '' ),
'zipcode' => (string) ( $_POST['customer_zipcode'] ?? '' ),
'city' => (string) ( $_POST['customer_city'] ?? '' ),
'country' => (string) ( $_POST['customer_country'] ?? 'Deutschland' ),
'phone' => (string) ( $_POST['customer_phone'] ?? '' ),
'email' => (string) ( $_POST['customer_email'] ?? '' ),
),
'plate' => (string) ( $_POST['plate'] ?? '' ),
'event' => (string) ( $_POST['event'] ?? '' ),
'begin' => (string) ( $_POST['begin'] ?? '' ),
'end' => (string) ( $_POST['end'] ?? '' ),
'type' => (int) ( $_POST['type'] ?? 1 ),
'products' => isset( $_POST['products'] ) ? (array) $_POST['products'] : array(),
'guests' => (int) ( $_POST['guests'] ?? 0 ),
'hint' => (string) ( $_POST['hint'] ?? '' ), // Partner-Hinweis zur Buchung (Freitext)
) );
ba_json( $res );
}
/* ---------------- Eigene Buchungen ---------------- */
if ( $action === 'bookings' ) {
$rows = $db->rawQuery(
"SELECT d.invoice_id, b.booking_id, b.booking_no, b.booking_event,
DATE_FORMAT(b.booking_begin, '%d.%m.%Y') AS begin, DATE_FORMAT(b.booking_end, '%d.%m.%Y') AS end,
b.booking_begin AS begin_raw, b.booking_type, b.booking_serial, b.booking_hint,
TRIM(CONCAT(COALESCE(c.customer_lastname,''),', ',COALESCE(c.customer_firstname,''))) AS customer,
d.invoice_no, d.invoice_payment, d.invoice_status, d.invoice_broker_commission,
COALESCE(d.invoice_broker_commission_addon, d.invoice_broker_commission) AS rate_addon,
DATE_FORMAT(d.invoice_datetime,'%d.%m.%Y') AS created,
(SELECT SUM(p.invoice_pos_price*p.invoice_pos_quantity*1.19) FROM pacim_invoice_pos p WHERE p.invoice_id=d.invoice_id) AS gross,
" . broker_commission_sql( 'd' ) . " AS commission
FROM pacim_invoice d
JOIN pacim_booking b ON b.booking_invoice = d.invoice_id
LEFT JOIN pacim_customer c ON c.customer_id = b.booking_customer
WHERE d.invoice_broker = ?
GROUP BY d.invoice_id
ORDER BY d.invoice_datetime DESC, d.invoice_id DESC",
array( $brokerId )
);
$out = array();
foreach ( (array) $rows as $r ) {
$gross = (float) $r['gross'];
$rate = (float) $r['invoice_broker_commission'];
$storno = ( (int) $r['invoice_status'] === 3 );
$out[] = array(
'invoice_id' => (int) $r['invoice_id'], 'booking_no' => $r['booking_no'], 'event' => $r['booking_event'],
'begin' => $r['begin'], 'end' => $r['end'], 'begin_raw' => $r['begin_raw'],
'type' => ( (int) $r['booking_type'] === 2 ? 'Außen' : 'Halle' ), 'plate' => $r['booking_serial'],
'customer' => $r['customer'], 'created' => $r['created'], 'hint' => (string) ( $r['booking_hint'] ?? '' ),
'gross' => round( $gross, 2 ), 'rate' => $rate, 'addon_rate' => (float) $r['rate_addon'], 'commission' => $storno ? 0.0 : round( (float) $r['commission'], 2 ),
'paid' => ( (int) $r['invoice_payment'] > 0 && (int) $r['invoice_payment'] != 4 ),
'storno' => $storno, 'cancelled' => $storno, 'status' => ( $storno ? 'cancelled' : 'active' ),
'comm_status' => broker_commission_status( $r['begin_raw'], $r['invoice_status'] ),
);
}
ba_json( array( 'ok' => true, 'bookings' => $out ) );
}
/* ---------------- Hinweis einer eigenen Buchung ändern ---------------- */
/* Partner darf NUR den Hinweis (booking_hint) seiner EIGENEN Buchungen anpassen. */
if ( $action === 'booking-hint' ) {
$bid = (int) ( $_POST['booking_id'] ?? 0 );
if ( $bid <= 0 ) ba_json( array( 'ok' => false, 'error' => 'booking_id fehlt.' ) );
// Eigentum prüfen: Buchung muss zur Rechnung eines eigenen (invoice_broker = brokerId) Vorgangs gehören.
$own = $db->rawQueryOne(
"SELECT b.booking_id FROM pacim_booking b JOIN pacim_invoice d ON d.invoice_id = b.booking_invoice
WHERE b.booking_id = ? AND d.invoice_broker = ? LIMIT 1", array( $bid, $brokerId ) );
if ( ! $own ) ba_json( array( 'ok' => false, 'error' => 'Kein Zugriff auf diese Buchung.' ) );
$db->where( 'booking_id', $bid );
$db->update( 'pacim_booking', array( 'booking_hint' => trim( (string) ( $_POST['hint'] ?? '' ) ) ) );
ba_json( array( 'ok' => true, 'booking_id' => $bid ) );
}
/* ---------------- Provisionsübersicht (Summen) ---------------- */
if ( $action === 'commission' ) {
$rows = $db->rawQuery(
"SELECT d.invoice_id, b.booking_no, b.booking_event, DATE_FORMAT(d.invoice_datetime,'%Y-%m') AS ym,
DATE_FORMAT(d.invoice_datetime,'%d.%m.%Y') AS created, d.invoice_broker_commission AS rate, d.invoice_status,
MIN(b.booking_begin) AS begin_raw,
COALESCE(d.invoice_broker_commission_addon, d.invoice_broker_commission) AS rate_addon,
(SELECT SUM(p.invoice_pos_price*p.invoice_pos_quantity*1.19) FROM pacim_invoice_pos p WHERE p.invoice_id=d.invoice_id) AS gross,
" . broker_commission_sql( 'd' ) . " AS commission
FROM pacim_invoice d JOIN pacim_booking b ON b.booking_invoice=d.invoice_id
WHERE d.invoice_broker = ?
GROUP BY d.invoice_id ORDER BY d.invoice_datetime DESC",
array( $brokerId )
);
$list = array(); $totalGross = 0.0; $totalComm = 0.0; $months = array();
$sumReleased = 0.0; $sumPending = 0.0; $cntReleased = 0; $cntPending = 0; $cntCancelled = 0;
foreach ( (array) $rows as $r ) {
$gross = (float) $r['gross']; $rate = (float) $r['rate'];
$status = broker_commission_status( $r['begin_raw'], $r['invoice_status'] ); // released | pending | cancelled
$comm = ( $status === 'cancelled' ) ? 0.0 : round( (float) $r['commission'], 2 );
$list[] = array( 'booking_no' => $r['booking_no'], 'event' => $r['booking_event'], 'created' => $r['created'], 'gross' => round($gross,2), 'rate' => $rate, 'addon_rate' => (float) $r['rate_addon'], 'commission' => $comm, 'storno' => ($status==='cancelled'), 'status' => $status );
$totalGross += $gross;
if ( $status === 'released' ) { $sumReleased += $comm; $cntReleased++; }
elseif ( $status === 'pending' ) { $sumPending += $comm; $cntPending++; }
else { $cntCancelled++; }
$totalComm = $sumReleased + $sumPending; // storniert zählt NICHT
if ( $status !== 'cancelled' ) { if ( ! isset( $months[ $r['ym'] ] ) ) $months[ $r['ym'] ] = 0.0; $months[ $r['ym'] ] += $comm; }
}
ba_json( array( 'ok' => true, 'list' => $list, 'totalGross' => round($totalGross,2), 'totalCommission' => round($totalComm,2), 'count' => count($list), 'months' => $months, 'addon_enabled' => broker_addon_enabled(),
'released' => round($sumReleased,2), 'pending' => round($sumPending,2), 'cnt_released' => $cntReleased, 'cnt_pending' => $cntPending, 'cnt_cancelled' => $cntCancelled ) );
}
/* ---------------- Stammdaten (lesen) ---------------- */
if ( $action === 'me' ) {
$b = broker_record( $brokerId );
$u = $db->rawQueryOne( 'SELECT user_firstname, user_lastname, user_email FROM pacim_users WHERE user_id = ?', array( $brokerId ) );
ba_json( array( 'ok' => true,
'user' => $u ? $u : array(),
'broker' => $b ? $b : new stdClass(),
'commission_rate' => broker_commission_rate( $brokerId ),
'commission_addon_rate' => broker_commission_addon_rate( $brokerId ),
'addon_enabled' => broker_addon_enabled(),
) );
}
/* ---------------- Persönliche Daten speichern ---------------- */
if ( $action === 'profile-save' ) {
$now = date( 'Y-m-d H:i:s' );
// pacim_users (Name)
$db->where( 'user_id', $brokerId );
$db->update( 'pacim_users', array(
'user_firstname' => trim( (string) ( $_POST['firstname'] ?? '' ) ),
'user_lastname' => trim( (string) ( $_POST['lastname'] ?? '' ) ),
'user_updated' => $now,
) );
// pacim_broker (Firma/Anschrift/Kontakt) – Upsert
$fields = array(
'broker_company' => trim((string)($_POST['company'] ?? '')),
'broker_street' => trim((string)($_POST['street'] ?? '')),
'broker_zipcode' => trim((string)($_POST['zipcode'] ?? '')),
'broker_city' => trim((string)($_POST['city'] ?? '')),
'broker_country' => trim((string)($_POST['country'] ?? '')),
'broker_phone' => trim((string)($_POST['phone'] ?? '')),
'broker_taxid' => trim((string)($_POST['taxid'] ?? '')),
'broker_updated' => $now,
);
if ( broker_record( $brokerId ) ) { $db->where( 'broker_id', $brokerId ); $db->update( 'pacim_broker', $fields ); }
else { $fields['broker_id'] = $brokerId; $fields['broker_created'] = $now; $db->insert( 'pacim_broker', $fields ); }
ba_json( array( 'ok' => true ) );
}
/* ---------------- Bankverbindung speichern ---------------- */
if ( $action === 'bank-save' ) {
$now = date( 'Y-m-d H:i:s' );
$fields = array(
'broker_iban' => strtoupper( preg_replace( '/\s+/', '', (string) ( $_POST['iban'] ?? '' ) ) ),
'broker_bic' => strtoupper( trim( (string) ( $_POST['bic'] ?? '' ) ) ),
'broker_account_holder' => trim( (string) ( $_POST['account_holder'] ?? '' ) ),
'broker_updated' => $now,
);
if ( broker_record( $brokerId ) ) { $db->where( 'broker_id', $brokerId ); $db->update( 'pacim_broker', $fields ); }
else { $fields['broker_id'] = $brokerId; $fields['broker_created'] = $now; $db->insert( 'pacim_broker', $fields ); }
ba_json( array( 'ok' => true ) );
}
/* ---------------- API-Token (Partner-eigene Zugänge) ---------------- */
if ( $action === 'api-keys' ) {
ba_json( array( 'ok' => true, 'keys' => apikeys::allForBroker( $brokerId ), 'scopes' => apikeys::partnerScopes() ) );
}
if ( $action === 'api-key-create' ) {
$name = trim( (string) ( $_POST['name'] ?? '' ) );
if ( $name === '' ) ba_json( array( 'ok' => false, 'error' => 'Bitte einen Namen/Zweck angeben.' ) );
$res = apikeys::createForBroker( $name, $brokerId );
ba_json( $res ); // enthält bei Erfolg den EINMALIGEN Klartext-Token
}
if ( $action === 'api-key-toggle' ) {
$id = (int) ( $_POST['id'] ?? 0 );
apikeys::setActiveForBroker( $id, $brokerId, ! empty( $_POST['active'] ) ? 1 : 0 );
ba_json( array( 'ok' => true, 'active' => ! empty( $_POST['active'] ) ) );
}
if ( $action === 'api-key-delete' ) {
apikeys::deleteForBroker( (int) ( $_POST['id'] ?? 0 ), $brokerId );
ba_json( array( 'ok' => true ) );
}
http_response_code( 400 );
ba_json( array( 'ok' => false, 'error' => 'unknown_action' ) );