config_factory = $config_factory;
$this->status_provider = $status_provider;
$this->plugin_core = $plugin_core;
}
/**
* Get config in strict mode.
*
* @param string $currency The currency.
* @return P24_Config_Accessor
* @throws LogicException Should be not thrown in normal operation.
*/
private function get_config( $currency ) {
/* It may be not initialized. */
if ( is_callable( $this->config_factory ) ) {
$config_factory = $this->config_factory;
$config = $config_factory( $currency );
} else {
$config = P24_Settings_Helper::load_settings( $currency );
}
if ( ! $config ) {
throw new LogicException( 'Cannot load config for provided currency.' );
}
$config->access_mode_to_strict();
return $config;
}
/**
* Set decoration mode.
*
* @param bool $mode Desired mode of decorator.
* @param string $currency Currency.
* @return bool
*/
public function try_set_decoration_mode( $mode, $currency ) {
$config_accessor = $this->get_config( $currency );
if ( $mode && $config_accessor->get_p24_use_special_status() ) {
$this->in_decoration_mode = true;
} else {
$this->in_decoration_mode = false;
}
return $this->in_decoration_mode;
}
/**
* Check if code is in edit mode of order.
*
* @return bool
*/
private function check_if_in_edit_mode() {
global $typenow;
global $editing;
return 'shop_order' === $typenow && $editing;
}
/**
* Add pending status.
*
* @param WC_Order $order The order.
* @param array $data Additional order data.
*/
public function try_set_custom_pending_status( $order, $data ) { #phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
if ( $this->plugin_core->check_if_from_przelewy24( $order ) ) {
$config_accessor = $this->get_config( $order->get_currency() );
if ( $config_accessor->get_p24_use_special_status() ) {
$custom_pending_status = $config_accessor->get_p24_custom_pending_status();
if ( $custom_pending_status ) {
$order->set_status( $custom_pending_status );
} else {
$order->set_status( 'pending' . self::STATUS_SUFFIX );
}
}
}
}
/**
* Decorate order status.
*
* @param string $status Proposed new status for order.
* @param int $order_id Order id.
* @param WC_Order $order Order object.
*/
public function try_set_custom_processing_status( $status, $order_id, $order ) {
if ( $this->in_decoration_mode ) {
if ( 'processing' === $status ) {
$config_accessor = $this->get_config( $order->get_currency() );
$custom_processing_status = $config_accessor->get_p24_custom_processing_status();
if ( $custom_processing_status ) {
return $custom_processing_status;
} else {
return $status . self::STATUS_SUFFIX;
}
}
}
return $status;
}
/**
* Add valid statuses.
*
* @param array $statuses Default WooCommerce statuses.
* @return array
*/
public function add_valid_statuses( $statuses ) {
/*
* We have to add status with and without wc- prefix. There is a mess in WooCommerce code.
* There is an exception from this rule though.
*/
if ( ! $this->check_if_in_edit_mode() ) {
$statuses[ 'pending' . self::STATUS_SUFFIX ] = $statuses['wc-pending'] . self::STATUS_SUFFIX_HUMAN;
/* WooCommerce standards force us to use raw literals. */
$statuses[ 'processing' . self::STATUS_SUFFIX ] = __( 'Opłacone przez P24', 'przelewy24' );
$statuses += $this->status_provider->get_additional_valid_statuses( '' );
}
$statuses[ 'wc-pending' . self::STATUS_SUFFIX ] = $statuses['wc-pending'] . self::STATUS_SUFFIX_HUMAN;
/* WooCommerce standards force us to use raw literals. */
$statuses[ 'wc-processing' . self::STATUS_SUFFIX ] = __( 'Opłacone przez P24', 'przelewy24' );
$statuses += $this->status_provider->get_additional_valid_statuses( 'wc-' );
return $statuses;
}
/**
* Add valid statuses for unpaid.
*
* @param array $defaults Default unpaid statuses.
* @param WC_Order $order Order.
* @return array
*/
public function add_valid_for_unpaid( $defaults, $order ) {
if ( ! $this->plugin_core->check_if_from_przelewy24( $order ) ) {
return $defaults;
} else {
$defaults[] = 'pending' . self::STATUS_SUFFIX;
$config_accessor = $this->get_config( $order->get_currency() );
$defaults[] = $config_accessor->get_p24_custom_pending_status();
}
return $defaults;
}
/**
* Add valid statuses for unpaid if we do not know the order.
*
* @param array $defaults Default unpaid statuses.
* @return array
*/
public function add_pending_statuses_blind( $defaults ) {
/* We need to get the order object somehow. */
global $wp;
if ( isset( $wp->query_vars['order-pay'] ) ) {
$order = new WC_Order( $wp->query_vars['order-pay'] );
$defaults = $this->add_valid_for_unpaid( $defaults, $order );
}
return $defaults;
}
/**
* Add valid status to change from.
*
* @param array $defaults Default WooCommerce statuses.
* @return array
*/
public function add_valid_for_from( $defaults ) {
$defaults[] = 'pending' . self::STATUS_SUFFIX;
$defaults[] = 'processing' . self::STATUS_SUFFIX;
$additional = $this->status_provider->get_additional_valid_statuse_codes( '' );
$defaults = array_merge( $defaults, $additional );
/* We have to add status with and without wc- prefix. There is a mess in WooCommerce code. */
$defaults[] = 'wc-pending' . self::STATUS_SUFFIX;
$defaults[] = 'wc-processing' . self::STATUS_SUFFIX;
$additional = $this->status_provider->get_additional_valid_statuse_codes( 'wc-' );
$defaults = array_merge( $defaults, $additional );
return $defaults;
}
/**
* Fix statuses in args.
*
* @param array $args Default args.
* @param array $extra Extra data.
* @return array
*/
public function fix_statuses_in_args( $args, $extra ) { #phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
/* Used on my orders list. */
$ret = $args;
if ( isset( $args['post_status'] ) && is_array( $args['post_status'] ) ) {
$statuses = $args['post_status'];
$custom_statuses = $this->status_provider->get_additional_valid_statuse_codes( '' );
$custom_statuses[] = 'pending' . self::STATUS_SUFFIX;
$custom_statuses[] = 'processing' . self::STATUS_SUFFIX;
foreach ( $statuses as $wk => $wv ) {
if ( preg_match( '/^wc-(.+)/', $wv, $m ) ) {
$ck = array_search( $m[1], $custom_statuses, true );
if ( false !== $ck ) {
/* There is a mess in WooCommerce code. Fix one of it. */
$ret['post_status'][ $wk ] = $custom_statuses[ $ck ];
}
}
}
}
return $ret;
}
/**
* Add valid status to change to.
*
* @param array $defaults Default WooCommerce statuses.
* @return array
*/
public function add_valid_for_to( $defaults ) {
if ( $this->in_decoration_mode ) {
$defaults[] = 'pending' . self::STATUS_SUFFIX;
$defaults[] = 'processing' . self::STATUS_SUFFIX;
$additional = $this->status_provider->get_additional_valid_statuse_codes( '' );
$defaults = array_merge( $defaults, $additional );
}
return $defaults;
}
/**
* Add description for status.
*
* @param array $defaults Default WooCommerce statuses.
* @return array
*/
public function add_all_status_descriptions( $defaults ) {
$defaults[ 'pending' . self::STATUS_SUFFIX ] = $this->prep_status_description( $defaults, 'wc-pending' );
$defaults[ 'processing' . self::STATUS_SUFFIX ] = $this->prep_status_description( $defaults, 'wc-processing' );
$defaults += $this->status_provider->status_description_list( $defaults );
return $defaults;
}
/**
* Prep status description.
*
* @param array $defaults Default statuses.
* @param string $base_key The code for base status.
* @return array
*/
public function prep_status_description( array $defaults, $base_key ): array {
$new = $defaults[ $base_key ];
if ( P24_Woo_Commerce_Internals::PROCESSING_STATUS === $base_key ) {
/* WooCommerce standards force us to use raw literals. */
$new['label'] = __( 'Opłacone przez P24', 'przelewy24' );
} else {
$new['label'] = $new['label'] . self::STATUS_SUFFIX_HUMAN;
}
$rx = '/([^\\<]+)(\\<.*)/';
$new_label_count = array();
foreach ( $new['label_count'] as $k => $v ) {
if ( is_string( $v ) && preg_match( $rx, $v, $m ) ) {
$new_label_count[ $k ] = $m[1] . self::STATUS_SUFFIX_HUMAN . ' ' . $m[2];
} else {
$new_label_count[ $k ] = $v;
}
}
$new['label_count'] = $new_label_count;
return $new;
}
/**
* Super translation.
*
* @param string $translation Proposed translation.
* @param string $single Proposed translation for single.
* @param string $plural Proposed translation for plural.
* @param int $number Number of items.
* @param string $domain Domain of translation.
* @return mixed|string
*/
public function super_translation( $translation, $single, $plural, $number, $domain ) {
if ( P24_Woo_Commerce_Internals::TRANSLATION_DOMAIN !== $domain ) {
return $translation;
}
$suffix = preg_quote( self::STATUS_SUFFIX_HUMAN, '/' );
$rx = '/([^\\<]+)' . $suffix . ' (\\<.*)/';
if ( preg_match( $rx, $translation, $m ) ) {
$filtered = $m[1] . $m[2];
if ( P24_Woo_Commerce_Strings::PENDING_PAYMENT_WITH_COUNT === $filtered ) {
/* WooCommerce standards force us to use raw literals, special comments and blank lines below. */
/* translators: %s number of orders. */
$raw = _n( 'Pending payment (%s)', 'Pending payment (%s)', $number, 'woocommerce' );
$rx = '/([^\\<]+)(\\<.*)/';
if ( preg_match( $rx, $raw, $m ) ) {
$translation = $m[1] . self::STATUS_SUFFIX_HUMAN . ' ' . $m[2];
}
} elseif ( P24_Woo_Commerce_Strings::PROCESSING_PAYMENT_WITH_COUNT === $filtered ) {
/* WooCommerce standards force us to use raw literals, special comments and blank lines below. */
/* translators: %s number of orders. */
$translation = __( 'Opłacone przez P24 (%s)', 'przelewy24' );
}
}
return $translation;
}
/**
* Signal internal status changes.
*
* @param int $order_id Order id.
* @param string $from Existing status.
* @param string $to Proposed status.
* @param WC_Order $order The order.
*/
public function signal_more_status_changes( $order_id, $from, $to, $order ) {
$need_action = false;
$internal_from = $from;
$internal_to = $to;
$config_accessor = $this->get_config( $order->get_currency() );
$statuses = array(
'pending' . self::STATUS_SUFFIX => 'pending',
'processing' . self::STATUS_SUFFIX => 'processing',
$config_accessor->get_p24_custom_pending_status() => 'pending',
$config_accessor->get_p24_custom_processing_status() => 'processing',
);
foreach ( $statuses as $status => $internal ) {
if ( $from === $status ) {
$internal_from = $internal;
$need_action = true;
}
if ( $to === $status ) {
$internal_to = $internal;
$need_action = true;
}
}
if ( $need_action ) {
do_action( 'woocommerce_order_status_' . $internal_from . '_to_' . $internal_to, $order_id, $order );
do_action( 'woocommerce_order_status_changed', $order_id, $internal_from, $internal_to, $order );
if ( $internal_to !== $to ) {
do_action( 'woocommerce_order_status_' . $internal_to, $order_id, $order );
}
}
}
/**
* Check need of payment.
*
* @param bool $need_by_wc Default need.
* @param WC_Order $order The order.
* @param array $statuses List of statuses.
* @return bool
*/
public function check_need_of_payment( $need_by_wc, $order, $statuses ) { #phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
if ( ! $this->plugin_core->check_if_from_przelewy24( $order ) ) {
return $need_by_wc;
} elseif ( $need_by_wc ) {
$status = $order->get_status();
$suffixed_paid_statuses = array(
'processing' . self::STATUS_SUFFIX,
'wc-processing' . self::STATUS_SUFFIX,
);
if ( in_array( $status, $suffixed_paid_statuses, true ) ) {
return false;
} else {
$config_accessor = $this->get_config( $order->get_currency() );
/* As long it is not precessing, we are fine. */
return $config_accessor->get_p24_custom_processing_status() !== $status;
}
} else {
return false;
}
}
/**
* Validate statuses.
*
* It should be safe as long as they are different.
*
* @param string $pending Code for status penging.
* @param string $processing Code for status processing.
* @return bool
*/
public static function validate_statuses( $pending, $processing ) {
if ( $pending ) {
$pending = (string) $pending;
} else {
$pending = 'pending' . self::STATUS_SUFFIX;
}
if ( $processing ) {
$processing = (string) $processing;
} else {
$processing = 'processing' . self::STATUS_SUFFIX;
}
return $processing !== $pending;
}
/**
* Check if module for statuses is active.
*
* @return bool
*/
public static function is_active() {
$status = get_option( 'p24_statuses_active', 'no' );
return 'yes' === $status;
}
/**
* Cancel unpaid orders that has custom Przelewy24 status.
*/
public function cancel_unpaid_p24_orders() {
$currencies = $this->plugin_core->get_available_currencies_or_default();
foreach ( $currencies as $currency ) {
$config = $this->get_config( $currency );
$pending_status = $config->get_p24_custom_pending_status();
if ( ! $pending_status ) {
$pending_status = 'pending' . self::STATUS_SUFFIX;
}
P24_Status_Decorator_Db::cancel_unpaid_p24_orders( $pending_status );
}
}
/**
* Fix for paid orders with custom statuses.
*
* @param bool $paid_by_wc The paid status from WC.
* @param WC_Order $order The order.
* @return bool
*/
public function check_if_paid_filter( $paid_by_wc, $order ) {
if ( $paid_by_wc ) {
/* Other paid status. */
return true;
} elseif ( ! $this->plugin_core->check_if_from_przelewy24( $order ) ) {
return $paid_by_wc;
}
$config = $this->get_config( $order->get_currency() );
$order_status = $order->get_status();
$processing_status = $config->get_p24_custom_processing_status();
return $order_status === $processing_status;
}
/**
* Bind events.
*/
public function bind_events() {
if ( ! self::is_active() ) {
/* Nothing to bind. */
return;
}
add_action( 'woocommerce_cancel_unpaid_orders', array( $this, 'cancel_unpaid_p24_orders' ) );
add_action( 'woocommerce_checkout_create_order', array( $this, 'try_set_custom_pending_status' ), 10, 2 );
add_action( 'woocommerce_order_status_changed', array( $this, 'signal_more_status_changes' ), 5, 4 );
add_filter( 'woocommerce_payment_complete_order_status', array( $this, 'try_set_custom_processing_status' ), 10, 3 );
add_filter( 'woocommerce_valid_order_statuses_for_payment_complete', array( $this, 'add_valid_for_unpaid' ), 10, 2 );
add_filter( 'woocommerce_valid_order_statuses_for_payment', array( $this, 'add_valid_for_from' ) );
add_filter( 'woocommerce_order_is_paid_statuses', array( $this, 'add_valid_for_to' ) );
add_filter( 'woocommerce_register_shop_order_post_statuses', array( $this, 'add_all_status_descriptions' ) );
add_filter( 'wc_order_statuses', array( $this, 'add_valid_statuses' ) );
add_filter( 'woocommerce_get_wp_query_args', array( $this, 'fix_statuses_in_args' ), 10, 2 );
add_filter( 'woocommerce_order_needs_payment', array( $this, 'check_need_of_payment' ), 10, 3 );
add_filter( 'ngettext_woocommerce', array( $this, 'super_translation' ), 10, 5 );
add_filter( 'woocommerce_order_is_pending_statuses', array( $this, 'add_pending_statuses_blind' ), 10, 1 );
add_filter( 'woocommerce_order_is_paid', array( $this, 'check_if_paid_filter' ), 10, 2 );
}
}