[ 'name' => 'Szerzők', 'singular_name' => 'Szerző', 'menu_name' => 'Szerzők', 'all_items' => 'Összes szerző', 'edit_item' => 'Szerző szerkesztése', 'update_item' => 'Szerző frissítése', 'add_new_item' => 'Új szerző', 'search_items' => 'Szerző keresése', ], 'hierarchical' => true, 'public' => true, 'show_ui' => true, 'show_admin_column' => true, 'show_in_rest' => true, 'rewrite' => [ 'slug' => 'supplier', 'with_front' => false ], ] ); } // ===================================================================== // Szerző-adatok (a régi term meta kulcsokból) // ===================================================================== public static function szerzo_adat( $term_id ) { $term = get_term( (int) $term_id, 'supplier' ); if ( ! $term || is_wp_error( $term ) ) { return null; } return [ 'term_id' => (int) $term->term_id, 'nev' => $term->name, 'email' => sanitize_email( get_term_meta( $term->term_id, 'mcisoe_supplier_email', true ) ), ]; } // ===================================================================== // Rendelés-feldolgozás: csoportosítás + rekordok + küldés // ===================================================================== public function rendeles_feldolgozas( $order_id ) { $order = wc_get_order( $order_id ); if ( ! $order ) { return; } // Ha már feldolgoztuk (pl. státusz oda-vissza váltás), nem küldünk újra $meglevo = $order->get_meta( MBSRR_META_SZERZOK ); if ( ! empty( $meglevo ) && is_array( $meglevo ) ) { return; } $csoportok = $this->tetel_csoportositas( $order ); if ( empty( $csoportok ) ) { $order->add_order_note( 'SRR: a rendelésben nincs szerzőhöz rendelt termék – szerzői értesítés nem ment ki.' ); return; } $rekordok = []; foreach ( $csoportok as $term_id => $item_ids ) { $szerzo = self::szerzo_adat( $term_id ); if ( ! $szerzo ) { continue; } $rekord = [ 'nev' => $szerzo['nev'], 'email' => $szerzo['email'], 'allapot' => 'ertesitve', 'item_ids' => $item_ids, 'ertesitve' => '', 'emlekeztetok' => 0, 'utolso_akcio' => '', 'tortenet' => [], ]; if ( empty( $szerzo['email'] ) || ! is_email( $szerzo['email'] ) ) { $rekord['allapot'] = 'nincs_email'; $rekord['tortenet'][] = self::esemeny( 'Hiányzó vagy hibás szerzői e-mail cím – kézi intézkedés szükséges!' ); $order->add_order_note( sprintf( 'SRR FIGYELEM: %s szerzőnek nincs érvényes e-mail címe, értesítés NEM ment ki!', $szerzo['nev'] ) ); $this->admin_ertesites( $order, sprintf( '%s szerzőnek nincs érvényes e-mail címe (rendelés: #%s) – kézi intézkedés szükséges.', $szerzo['nev'], $order->get_order_number() ), 'nincs_email' ); } else { $kimenet = $this->szerzoi_email_kuldes( $order, $term_id, $rekord, false ); $rekord['ertesitve'] = current_time( 'mysql' ); $rekord['tortenet'][] = self::esemeny( ( $kimenet ? 'Értesítő e-mail kiküldve: ' . $rekord['email'] : 'Értesítő e-mail küldése SIKERTELEN (wp_mail hiba)!' ) . self::teszt_jeloles() ); $order->add_order_note( sprintf( 'SRR: szerzői értesítés %s – %s (%s), tételek: %d db.', $kimenet ? 'kiküldve' : 'SIKERTELEN', $rekord['nev'], $rekord['email'], count( $item_ids ) ) ); if ( ! $kimenet ) { $this->admin_ertesites( $order, sprintf( 'A(z) #%s rendelés szerzői értesítője NEM ment ki (%s, %s) – ellenőrzés szükséges.', $order->get_order_number(), $rekord['nev'], $rekord['email'] ) ); } } $rekordok[ $term_id ] = $rekord; } $order->update_meta_data( MBSRR_META_SZERZOK, $rekordok ); $order->update_meta_data( MBSRR_META_NYITOTT, self::van_nyitott( $rekordok ) ? '1' : '0' ); $order->save(); } /** Tételek csoportosítása szerzőnként: term_id => [order_item_id, ...] */ private function tetel_csoportositas( $order ) { $csoportok = []; foreach ( $order->get_items() as $item_id => $item ) { $product_id = $item->get_product_id(); // variációnál is a szülő termék $termek_szerzoi = wp_get_post_terms( $product_id, 'supplier', [ 'fields' => 'ids' ] ); if ( is_wp_error( $termek_szerzoi ) ) { continue; } foreach ( $termek_szerzoi as $term_id ) { $csoportok[ $term_id ][] = $item_id; } } return $csoportok; } // ===================================================================== // E-mail küldés (WC_Email-en keresztül) // ===================================================================== /** @return bool sikeres volt-e a küldés */ public function szerzoi_email_kuldes( $order, $term_id, $rekord, $emlekezteto = false ) { $mailer = WC()->mailer(); $emails = $mailer->get_emails(); if ( empty( $emails['MBSRR_Email_Szerzo'] ) ) { return false; } $cimzett = $rekord['email']; $teszt = ( get_option( 'mbsrr_teszt_mod', '0' ) === '1' ); if ( $teszt ) { $cimzett = sanitize_email( get_option( 'mbsrr_teszt_email', get_option( 'admin_email' ) ) ); } return (bool) $emails['MBSRR_Email_Szerzo']->trigger( $order, [ 'term_id' => (int) $term_id, 'nev' => $rekord['nev'], 'email' => $rekord['email'], 'cimzett' => $cimzett, 'item_ids' => $rekord['item_ids'], 'emlekezteto' => (bool) $emlekezteto, 'teszt_mod' => $teszt, 'linkek' => $this->akcio_linkek( $order->get_id(), $term_id ), ] ); } // ===================================================================== // Tokenes linkek + végpont // ===================================================================== public static function token( $order_id, $term_id ) { return hash_hmac( 'sha256', $order_id . '|' . $term_id, get_option( 'mbsrr_titok' ) ); } public function akcio_linkek( $order_id, $term_id ) { $alap = [ 'order' => $order_id, 'szerzo' => $term_id, 'token' => self::token( $order_id, $term_id ), ]; $url = home_url( 'wc-api/mbsrr' ); return [ 'kapcsolatfelvetel' => add_query_arg( $alap + [ 'muvelet' => 'kapcsolatfelvetel' ], $url ), 'lezarva' => add_query_arg( $alap + [ 'muvelet' => 'lezarva' ], $url ), 'sikertelen' => add_query_arg( $alap + [ 'muvelet' => 'sikertelen' ], $url ), ]; } /** A szerző kattintása a levél gombjaira */ public function vegpont_kezeles() { $order_id = isset( $_GET['order'] ) ? absint( $_GET['order'] ) : 0; $term_id = isset( $_GET['szerzo'] ) ? absint( $_GET['szerzo'] ) : 0; $muvelet = isset( $_GET['muvelet'] ) ? sanitize_key( $_GET['muvelet'] ) : ''; $token = isset( $_GET['token'] ) ? sanitize_text_field( wp_unslash( $_GET['token'] ) ) : ''; $ervenyes_muveletek = [ 'kapcsolatfelvetel', 'lezarva', 'sikertelen' ]; if ( ! $order_id || ! $term_id || ! in_array( $muvelet, $ervenyes_muveletek, true ) || ! hash_equals( self::token( $order_id, $term_id ), $token ) ) { $this->megerosito_oldal( 'hibas', null, '' ); exit; } $order = wc_get_order( $order_id ); if ( ! $order ) { $this->megerosito_oldal( 'hibas', null, '' ); exit; } $rekordok = $order->get_meta( MBSRR_META_SZERZOK ); if ( empty( $rekordok[ $term_id ] ) ) { $this->megerosito_oldal( 'hibas', null, '' ); exit; } $rekord = $rekordok[ $term_id ]; // Állapotgép: lezárt rekordot nem írunk felül a levélből if ( in_array( $rekord['allapot'], [ 'lezarva', 'sikertelen' ], true ) ) { $this->megerosito_oldal( 'mar_lezart', $rekord, $muvelet ); exit; } $cimkek = self::allapot_cimkek(); $rekordok[ $term_id ]['allapot'] = $muvelet; $rekordok[ $term_id ]['utolso_akcio'] = current_time( 'mysql' ); $rekordok[ $term_id ]['tortenet'][] = self::esemeny( 'Szerzői visszajelzés a levélből: ' . $cimkek[ $muvelet ] ); $order->update_meta_data( MBSRR_META_SZERZOK, $rekordok ); $order->update_meta_data( MBSRR_META_NYITOTT, self::van_nyitott( $rekordok ) ? '1' : '0' ); $order->add_order_note( sprintf( 'SRR: %s visszajelzett – új állapot: %s.', $rekord['nev'], $cimkek[ $muvelet ] ) ); $order->save(); $this->admin_ertesites( $order, sprintf( '%s szerző visszajelzett a(z) #%s rendelésnél – új állapot: %s.', $rekord['nev'], $order->get_order_number(), $cimkek[ $muvelet ] ), $muvelet ); $this->megerosito_oldal( 'siker', $rekordok[ $term_id ], $muvelet ); exit; } /** Egyszerű, brandelt megerősítő oldal a kattintás után */ private function megerosito_oldal( $tipus, $rekord, $muvelet ) { status_header( 200 ); nocache_headers(); $sablon = MBSRR_DIR . 'templates/megerosito-oldal.php'; if ( file_exists( $sablon ) ) { include $sablon; // $tipus, $rekord, $muvelet változókkal } else { echo esc_html( 'siker' === $tipus ? 'Köszönjük, a visszajelzését rögzítettük!' : 'Érvénytelen hivatkozás.' ); } } // ===================================================================== // Emlékeztető cron // ===================================================================== public function emlekezteto_futtatas() { $ora = max( 1, (int) get_option( 'mbsrr_emlekezteto_ora', 48 ) ); $max = max( 0, (int) get_option( 'mbsrr_emlekezteto_max', 3 ) ); if ( 0 === $max ) { return; } $nyitott_rendelesek = wc_get_orders( [ 'limit' => 50, 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery [ 'key' => MBSRR_META_NYITOTT, 'value' => '1', ], ], ] ); foreach ( $nyitott_rendelesek as $order ) { $rekordok = $order->get_meta( MBSRR_META_SZERZOK ); $valtozott = false; if ( empty( $rekordok ) || ! is_array( $rekordok ) ) { continue; } foreach ( $rekordok as $term_id => $rekord ) { if ( 'ertesitve' !== $rekord['allapot'] ) { continue; } if ( (int) $rekord['emlekeztetok'] >= $max ) { continue; } $alap_ido = ! empty( $rekord['utolso_emlekezteto'] ) ? $rekord['utolso_emlekezteto'] : $rekord['ertesitve']; if ( empty( $alap_ido ) ) { continue; } if ( ( current_time( 'timestamp' ) - strtotime( $alap_ido ) ) < $ora * HOUR_IN_SECONDS ) { continue; } $kimenet = $this->szerzoi_email_kuldes( $order, $term_id, $rekord, true ); $rekordok[ $term_id ]['emlekeztetok'] = (int) $rekord['emlekeztetok'] + 1; $rekordok[ $term_id ]['utolso_emlekezteto'] = current_time( 'mysql' ); $rekordok[ $term_id ]['tortenet'][] = self::esemeny( sprintf( '%d. emlékeztető %s.', $rekordok[ $term_id ]['emlekeztetok'], $kimenet ? 'kiküldve' : 'küldése SIKERTELEN' ) . self::teszt_jeloles() ); $valtozott = true; $order->add_order_note( sprintf( 'SRR: %d. emlékeztető kiküldve – %s (%s).', $rekordok[ $term_id ]['emlekeztetok'], $rekord['nev'], $rekord['email'] ) ); $this->admin_ertesites( $order, sprintf( '%s szerző még nem jelzett vissza a(z) #%s rendelésre – %d. emlékeztető kiküldve.', $rekord['nev'], $order->get_order_number(), $rekordok[ $term_id ]['emlekeztetok'] ), 'ertesitve' ); if ( $rekordok[ $term_id ]['emlekeztetok'] >= $max ) { $this->admin_ertesites( $order, sprintf( '%s szerző a(z) #%s rendelésnél elérte a maximális emlékeztető-számot (%d) visszajelzés nélkül – KÉZI INTÉZKEDÉS SZÜKSÉGES.', $rekord['nev'], $order->get_order_number(), $max ) ); } } if ( $valtozott ) { $order->update_meta_data( MBSRR_META_SZERZOK, $rekordok ); $order->save(); } } } // ===================================================================== // Segédek // ===================================================================== public function admin_ertesites( $order, $szoveg, $allapot = '' ) { $cim = sanitize_email( get_option( 'mbsrr_admin_email', get_option( 'admin_email' ) ) ); if ( ! $cim ) { return; } $targy = sprintf( '[My-Book SRR] #%s – állapotváltozás', $order->get_order_number() ); $body = $szoveg . "\n"; $magyarazat = self::allapot_magyarazat( $allapot ); if ( $magyarazat ) { $body .= "\n––– Mit jelent ez az állapot? –––\n" . $magyarazat . "\n"; } $body .= "\nRendelés megnyitása: " . $order->get_edit_order_url() . "\n"; wp_mail( $cim, $targy, $body ); } /** * Közérthető állapot-magyarázat az admin értesítőkhöz. * Úgy fogalmazva, hogy a rendszert nem ismerő kolléga (helyettesítő) is értse. */ public static function allapot_magyarazat( $allapot ) { $m = [ 'ertesitve' => "A szerző megkapta az e-mail értesítést a rendelésről, de még NEM jelzett vissza, hogy felvette-e a kapcsolatot a vásárlóval.\nTeendő: egyelőre nincs – a rendszer automatikusan emlékeztetőt küld a szerzőnek, ha sokáig nem reagál. Ha a maximális emlékeztető-szám is elfogyott, külön levélben kérünk kézi közbelépést.", 'kapcsolatfelvetel' => "A szerző jelezte, hogy FELVETTE A KAPCSOLATOT a vásárlóval – az átadás és a fizetés részleteit egyeztetik egymás között.\nTeendő: nincs. Ha a rendelés hosszabb ideig (több nap) ebben az állapotban marad, érdemes rákérdezni a szerzőnél, hogy megegyeztek-e.", 'lezarva' => "A szerző és a vásárló MEGEGYEZTEK: a szerző intézi a könyv átadását és a fizetést. A webáruház oldaláról az ügy le van zárva.\nTeendő: nincs, az ügy rendben lezárult.", 'sikertelen' => "A szerző jelezte, hogy NEM ÉRI EL a vásárlót (nem veszi fel a telefont / nem válaszol e-mailre).\nTeendő: itt nekünk kell közbelépni – próbáljuk meg elérni a vásárlót a rendelésben szereplő elérhetőségeken, és segítsünk összekötni a szerzővel, vagy egyeztessünk a rendelés sorsáról.", 'nincs_email' => "A szerzőhöz NINCS érvényes e-mail cím rögzítve, ezért az értesítést nem tudtuk kiküldeni – a szerző NEM tud a rendelésről!\nTeendő: pótoljuk a szerző e-mail címét (WordPress admin » Termékek » Szerzők), majd a rendelés oldalán az SRR dobozban kattintsunk az „Értesítő újraküldése” gombra. Ha nincs e-mail címe, telefonon értesítsük a szerzőt.", ]; return isset( $m[ $allapot ] ) ? $m[ $allapot ] : ''; } /** Történet-bejegyzéshez: teszt-módban jelöljük a tényleges címzettet */ public static function teszt_jeloles() { if ( get_option( 'mbsrr_teszt_mod', '0' ) === '1' ) { return ' [TESZT üzemmód – a levél valójában ide ment: ' . sanitize_email( get_option( 'mbsrr_teszt_email' ) ) . ']'; } return ''; } public static function esemeny( $szoveg ) { return [ 'ido' => current_time( 'mysql' ), 'szoveg' => $szoveg ]; } public static function van_nyitott( $rekordok ) { foreach ( (array) $rekordok as $r ) { if ( isset( $r['allapot'] ) && 'ertesitve' === $r['allapot'] ) { return true; } } return false; } public static function allapot_cimkek() { return [ 'ertesitve' => 'Értesítve', 'kapcsolatfelvetel' => 'Kapcsolatfelvétel megtörtént', 'lezarva' => 'Lezárva (megegyeztek)', 'sikertelen' => 'Sikertelen (a vevő nem elérhető)', 'nincs_email' => 'HIBA: nincs szerzői e-mail', ]; } public static function allapot_szinek() { return [ 'ertesitve' => '#0d6efd', 'kapcsolatfelvetel' => '#A26769', 'lezarva' => '#2C5F2D', 'sikertelen' => '#9A3B3B', 'nincs_email' => '#dc3545', ]; } }