diff --git a/wp-ingame-shop/wp-ingame-shop-pro.php b/wp-ingame-shop/wp-ingame-shop-pro.php index 4d3cf6b..71c22cd 100644 --- a/wp-ingame-shop/wp-ingame-shop-pro.php +++ b/wp-ingame-shop/wp-ingame-shop-pro.php @@ -243,6 +243,18 @@ class WIS_Activator { $wpdb->query("ALTER TABLE $table ADD COLUMN sell_price_value int(11) NOT NULL DEFAULT 80 AFTER sell_price_mode"); } + // Gift-Spalte nachrüsten (ab v6.5-gift) + $orders_table = $wpdb->prefix . 'wis_orders'; + $col_gift = $wpdb->get_var("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '$orders_table' AND COLUMN_NAME = 'gift_recipient'"); + if (!$col_gift) { + $wpdb->query("ALTER TABLE $orders_table ADD COLUMN gift_recipient varchar(100) DEFAULT NULL AFTER player_name"); + } + + // Auto-Expire Cron registrieren (7-Tage-Ablauf für unbestätigte Orders) + if (!wp_next_scheduled('wis_auto_expire_orders')) { + wp_schedule_event(time(), 'hourly', 'wis_auto_expire_orders'); + } + // Sell-Log-Tabelle anlegen $wpdb->query("CREATE TABLE IF NOT EXISTS {$wpdb->prefix}wis_sell_log ( id mediumint(9) NOT NULL AUTO_INCREMENT, @@ -278,6 +290,7 @@ class WIS_Activator { public static function deactivate() { wp_clear_scheduled_hook('wis_daily_deal_event'); wp_clear_scheduled_hook('wis_abo_renewal_event'); + wp_clear_scheduled_hook('wis_auto_expire_orders'); flush_rewrite_rules(); } @@ -312,6 +325,7 @@ class WIS_Activator { $tables[] = "CREATE TABLE {$wpdb->prefix}wis_orders ( id mediumint(9) NOT NULL AUTO_INCREMENT, player_name varchar(100) NOT NULL, + gift_recipient varchar(100) DEFAULT NULL, server varchar(100) NOT NULL, item_id varchar(100) NOT NULL, item_title varchar(255) NOT NULL, @@ -322,6 +336,7 @@ class WIS_Activator { created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY player_name (player_name), + KEY gift_recipient (gift_recipient), KEY status (status) ) $charset_collate;"; @@ -2717,7 +2732,10 @@ class WIS_Admin {
| ID | id); ?> | |||||
|---|---|---|---|---|---|---|
| Datum | created_at))); ?> | |||||
| Spieler | player_name); ?> | |||||
| Käufer | player_name); ?> | |||||
| 🎁 Geschenk für | gift_recipient); ?> | |||||
| Server | server); ?> | |||||
| Zusammenfassung | item_title); ?> | |||||
| Preis | price); ?> | |||||
| Datum | -Spieler | +Käufer | +Empfänger | Inhalt | Preis | Status | @@ -2775,6 +2794,7 @@ class WIS_Admin {
| created_at))); ?> | player_name); ?> | +gift_recipient)): ?>🎁 gift_recipient); ?>– | item_title, 0, 50)) . (strlen($order->item_title) > 50 ? '...' : ''); ?> | price); ?> | status] ?? $order->status; ?> | @@ -3086,6 +3106,22 @@ class WIS_API { 'callback' => [self::class, 'cancel_order'], 'permission_callback' => [WIS_Activator::class, 'spigot_permission'], ]); + // Gift-System Endpunkte (ab v6.5-gift) + register_rest_route('wis/v1', '/pending_gifts', [ + 'methods' => 'GET', + 'callback' => [self::class, 'get_pending_gifts'], + 'permission_callback' => [WIS_Activator::class, 'spigot_permission'], + ]); + register_rest_route('wis/v1', '/gift_accept', [ + 'methods' => 'POST', + 'callback' => [self::class, 'gift_accept'], + 'permission_callback' => [WIS_Activator::class, 'spigot_permission'], + ]); + register_rest_route('wis/v1', '/gift_decline', [ + 'methods' => 'POST', + 'callback' => [self::class, 'gift_decline'], + 'permission_callback' => [WIS_Activator::class, 'spigot_permission'], + ]); register_rest_route('wis/v1', '/pending_offline', [ 'methods' => 'GET', 'callback' => [self::class, 'get_pending_offline'], @@ -3327,6 +3363,9 @@ class WIS_API { $table = $wpdb->prefix . 'wis_orders'; + // Gift-Orders werden genauso wie normale Orders für Spieler A gepollt. + // Spieler A muss zuerst ingame bestätigen (Geld abbuchen), erst dann + // bekommt Spieler B die Gift-Anfrage. $results = $wpdb->get_results($wpdb->prepare( "SELECT * FROM $table WHERE player_name = %s AND status = 'pending' @@ -3436,6 +3475,74 @@ class WIS_API { return new WP_REST_Response(['success' => true]); } + + // ── Gift-System Endpoints ───────────────────────────────────────────── + + /** + * GET /wis/v1/pending_gifts?recipient={player} + * Gibt ausstehende Geschenk-Orders zurück, die an diesen Empfänger gerichtet sind. + */ + public static function get_pending_gifts($request) { + global $wpdb; + $recipient = sanitize_text_field($request->get_param('recipient')); + + if (!$recipient) { + return new WP_REST_Response(['orders' => []]); + } + + $table = $wpdb->prefix . 'wis_orders'; + // Status NICHT auf 'claimed' setzen – bleibt 'pending' bis der Empfänger + // ingame annimmt (gift_accept) oder ablehnt (gift_decline). + // Das Spigot-Plugin prüft pendingGiftRequests intern gegen Duplikate. + $results = $wpdb->get_results($wpdb->prepare( + "SELECT * FROM $table + WHERE gift_recipient = %s AND status IN ('pending', 'processing') + ORDER BY created_at ASC LIMIT 1", + $recipient + )); + + return new WP_REST_Response(['orders' => $results]); + } + + /** + * POST /wis/v1/gift_accept { "id": 123 } + * Wird aufgerufen wenn Empfänger das Geschenk annimmt. + * Setzt Status auf 'processing' – der Spigot-Server liefert dann die Ware aus. + */ + public static function gift_accept($request) { + global $wpdb; + $data = $request->get_json_params(); + $id = intval($data['id'] ?? 0); + if (!$id) return new WP_REST_Response(['success' => false], 400); + + $wpdb->update( + $wpdb->prefix . 'wis_orders', + ['status' => 'processing'], + ['id' => $id] + ); + + return new WP_REST_Response(['success' => true]); + } + + /** + * POST /wis/v1/gift_decline { "id": 123, "sender": "SpielerA", "price": 500 } + * Empfänger lehnt ab → Order stornieren. + * Rückerstattung erfolgt auf Spigot-Seite via Vault direkt. + */ + public static function gift_decline($request) { + global $wpdb; + $data = $request->get_json_params(); + $id = intval($data['id'] ?? 0); + if (!$id) return new WP_REST_Response(['success' => false], 400); + + $wpdb->update( + $wpdb->prefix . 'wis_orders', + ['status' => 'cancelled'], + ['id' => $id] + ); + + return new WP_REST_Response(['success' => true]); + } public static function import_json($request) { $data = $request->get_json_params(); @@ -3494,14 +3601,21 @@ class WIS_API { global $wpdb; $data = $request->get_json_params(); - $player = sanitize_text_field($data['player'] ?? ''); - $cart = $data['cart'] ?? []; - $server = sanitize_text_field($data['server'] ?? ''); + $player = sanitize_text_field($data['player'] ?? ''); + $cart = $data['cart'] ?? []; + $server = sanitize_text_field($data['server'] ?? ''); $coupon_code = isset($data['coupon_code']) ? sanitize_text_field(strtoupper($data['coupon_code'])) : ''; - + // Gift: optionaler Empfänger-Spielername + $gift_recipient = isset($data['gift_recipient']) + ? sanitize_text_field(trim($data['gift_recipient'])) : ''; + if (!$player || empty($cart) || !$server) { return new WP_REST_Response(['success' => false, 'message' => 'Fehlende Daten'], 400); } + // Gift-Validierung: Spieler kann sich nicht selbst beschenken + if ($gift_recipient !== '' && strcasecmp($gift_recipient, $player) === 0) { + return new WP_REST_Response(['success' => false, 'message' => 'Selbst-Geschenk nicht erlaubt'], 400); + } $exclude_offers = get_option('wis_coupon_exclude_offers', '0'); $currency = get_option('wis_currency_name', 'Coins'); @@ -3702,14 +3816,15 @@ class WIS_API { ]; WIS_DB::insert_order([ - 'player_name' => $player, - 'server' => $server, - 'item_id' => 'cart', - 'item_title' => $title, - 'price' => $final_price, - 'quantity' => count($valid_cart), - 'status' => 'pending', - 'response' => json_encode($payload) + 'player_name' => $player, + 'gift_recipient' => $gift_recipient !== '' ? $gift_recipient : null, + 'server' => $server, + 'item_id' => 'cart', + 'item_title' => $title, + 'price' => $final_price, + 'quantity' => count($valid_cart), + 'status' => 'pending', + 'response' => json_encode($payload) ]); // Fly-Abo Abonnements registrieren / verlängern @@ -3758,7 +3873,9 @@ class WIS_API { } } - $msg = '✅ Bestellung erfolgreich!'; + $msg = $gift_recipient !== '' + ? "🎁 Geschenk-Bestellung für {$gift_recipient} erfolgreich!" + : '✅ Bestellung erfolgreich!'; if ($coupon_msg) $msg .= ' (' . $coupon_msg . ')'; return new WP_REST_Response(['success' => true, 'message' => $msg]); @@ -3900,6 +4017,12 @@ class WIS_Shortcode { .wis-coupon-input { flex-grow: 1; padding: 10px; border: 1px solid #ddd; border-radius: 6px; } .wis-coupon-btn { padding: 10px 15px; background: #6f42c1; color: white; border: none; border-radius: 6px; font-weight: bold; cursor: pointer; } .wis-coupon-msg { font-size: 0.85rem; color: #e67e22; margin-top: 5px; min-height: 20px; } + .wis-gift-toggle { display: flex; align-items: center; gap: 10px; margin-bottom: 15px; cursor: pointer; font-weight: 600; color: #6f42c1; user-select: none; } + .wis-gift-toggle input[type=checkbox] { width: 18px; height: 18px; cursor: pointer; accent-color: #9b59b6; } + .wis-gift-field { display: none; background: #f3eeff; border: 1px solid #c39bd3; border-radius: 8px; padding: 14px 16px; margin-bottom: 15px; } + .wis-gift-field label { display: block; font-weight: 600; color: #6f42c1; margin-bottom: 6px; font-size: 0.9rem; } + .wis-gift-input { width: 100%; padding: 10px 14px; border: 1px solid #c39bd3; border-radius: 6px; font-size: 1rem; box-sizing: border-box; background: #fff; } + .wis-gift-hint { font-size: 0.8rem; color: #888; margin-top: 6px; } .wis-alert { margin-top: 15px; padding: 12px; border-radius: 5px; display: none; } .wis-alert.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .wis-alert.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } @@ -3993,6 +4116,17 @@ class WIS_Shortcode { + + +