Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Por que o metabox do PagHiper não aparece no editar pedidos no WooCommerce HPOS #100

Open
proteusbr1 opened this issue Feb 18, 2025 · 0 comments

Comments

@proteusbr1
Copy link

Problema:
Até agora, o plugin verificava se global $post->post_type era 'shop_order' para registrar o metabox apenas nessa condição. Isso funcionava no modo antigo (sem HPOS), em que a edição de pedidos ocorria via post.php?post=XXX&post_type=shop_order. Porém, com o HPOS ativado, a tela de edição de pedidos é admin.php?page=wc-orders&action=edit&id=XXX e não existe mais um objeto $post do tipo 'shop_order'. Dessa forma, a checagem falhava e o código nunca chamava add_meta_box(), impedindo que o metabox aparecesse na nova interface.

Causa técnica:

  • Quando o HPOS está ativo, o WooCommerce não usa WP_Post com post_type = shop_order para abrir a tela de pedidos.
  • Qualquer trecho de código que faça if ( ! $post || $post->post_type !== 'shop_order' ) { return; } impedirá o registro do metabox na nova tela, pois $post nem sequer é um objeto do tipo 'shop_order'.

Solução:

  1. Remover a checagem if ( !$post || $post->post_type !== 'shop_order' ) return;.
  2. Em vez disso, detectar o ID do pedido via $_GET['post'] (no modo tradicional) ou $_GET['id'] (no modo HPOS), e então chamar wc_get_order($id) para verificar se realmente é um pedido com método “paghiper”.
  3. Registrar o metabox com add_meta_box() tanto no ID de tela 'shop_order' quanto em wc_get_page_screen_id( 'shop-order' ) (que é a tela correta no HPOS), se o pedido realmente for paghiper/pix/billet.
  4. Assim, o metabox passa a aparecer normalmente em ambos os cenários (HPOS ativo ou não).

Exemplo resumido:

$post_id = isset($_GET['id']) ? absint($_GET['id']) : ( isset($_GET['post']) ? absint($_GET['post']) : 0 );

$order = wc_get_order( $post_id );
if ( $order && in_array( $order->get_payment_method(), array( 'paghiper', 'paghiper_billet', 'paghiper_pix' ), true ) ) {
    // Registrar o metabox sem depender de $post->post_type.
}

Com isso, o plugin não fica preso ao global $post->post_type e o metabox aparecerá nos pedidos HPOS sem problemas.

código completo woo-boleto-paghiper/includes/class-wc-paghiper-admin.php

<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Utilities\OrderUtil;

/**
 * Boleto Admin.
 */
class WC_Paghiper_Admin {

	private $timezone;

	/**
	 * Initialize the admin.
	 */
	public function __construct() {
		// Add metabox.
		add_action( 'add_meta_boxes', array( $this, 'register_metabox' ) );

		// Save Metabox.
		add_action( 'save_post', array( $this, 'save' ) );

		// Define nosso timezone default
		$this->timezone = new DateTimeZone('America/Sao_Paulo');

		// Enqueue styles and assets
		add_action( 'admin_enqueue_scripts', array( $this, 'load_plugin_assets' ) );
	}

	/**
	 * Register paghiper metabox, compatível com HPOS e interface legada.
	 */
	public function register_metabox() {

		/**
		 * Antes, o código fazia:
		 *
		 *    global $post;
		 *    if ( ! $post || $post->post_type !== 'shop_order' ) {
		 *        return;
		 *    }
		 *
		 * Isso impedia a exibição no HPOS porque $post não é necessariamente "shop_order".
		 * Agora, pegamos o ID do pedido via GET (tanto 'post' quanto 'id') e tentamos
		 * wc_get_order para checar se método de pagamento é Paghiper.
		 */

		$post_id = 0;

		// No modo legado, a URL costuma ter ?post=XXX
		if ( isset( $_GET['post'] ) ) {
			$post_id = absint( $_GET['post'] );
		}
		// Na nova tela HPOS, a URL costuma ter ?id=XXX
		elseif ( isset( $_GET['id'] ) ) {
			$post_id = absint( $_GET['id'] );
		}

		if ( ! $post_id ) {
			return; // Não há pedido para checar.
		}

		$order = wc_get_order( $post_id );
		if ( ! $order ) {
			return; // Não achamos um WC_Order válido
		}

		$payment_method = $order->get_payment_method();

		// Só adiciona se for "paghiper", "paghiper_pix" ou "paghiper_billet"
		if ( ! in_array( $payment_method, array( 'paghiper', 'paghiper_pix', 'paghiper_billet' ), true ) ) {
			return;
		}

		// Define o título do metabox com base no método
		$method_title = ( 'paghiper_pix' === $payment_method ) ? "PIX" : "Boleto";

		// Ajuste de compatibilidade HPOS: se HPOS está ativo, usamos wc_get_page_screen_id('shop-order')
		$target_screen = class_exists( '\Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController' )
			&& wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled()
				? wc_get_page_screen_id( 'shop-order' )
				: 'shop_order';

		add_meta_box(
			'paghiper-boleto',
			__( "Configurações do {$method_title}", 'woo_paghiper' ),
			array( $this, 'metabox_content' ),
			$target_screen,
			'side',
			'default'
		);
	}

	/**
	 * Banking Ticket metabox content.
	 *
	 * @param  WP_Post|WC_Order $post_or_order_object Data do pedido ou post
	 *
	 * @return string       Metabox HTML.
	 */
	public function metabox_content( $post_or_order_object ) {
		// Garante que $order seja instância de WC_Order
		$order = ( $post_or_order_object instanceof WP_Post )
			? wc_get_order( $post_or_order_object->ID )
			: $post_or_order_object;

		if ( ! $order ) {
			echo '<p>' . __( 'Este pedido não foi encontrado.', 'woo_paghiper' ) . '</p>';
			return;
		}

		$gateway_name = $order->get_payment_method();

		// Somente se for boleto ou pix PagHiper
		if ( in_array( $gateway_name, array( 'paghiper', 'paghiper_billet', 'paghiper_pix' ), true ) ) {
			$paghiper_data = $order->get_meta( 'wc_paghiper_data' );

			// Retrocompatibilidade com chaves antigas
			if ( isset( $paghiper_data['order_billet_due_date'] ) && ! isset( $paghiper_data['order_transaction_due_date'] ) ) {
				$paghiper_data['order_transaction_due_date'] = $paghiper_data['order_billet_due_date'];
			}

			// Se não existir data de vencimento, salva a default
			if ( ! isset( $paghiper_data['order_transaction_due_date'] ) ) {
				$settings = ( 'paghiper_pix' === $gateway_name )
					? get_option( 'woocommerce_paghiper_pix_settings' )
					: get_option( 'woocommerce_paghiper_billet_settings' );

				$days_due_date = isset( $settings['days_due_date'] ) ? absint( $settings['days_due_date'] ) : 5;
				$data = array();
				$data['order_transaction_due_date'] = date( 'Y-m-d', time() + ( $days_due_date * 86400 ) );

				$order->update_meta_data( 'wc_paghiper_data', $data );
				$order->save();

				$paghiper_data['order_transaction_due_date'] = $data['order_transaction_due_date'];
			}

			// Exibe código de barras, etc.
			require_once WC_Paghiper::get_plugin_path() . 'includes/class-wc-paghiper-transaction.php';
			$paghiperTransaction = new WC_PagHiper_Transaction( $order->get_id() );
			$html = $paghiperTransaction->printBarCode( false, true, array( 'code', 'digitable' ) );

			// Mostra data de vencimento formatada
			$order_transaction_due_date = DateTime::createFromFormat( 'Y-m-d', $paghiper_data['order_transaction_due_date'], $this->timezone );
			$formatted_due_date = $order_transaction_due_date
				? $order_transaction_due_date->format( 'd/m/Y' )
				: sprintf( __( '%s indisponível', 'woo_paghiper' ), ( 'paghiper_pix' === $gateway_name ? __( 'PIX', 'woo_paghiper' ) : __( 'Boleto', 'woo_paghiper' ) ) );

			$html .= '<p><strong>' . __( 'Data de Vencimento:', 'woo_paghiper' ) . '</strong> ' . $formatted_due_date . '</p>';

			// Se for boleto, mostra link
			if ( 'paghiper_pix' !== $gateway_name ) {
				$html .= '<p><strong>' . __( 'URL:', 'woo_paghiper' ) . '</strong> <a target="_blank" href="' . esc_url( wc_paghiper_get_paghiper_url( $order->get_order_key() ) ) . '">' . __( 'Visualizar boleto', 'woo_paghiper' ) . '</a></p>';
			}

			$html .= '<p style="border-top: 1px solid #ccc;"></p>';

			$html .= '<label for="woo_paghiper_expiration_date">' . __( 'Digite uma nova data de vencimento:', 'woo_paghiper' ) . '</label><br />';
			$html .= '<input type="text" id="woo_paghiper_expiration_date" name="woo_paghiper_expiration_date" class="date" style="width: 100%;" />';
			$html .= '<span class="description">' . sprintf( __( 'Ao configurar uma nova data de vencimento, o %s é re-enviado ao cliente por e-mail.', 'woo_paghiper' ), ( 'paghiper_pix' !== $gateway_name ? 'boleto' : 'PIX' ) ) . '</span>';

			// Mostra erros se houver
			if ( $error = get_transient( "woo_paghiper_save_order_errors_{$order->get_id()}" ) ) {
				$html .= sprintf( '<div class="error"><p>%s</p></div>', $error );
				delete_transient( "woo_paghiper_save_order_errors_{$order->get_id()}" );
			}

			if ( $error = get_transient( "woo_paghiper_due_date_order_errors_{$order->get_id()}" ) ) {
				$html .= sprintf( '<div class="error"><p>%s</p></div>', $error );
			}

		} else {
			// Caso não seja PagHiper
			$html = '<p>' . __( 'Este pedido não foi efetuado ou pago com PagHiper.', 'woo_paghiper' ) . '</p>';
			$html .= '<style>#paghiper-boleto.postbox {display: none;}</style>';
		}

		echo $html;
	}

	/**
	 * Salva a data de vencimento customizada do metabox.
	 *
	 * @param int $post_id Current post type ID.
	 */
	public function save( $post_id ) {
		// Verify nonce.
		if ( ! isset( $_POST['woo_paghiper_metabox_nonce'] ) || ! wp_verify_nonce( $_POST['woo_paghiper_metabox_nonce'], basename( __FILE__ ) ) ) {
			return $post_id;
		}

		// Verify if this is an auto save routine.
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return $post_id;
		}

		// Check permissions.
		if ( OrderUtil::is_order( $post_id, wc_get_order_types() ) && ! current_user_can( 'edit_page', $post_id ) ) {
			return $post_id;
		}

		if ( isset( $_POST['woo_paghiper_expiration_date'] ) && ! empty( $_POST['woo_paghiper_expiration_date'] ) ) {
			$input_date = sanitize_text_field( trim( $_POST['woo_paghiper_expiration_date'] ) );

			$today_date = new \DateTime();
			$today_date->setTimezone( $this->timezone );

			$order = wc_get_order( $post_id );
			$paghiper_data = $order->get_meta( 'wc_paghiper_data' );
			$new_due_date = DateTime::createFromFormat( 'd/m/Y', $input_date, $this->timezone );
			$formatted_date = ( $new_due_date ) ? $new_due_date->format( 'd/m/Y' ) : null;

			if ( ! $new_due_date || $formatted_date !== $input_date ) {
				$error = __( '<strong>Boleto PagHiper</strong>: Data de vencimento inválida!', 'woo_paghiper' );
				set_transient( "woo_paghiper_save_order_errors_{$post_id}", $error, 45 );
				return $post_id;
			} elseif ( $new_due_date && $today_date->diff( $new_due_date )->format( "%r%a" ) < 0 ) {
				$error = __( '<strong>Boleto PagHiper</strong>: A data de vencimento não pode ser anterior a data de hoje!', 'woo_paghiper' );
				set_transient( "woo_paghiper_save_order_errors_{$post_id}", $error, 45 );
				return $post_id;
			}

			// Atualiza data de vencimento
			$paghiper_data['order_transaction_due_date'] = $new_due_date->format( 'Y-m-d' );
			$order->update_meta_data( 'wc_paghiper_data', $paghiper_data );
			$order->save();

			// Delete eventual notificação de erro
			delete_transient( "woo_paghiper_due_date_order_errors_{$post_id}" );

			// Add order note.
			$order->add_order_note( sprintf( __( 'Data de vencimento alterada para %s', 'woo_paghiper' ), $formatted_date ) );

			// Envia email de notificação
			$this->email_notification( $order, $new_due_date->format( 'd/m/Y' ) );
		}
	}

	/**
	 * Envia e-mail após alterar a data de vencimento.
	 *
	 * @param WC_Order $order           Objeto de pedido
	 * @param string   $expiration_date Nova data (ex: 15/03/2025)
	 */
	protected function email_notification( $order, $expiration_date ) {
		if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '2.1', '>=' ) ) {
			$mailer = WC()->mailer();
		} else {
			global $woocommerce;
			$mailer = $woocommerce->mailer();
		}

		$gateway_name = $order->get_payment_method();
		$billing_email = $order->get_billing_email();

		if ( ! $billing_email ) {
			return;
		}

		// Assunto
		$subject = sprintf(
			__( 'O %s do seu pedido foi atualizado (%s)', 'woo_paghiper' ),
			( $gateway_name !== 'paghiper_pix' ? 'boleto' : 'PIX' ),
			$order->get_order_number()
		);

		// Cabeçalhos
		$headers = array( 'Content-Type: text/html; charset=UTF-8' );

		// Gera PDF ou link do boleto/pix
		require_once WC_Paghiper::get_plugin_path() . 'includes/class-wc-paghiper-transaction.php';
		$paghiperTransaction = new WC_PagHiper_Transaction( $order->get_id() );

		// Corpo do e-mail
		$main_message  = '<p>' . sprintf( __( 'A data de vencimento do seu %s foi atualizada para: %s', 'woo_paghiper' ),
							( $gateway_name !== 'paghiper_pix' ? 'boleto' : 'PIX' ),
							'<code>' . $expiration_date . '</code>' ) . '</p>';
		$main_message .= $paghiperTransaction->printBarCode();
		$main_message .= '<p>' . sprintf(
			'<a class="button" href="%s" target="_blank">%s</a>',
			esc_url( wc_paghiper_get_paghiper_url( $order->get_order_key() ) ),
			__( 'Pagar o boleto &rarr;', 'woo_paghiper' )
		) . '</p>';

		$message = $mailer->wrap_message(
			sprintf(
				__( 'Nova data de vencimento para o seu %s', 'woo_paghiper' ),
				( $gateway_name !== 'paghiper_pix' ? 'boleto' : 'PIX' )
			),
			$main_message
		);

		$mailer->send( $billing_email, $subject, $message, $headers, '' );
	}

	/**
	 * Register and enqueue assets
	 */
	public function load_plugin_assets() {

		if( ! wp_script_is( 'jquery-mask', 'registered' ) ) {
			wp_register_script(
				'jquery-mask',
				wc_paghiper_assets_url() . 'js/libs/jquery.mask/jquery.mask.min.js',
				array( 'jquery' ),
				'1.14.16',
				false
			);
		}

		if( ! wp_script_is( 'paghiper-backend-js', 'registered' ) ) {
			wp_register_script(
				'paghiper-backend-js',
				wc_paghiper_assets_url() . 'js/backend.min.js',
				array( 'jquery' ),
				'1.1',
				false
			);
		}

		wp_register_style(
			'paghiper-backend-css',
			wc_paghiper_assets_url() . 'css/backend.min.css',
			false,
			'1.0.0'
		);

		if ( is_admin() ) {
			global $current_screen;
			$req_action = empty( $_REQUEST['action'] ) ? false : $_REQUEST['action'];

			if ( $current_screen && $current_screen->post_type === 'shop_order' && 'edit' === $req_action ) {
				wp_enqueue_script( 'jquery-mask' );
				wp_enqueue_script( 'paghiper-backend-js' );
			}
			wp_enqueue_style( 'paghiper-backend-css' );
		}
	}
}

new WC_Paghiper_Admin();

referência:
https://developer.woocommerce.com/docs/hpos-extension-recipe-book/#:~:text=add_action%28%20%27before_woocommerce_init%27%2C%20function%28%29%20,FeaturesUtil%3A%3Aclass%20%29%20%29

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant