AZA License Bridge

Hetzner API URL
WC Provision Secret

Muss identisch sein mit WC_PROVISION_SECRET auf Hetzner.

Standard lookup_key

z. B. aza_basic_monthly, aza_basic_yearly


Status

API URL:

Secret gesetzt:

get_items(); if ( empty( $items ) || ! is_array( $items ) ) { return ''; } foreach ( $items as $item ) { if ( ! is_object( $item ) || ! method_exists( $item, 'get_product' ) ) { continue; } $product = $item->get_product(); if ( ! $product || ! is_object( $product ) || ! method_exists( $product, 'get_meta' ) ) { continue; } $lookup_key = trim( (string) $product->get_meta( '_aza_lookup_key' ) ); if ( $lookup_key !== '' ) { return $lookup_key; } } return ''; } function aza_lb_get_parent_order_id_from_subscription( $subscription ) { if ( ! is_object( $subscription ) ) { return 0; } if ( method_exists( $subscription, 'get_parent_id' ) ) { return (int) $subscription->get_parent_id(); } return 0; } function aza_lb_get_billing_email_from_subscription( $subscription ) { if ( ! is_object( $subscription ) ) { return ''; } if ( method_exists( $subscription, 'get_billing_email' ) ) { $email = trim( (string) $subscription->get_billing_email() ); if ( $email !== '' ) { return $email; } } if ( method_exists( $subscription, 'get_parent' ) ) { $parent_order = $subscription->get_parent(); if ( $parent_order && is_object( $parent_order ) && method_exists( $parent_order, 'get_billing_email' ) ) { $email = trim( (string) $parent_order->get_billing_email() ); if ( $email !== '' ) { return $email; } } } return ''; } // ── Phase 1f: Abrechnungsperiode → Hetzner (ohne Woo /wc/v3/subscriptions von AZA aus) ── /** * Liest nächste Zahlung / Billing aus Subscription-Objekt oder Post-Meta. * Kompatibel mit WooCommerce-Subscriptions-APIs und WP Desk Flexible Subscriptions (u. a. billing_period M/D/W/Y). * * @param object $subscription * @return array Teilmenge für POST /wc/subscription_period */ function aza_lb_collect_period_fields_from_subscription( $subscription ) { $fields = array(); if ( ! is_object( $subscription ) || ! method_exists( $subscription, 'get_id' ) ) { return $fields; } $sid = (int) $subscription->get_id(); if ( $sid <= 0 ) { return $fields; } if ( method_exists( $subscription, 'get_date' ) ) { $next = $subscription->get_date( 'next_payment' ); if ( is_numeric( $next ) ) { $fields['next_payment_date'] = (int) $next; } elseif ( is_string( $next ) && $next !== '' && $next !== '0' ) { $fields['next_payment_date'] = $next; } } if ( empty( $fields['next_payment_date'] ) ) { $meta_keys = array( '_schedule_next_payment', 'wps_next_payment_date' ); foreach ( $meta_keys as $meta_key ) { $raw = get_post_meta( $sid, $meta_key, true ); if ( is_string( $raw ) && $raw !== '' ) { $fields['next_payment_date'] = $raw; break; } if ( is_numeric( $raw ) && (int) $raw > 0 ) { $fields['next_payment_date'] = (int) $raw; break; } } } if ( method_exists( $subscription, 'get_billing_period' ) ) { $fields['billing_period'] = (string) $subscription->get_billing_period(); } else { $bp = get_post_meta( $sid, '_billing_period', true ); if ( $bp !== '' && $bp !== null ) { $fields['billing_period'] = (string) $bp; } } if ( method_exists( $subscription, 'get_billing_interval' ) ) { $fields['billing_interval'] = (int) $subscription->get_billing_interval(); } else { $bi = get_post_meta( $sid, '_billing_interval', true ); if ( $bi !== '' && $bi !== null ) { $fields['billing_interval'] = (int) $bi; } } if ( method_exists( $subscription, 'get_status' ) ) { $fields['subscription_status'] = (string) $subscription->get_status(); } return $fields; } /** * Sendet nur Periodenfelder an Hetzner (POST /wc/subscription_period, X-WC-Secret). * * @param object $subscription * @return void */ function aza_lb_push_subscription_period_to_backend( $subscription ) { $api_url = rtrim( (string) get_option( 'aza_lb_api_url', 'https://api.aza-medwork.ch' ), '/' ); $wc_secret = (string) get_option( 'aza_lb_wc_secret', '' ); if ( $wc_secret === '' || ! is_object( $subscription ) || ! method_exists( $subscription, 'get_id' ) ) { return; } $sub_numeric = (int) $subscription->get_id(); if ( $sub_numeric <= 0 ) { return; } $order_id = 0; if ( function_exists( 'aza_lb_get_parent_order_id_from_subscription' ) ) { $order_id = (int) aza_lb_get_parent_order_id_from_subscription( $subscription ); } $period = aza_lb_collect_period_fields_from_subscription( $subscription ); if ( empty( $period['next_payment_date'] ) ) { aza_lb_log( "PERIOD PUSH SKIP: sub={$sub_numeric} — kein next_payment ermittelbar" ); return; } $payload = array_merge( array( 'wc_subscription_id' => $sub_numeric, 'wc_order_id' => $order_id, ), $period ); $url = $api_url . '/wc/subscription_period'; $response = wp_remote_post( $url, array( 'timeout' => 20, 'headers' => array( 'Content-Type' => 'application/json', 'X-WC-Secret' => $wc_secret, 'User-Agent' => 'AZA-License-Bridge/1.0-flex-period', ), 'body' => wp_json_encode( $payload ), ) ); if ( is_wp_error( $response ) ) { aza_lb_log( 'PERIOD PUSH ERR: ' . $response->get_error_message() ); return; } $code = (int) wp_remote_retrieve_response_code( $response ); aza_lb_log( "PERIOD PUSH sub={$sub_numeric} HTTP {$code}" ); } // ── Provisioning Request ────────────────────────────────────────────────────── /** * Sendet den Lizenz-Provisioning-Request an das Hetzner-Backend. * * @param int $subscription_id WooCommerce Subscription ID * @param int $order_id WooCommerce Order ID * @param string $email Kunden-E-Mail * @param string $lookup_key Produkt-/Planschlüssel * @return array|WP_Error */ function aza_lb_provision_license( $subscription_id, $order_id, $email, $lookup_key = '' ) { $api_url = rtrim( (string) get_option( 'aza_lb_api_url', 'https://api.aza-medwork.ch' ), '/' ); $wc_secret = (string) get_option( 'aza_lb_wc_secret', '' ); if ( $wc_secret === '' ) { aza_lb_log( "SKIP: WC_PROVISION_SECRET nicht konfiguriert (sub={$subscription_id})" ); return new WP_Error( 'aza_lb_no_secret', 'WC Provision Secret nicht konfiguriert.' ); } if ( $lookup_key === '' ) { $lookup_key = (string) get_option( 'aza_lb_lookup_key', 'aza_basic_monthly' ); } $url = $api_url . '/wc/provision'; $payload = array( 'customer_email' => (string) $email, 'wc_order_id' => (int) $order_id, 'wc_subscription_id' => (int) $subscription_id, 'lookup_key' => (string) $lookup_key, 'allowed_users' => 1, 'devices_per_user' => 2, ); $body = wp_json_encode( $payload ); aza_lb_log( sprintf( 'POST %s (sub=%d, order=%d, email=%s, lookup_key=%s)', $url, (int) $subscription_id, (int) $order_id, (string) $email, (string) $lookup_key ) ); $response = wp_remote_post( $url, array( 'timeout' => 20, 'headers' => array( 'Content-Type' => 'application/json', 'X-WC-Secret' => $wc_secret, 'User-Agent' => 'AZA-License-Bridge/1.0.1', ), 'body' => $body, ) ); if ( is_wp_error( $response ) ) { aza_lb_log( 'FEHLER: ' . $response->get_error_message() ); return $response; } $code = (int) wp_remote_retrieve_response_code( $response ); $resp_body = (string) wp_remote_retrieve_body( $response ); aza_lb_log( "Response HTTP {$code}: {$resp_body}" ); if ( $code >= 200 && $code < 300 ) { $data = json_decode( $resp_body, true ); return is_array( $data ) ? $data : array( 'raw' => $resp_body ); } return new WP_Error( 'aza_lb_provision_failed', "HTTP {$code}: {$resp_body}" ); } // ── WooCommerce Hook ────────────────────────────────────────────────────────── /** * Hook: Subscription wird aktiv. * * Ziel: * - Neukauf sauber provisionieren * - Mehrfachauslösung durch Meta-Flag verhindern */ add_action( 'woocommerce_subscription_status_active', 'aza_lb_on_subscription_active', 10, 1 ); function aza_lb_on_subscription_active( $subscription ) { if ( ! is_object( $subscription ) ) { aza_lb_log( 'SKIP: Hook erhielt kein Objekt.' ); return; } if ( ! method_exists( $subscription, 'get_id' ) ) { aza_lb_log( 'SKIP: Hook-Objekt ohne get_id().' ); return; } $sub_id = (int) $subscription->get_id(); if ( $sub_id <= 0 ) { aza_lb_log( 'SKIP: ungültige Subscription-ID.' ); return; } $already = (string) get_post_meta( $sub_id, '_aza_license_provisioned', true ); if ( $already === 'yes' ) { aza_lb_log( "SKIP: sub={$sub_id} bereits provisioniert" ); return; } $email = aza_lb_get_billing_email_from_subscription( $subscription ); if ( $email === '' ) { aza_lb_log( "SKIP: sub={$sub_id} – keine E-Mail gefunden" ); return; } $order_id = aza_lb_get_parent_order_id_from_subscription( $subscription ); $lookup_key = aza_lb_get_lookup_key_from_subscription( $subscription ); if ( $lookup_key === '' ) { $lookup_key = (string) get_option( 'aza_lb_lookup_key', 'aza_basic_monthly' ); } $result = aza_lb_provision_license( $sub_id, $order_id, $email, $lookup_key ); if ( is_wp_error( $result ) ) { aza_lb_log( "PROVISION FEHLGESCHLAGEN: sub={$sub_id} – " . $result->get_error_message() ); return; } $license_key = ''; if ( isset( $result['license_key'] ) ) { $license_key = trim( (string) $result['license_key'] ); } update_post_meta( $sub_id, '_aza_license_provisioned', 'yes' ); update_post_meta( $sub_id, '_aza_license_provisioned_at', current_time( 'mysql' ) ); update_post_meta( $sub_id, '_aza_license_lookup_key', $lookup_key ); if ( $license_key !== '' ) { update_post_meta( $sub_id, '_aza_license_key', $license_key ); } if ( $order_id > 0 && $license_key !== '' ) { update_post_meta( $order_id, '_aza_license_key', $license_key ); } $status = isset( $result['status'] ) ? (string) $result['status'] : 'unknown'; aza_lb_log( "PROVISION OK: sub={$sub_id}, order={$order_id}, key={$license_key}, status={$status}" ); } /** * Nach Provision (oder bei reaktivem „active“): Perioden an Hetzner senden. * Läuft mit Priorität 20 nach aza_lb_on_subscription_active (10). */ add_action( 'woocommerce_subscription_status_active', 'aza_lb_after_subscription_active_push_period', 20, 1 ); function aza_lb_after_subscription_active_push_period( $subscription ) { aza_lb_push_subscription_period_to_backend( $subscription ); } /** * Subscription-Objekt laden (WCS oder Flexible Subscriptions / shop_subscription Order). * * @param int $sub_id * @return object|null */ function aza_lb_get_subscription_object( $sub_id ) { $sub_id = (int) $sub_id; if ( $sub_id <= 0 ) { return null; } if ( function_exists( 'wcs_get_subscription' ) ) { $sub = wcs_get_subscription( $sub_id ); if ( $sub ) { return $sub; } } if ( function_exists( 'wc_get_order' ) ) { $order = wc_get_order( $sub_id ); if ( $order && method_exists( $order, 'get_type' ) ) { $type = (string) $order->get_type(); if ( $type === 'shop_subscription' || $type === 'subscription' ) { return $order; } } } return null; } // ── Admin: manueller Perioden-Push (keine Zahlung, nur Hetzner-Sync) ───────── add_action( 'admin_menu', function () { add_management_page( 'AZA Period Sync', 'AZA Period Sync', 'manage_options', 'aza-lb-period-sync', 'aza_lb_period_sync_admin_page' ); } ); function aza_lb_period_sync_admin_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } $notice = ''; if ( isset( $_POST['aza_lb_period_sync_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['aza_lb_period_sync_nonce'] ) ), 'aza_lb_period_sync' ) ) { $sub_id = isset( $_POST['wc_subscription_id'] ) ? (int) $_POST['wc_subscription_id'] : 0; $sub = aza_lb_get_subscription_object( $sub_id ); if ( ! $sub ) { $notice = 'Subscription nicht gefunden oder kein Abo-Typ.'; } else { $result = aza_lb_push_subscription_period_to_backend( $sub ); if ( is_wp_error( $result ) ) { $notice = 'Fehler: ' . esc_html( $result->get_error_message() ); } else { $notice = 'Perioden-Push ausgelöst (sub=' . (int) $sub_id . '). Log: uploads/aza-logs/license-bridge.log'; } } } ?>

AZA Period Sync (Hetzner)

Sendet nur current_period_* an POST /wc/subscription_period. Keine Zahlung, keine Kundenänderung.

get_id(); $key = (string) get_post_meta( $order_id, '_aza_license_key', true ); if ( $key === '' && function_exists( 'wcs_get_subscriptions_for_order' ) ) { $subscriptions = wcs_get_subscriptions_for_order( $order_id ); if ( is_array( $subscriptions ) ) { foreach ( $subscriptions as $subscription ) { if ( ! is_object( $subscription ) || ! method_exists( $subscription, 'get_id' ) ) { continue; } $sub_key = (string) get_post_meta( (int) $subscription->get_id(), '_aza_license_key', true ); if ( $sub_key !== '' ) { $key = $sub_key; break; } } } } if ( $key !== '' ) { echo '

AZA Lizenzschlüssel: ' . esc_html( $key ) . '

'; } }, 10, 1 );