| 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 : |
<?php
/**
* partner-api.php – Admin-Verwaltung des Partnerprogramms (Vermittler/Reisebüros).
* Nur Admins (is_admin). Verwaltet pacim_users(level=BROKER_LEVEL) + pacim_broker,
* den globalen Provisions-Default und liefert Übersichten der vermittelten Buchungen.
*
* action=brokers GET -> { ok, default, brokers:[{...,bookings,commission_sum}] }
* action=get GET id -> { ok, broker:{user+broker} }
* action=save POST <felder> -> { ok, id } (anlegen/bearbeiten; pw optional)
* action=default-save POST commission -> { ok }
* action=bookings GET [broker] -> { ok, bookings:[...], totals:{gross,commission} }
*/
require_once( __DIR__ . '/includes/config.inc.php' );
@ini_set( 'display_errors', '0' );
error_reporting( 0 );
ob_start();
function pa_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_admin' ) || ! is_admin() ) { http_response_code( 403 ); pa_json( array( 'ok' => false, 'error' => 'forbidden' ) ); }
$action = isset( $_GET['action'] ) ? $_GET['action'] : ( isset( $_POST['action'] ) ? $_POST['action'] : '' );
$db = new MysqliDb( MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB );
$LVL = (int) BROKER_LEVEL;
/* ---------------- Vermittler-Liste + Statistik ---------------- */
if ( $action === 'brokers' ) {
$rows = $db->rawQuery(
"SELECT u.user_id, u.user_firstname, u.user_lastname, u.user_email,
br.broker_company, br.broker_commission, br.broker_commission_addon, br.broker_payment_mode, br.broker_active, br.broker_pending,
br.broker_phone, DATE_FORMAT(br.broker_created,'%d.%m.%Y') AS applied,
(SELECT COUNT(*) FROM pacim_invoice i WHERE i.invoice_broker = u.user_id) AS bookings,
(SELECT COALESCE(SUM(" . broker_commission_sql( 'i' ) . "),0)
FROM pacim_invoice i WHERE i.invoice_broker = u.user_id AND i.invoice_status != 3) AS commission_sum
FROM pacim_users u
LEFT JOIN pacim_broker br ON br.broker_id = u.user_id
WHERE u.user_level = $LVL
ORDER BY u.user_lastname, u.user_firstname",
null
);
$out = array();
foreach ( (array) $rows as $r ) {
$out[] = array(
'id' => (int) $r['user_id'],
'name' => trim( $r['user_firstname'] . ' ' . $r['user_lastname'] ),
'email' => $r['user_email'],
'company' => $r['broker_company'],
'commission' => ( $r['broker_commission'] === null ) ? null : (float) $r['broker_commission'],
'commission_addon' => ( $r['broker_commission_addon'] === null ) ? null : (float) $r['broker_commission_addon'],
'payment_mode' => $r['broker_payment_mode'] ?: 'payout',
'active' => (int) $r['broker_active'],
'pending' => (int) $r['broker_pending'],
'phone' => $r['broker_phone'],
'applied' => $r['applied'],
'bookings' => (int) $r['bookings'],
'commission_sum' => round( (float) $r['commission_sum'], 2 ),
'effective_rate' => broker_commission_rate( (int) $r['user_id'] ),
'effective_addon_rate' => broker_commission_addon_rate( (int) $r['user_id'] ),
);
}
pa_json( array( 'ok' => true, 'default' => (float) pacim_setting( 'broker_commission_default', 0 ), 'default_addon' => (float) pacim_setting( 'broker_commission_addon_default', 0 ), 'addon_enabled' => broker_addon_enabled(), 'terms' => broker_terms_text(), 'brokers' => $out ) );
}
/* ---------------- Einen Vermittler laden ---------------- */
if ( $action === 'get' ) {
$id = (int) ( $_GET['id'] ?? 0 );
$u = $db->rawQueryOne( "SELECT user_id, user_firstname, user_lastname, user_email, user_level FROM pacim_users WHERE user_id = ? AND user_level = $LVL", array( $id ) );
if ( ! $u ) pa_json( array( 'ok' => false, 'error' => 'not_found' ) );
$b = broker_record( $id );
pa_json( array( 'ok' => true, 'broker' => array( 'user' => $u, 'broker' => $b ? $b : new stdClass() ) ) );
}
/* ---------------- Anlegen / Bearbeiten ---------------- */
if ( $action === 'save' ) {
$id = (int) ( $_POST['id'] ?? 0 );
$email = trim( (string) ( $_POST['email'] ?? '' ) );
$firstname = trim( (string) ( $_POST['firstname'] ?? '' ) );
$lastname = trim( (string) ( $_POST['lastname'] ?? '' ) );
$password = (string) ( $_POST['password'] ?? '' );
if ( $lastname === '' && trim( (string)($_POST['company'] ?? '') ) === '' ) pa_json( array( 'ok' => false, 'error' => 'Bitte Name oder Firma angeben.' ) );
if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) pa_json( array( 'ok' => false, 'error' => 'Bitte eine gültige E-Mail angeben.' ) );
// E-Mail-Eindeutigkeit
$ex = $db->rawQueryOne( 'SELECT user_id FROM pacim_users WHERE user_email = ?' . ( $id ? ' AND user_id <> ' . $id : '' ), array( $email ) );
if ( $ex ) pa_json( array( 'ok' => false, 'error' => 'E-Mail ist bereits vergeben.' ) );
$now = date( 'Y-m-d H:i:s' );
$commission = ( isset( $_POST['commission'] ) && $_POST['commission'] !== '' ) ? (float) str_replace( ',', '.', $_POST['commission'] ) : null;
$commissionAddon = ( isset( $_POST['commission_addon'] ) && $_POST['commission_addon'] !== '' ) ? (float) str_replace( ',', '.', $_POST['commission_addon'] ) : null;
$payMode = in_array( ( $_POST['payment_mode'] ?? 'payout' ), array( 'payout', 'collect' ), true ) ? $_POST['payment_mode'] : 'payout';
$active = ! empty( $_POST['active'] ) ? 1 : 0;
if ( ! $id ) {
// anlegen
if ( strlen( $password ) < 6 ) pa_json( array( 'ok' => false, 'error' => 'Bitte ein Passwort (min. 6 Zeichen) vergeben.' ) );
$id = $db->insert( 'pacim_users', array(
'user_firstname' => $firstname, 'user_lastname' => $lastname, 'user_email' => $email,
'user_password' => password_hash( $password, PASSWORD_DEFAULT ), 'user_level' => $LVL,
'user_created' => $now, 'user_updated' => $now,
) );
if ( ! $id ) pa_json( array( 'ok' => false, 'error' => 'Konto konnte nicht angelegt werden.' ) );
} else {
$db->where( 'user_id', $id );
$upd = array( 'user_firstname' => $firstname, 'user_lastname' => $lastname, 'user_email' => $email, 'user_level' => $LVL, 'user_updated' => $now );
if ( $password !== '' ) { if ( strlen( $password ) < 6 ) pa_json( array( 'ok' => false, 'error' => 'Passwort zu kurz (min. 6 Zeichen).' ) ); $upd['user_password'] = password_hash( $password, PASSWORD_DEFAULT ); }
$db->update( 'pacim_users', $upd );
}
// pacim_broker upsert
$bf = 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_commission' => $commission,
'broker_commission_addon' => $commissionAddon,
'broker_payment_mode' => $payMode,
'broker_active' => $active,
'broker_pending' => 0, // Admin-Bearbeitung beendet den Anfrage-Status
'broker_updated' => $now,
);
if ( broker_record( $id ) ) { $db->where( 'broker_id', $id ); $db->update( 'pacim_broker', $bf ); }
else { $bf['broker_id'] = $id; $bf['broker_created'] = $now; $db->insert( 'pacim_broker', $bf ); }
pa_json( array( 'ok' => true, 'id' => (int) $id ) );
}
/* ---------------- Globalen Default speichern ---------------- */
if ( $action === 'default-save' ) {
$v = (float) str_replace( ',', '.', (string) ( $_POST['commission'] ?? '' ) );
if ( $v < 0 || $v > 100 ) pa_json( array( 'ok' => false, 'error' => 'Parkplatz-Provision: Wert zwischen 0 und 100.' ) );
settings::set( 'broker_commission_default', number_format( $v, 2, '.', '' ) );
if ( isset( $_POST['commission_addon'] ) && $_POST['commission_addon'] !== '' ) {
$va = (float) str_replace( ',', '.', (string) $_POST['commission_addon'] );
if ( $va < 0 || $va > 100 ) pa_json( array( 'ok' => false, 'error' => 'Zusatzprodukt-Provision: Wert zwischen 0 und 100.' ) );
settings::set( 'broker_commission_addon_default', number_format( $va, 2, '.', '' ) );
}
pa_json( array( 'ok' => true, 'default' => $v ) );
}
/* ---------------- Teilnahmebedingungen speichern ---------------- */
if ( $action === 'terms-save' ) {
$t = trim( (string) ( $_POST['terms'] ?? '' ) );
settings::set( 'broker_terms', $t );
pa_json( array( 'ok' => true ) );
}
/* ---------------- Anfrage freischalten ---------------- */
if ( $action === 'approve' ) {
$id = (int) ( $_POST['id'] ?? 0 );
$u = $db->rawQueryOne( "SELECT user_id FROM pacim_users WHERE user_id = ? AND user_level = $LVL", array( $id ) );
if ( ! $u ) pa_json( array( 'ok' => false, 'error' => 'not_found' ) );
$db->where( 'broker_id', $id );
$db->update( 'pacim_broker', array( 'broker_active' => 1, 'broker_pending' => 0, 'broker_updated' => date( 'Y-m-d H:i:s' ) ) );
// Regel-Engine: Ereignis „Partner freigeschaltet" (Fallback: partner_approved). No-Op solange SMTP nicht aktiv.
// Echte Partner-Platzhalter (partner_*) mergen, sonst blieben die Beispielwerte aus context(0) stehen.
if ( class_exists( 'mailrules' ) ) {
$bu = $db->rawQueryOne( "SELECT user_email, user_firstname, user_lastname FROM pacim_users WHERE user_id = ?", array( $id ) );
if ( $bu ) {
$pctx = class_exists( 'mailrenderer' ) ? mailrenderer::partnerPlaceholders( (int) $id ) : array();
$pctx = array_merge( $pctx, array(
'customer_firstname' => $bu['user_firstname'], 'customer_lastname' => $bu['user_lastname'], 'salutation' => trim( $bu['user_firstname'] . ' ' . $bu['user_lastname'] ),
) );
// broker_id → Dedupe „eine Freischaltungsmail je Partner" (message_broker, kollidiert nicht mit customer_id).
mailrules::evaluateEvent( 'partner_approved', array( 'to' => $bu['user_email'], 'broker_id' => (int) $id, 'ctx' => $pctx ), 'partner_approved' );
}
}
pa_json( array( 'ok' => true, 'id' => $id ) );
}
/* ---------------- Anfrage ablehnen (löscht den angefragten Account) ---------------- */
if ( $action === 'reject' ) {
$id = (int) ( $_POST['id'] ?? 0 );
// Nur noch offene Anfragen dürfen gelöscht werden – niemals aktive Vermittler.
$b = $db->rawQueryOne( "SELECT broker_id, broker_pending, broker_active FROM pacim_broker WHERE broker_id = ?", array( $id ) );
if ( ! $b || (int) $b['broker_pending'] !== 1 || (int) $b['broker_active'] === 1 ) pa_json( array( 'ok' => false, 'error' => 'Nur offene Anfragen können abgelehnt werden.' ) );
// Sicherheitsnetz: keine Buchungen vorhanden?
$cnt = $db->rawQueryOne( "SELECT COUNT(*) AS c FROM pacim_invoice WHERE invoice_broker = ?", array( $id ) );
if ( $cnt && (int) $cnt['c'] > 0 ) pa_json( array( 'ok' => false, 'error' => 'Vermittler hat bereits Buchungen – Ablehnung nicht möglich.' ) );
$db->where( 'broker_id', $id ); $db->delete( 'pacim_broker' );
$db->where( 'user_id', $id ); $db->where( 'user_level', $LVL ); $db->delete( 'pacim_users' );
pa_json( array( 'ok' => true, 'id' => $id ) );
}
/* ---------------- Vermittelte Buchungen (alle / je Vermittler) ---------------- */
if ( $action === 'bookings' ) {
$broker = (int) ( $_GET['broker'] ?? 0 );
$where = 'd.invoice_broker IS NOT NULL AND d.invoice_broker > 0' . ( $broker ? ' AND d.invoice_broker = ' . $broker : '' );
$rows = $db->rawQuery(
"SELECT d.invoice_id, b.booking_no, b.booking_event, b.booking_serial,
DATE_FORMAT(b.booking_begin,'%d.%m.%Y') AS begin, DATE_FORMAT(b.booking_end,'%d.%m.%Y') AS end,
MIN(b.booking_begin) AS begin_raw,
DATE_FORMAT(d.invoice_datetime,'%d.%m.%Y') AS created,
TRIM(CONCAT(COALESCE(c.customer_lastname,''),', ',COALESCE(c.customer_firstname,''))) AS customer,
d.invoice_no, d.invoice_payment, d.invoice_status, d.invoice_broker, d.invoice_broker_commission AS rate,
COALESCE(d.invoice_broker_commission_addon, d.invoice_broker_commission) AS rate_addon,
TRIM(CONCAT(COALESCE(u.user_firstname,''),' ',COALESCE(u.user_lastname,''))) AS broker_name,
(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
LEFT JOIN pacim_users u ON u.user_id = d.invoice_broker
WHERE $where
GROUP BY d.invoice_id
ORDER BY d.invoice_datetime DESC, d.invoice_id DESC",
null
);
$out = array(); $tg = 0.0; $tc = 0.0;
$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
$storno = ( $status === 'cancelled' );
$comm = $storno ? 0.0 : round( (float) $r['commission'], 2 );
$tg += $gross; $tc += $comm;
if ( $status === 'released' ) { $sumReleased += $comm; $cntReleased++; }
elseif ( $status === 'pending' ) { $sumPending += $comm; $cntPending++; }
else { $cntCancelled++; }
$out[] = array(
'invoice_id' => (int) $r['invoice_id'], 'broker_id' => (int) $r['invoice_broker'], 'broker' => $r['broker_name'],
'booking_no' => $r['booking_no'], 'event' => $r['booking_event'], 'plate' => $r['booking_serial'],
'customer' => $r['customer'], 'begin' => $r['begin'], 'end' => $r['end'], 'created' => $r['created'],
'gross' => round( $gross, 2 ), 'rate' => $rate, 'addon_rate' => (float) $r['rate_addon'], 'commission' => $comm,
'paid' => ( (int) $r['invoice_payment'] > 0 && (int) $r['invoice_payment'] != 4 ), 'storno' => $storno, 'status' => $status,
);
}
pa_json( array( 'ok' => true, 'bookings' => $out,
'totals' => array( 'gross' => round($tg,2), 'commission' => round($tc,2), 'count' => count($out),
'released' => round($sumReleased,2), 'pending' => round($sumPending,2),
'cnt_released' => $cntReleased, 'cnt_pending' => $cntPending, 'cnt_cancelled' => $cntCancelled ) ) );
}
http_response_code( 400 );
pa_json( array( 'ok' => false, 'error' => 'unknown_action' ) );