| 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
/**
* invoice-reverse.php – Rückabwicklung einer Rechnung aus der Tagesansicht (Tab Rechnungen).
*
* Setzt die Rechnung auf storniert, entfernt Rechnungsnummer + Zahlung und gibt die
* Nummer für die lückenlose Wiederverwendung frei (Pool). Nur am selben Tag und nur
* bis 21:00 Uhr möglich. Liefert die aktualisierte Rechnungsliste/Statistik des Tages zurück.
*
* Aktionen: reverse POST invoice_id
*/
require_once( __DIR__ . '/includes/config.inc.php' );
@ini_set( 'display_errors', '0' );
error_reporting( 0 );
ob_start();
function ir_json( $a ) { while ( ob_get_level() > 0 ) ob_end_clean(); header( 'Content-Type: application/json; charset=utf-8' ); echo json_encode( $a ); exit(); }
function ir_fail( $m, $code = 200 ) { http_response_code( $code ); ir_json( array( 'ok' => false, 'error' => $m ) ); }
if ( ! function_exists( 'is_admin' ) || ! is_admin() ) { ir_fail( 'forbidden', 403 ); }
$action = $_GET['action'] ?? ( $_POST['action'] ?? '' );
$db = new MysqliDb( MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB );
/** Zeitfenster: Rückabwicklung am Anreisetag (bis 21:00 Uhr) ODER an einem zukünftigen Anreisetag
* (jederzeit, z. B. Vorab-Zahlung/-Check-in). Vergangene Anreisetage sind gesperrt. */
function ir_within_window( $arrivalDay ) {
$day = substr( (string) $arrivalDay, 0, 10 );
if ( $day === '' ) return false;
$today = date( 'Y-m-d' );
if ( $day < $today ) return false; // Vergangenheit: gesperrt
if ( $day > $today ) return true; // Zukunft: jederzeit
return ( (int) date( 'H' ) < 21 ); // heute: bis 21:00 Uhr
}
if ( $action === 'reverse' ) {
if ( $_SERVER['REQUEST_METHOD'] !== 'POST' ) ir_fail( 'method', 405 );
$iid = (int) ( $_POST['invoice_id'] ?? 0 );
if ( $iid <= 0 ) ir_fail( 'Ungültige Rechnung.' );
$inv = $db->rawQueryOne( "SELECT invoice_id, invoice_no, invoice_status, invoice_date FROM pacim_invoice WHERE invoice_id = ?", array( $iid ) );
if ( ! $inv ) ir_fail( 'Rechnung nicht gefunden.', 404 );
if ( (int) $inv['invoice_status'] === 3 ) ir_fail( 'Rechnung ist bereits storniert.' );
// Zeitfenster auf Basis des ANREISETAGS (Tagesansicht = Anreisedatum), nicht des Rechnungsdatums –
// so ist die Rückabwicklung auch für künftige Anreisen (Vorab-Zahlung/-Check-in) möglich.
$arr = $db->rawQueryOne( "SELECT MIN(booking_begin) AS arrival FROM pacim_booking WHERE booking_invoice = ?", array( $iid ) );
$gateDay = substr( (string) ( ( $arr && $arr['arrival'] ) ? $arr['arrival'] : $inv['invoice_date'] ), 0, 10 );
if ( ! ir_within_window( $gateDay ) ) ir_fail( 'Rückabwicklung ist nur bis zum Anreisetag möglich (am Anreisetag selbst bis 21:00 Uhr).', 403 );
$no = (string) $inv['invoice_no'];
$num = ( preg_match( '/(\d+)/', $no, $m ) ) ? (int) $m[1] : 0;
$db->startTransaction();
try {
// Rechnung stornieren, Nummer + Zahlung entfernen
$db->where( 'invoice_id', $iid );
$ok = $db->update( 'pacim_invoice', array(
'invoice_no' => '',
'invoice_status' => 3,
'invoice_payment' => 0,
'invoice_paydate' => null,
) );
if ( ! $ok ) throw new Exception( 'Rechnung konnte nicht aktualisiert werden.' );
// Zahlungsdatensätze entfernen
$db->rawQuery( "DELETE FROM pacim_payments WHERE payment_invoice = ?", array( $iid ) );
// Check-in (und Check-out) der zugehörigen Buchungen zurücksetzen – als wäre nie eingecheckt worden
$db->rawQuery( "UPDATE pacim_booking SET booking_checkin = NULL, booking_checkout = NULL WHERE booking_invoice = ?", array( $iid ) );
// Nummer für lückenlose Wiederverwendung freigeben (Pool)
if ( $num > 0 && class_exists( 'bookingservice' ) ) bookingservice::freeInvoiceNo( $db, $num );
$db->commit();
} catch ( Exception $e ) {
$db->rollback();
ir_fail( 'Rückabwicklung fehlgeschlagen: ' . $e->getMessage() );
}
// Erzeugtes Rechnungs-PDF best-effort entfernen (Nummer ist nun frei)
if ( $no !== '' && defined( 'PATH_DATAS' ) ) { $pdf = rtrim( PATH_DATAS, '/' ) . '/invoice/' . $no . '.pdf'; if ( is_file( $pdf ) ) @unlink( $pdf ); }
// Aktualisierte Tagesdaten zurückgeben (Anreisetag = Tagesansicht)
$data = ( class_exists( 'dayview' ) ) ? ( new dayview() )->invoices( $gateDay ) : null;
ir_json( array( 'ok' => true, 'invoice_id' => $iid, 'freed_no' => $no, 'invoices' => $data ) );
}
ir_fail( 'unknown_action' );