first commit

This commit is contained in:
2026-03-05 13:07:40 +01:00
commit 64ba0721ee
25709 changed files with 4691006 additions and 0 deletions

View File

@@ -0,0 +1,236 @@
<?php
class Przelewy24Generator
{
const P24NOW = 266;
/**
* @var WC_Gateway_Przelewy24
*/
private $gateway;
/**
* Przelewy24Generator constructor.
*
* @param WC_Gateway_Przelewy24 $gateway The class that provide configuration.
*/
public function __construct(WC_Gateway_Przelewy24 $gateway) {
$this->gateway = $gateway;
}
/**
* Generate przelewy24 button link
*
* @param WC_Order $order
* @param string|null $transaction_id
* @return array|false
* @throws Exception
*/
public function generate_fields_array($order, $transaction_id = null)
{
if (!$order) return false;
global $locale;
$localization = !empty($locale) ? explode("_", $locale) : 'pl';
/* We need raw order id integer to generate transaction and get metadata. */
$order_id = (int) $order->get_id();
if (is_null($transaction_id)) {
$transaction_id = $order_id . "_" . uniqid(md5($order_id . '_' . date("ymds")), true);
}
$description_order_id = $order->get_order_number();
// modifies order number if Sequential Order Numbers Pro plugin is installed
if (class_exists('WC_Seq_Order_Number_Pro')) {
$seq = new WC_Seq_Order_Number_Pro();
$description_order_id = $seq->get_order_number($description_order_id, $order);
} else if (class_exists('WC_Seq_Order_Number')) {
$seq = new WC_Seq_Order_Number();
$description_order_id = $seq->get_order_number($description_order_id, $order);
}
$config = $this->gateway->load_settings_from_db_formatted( $order->get_currency() );
$config->access_mode_to_strict();
//p24_opis depend of test mode
$desc = ($config->is_p24_operation_mode( 'sandbox' ) ? __('Transakcja testowa', 'przelewy24') . ', ' : '') .
__('Zamówienie nr', 'przelewy24') . ': ' . $description_order_id . ', ' . $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() . ', ' . date('Ymdhi');
$status_page = add_query_arg(array('wc-api' => 'WC_Gateway_Przelewy24'), home_url('/'));
/*Form send to przelewy24*/
$amount = $order->get_total() * 100;
$amount = number_format($amount, 0, "", "");
$currency = strtoupper($order->get_currency());
$przelewy24_arg = array(
'p24_session_id' => addslashes($transaction_id),
'p24_merchant_id' => (int) $config->get_merchant_id(),
'p24_pos_id' => (int) $config->get_shop_id(),
'p24_email' => filter_var($order->get_billing_email(), FILTER_SANITIZE_EMAIL),
'p24_amount' => (int)$amount,
'p24_currency' => filter_var($currency, FILTER_SANITIZE_STRING),
'p24_description' => addslashes($desc),
'p24_language' => filter_var($localization[0], FILTER_SANITIZE_STRING),
'p24_client' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
'p24_address' => $order->get_billing_address_1(),
'p24_city' => $order->get_billing_city(),
'p24_zip' => $order->get_billing_postcode(),
'p24_country' => $order->get_billing_country(),
'p24_encoding' => 'UTF-8',
'p24_url_status' => filter_var($status_page, FILTER_SANITIZE_URL),
'p24_url_return' => filter_var(WC_Gateway_Przelewy24::getReturnUrlStatic($order), FILTER_SANITIZE_URL),
'p24_api_version' => P24_VERSION,
'p24_ecommerce' => 'woocommerce_' . WOOCOMMERCE_VERSION,
'p24_ecommerce2' => '1.0.0',
'p24_method' => (int)get_post_meta($order_id, 'p24_method', true),
'p24_shipping' => number_format($order->get_shipping_total() * 100, 0, '', ''),
'p24_wait_for_result' => (int) $config->get_p24_wait_for_result(),
'p24_provided_blik_code' => $order->get_meta(P24_Extra_Gateway::BLIK_CODE_META_KEY),
'p24_channel' => '',
);
if ($this->activateChannel2ki($przelewy24_arg)) {
$przelewy24_arg['p24_channel'] = 2048;
}
$productsInfo = array();
foreach ($order->get_items() as $product) {
$productsInfo[] = array(
'name' => filter_var($product['name'], FILTER_SANITIZE_STRING),
'description' => strip_tags(get_post($product['product_id'])->post_content),
'quantity' => (int)$product['qty'],
'price' => ($product['line_total'] / $product['qty']) * 100,
'number' => (int)$product['product_id'],
);
}
$shipping = number_format($order->get_shipping_total() * 100, 0, '', '');
$translations = array(
'virtual_product_name' => __('Dodatkowe kwoty [VAT, rabaty]', 'przelewy24'),
'cart_as_product' => __('Twoje zamówienie', 'przelewy24'),
);
$p24Product = new Przelewy24Product($translations);
$p24ProductItems = $p24Product->prepareCartItems($amount, $productsInfo, $shipping);
$przelewy24_arg = array_merge($przelewy24_arg, $p24ProductItems);
Przelewy24Class::checkMandatoryFieldsForAction($przelewy24_arg);
return $przelewy24_arg;
}
/**
* Generate payload for REST transaction.
*
* @param WC_Order $order
* @param null|string $transaction_id
* @param null|int $method
* @return array
* @throws Exception
*/
public function generate_payload_for_rest( $order, $transaction_id = null, $method = null ) {
$args = $this->generate_fields_array( $order, $transaction_id );
$status_page = add_query_arg(array('wc-api' => 'WC_Gateway_Przelewy24', 'status' => 'REST'), home_url('/'));
return array(
"merchantId" => (int)$args['p24_merchant_id'],
"posId" => (int)$args['p24_pos_id'],
"sessionId" => (string)$args["p24_session_id"],
"amount" => (int)$args["p24_amount"],
"currency" => (string)$args["p24_currency"],
"description" => (string)$args["p24_description"],
"email" => (string)$args["p24_email"],
"client" => (string)$args["p24_client"],
"address" => (string)$args["p24_address"],
"zip" => (string)$args["p24_zip"],
"city" => (string)$args["p24_city"],
"country" => (string)$args["p24_country"],
"language" => (string)$args["p24_language"],
"urlReturn" => (string)$args["p24_url_return"],
"urlStatus" => (string)filter_var($status_page, FILTER_SANITIZE_URL),
"shipping" => (int)$args["p24_shipping"],
"encoding" => (string)$args["p24_encoding"],
"method" => ($method||$args["p24_method"])?($method?:$args["p24_method"]):null
);
}
/**
* @param WC_Order $order
* @param bool $autoSubmit
* @param bool $makeRecurringForm
* @return string
* @throws Exception
*/
public function generate_przelewy24_form($order, $autoSubmit = true, $makeRecurringForm = false)
{
$przelewy24_arg = $this->generate_fields_array($order);
$config = $this->gateway->load_settings_from_db_formatted( $order->get_currency() );
$strict_config = clone $config;
$strict_config->access_mode_to_strict();
$blik_code = '';
if ($strict_config->get_p24_payinshop()) {
$blik_code .= '<input type="hidden" name="p24_url_return" value="' . $przelewy24_arg['p24_url_return'] . '" />'."\n";
}
if ((int)$przelewy24_arg['p24_method'] === (int)P24_Extra_Gateway::BLIK_METHOD && $przelewy24_arg['p24_provided_blik_code']) {
$blik_code .= '<input type="hidden" name="p24_provided_blik_code" value="' . $przelewy24_arg['p24_provided_blik_code'] . '" />'."\n";
}
$accept_in_shop = '';
if ( $config->get_p24_acceptinshop() === 'yes' && $config->get_p24_show_methods_confirmation() === 'yes' ) {
$accept_in_shop = '<p><label><input type="checkbox" required="required" name="p24_regulation_accept" value="1" />'. __('Tak, przeczytałem i akceptuję regulamin Przelewy24.', 'przelewy24') .'</label></p>';
}
$return = '<div id="payment" style="background: none"> ' .
'<form action="'.get_rest_url(null,'/przelewy24/v1/create-payment').'" method="post" id="przelewy_payment_form"'.
($autoSubmit ? '' : ' onSubmit="return p24_processPayment()" ') .
'><input type="hidden" name="order_id" value="'.((int) $order->get_id()).'"> ' .
"<input type=\"hidden\" name=\"p24_session_id\" value=\"{$przelewy24_arg['p24_session_id']}\" />".
"<input type=\"hidden\" name=\"p24_method\" />".
$blik_code .
$accept_in_shop .
'<input type="submit" class="button alt" id="place_order" value="' . __('Potwierdzam zamówienie', 'przelewy24') . '" /> ' .
'<p style="text-align:right; float:right; width:100%; font-size:12px;">' . __('Złożenie zamówienia wiąże się z obowiązkiem zapłaty', 'przelewy24') . '</p>' .
'<a class="button cancel" href="' . $order->get_cancel_order_url() . '">' . __('Anuluj zamówienie', 'przelewy24') . '</a>' .
($autoSubmit ?
'<script type="text/javascript">jQuery(function(){jQuery("body").block({message: "' .
__('Dziękujemy za złożenie zamówienia. Za chwilę nastąpi przekierowanie na stronę przelewy24.pl', 'przelewy24') .
'",overlayCSS: {background: "#fff",opacity: 0.6},css: {padding:20,textAlign:"center",color:"#555",border:"2px solid #AF2325",backgroundColor:"#fff",cursor:"wait",lineHeight:"32px"}});' .
'jQuery("#przelewy_payment_form input[name=p24_regulation_accept]").prop("required", false);' .
'p24_processPayment(); });' .
'</script>' : '') .
'</form>' .
'</div>' .
'';
if (!!$makeRecurringForm) {
$return .= <<<FORMRECURING
<form method="post" id="przelewy24FormRecuring" name="przelewy24FormRecuring" accept-charset="utf-8">
<input type="hidden" name="p24_session_id" value="{$przelewy24_arg['p24_session_id']}" />
<input type="hidden" name="p24_regulation_accept" />
<input type="hidden" name="p24_cc" />
</form>
FORMRECURING;
}
return $return;
}
/**
* Check if activate channel 2024.
*
* @param array $przelewy24_arg
*
* @return bool
*/
private function activateChannel2ki(array $przelewy24_arg)
{
$hasP24NowSelected = self::P24NOW === $przelewy24_arg['p24_method'];
/* The p24_amount is PLN * 100. */
$isAmount = (int)$przelewy24_arg['p24_amount'] < (100 * 10000) && (int)$przelewy24_arg['p24_amount'] > 0;
$isCurrency = $przelewy24_arg['p24_currency'] == "PLN";
return $isCurrency && $isAmount && $hasP24NowSelected;
}
}

View File

@@ -0,0 +1,95 @@
<?php
class Przelewy24Helpers
{
public static function getBankTxt(&$checkedCounter, $bank_id, $bank_name, $text = '', $cc_id = '', $class = '', $onclick = '')
{
$checkedCounter++;
$bank_id = sanitize_text_field($bank_id);
$bank_name = sanitize_text_field($bank_name);
$text = sanitize_text_field($text);
$cc_id = sanitize_text_field($cc_id);
$class = sanitize_text_field($class);
$onclick = sanitize_text_field($onclick);
return
'
<li onclick="' . $onclick . '">' .
'<div class="input-box bank-item" data-id="' . (int)$bank_id . '" data-cc="' . $cc_id . '" data-text="' . $text . '" >' .
'<label for="przelewy_method_id_' . $bank_id . '-' . $cc_id . '">' .
'<input id="przelewy_method_id_' . $bank_id . '-' . $cc_id . '" name="payment_method_id" ' .
' class="radio" type="radio" ' . ($checkedCounter == 1 ? 'checked="checked"' : '') . ' />' .
'<span>' . $bank_name . '</span></label>' .
(empty($cc_id) ? '' : '<span class="removecc" ' .
' title="' . __('Usuń zapamiętaną kartę', 'przelewy24') . ' ' . $bank_name . ' ' . $text . '" ' .
' onclick="arguments[0].stopPropagation(); if (confirm(\'' . __('Czy na pewno?', 'przelewy24') . '\')) removecc(' . $cc_id . ')"></span>') .
'</div></li>
';
}
public static function getExtraPromotedTxt(&$checkedCounter, $bank_id, $bank_name, $text = '', $cc_id = '', $class = '', $onclick = '')
{
$checkedCounter++;
$bank_id = sanitize_text_field($bank_id);
$bank_name = sanitize_text_field($bank_name);
$text = sanitize_text_field($text);
$cc_id = sanitize_text_field($cc_id);
$class = sanitize_text_field($class);
$onclick = sanitize_text_field($onclick);
return
'
<li onclick="' . $onclick . '">' .
'<div class="input-box bank-box bank-item" data-id="' . (int)$bank_id . '" data-cc="' . $cc_id . '" data-text="' . $text . '" >' .
'<label for="przelewy_method_id_' . $bank_id . '-' . $cc_id . '">' .
'<input id="przelewy_method_id_' . $bank_id . '-' . $cc_id . '" name="payment_method_id" ' .
' class="radio" type="radio" ' . ($checkedCounter == 1 ? 'checked="checked"' : '') . ' />' .
'<span>' . $bank_name . '</span></label>' .
(empty($cc_id) ? '' : '<span class="removecc" ' .
' title="' . __('Usuń zapamiętaną kartę', 'przelewy24') . ' ' . $bank_name . ' ' . $text . '" ' .
' onclick="arguments[0].stopPropagation(); if (confirm(\'' . __('Czy na pewno?', 'przelewy24') . '\')) removecc(' . $cc_id . ')"></span>') .
'</div></li>
';
}
public static function checkoutOrderProcessed($order_id, $posted)
{
if (empty($_POST) || empty($_POST['selected_banks']) || !is_array($_POST['selected_banks'])) {
return false;
}
return false;
}
/**
* Set custom data.
*
* @param string $data_type Data type.
* @param int $data_id Data id.
* @param string $key Key.
* @param string|object|array $value Value.
* @return bool True on success.
*/
public static function setCustomData($data_type, $data_id, $key, $value)
{
global $wpdb;
$table_name = $wpdb->prefix . 'woocommerce_p24_data';
if ($key != 'oneclick') {
$wpdb->delete($table_name, ['data_type' => $data_type, 'data_id' => $data_id, 'custom_key' => $key], ['%s', '%d', '%s']);
}
if (empty($value)) return false;
if (is_object($value) || is_array($value)) $value = json_encode($value);
return (bool) $wpdb->insert($table_name, array(
'data_type' => $data_type,
'data_id' => $data_id,
'custom_key' => $key,
'custom_value' => $value,
), array('%s', '%d', '%s', '%s'));
}
}

View File

@@ -0,0 +1,103 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
/**
* Class Przelewy24Mailer
*/
class Przelewy24Mailer {
/**
* Function to find gateway that can provide configuration.
*
* @return null|WC_Gateway_Przelewy24 The class that can provide configuration.
*/
private function find_p24_gateway() {
$gateways = WC()->payment_gateways()->payment_gateways;
foreach ($gateways as $gateway) {
if ($gateway instanceof WC_Gateway_Przelewy24) {
return $gateway;
}
}
return null;
}
/**
* Send amil.
*
* @param WC_Order|null $order Order that need an mail.
*/
public function trigger( $order ) {
if ( !$order )
return;
if($order->is_paid() || $order->get_payment_method() !== 'przelewy24')
return;
$subject = __('Dziękujemy za złożenie zamówienia', 'przelewy24');
$this->send_email( $order, $subject, '/emails/notification_email.php' );
}
/**
* Send order summary email.
*
* @param WC_Order|null $order Order that need an mail.
*/
public function send_order_summary_mail( $order )
{
if (
! $order ||
$order->get_payment_method() !== WC_Gateway_Przelewy24::PAYMENT_METHOD ||
! get_przelewy24_plugin_instance()->should_activate_order_created_notification()
) {
return;
}
$subject = __('Dziękujemy za złożenie zamówienia', 'przelewy24');
$this->send_email( $order, $subject, '/emails/order_summary.php' );
}
/**
* Get email content
*
* @param string $template
* @param WC_Order $order
* @param bool $heading
* @param WC_Emails $mailer
*
* @return string
*/
function get_content( $template, $order, $heading = false, $mailer ) {
return wc_get_template_html( $template, array(
'order' => $order,
'email_heading' => $heading,
'sent_to_admin' => false,
'plain_text' => false,
'email' => $mailer,
), '', PRZELEWY24_PATH );
}
/**
* Perform sending email
*
* @param WC_Order $order
* @param string $subject
* @param string $template
*/
private function send_email( $order, $subject, $template )
{
$recipient = $order->get_billing_email();
$mailer = WC()->mailer();
$content = $this->get_content( $template, $order, $subject, $mailer );
$headers = 'Content-Type: text/html';
$mailer->send( $recipient, $subject, $content, $headers );
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,119 @@
<?php
/**
* File that define P24_Soap_Blik_Html.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class P24_Soap_Blik_Html
*/
class P24_Blik_Html {
/**
* Plugin core.
*
* @var P24_Core The plugin core.
*/
private $core;
/**
* P24_Blik_Html constructor.
*
* @param P24_Core $core The plugin core.
*/
public function __construct( $core ) {
$this->core = $core;
add_action( 'woocommerce_checkout_after_order_review', array( $this, 'extend_checkout_page_form' ) );
add_action( 'woocommerce_after_checkout_form', array( $this, 'extend_checkout_page_bottom' ) );
}
/**
* Get additional HTML code for checkout form.
*/
public function extend_checkout_page_form() {
echo '<input type="hidden" id="p24-blik-code-input" name="p24-blik-code">';
}
/**
* Extend_checkout_page_bottom.
*
* Check and embed code for modal if needed on checkout page.
*/
public function extend_checkout_page_bottom() {
$config = $this->core->get_config_for_currency();
$config->access_mode_to_strict();
if ( $config->get_p24_payinshop() ) {
$display_terms = $config->get_p24_acceptinshop();
self::echo_modal_html( $display_terms );
}
}
/**
* Get HTML code for modal
*
* @param bool $need_terms If checkbox to show terms is needed. Default to false.
*
* @return string
*/
public static function get_modal_html( $need_terms = false ) {
$header = esc_html( __( 'Wprowadź kod BLIK', 'przelewy24' ) );
$label = esc_html( __( 'Wprowadź 6-cyfrowy kod BLIK pobrany z aplikacji bankowej.', 'przelewy24' ) );
$error = esc_html( __( 'Niepoprawny kod BLIK.', 'przelewy24' ) );
$unccepted = esc_html( __( 'Brak zaakceptowanego regulaminu Przelewy24.', 'przelewy24' ) );
$button = esc_html( __( 'Zapłać', 'przelewy24' ) );
$terms = esc_html( __( 'Tak, przeczytałem i akceptuję regulamin Przelewy24.', 'przelewy24' ) );
if ( $need_terms ) {
$terms_input = <<<TERMS
<p>
<label>
<input type="checkbox" name="terms">
$terms
</label>
</p>
<p class="error error-terms">$unccepted</p>
TERMS;
} else {
$terms_input = "\n";
}
return <<<MODAL
<div id="p24-blik-modal-background">
<div id="p24-blik-modal-holder">
<div id="p24-blik-modal">
<h1>$header</h1>
<a href="" class="close-modal">✖</a>
<form>
<div>
<p>$label</p>
<p>
<input type="text" name="blik" placeholder="______" pattern="^\d{6}$" maxlength="6">
</p>
<p class="error error-common">$error</p>
$terms_input
<p>
<button>$button</button>
</p>
</div>
</form>
</div>
</div>
</div>
MODAL;
}
/**
* Echo HTML code for modal
*
* @param bool $need_terms If checkbox to show terms is needed. Default to false.
*/
public static function echo_modal_html( $need_terms = false ) {
echo self::get_modal_html( $need_terms ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}

View File

@@ -0,0 +1,146 @@
<?php
/**
* File that define P24_Communication_Parser class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class to parse input from Przelewy24 backend.
*/
class P24_Communication_Parser {
/**
* Set for true if response is from Przelewy24.
*
* @var bool
*/
private $is_przelewy24_response = false;
/**
* Set for true if CRC is valid.
*
* @var bool
*/
private $is_crc_valid = false;
/**
* The currency of response.
*
* @var null|string
*/
private $currency;
/**
* The response from Przelewy24.
*
* @var null|array
*/
private $response;
/**
* Class to validate messages.
*
* @var P24_Message_Validator
*/
private $message_validator;
/**
* P24_Communication_Parser constructor.
*
* @param P24_Message_Validator $message_validator P24_Message_Validator instance.
*/
public function __construct( P24_Message_Validator $message_validator ) {
$this->message_validator = $message_validator;
}
/**
* Return request.
*
* @return array
*/
private function get_post_data() {
wp_verify_nonce( null ); /* There is no nonce in request. */
if ( is_array( $_POST ) ) {
return $_POST;
} else {
return array();
}
}
/**
* Parse and validate POST response data from Przelewy24.
*
* @param WC_Gateway_Przelewy24 $gateway The gateway.
* @return bool True on success, false otherwise.
*/
public function parse_status_response( WC_Gateway_Przelewy24 $gateway ) {
$this->is_przelewy24_response = false;
$this->is_crc_valid = false;
$this->currency = null;
$this->response = null;
$data = $this->get_post_data();
if ( ! isset( $data['p24_session_id'], $data['p24_order_id'], $data['p24_merchant_id'], $data['p24_pos_id'], $data['p24_amount'], $data['p24_currency'], $data['p24_method'], $data['p24_sign'] ) ) {
/* Early exit. */
return false;
}
$this->is_przelewy24_response = true;
$session_id = $this->message_validator->filter_value( 'p24_session_id', $data['p24_session_id'] );
$merchant_id = $this->message_validator->filter_value( 'p24_merchant_id', $data['p24_merchant_id'] );
$pos_id = $this->message_validator->filter_value( 'p24_pos_id', $data['p24_pos_id'] );
$order_id = $this->message_validator->filter_value( 'p24_order_id', $data['p24_order_id'] );
$amount = $this->message_validator->filter_value( 'p24_amount', $data['p24_amount'] );
$currency = $this->message_validator->filter_value( 'p24_currency', $data['p24_currency'] );
$method = $this->message_validator->filter_value( 'p24_method', $data['p24_method'] );
$sign = $this->message_validator->filter_value( 'p24_sign', $data['p24_sign'] );
$this->currency = $currency;
$config = $gateway->load_settings_from_db_formatted( $currency );
$expected_sign = md5( $session_id . '|' . $order_id . '|' . $amount . '|' . $currency . '|' . $config->get_salt() );
if ( $merchant_id === $config->get_merchant_id()
&& $pos_id === $config->get_shop_id()
&& $sign === $expected_sign
) {
$this->is_crc_valid = true;
$this->response = array(
'p24_session_id' => $session_id,
'p24_order_id' => $order_id,
'p24_amount' => $amount,
'p24_currency' => $currency,
'p24_method' => $method,
);
return true;
} else {
return false;
}
}
/**
* Return if request was valid.
*
* @return bool
*/
public function is_valid() {
return $this->is_crc_valid;
}
/**
* Get currency.
*
* @return string
* @throws LogicException If request is not validated.
*/
public function get_currency() {
if ( $this->currency ) {
return $this->currency;
} else {
$msg = 'You have to validate request first.';
throw new LogicException( $msg );
}
}
}

View File

@@ -0,0 +1,703 @@
<?php
/**
* File that define P24_Config_Accessor class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Accessor for P24_Config_Holder.
*
* This class know active currency and style of booleans.
* These two properties are unknown to P24_Config_Holder.
*/
class P24_Config_Accessor {
const AM_STRICT = 'am_strict';
const AM_WORDPRESS = 'am_wordpress';
/**
* Name of currency that is described by config.
*
* @var string
*/
private $currency;
/**
* The object holding config.
*
* @var P24_Config_Holder
*/
private $config;
/**
* The style of accessor.
*
* The booleans may be expected to be in form yes/no.
*
* @var string
*/
private $access_mode;
/**
* Array holding translation of bool representations.
*
* @var array
*/
private $bool_translation_table;
/**
* The constructor.
*
* The default boolean mode is yes/no.
*
* @param string $currency Name of currency.
* @param P24_Config_Holder $config The config.
*/
public function __construct( $currency, P24_Config_Holder $config ) {
$this->currency = (string) $currency;
$this->config = $config;
$this->access_mode_to_wordpress();
$this->bool_translation_table = array(
self::AM_STRICT => array( false, true ),
self::AM_WORDPRESS => array( 'no', 'yes' ),
);
$this->fix_booleans();
}
/**
* Convert variable to selected bool representation.
*
* @param bool $input The input variable to be converted.
* @return bool|string
* @throws InvalidArgumentException If conversion cannot be made.
*/
public function to_selected_bool( $input ) {
if ( false === $input ) {
return $this->bool_translation_table[ $this->access_mode ][0];
} elseif ( true === $input ) {
return $this->bool_translation_table[ $this->access_mode ][1];
} else {
throw new InvalidArgumentException( 'Wrong input type, it has to be bool.' );
}
}
/**
* Convert variable from selected bool representation.
*
* @param bool|string $input The input variable to be converted.
* @return bool
* @throws InvalidArgumentException If conversion cannot be made.
*/
public function from_selected_bool( $input ) {
$row = $this->bool_translation_table[ $this->access_mode ];
$key = array_search( $input, $row, true );
if ( 0 === $key ) {
return false;
} elseif ( 1 === $key ) {
return true;
} else {
throw new InvalidArgumentException( 'Wrong input, it cannot be converted to bool.' );
}
}
/**
* Convert all booleans in config to PHP representation.
*/
private function fix_booleans() {
$to_fix = array(
'p24_oneclick',
'p24_payinshop',
'p24_acceptinshop',
'p24_show_methods_checkout',
'p24_show_methods_confirmation',
'p24_graphics',
'p24_wait_for_result',
'p24_use_special_status',
'sub_enabled',
);
foreach ( $to_fix as $one ) {
if ( null === $this->config->{$one} ) {
$this->config->{$one} = false;
} elseif ( ! is_bool( $this->config->{$one} ) ) {
$this->config->{$one} = self::from_selected_bool( $this->config->{$one} );
}
}
}
/**
* The cloner.
*/
public function __clone() {
$this->config = clone $this->config;
}
/**
* Set access mode for booleans to PHP types.
*
* @return $this
*/
public function access_mode_to_strict() {
$this->access_mode = self::AM_STRICT;
return $this;
}
/**
* Set access mode for booleans to strings yes and no.
*
* @return $this
*/
public function access_mode_to_wordpress() {
$this->access_mode = self::AM_WORDPRESS;
return $this;
}
/**
* Get currency.
*
* @return string
*/
public function get_currency() {
return (string) $this->currency;
}
/**
* Get title from config.
*
* @return string
*/
public function get_title() {
return (string) $this->config->title;
}
/**
* Set title in config.
*
* @param string $title The new title.
* @return P24_Config_Accessor
*/
public function set_title( $title ) {
$this->config->title = (string) $title;
return $this;
}
/**
* Get merchant_id from config.
*
* @return string
*/
public function get_merchant_id() {
return (string) $this->config->merchant_id;
}
/**
* Set merchant_id in config.
*
* @param string $merchant_id The new merchant_id.
* @return P24_Config_Accessor
*/
public function set_merchant_id( $merchant_id ) {
$this->config->merchant_id = (string) $merchant_id;
return $this;
}
/**
* Get shop_id form config.
*
* @return string
*/
public function get_shop_id() {
return (string) $this->config->shop_id;
}
/**
* Set shop_id in config.
*
* @param string $shop_id The new shop_id.
* @return P24_Config_Accessor
*/
public function set_shop_id( $shop_id ) {
$this->config->shop_id = (string) $shop_id;
return $this;
}
/**
* Get salt from config.
*
* @return string
*/
public function get_salt() {
return (string) $this->config->salt;
}
/**
* Set salt in config.
*
* @param string $salt The new salt.
* @return P24_Config_Accessor
*/
public function set_salt( $salt ) {
$this->config->salt = (string) $salt;
return $this;
}
/**
* Get operation mode from config.
*
* @return string The new p24_operation_mode
*/
public function get_p24_operation_mode() {
return (string) $this->config->p24_operation_mode;
}
/**
* Set operation mode in config.
*
* @param string $p24_operation_mode The new p24_operation_mode.
* @return P24_Config_Accessor
*/
public function set_p24_operation_mode( $p24_operation_mode ) {
$this->config->p24_operation_mode = (string) $p24_operation_mode;
return $this;
}
/**
* Compare modes and return bool.
*
* @param string $checked The value to compare mode with.
* @return bool|string
*/
public function is_p24_operation_mode( $checked ) {
$mode = $this->get_p24_operation_mode();
$is_mode = $checked === $mode;
return $this->to_selected_bool( $is_mode );
}
/**
* Get description from config.
*
* @return string
*/
public function get_description() {
return (string) $this->config->description;
}
/**
* Set description in config.
*
* @param string $description The new description.
* @return P24_Config_Accessor
*/
public function set_description( $description ) {
$this->config->description = (string) $description;
return $this;
}
/**
* Get p24_api from config.
*
* @return string
*/
public function get_p24_api() {
return (string) $this->config->p24_api;
}
/**
* Set p24_api in config.
*
* @param string $p24_api The new p24_api.
* @return P24_Config_Accessor
*/
public function set_p24_api( $p24_api ) {
$this->config->p24_api = (string) $p24_api;
return $this;
}
/**
* Get p24_paymethods_super_first from config.
*
* @return string
*/
public function get_p24_paymethods_super_first() {
return (string) $this->config->p24_paymethods_super_first;
}
/**
* Set p24_paymethods_super_first in config.
*
* @param string $p24_paymethods_super_first The new p24_paymethods_first.
* @return P24_Config_Accessor
*/
public function set_p24_paymethods_super_first( $p24_paymethods_super_first ) {
$this->config->p24_paymethods_super_first = (string) $p24_paymethods_super_first;
return $this;
}
/**
* Return p24_oneclick from config.
*
* The value is converted to selected representation.
*
* @return bool|string
* @throws LogicException If the internal representation of value is broken.
*/
public function get_p24_oneclick() {
try {
$p24_oneclick = $this->config->p24_oneclick;
return $this->to_selected_bool( $p24_oneclick );
} catch ( InvalidArgumentException $ex ) {
$msg = 'The internal representation of p24_oneclick is invalid.';
throw new LogicException( $msg, 0, $ex );
}
}
/**
* Set p24_oneclick in config.
*
* The input is expected to be in selected representation.
*
* @param bool|string $p24_oneclick The new p24_oneclick.
* @return P24_Config_Accessor
* @throws InvalidArgumentException If input is in wrong representation.
*/
public function set_p24_oneclick( $p24_oneclick ) {
$this->config->p24_oneclick = $this->from_selected_bool( $p24_oneclick );
return $this;
}
/**
* Return p24_payinshop from config.
*
* The value is converted to selected representation.
*
* @return bool|string
* @throws LogicException If the internal representation of value is broken.
*/
public function get_p24_payinshop() {
try {
$p24_payinshop = $this->config->p24_payinshop;
return $this->to_selected_bool( $p24_payinshop );
} catch ( InvalidArgumentException $ex ) {
$msg = 'The internal representation of p24_payinshop is invalid.';
throw new LogicException( $msg, 0, $ex );
}
}
/**
* Set p24_acceptinshop in config.
*
* The input is expected to be in selected representation.
*
* @param bool|string $p24_acceptinshop The new p24_oneclick.
* @return P24_Config_Accessor
* @throws InvalidArgumentException If input is in wrong representation.
*/
public function set_p24_acceptinshop( $p24_acceptinshop ) {
$this->config->p24_acceptinshop = $this->from_selected_bool( $p24_acceptinshop );
return $this;
}
/**
* Return p24_acceptinshop from config.
*
* The value is converted to selected representation.
*
* @return bool|string
* @throws LogicException If the internal representation of value is broken.
*/
public function get_p24_acceptinshop() {
try {
$p24_acceptinshop = $this->config->p24_acceptinshop;
return $this->to_selected_bool( $p24_acceptinshop );
} catch ( InvalidArgumentException $ex ) {
$msg = 'The internal representation of p24_acceptinshop is invalid.';
throw new LogicException( $msg, 0, $ex );
}
}
/**
* Set p24_payinshop in config.
*
* The input is expected to be in selected representation.
*
* @param bool|string $p24_payinshop The new p24_payinshop.
* @return P24_Config_Accessor
* @throws InvalidArgumentException If input is in wrong representation.
*/
public function set_p24_payinshop( $p24_payinshop ) {
$this->config->p24_payinshop = $this->from_selected_bool( $p24_payinshop );
return $this;
}
/**
* Return p24_show_methods_checkout from config.
*
* The value is converted to selected representation.
*
* @return bool|string
* @throws LogicException If the internal representation of value is broken.
*/
public function get_p24_show_methods_checkout() {
try {
$p24_show_methods_checkout = $this->config->p24_show_methods_checkout;
return $this->to_selected_bool( $p24_show_methods_checkout );
} catch ( InvalidArgumentException $ex ) {
$msg = 'The internal representation of p24_show_methods_checkout is invalid.';
throw new LogicException( $msg, 0, $ex );
}
}
/**
* Set p24_show_methods_checkout in config.
*
* The input is expected to be in selected representation.
*
* @param bool|string $p24_show_methods_checkout The new p24_show_methods_checkout.
* @return P24_Config_Accessor
* @throws InvalidArgumentException If input is in wrong representation.
*/
public function set_p24_show_methods_checkout( $p24_show_methods_checkout ) {
$this->config->p24_show_methods_checkout = $this->from_selected_bool( $p24_show_methods_checkout );
return $this;
}
/**
* Return p24_show_methods_confirmation from config.
*
* The value is converted to selected representation.
*
* @return bool|string
* @throws LogicException If the internal representation of value is broken.
*/
public function get_p24_show_methods_confirmation() {
try {
$p24_show_methods_confirmation = $this->config->p24_show_methods_confirmation;
return $this->to_selected_bool( $p24_show_methods_confirmation );
} catch ( InvalidArgumentException $ex ) {
$msg = 'The internal representation of p24_show_methods_confirmation is invalid.';
throw new LogicException( $msg, 0, $ex );
}
}
/**
* Set p24_show_methods_confirmation in config.
*
* The input is expected to be in selected representation.
*
* @param bool|string $p24_show_methods_confirmation The new p24_show_methods_confirmation.
* @return P24_Config_Accessor
* @throws InvalidArgumentException If input is in wrong representation.
*/
public function set_p24_show_methods_confirmation( $p24_show_methods_confirmation ) {
$this->config->p24_show_methods_confirmation = $this->from_selected_bool( $p24_show_methods_confirmation );
return $this;
}
/**
* Return p24_graphics from config.
*
* The value is converted to selected representation.
*
* @return bool|string
* @throws LogicException If the internal representation of value is broken.
*/
public function get_p24_graphics() {
try {
$p24_graphics = $this->config->p24_graphics;
return $this->to_selected_bool( $p24_graphics );
} catch ( InvalidArgumentException $ex ) {
$msg = 'The internal representation of p24_graphics is invalid.';
throw new LogicException( $msg, 0, $ex );
}
}
/**
* Set p24_graphics in config.
*
* The input is expected to be in selected representation.
*
* @param bool|string $p24_graphics The new p24_graphics.
* @return P24_Config_Accessor
* @throws InvalidArgumentException If input is in wrong representation.
*/
public function set_p24_graphics( $p24_graphics ) {
$this->config->p24_graphics = $this->from_selected_bool( $p24_graphics );
return $this;
}
/**
* Get p24_paymethods_first from config.
*
* @return string
*/
public function get_p24_paymethods_first() {
return (string) $this->config->p24_paymethods_first;
}
/**
* Set p24_paymethods_first in config.
*
* @param string $p24_paymethods_first The new p24_paymethods_first.
* @return P24_Config_Accessor
*/
public function set_p24_paymethods_first( $p24_paymethods_first ) {
$this->config->p24_paymethods_first = (string) $p24_paymethods_first;
return $this;
}
/**
* Get p24_paymethods_second from config.
*
* @return string
*/
public function get_p24_paymethods_second() {
return (string) $this->config->p24_paymethods_second;
}
/**
* Set p24_paymethods_second in config.
*
* @param string $p24_paymethods_second The new p24_paymethods_second.
* @return P24_Config_Accessor
*/
public function set_p24_paymethods_second( $p24_paymethods_second ) {
$this->config->p24_paymethods_second = (string) $p24_paymethods_second;
return $this;
}
/**
* Return p24_wait_for_result from config.
*
* The value is converted to selected representation.
*
* @return bool|string
* @throws LogicException If the internal representation of value is broken.
*/
public function get_p24_wait_for_result() {
try {
$p24_wait_for_result = $this->config->p24_wait_for_result;
return $this->to_selected_bool( $p24_wait_for_result );
} catch ( InvalidArgumentException $ex ) {
$msg = 'The internal representation of p24_wait_for_result is invalid.';
throw new LogicException( $msg, 0, $ex );
}
}
/**
* Set p24_wait_for_result in config.
*
* The input is expected to be in selected representation.
*
* @param bool|string $p24_wait_for_result The new p24_wait_for_result.
* @return P24_Config_Accessor
* @throws InvalidArgumentException If input is in wrong representation.
*/
public function set_p24_wait_for_result( $p24_wait_for_result ) {
$this->config->p24_wait_for_result = $this->from_selected_bool( $p24_wait_for_result );
return $this;
}
/**
* Return p24_use_special_status from config.
*
* The value is converted to selected representation.
*
* @return bool|string
* @throws LogicException If the internal representation of value is broken.
*/
public function get_p24_use_special_status() {
try {
$p24_use_special_status = $this->config->p24_use_special_status;
return $this->to_selected_bool( $p24_use_special_status );
} catch ( InvalidArgumentException $ex ) {
$msg = 'The internal representation of p24_use_special_status is invalid.';
throw new LogicException( $msg, 0, $ex );
}
}
/**
* Set p24_use_special_status in config.
*
* The input is expected to be in selected representation.
*
* @param bool|string $p24_use_special_status The new p24_use_special_status.
* @return P24_Config_Accessor
* @throws InvalidArgumentException If input is in wrong representation.
*/
public function set_p24_use_special_status( $p24_use_special_status ) {
$this->config->p24_use_special_status = $this->from_selected_bool( $p24_use_special_status );
return $this;
}
/**
* Get p24_custom_pending_status from config.
*
* @return string
*/
public function get_p24_custom_pending_status() {
return (string) $this->config->p24_custom_pending_status;
}
/**
* Get p24_custom_pending_status from config.
*
* @return string
*/
public function get_p24_custom_processing_status() {
return (string) $this->config->p24_custom_processing_status;
}
/**
* Return sub_enabled from config.
*
* The value is converted to selected representation.
*
* @return bool|string
* @throws LogicException If the internal representation of value is broken.
*/
public function get_sub_enabled() {
try {
$sub_enabled = $this->config->sub_enabled;
return $this->to_selected_bool( $sub_enabled );
} catch ( InvalidArgumentException $ex ) {
$msg = 'The internal representation of sub_enabled is invalid.';
throw new LogicException( $msg, 0, $ex );
}
}
/**
* Set sub_enabled in config.
*
* The input is expected to be in selected representation.
*
* @param bool|string $sub_enabled The new sub_enabled.
* @return P24_Config_Accessor
* @throws InvalidArgumentException If input is in wrong representation.
*/
public function set_sub_enabled( $sub_enabled ) {
$this->config->sub_enabled = $this->from_selected_bool( $sub_enabled );
return $this;
}
/**
* Get p24_custom_promote_p24 from config
*
* @return bool|string
*/
public function get_is_pay_now_promoted() {
$is_pay_now_promoted = $this->config->p24_custom_promote_p24;
return $this->to_selected_bool( $is_pay_now_promoted );
}
/**
* Get p24_add_to_alternative_button from config
*
* @return bool|string
*/
public function get_is_pay_now_alternative_button() {
$is_pay_now_alt_button = $this->config->p24_add_to_alternative_button;
return $this->to_selected_bool( $is_pay_now_alt_button );
}
}

View File

@@ -0,0 +1,134 @@
<?php
/**
* File that define P24_Config_Eraser class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class to erase Przelewy24 configuration.
*/
class P24_Config_Eraser {
const SLUG_CLEAR_CONFIG = 'p24_clear_config';
/**
* Instance of core of plugin.
*
* @var P24_Core
*/
private $plugin_core;
/**
* Construct class instance.
*
* @param P24_Core $plugin_core The core class for plugin.
*/
public function __construct( P24_Core $plugin_core ) {
$this->plugin_core = $plugin_core;
}
/**
* Get kay of option record from database.
*
* It is different for each currency.
*
* @param string $for_currency Code of currency.
*
* @return string
*/
public static function get_key_for_config_for_currency( $for_currency ) {
$code = strtolower( $for_currency );
return 'woocommerce_' . WC_Gateway_Przelewy24::PAYMENT_METHOD . '_' . $code . '_settings';
}
/**
* Execute clear payment config.
*/
private function execute_clear_payment_config() {
$currencies = $this->plugin_core->get_available_currencies_or_default();
foreach ( $currencies as $currency ) {
$key = self::get_key_for_config_for_currency( $currency );
delete_option( $key );
}
delete_option( P24_Settings_Helper::OPTION_KEY_COMMON );
delete_option( 'p24_statuses_active' );
delete_option( P24_Status_Provider::ADDITIONAL_STATUSES_KEY );
delete_option( 'przelewy24_multi_currency_formats' );
delete_option( 'przelewy24_multi_currency_multipliers' );
delete_option( P24_Install::P24_INSTALLED_VERSION );
delete_option( 'przelewy24_subscriptions_days' );
delete_option( 'przelewy24_subscriptions_active' );
delete_option( 'p24_subscription_page_id' );
}
/**
* Render page to clear config.
*/
public function render_clear_config() {
$params = array(
'field_name' => strtr( self::SLUG_CLEAR_CONFIG, '-', '_' ),
'deleted' => false,
);
if ( isset( $_POST['p24_nonce'] ) ) {
$nonce = sanitize_key( $_POST['p24_nonce'] );
if ( wp_verify_nonce( $nonce, 'p24_action' ) ) {
if ( isset( $_POST[ $params['field_name'] ] ) ) {
$this->execute_clear_payment_config();
$params['deleted'] = true;
}
}
}
$this->plugin_core->render_template( 'confirm-clear-config', $params );
}
/**
* Prepare additional config pages.
*/
public function prepare_pages() {
add_submenu_page(
'wc-settings',
__( 'Wyczyść ustawienia' ),
__( 'Wyczyść ustawienia' ),
'delete_plugins',
self::SLUG_CLEAR_CONFIG,
array( $this, 'render_clear_config' )
);
}
/**
* Add link for plugins page
*
* @param array $actions Default actions.
* @param string $plugin_file Main filename of plugin.
* @param array $plugin_data Plugin data.
* @param string $context Context.
* @return array
*/
public function add_plugin_action_link( $actions, $plugin_file, $plugin_data, $context ) {
if ( 'przelewy24/woocommerce-gateway-przelewy24.php' !== $plugin_file ) {
return $actions;
} elseif ( current_user_can( 'delete_plugins' ) ) {
$url = menu_page_url( self::SLUG_CLEAR_CONFIG, false );
$actions['clear'] = '<a href="' . $url . '">' . __( 'Wyczyść ustawienia' ) . '</a>';
return $actions;
} else {
return $actions;
}
}
/**
* Bind events.
*/
public function bind_events() {
add_filter( 'plugin_action_links', array( $this, 'add_plugin_action_link' ), 10, 4 );
add_action( 'admin_menu', array( $this, 'prepare_pages' ) );
}
}

View File

@@ -0,0 +1,179 @@
<?php
/**
* File that define P24_Config_Holder class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Simple class that hold config.
*
* The active currency and style of booleans are unknown to this class.
* The accessor is external.
*/
class P24_Config_Holder {
/**
* Title
*
* @var string
*/
public $title;
/**
* Identification of merchant.
*
* @var string
*/
public $merchant_id;
/**
* Identification of store.
*
* It may be the same as $merchant_id.
*
* @var string
*/
public $shop_id;
/**
* Salt or CRC key.
*
* @var string
*/
public $salt;
/**
* Mode of operation.
*
* @var string
*/
public $p24_operation_mode;
/**
* Longer description.
*
* @var string
*/
public $description;
/**
* Key to API.
*
* @var string
*/
public $p24_api;
/**
* Methods to put on peyment selection page.
*
* @var string
*/
public $p24_paymethods_super_first;
/**
* Activate the Onclick.
*
* @var bool
*/
public $p24_oneclick;
/**
* Option to pay in shop via card.
*
* @var bool
*/
public $p24_payinshop;
/**
* Option to accept p24 terms in shop.
*
* @var bool
*/
public $p24_acceptinshop;
/**
* Select payment methods in shop on checkout page.
*
* @var bool
*/
public $p24_show_methods_checkout;
/**
* Select payment methods in shop on confirmation page.
*
* @var bool
*/
public $p24_show_methods_confirmation;
/**
* User graphic list of pay options.
*
* @var bool
*/
public $p24_graphics;
/**
* Comma separated list of promoted pay options.
*
* @var string
*/
public $p24_paymethods_first;
/**
* Comma separated list of additional methods.
*
* @var string
*/
public $p24_paymethods_second;
/**
* Wait for transaction result.
*
* @var bool
*/
public $p24_wait_for_result;
/**
* Use special statuses for orders.
*
* @var bool
*/
public $p24_use_special_status;
/**
* Special pending status.
*
* @var string
*/
public $p24_custom_pending_status;
/**
* Special processing status.
*
* @var string
*/
public $p24_custom_processing_status;
/**
* Enable selected currency.
*
* @var bool
*/
public $sub_enabled;
/**
* Enable P24NOW promoted.
*
* @var bool
*/
public $p24_custom_promote_p24;
/**
* Enable p24 alternative button.
*
* @var bool
*/
public $p24_add_to_alternative_button;
}

View File

@@ -0,0 +1,373 @@
<?php
/**
* File that define P24_Config class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Methods for Przelewy 24 plugin to display admin config.
*
* Processing of config is in different class.
*/
class P24_Config_Menu {
/**
* Instance of core of plugin.
*
* @var P24_Core
*/
private $plugin_core;
/**
* Construct class instance.
*
* @param P24_Core $plugin_core The core class for plugin.
*/
public function __construct( P24_Core $plugin_core ) {
$this->plugin_core = $plugin_core;
}
/**
* Render multi currency config page.
*/
public function render_mc_config_page() {
$tab = empty( $_GET['tab'] ) ? 'main' : sanitize_key( wp_unslash( $_GET['tab'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
$multicurrency = $this->plugin_core->is_internal_multi_currency_active();
switch ( $tab ) {
case 'main':
$this->render_config_tabs( $tab, $multicurrency );
$this->render_config_mc_main_page();
break;
case 'multipliers':
$this->render_config_tabs( $tab, $multicurrency );
$this->render_config_multipliers_page();
break;
case 'formats':
$this->render_config_tabs( $tab, $multicurrency );
$this->render_config_format_page();
break;
}
}
/**
* Render tabs of config page.
*
* @param string $tab The active tab.
* @param bool $multicurrency If multi currency is active.
*/
private function render_config_tabs( $tab, $multicurrency ) {
$params = compact( 'tab', 'multicurrency' );
$this->plugin_core->render_template( 'multi-currency-tabs', $params );
}
/**
* Render form to activate multi currency module.
*
* @throws LogicException Not expected.
*/
private function render_config_mc_main_page() {
$multi_currency_instance = $this->plugin_core->get_any_active_mc();
if ( $multi_currency_instance->is_internal() ) {
if ( ! $multi_currency_instance instanceof P24_Multi_Currency ) {
$class = get_class( $multi_currency_instance );
throw new LogicException( "The implementation of $class has broken is_internal method or the logic of application has changed." );
}
$this->render_config_main_page_extended( $multi_currency_instance );
return;
}
$value = $this->plugin_core->should_activate_multi_currency();
$order_created_notification_value = $this->plugin_core->should_activate_order_created_notification();
$params = compact( 'multi_currency_instance', 'value', 'order_created_notification_value' );
$this->plugin_core->render_template( 'multi-currency-main', $params );
}
/**
* Render config main page extended by reports currency field.
*
* @param P24_Multi_Currency $multi_currency_instance Multi currency instance.
*/
private function render_config_main_page_extended( P24_Multi_Currency $multi_currency_instance ) {
$value = $this->plugin_core->should_activate_multi_currency();
$currency_options = $multi_currency_instance->get_available_currencies();
$report_currency = P24_Multi_Currency::get_admin_reports_currency( get_woocommerce_currency() );
wp_verify_nonce( null ); /* There is no nonce in request. */
if ( isset( $_POST['p24_reports_currency'] ) ) {
$report_currency = sanitize_text_field( wp_unslash( $_POST['p24_reports_currency'] ) );
}
$order_created_notification_value = $this->plugin_core->should_activate_order_created_notification();
$params = compact( 'multi_currency_instance', 'value', 'currency_options', 'report_currency', 'order_created_notification_value' );
$this->plugin_core->render_template( 'multi-currency-main', $params );
}
/**
* Render form to set currency multipliers.
*/
private function render_config_multipliers_page() {
$available = get_woocommerce_currencies();
$multipliers = $this->plugin_core->get_multi_currency_instance()->get_multipliers();
$base_currency = P24_Woo_Commerce_Low_Level_Getter::get_unhooked_currency_form_woocommerce();
$multipliers[ $base_currency ] = 1;
$params = compact( 'multipliers', 'base_currency', 'available' );
$this->plugin_core->render_template( 'multi-currency-multipliers', $params );
}
/**
* Render form to change format of currency.
*/
private function render_config_format_page() {
$formats = get_option( 'przelewy24_multi_currency_formats', array() );
$active_currency = $this->plugin_core->get_multi_currency_instance()->get_active_currency();
if ( array_key_exists( $active_currency, $formats ) ) {
$format = $formats[ $active_currency ];
} else {
$base_currency = P24_Woo_Commerce_Low_Level_Getter::get_unhooked_currency_form_woocommerce();
if ( array_key_exists( $base_currency, $formats ) ) {
$format = $formats[ $base_currency ];
} else {
$format = array(
'currency_pos' => get_option( 'woocommerce_currency_pos' ),
'thousand_separator' => wc_get_price_thousand_separator(),
'decimal_separator' => wc_get_price_decimal_separator(),
'decimals' => wc_get_price_decimals(),
);
}
}
$currency_options = get_przelewy24_multi_currency_options();
$params = compact( 'format', 'active_currency', 'currency_options' );
$this->plugin_core->render_template( 'multi-currency-formats', $params );
}
/**
* Render status page.
*/
public function render_order_status_page() {
$tab = empty( $_GET['tab'] ) ? 'main' : sanitize_key( wp_unslash( $_GET['tab'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
switch ( $tab ) {
case 'main':
$this->render_order_status_tabs( $tab );
$this->render_order_status_activation_page();
break;
case 'list':
$this->render_order_status_tabs( $tab );
$this->render_order_status_config_page();
break;
}
}
/**
* Render tabs for statuses.
*
* @param string $tab The active tab.
*/
private function render_order_status_tabs( $tab ) {
$is_active = P24_Status_Decorator::is_active();
$params = compact( 'tab', 'is_active' );
$this->plugin_core->render_template( 'statuses-tabs', $params );
}
/**
* Render order status page.
*/
public function render_order_status_activation_page() {
$is_active = P24_Status_Decorator::is_active();
$params = compact( 'is_active' );
$this->plugin_core->render_template( 'status-config', $params );
}
/**
* Render order status config page.
*/
public function render_order_status_config_page() {
$status_provider = $this->plugin_core->get_status_provider_instance();
$statuses = P24_Status_Provider::get_formatted_config();
$error = $status_provider->get_adding_error();
$new_code = $status_provider->get_proposed_code_if_error();
$new_label = $status_provider->get_proposed_label_if_error();
$params = compact( 'statuses', 'error', 'new_code', 'new_label' );
$this->plugin_core->render_template( 'statuses', $params );
}
/**
* Render subscription page.
*/
public function render_subscription_page() {
$tab = empty( $_GET['tab'] ) ? 'main' : sanitize_key( wp_unslash( $_GET['tab'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
switch ( $tab ) {
case 'main':
$this->render_subscription_tabs( $tab );
$this->render_subscription_config_page();
break;
case 'list':
$this->render_subscription_tabs( $tab );
$this->render_subscription_list();
break;
case 'inactive':
$this->render_subscription_tabs( $tab );
$this->render_inactive_subscription_list();
break;
}
}
/**
* Render tabs for subscription.
*
* @param string $tab The active tab.
*/
private function render_subscription_tabs( $tab ) {
$is_active = P24_Subscription_Config::is_active();
$params = compact( 'tab', 'is_active' );
$this->plugin_core->render_template( 'subscriptions-tabs', $params );
}
/**
* Render subscription config page.
*/
public function render_subscription_config_page() {
$params = array(
'is_active' => P24_Subscription_Config::is_active(),
'days_to_renew' => P24_Subscription_Config::days_to_renew(),
'page_id' => P24_Subscription_Config::page_id(),
);
$this->plugin_core->render_template( 'subscriptions-config', $params );
}
/**
* Render subscription list.
*/
public function render_subscription_list() {
P24_Subscription_Admin::parse_cancellation_request();
$params = array(
'list' => P24_Subscription_Db::get_active_list(),
);
$this->plugin_core->render_template( 'subscriptions-list', $params );
}
/**
* Render inactive subscription list.
*/
public function render_inactive_subscription_list() {
$params = array(
'inactive_list' => P24_Subscription_Db::get_inactive_list(),
);
$this->plugin_core->render_template( 'subscriptions-list-inactive', $params );
}
/**
* Prepare common config menus.
*/
public function prepare_config_menu() {
add_submenu_page(
'woocommerce',
'P24 Multi Currency',
'P24 Multi Currency',
'manage_options',
'p24-multi-currency',
array( $this, 'render_mc_config_page' )
);
if ( $this->plugin_core->check_need_for_extra_statuses() ) {
add_submenu_page(
'woocommerce',
'P24 Order Status',
'P24 Order Status',
'manage_options',
'p24-order-status',
array( $this, 'render_order_status_page' )
);
}
add_submenu_page(
'woocommerce',
'P24 Subscriptions',
'P24 Subscriptions',
'manage_options',
'p24-subscription',
array( $this, 'render_subscription_page' )
);
}
/**
* Add scripts used on admin page.
*/
public function add_admin_scripts() {
wp_enqueue_style( 'p24_multi_currency_admin', PRZELEWY24_URI . 'assets/css/p24_multi_currency_style_admin.css', array(), P24_Core::SCRIPTS_VERSION );
}
/**
* Update WooCommerce settings panels.
*
* The MultiCurrency make few changes.
* Few config items have to be renamed or overwritten.
* The required config is added by different functions.
*
* @param array $input The WooCommerce settings.
* @return array
*/
public function clear_woocommerce_settings( $input ) {
$ret = array();
foreach ( $input as $k => $v ) {
switch ( $v['id'] ) {
case P24_Woo_Commerce_Internals::CURRENCY:
/* Change label. */
$v['title'] = __( 'Waluta podstawowa', 'przelewy24' );
$v['desc'] = null;
$ret[ $k ] = $v;
break;
case P24_Woo_Commerce_Internals::CURRENCY_POS:
case P24_Woo_Commerce_Internals::PRICE_THOUSAND_SEP:
case P24_Woo_Commerce_Internals::PRICE_DECIMAL_SEP:
case P24_Woo_Commerce_Internals::PRICE_NUM_DECIMALS:
/* These options are overwritten by multi currency. */
break;
default:
$ret[ $k ] = $v;
}
}
return $ret;
}
/**
* Add box to set currency for order.
*
* This box is used on admin panel.
*
* @param WP_Post $post The post object.
*/
public function add_admin_order_change_currency( WP_Post $post ) {
$currency_options = $this->plugin_core->get_multi_currency_instance()->get_available_currencies();
$params = compact( 'post', 'currency_options' );
$this->plugin_core->render_template( 'multi-currency-order-edit', $params );
}
/**
* Add all meta boxes for different pages.
*/
public function add_meta_boxes() {
foreach ( wc_get_order_types( 'order-meta-boxes' ) as $type ) {
add_meta_box( 'p24_admin_order_multi_currency', __( 'Aktywna waluta', 'przelewy24' ), array( $this, 'add_admin_order_change_currency' ), $type, 'side', 'high' );
}
}
/**
* Bind common events.
*/
public function bind_common_events() {
add_action( 'admin_enqueue_scripts', array( $this, 'add_admin_scripts' ) );
add_action( 'admin_menu', array( $this, 'prepare_config_menu' ) );
}
/**
* Bind multi currency events.
*/
public function bind_multi_currency_events() {
add_filter( 'woocommerce_general_settings', array( $this, 'clear_woocommerce_settings' ) );
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
}
}

View File

@@ -0,0 +1,56 @@
<?php
/**
* File that define P24_Context_Provider class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class with methods allowing user to determine context this script was run from.
*/
class P24_Context_Provider {
/**
* Is this reports context.
*
* @return bool
*/
public function is_reports_context() {
return $this->is_dashboard_context() || $this->is_analytics_context();
}
/**
* Is wc analytics context.
*
* @return bool
*/
public function is_analytics_context() {
if ( isset( $_GET['rest_route'] )
&& 0 === strpos( sanitize_text_field( wp_unslash( $_GET['rest_route'] ) ), '/wc-analytics/' ) ) {
return true;
}
return $this->is_admin_context()
&& isset( $_GET['path'] )
&& 0 === strpos( sanitize_text_field( wp_unslash( $_GET['path'] ) ), '/analytics/' );
}
/**
* Is this script launched from wc dashboard context.
*
* @return bool
*/
public function is_dashboard_context() {
return $this->is_admin_context() && ! isset( $_GET['path'] );
}
/**
* Is this script launched from wc admin context.
*
* @return bool
*/
public function is_admin_context() {
return isset( $_GET['page'] ) && 'wc-admin' === sanitize_text_field( wp_unslash( $_GET['page'] ) );
}
}

View File

@@ -0,0 +1,603 @@
<?php
/**
* File that define P24_Core class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Core methods for Przelewy 24 plugin.
*/
class P24_Core {
/**
* String to add to loaded scripts.
*
* @var string
*/
const SCRIPTS_VERSION = '1.6.0';
/**
* The internal version to use.
*
* Due to technical reasons, there may be few other places with the same purpose.
* This one should take precedence.
*
* @var string
*/
const INTERNAL_VERSION = '1.0.6';
/**
* Key used to mark when Przelewy24 has been used to pay for order.
*
* @var string
*/
const CHOSEN_TIMESTAMP_META_KEY = '_p24_chosen_timestamp';
/**
* Key to store Przelewy24 payment method id.
*/
const P24_METHOD_META_KEY = 'p24_method';
/**
* Key used to store session id, which may be used later i.e. for refunds
*/
const ORDER_SESSION_ID_KEY = '_p24_order_session_id';
/**
* Key used to store Przelewy24 internal order id.
*/
const ORDER_P24_ID = '_p24_order_id';
/**
* The null or P24_Multi_Currency instance.
*
* @var null|P24_Multi_Currency
*/
private $multi_currency = null;
/**
* The P24_Request_Support instance.
*
* @var P24_Request_Support
*/
private $request_support;
/**
* The P24_Config_Menu instance.
*
* @var P24_Config_Menu;
*/
private $config_menu;
/**
* The instance of class configuring WP menu.
*
* @var P24_Multi_Currency_Menu
*/
private $wp_menu_support;
/**
* The WC_Gateway_Przelewy24 instance.
*
* @var WC_Gateway_Przelewy24
*/
private $gateway;
/**
* Context provider.
*
* @var P24_Context_Provider
*/
private $context_provider;
/**
* HTML for SOAP BLIK.
*
* Most logic is in the constructor.
*
* @var P24_Blik_Html
*/
private $soap_blik_html;
/**
* Status provider.
*
* @var P24_Status_Provider
*/
private $status_provider;
/**
* Status_decorator.
*
* @var P24_Status_Decorator
*/
private $status_decorator;
/**
* Support for extra gateway.
*
* @var P24_Extra_Gateway_Support
*/
private $eg_support;
/**
* External_multicurrency.
*
* @var P24_MC_Pool
*/
private $mc_pool;
/**
* Subscription class.
*
* @var P24_Subscription
*/
private $subscription;
/**
* Icon generator.
*
* @var P24_Icon_Svg_Generator
*/
private $icon_generator;
/**
* Configuration helper
*
* @var P24_Config_Eraser
*/
private $config_eraser;
/**
* Construct class instance.
*/
public function __construct() {
$this->request_support = new P24_Request_Support();
$this->context_provider = new P24_Context_Provider();
$this->wp_menu_support = new P24_Multi_Currency_Menu( $this );
$config_factory = array( &$this->gateway, 'load_settings_from_db_formatted' );
$this->status_provider = new P24_Status_Provider();
$this->status_decorator = new P24_Status_Decorator( $config_factory, $this->status_provider, $this );
$this->eg_support = new P24_Extra_Gateway_Support( $this );
$this->mc_pool = new P24_MC_Pool( $this );
$this->subscription = new P24_Subscription( $this );
$this->config_eraser = new P24_Config_Eraser( $this );
if ( ! $this->is_in_user_mode() ) {
$this->config_menu = new P24_Config_Menu( $this );
}
}
/**
* Check if page is in user mode.
*
* @return bool
*/
public function is_in_user_mode() {
if ( is_admin() ) {
return false;
} elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
return false;
} elseif ( $this->is_in_json_mode() ) {
return false;
} else {
return true;
}
}
/**
* Check if application is in JSON mode.
*
* @return bool
*/
public function is_in_json_mode() {
$request_uri = filter_input( INPUT_SERVER, 'REQUEST_URI' );
return (bool) preg_match( '/^\\/wp\\-json\\//', $request_uri );
}
/**
* Check if internal multi currency is activated.
*
* @return bool
*/
public function is_internal_multi_currency_active() {
return (bool) $this->multi_currency;
}
/**
* Get any active multi currency instance or proxy.
*
* @return P24_MC_Interface
*/
public function get_any_active_mc() {
return $this->mc_pool->get_preffered_mc();
}
/**
* Get_external_active_mc.
*
* @return null|P24_MC_Interface
*/
public function get_external_active_mc() {
return $this->mc_pool->get_external_mc();
}
/**
* Return multi currency instance.
*
* Should be called only if multi currency i active.
*
* @return P24_Multi_Currency
* @throws LogicException If there is no instance.
*/
public function get_multi_currency_instance() {
if ( $this->is_internal_multi_currency_active() ) {
return $this->multi_currency;
} else {
throw new LogicException( 'Multi currency is not active. It should be tested.' );
}
}
/**
* Get status provider instance.
*
* @return P24_Status_Provider
*/
public function get_status_provider_instance() {
return $this->status_provider;
}
/**
* Get status decorator instance.
*
* @return P24_Status_Decorator
*/
public function get_status_decorator_instance() {
return $this->status_decorator;
}
/**
* Try override active currency.
*
* The communication with Przelewy24 is quite late.
*
* @param P24_Communication_Parser $parser The P24_Communication_Parser instance.
*/
public function try_override_active_currency( P24_Communication_Parser $parser ) {
if ( $this->is_internal_multi_currency_active() ) {
$this->multi_currency->try_override_active_currency( $parser );
}
}
/**
* Return current instance i parameter is null.
*
* This should be useful in filters.
*
* @param mixed $default Default value from filter.
* @return P24_Core
*/
public function get_this_if_null( $default ) {
return $default ? $default : $this;
}
/**
* Render template and output.
*
* @param string $template The name of template.
* @param array $params The array of parameters.
* @throws LogicException If the file is not found.
*/
public function render_template( $template, $params = array() ) {
$dir = __DIR__ . '/../templates/';
$file = $template . '.php';
wc_get_template( $file, $params, $dir, $dir );
}
/**
* Check if multi currency should be activated.
*
* @return bool
*/
public function should_activate_multi_currency() {
$common = get_option( P24_Request_Support::OPTION_KEY_COMMON, array() );
return array_key_exists( 'p24_multi_currency', $common ) && 'yes' === $common['p24_multi_currency'];
}
/**
* Check if order created notification should be activated.
*
* @return bool
*/
public function should_activate_order_created_notification() {
$common = get_option( P24_Request_Support::OPTION_KEY_COMMON, array() );
return array_key_exists( 'p24_notification_order_created', $common ) && 'yes' === $common['p24_notification_order_created'];
}
/**
* Register gateway.
*
* The constructor of gateway has to be called in external plugin.
* This function may be called before the main gateway is in a usable state.
*
* @param WC_Gateway_Przelewy24 $gateway The gateway instance.
*/
public function register_gateway( WC_Gateway_Przelewy24 $gateway ) {
$this->gateway = $gateway;
}
/**
* Code to execute after main gateway initiation.
*
* This function should be called on the main gateway becoming usable.
*
* @throws LogicException Throws if executed too early.
*/
public function after_main_gateway_initiation() {
if ( ! isset( $this->gateway ) ) {
throw new LogicException( 'This function has to be called after register_gateway.' );
}
$this->eg_support->prep_extra_gateways( $this->gateway );
$this->soap_blik_html = new P24_Blik_Html( $this );
}
/**
* Get config for currency.
*
* @param null|string $currency The currency for requested config.
* @return P24_Config_Accessor
* @throws LogicException If there is no gateway created.
*/
public function get_config_for_currency( $currency = null ) {
if ( ! $this->gateway ) {
throw new LogicException( 'Gateway in not registered yet.' );
}
return $this->gateway->load_settings_from_db_formatted( $currency );
}
/**
* Get P24_Message_Validator instance.
*
* @return P24_Message_Validator
*/
public function get_message_validator() {
return new P24_Message_Validator();
}
/**
* Get P24_Communication_Parser instance.
*
* @return P24_Communication_Parser
*/
public function get_communication_parser() {
$message_validator = $this->get_message_validator();
return new P24_Communication_Parser( $message_validator );
}
/**
* Get default currency.
*
* @return string
*/
public function get_default_currency() {
if ( $this->is_internal_multi_currency_active() ) {
return $this->multi_currency->get_default_currency();
} else {
return get_woocommerce_currency();
}
}
/**
* Get all currencies including default.
*
* @return array
*/
public function get_available_currencies_or_default() {
$mc = $this->mc_pool->get_preffered_mc();
if ( $mc->is_multi_currency_active() ) {
$currencies = $mc->get_available_currencies();
} else {
$currencies = array( $this->get_default_currency() );
}
return $currencies;
}
/**
* Late configuration after Woocommerce init.
*/
public function after_woocommerce_init() {
$this->request_support->analyse();
$this->request_support->flush_options();
$this->status_provider->try_add_new( $this->request_support->get_order_status_changes() );
$this->status_decorator->bind_events();
$currency_changes = $this->request_support->get_currency_changes();
if ( $this->should_activate_multi_currency() ) {
/* The logic to set active currency is in P24_Multi_Currency class. */
$this->multi_currency = new P24_Multi_Currency( $this, $currency_changes );
$this->multi_currency->bind_events();
if ( is_admin() ) {
$this->config_menu->bind_multi_currency_events();
}
}
if ( $currency_changes ) {
$this->mc_pool->set_active_currency( $currency_changes );
}
}
/**
* Check if order is cancellable.
*
* @param bool $default Default value.
* @param WC_Order $order The order to check.
*
* @return mixed
*/
public function check_if_cancellable( $default, $order ) {
if ( $default ) {
return $default;
} elseif ( ! $order instanceof WC_Order ) {
return $default;
} elseif ( WC_Gateway_Przelewy24::PAYMENT_METHOD === $order->get_payment_method() ) {
$minutes = (int) get_option( P24_Woo_Commerce_Internals::HOLD_STOCK_MINUTES );
$timestamp = $order->get_meta( self::CHOSEN_TIMESTAMP_META_KEY );
if ( $minutes && $timestamp ) {
$now = time();
$seconds = $minutes * 60;
return ( $timestamp + $seconds ) < $now;
}
}
return $default;
}
/**
* Check need for extra statuses.
*
* @return bool
*/
public function check_need_for_extra_statuses() {
if ( $this->is_internal_multi_currency_active() ) {
$active = $this->multi_currency->get_available_currencies();
foreach ( $active as $one ) {
$config = P24_Settings_Helper::load_settings( $one );
if ( ! $config ) {
continue;
}
$config->access_mode_to_strict();
if ( $config->get_p24_use_special_status() ) {
return true;
}
}
} else {
$currency = $this->get_default_currency();
$config = P24_Settings_Helper::load_settings( $currency );
if ( ! $config ) {
return false;
}
$config->access_mode_to_strict();
return $config->get_p24_use_special_status();
}
return false;
}
/**
* Add scripts used on admin page.
*/
public function add_admin_scripts() {
wp_enqueue_style( 'p24_admin', PRZELEWY24_URI . 'assets/css/p24_style_admin.css', array(), self::SCRIPTS_VERSION );
}
/**
* Get cached icon generator.
*
* @return P24_Icon_Svg_Generator
*/
public function get_cached_icon_generator() {
if ( ! isset( $this->icon_generator ) ) {
$config = $this->gateway->load_settings_from_db_formatted();
$this->icon_generator = new P24_Icon_Svg_Generator( $config );
}
return $this->icon_generator;
}
/**
* Generate hidden icon url list.
*/
public function generate_hidden_icon_url_list() {
global $current_section;
if ( 'przelewy24' !== $current_section ) {
/* Nothing to add. */
return;
}
$icon_generator = $this->get_cached_icon_generator();
$icons = $icon_generator->get_all();
echo '<table id="p24-hidden-bank-icon-list" style="display: none;">';
foreach ( $icons as $id => $icon ) {
echo '<tr class="js-bank-id-', esc_attr( $id ), '">';
echo '<td class="js-icon-type-base">', esc_html( $icon['base'] ), '</td>';
echo '<td class="js-icon-type-mobile">', esc_html( $icon['mobile'] ), '</td>';
echo '</tr>';
}
echo '</table>';
}
/**
* Bind events.
*/
public function bind_core_events() {
add_filter( 'przelewy24_plugin_instance', array( $this, 'get_this_if_null' ) );
add_action( 'woocommerce_init', array( $this, 'after_woocommerce_init' ) );
add_filter( 'woocommerce_cancel_unpaid_order', array( $this, 'check_if_cancellable' ), 10, 2 );
add_action( 'admin_enqueue_scripts', array( $this, 'add_admin_scripts' ) );
add_filter( 'woocommerce_settings_checkout', array( $this, 'generate_hidden_icon_url_list' ) );
$this->wp_menu_support->bind_events();
$this->eg_support->bind_common_events();
$this->mc_pool->bind_events();
$this->subscription->bind_core_events();
$this->config_eraser->bind_events();
if ( is_admin() ) {
$this->config_menu->bind_common_events();
}
add_action( 'rest_api_init', function () {
register_rest_route( 'przelewy24/v1', '/create-payment', array(
'methods' => 'POST',
'callback' => array($this, 'przelewy24_request'),
'permission_callback' => '__return_true',
) );
} );
}
public function przelewy24_request($data) {
return $this->gateway->przelewy24_request($data);
}
/**
* Get context provider.
*/
public function get_context_provider() {
return $this->context_provider;
}
/**
* Get P24_Blik_Html.
*
* @return P24_Blik_Html
*/
public function get_soap_blik_html() {
return $this->soap_blik_html;
}
/**
* Converts money amount from stringified float (1.10) to cents in int.
*
* @param string $string Stringified float.
*
* @return int
*/
public static function convert_stringified_float_to_cents( $string ) {
list( $fulls, $cents ) = explode( '.', $string );
$sum = (int) $fulls * 100;
if ( $cents ) {
$sum += $cents;
}
return $sum;
}
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* Class for a widget
*/
class P24_Currency_Selector_Widget extends WP_Widget {
/**
* The P24_Core instance.
*
* @var P24_Core
*/
private $plugin_core;
/**
* The constructor.
*
* @param P24_Core $plugin_core The P24_Core instance.
*/
public function __construct( P24_Core $plugin_core ) {
$this->plugin_core = $plugin_core;
$id_base = 'p24_currency_selector';
$name = __( 'Widget wyboru waluty Przelewy24' );
parent::__construct( $id_base, $name );
}
/**
* Display the widget.
*
* @param array $args Display arguments, ignored.
* @param array $instance Settings.
*/
public function widget( $args, $instance ) {
if ( isset( $instance['title'] ) && $instance['title'] ) {
$title = $instance['title'];
} else {
$title = $this->name;
}
$params = [
'widget_title' => $title,
'active_currency' => get_woocommerce_currency(),
'currency_options' => get_przelewy24_multi_currency_options(),
];
$this->plugin_core->render_template( 'change-currency-widget', $params );
do_action( 'przelewy24_multi_currency_change_form_rendered' );
}
/**
* Handles updating settings.
*
* @param array $new_instance New settings for this instance.
* @param array $old_instance Old settings for this instance.
* @return array Updated settings to save.
*/
public function update( $new_instance, $old_instance ) {
$instance = $old_instance;
$instance['title'] = sanitize_text_field( $new_instance['title'] );
return $instance;
}
/**
* Outputs the settings form.
*
* @param array $instance Current settings.
*/
public function form( $instance ) {
$instance = wp_parse_args( (array) $instance, array( 'title' => '' ) );
$title = sanitize_text_field( $instance['title'] );
$title_field_id = $this->get_field_id( 'title' );
$title_field_name = $this->get_field_name( 'title' );
$params = [
'widget_title' => $title,
'title_field_id' => $title_field_id,
'title_field_name' => $title_field_name,
];
$this->plugin_core->render_template( 'config-change-currency-widget', $params );
}
}

View File

@@ -0,0 +1,199 @@
<?php
/**
* File that define P24_Extra_Gateway_Support.
*
* @package Przelewy24
*/
/**
* Class P24_Extra_Gateway_Support
*/
class P24_Extra_Gateway_Support {
/**
* Plugin core.
*
* @var P24_Core The plugin core.
*/
private $core;
/**
* The set of extra gateways.
*
* @var array
*/
private $extra_gateways;
/**
* P24_Extra_Gateway_Support constructor.
*
* @param P24_Core $core The plugin core.
*/
public function __construct( $core ) {
$this->core = $core;
}
/**
* Prepare extra gateways.
*
* @param WC_Gateway_Przelewy24 $main_gateway The main Przelewy24 gateway.
*/
public function prep_extra_gateways( WC_Gateway_Przelewy24 $main_gateway ) {
$currency = get_woocommerce_currency();
$config = $this->core->get_config_for_currency( $currency );
$config->access_mode_to_strict();
$this->extra_gateways = array();
$to_prep = array();
if ( $config->get_p24_show_methods_checkout() ) {
$imploded = $config->get_p24_paymethods_super_first();
$to_prep = explode( ',', $imploded );
if ( $to_prep ) {
$all_banks = $main_gateway->get_all_payment_methods();
$generator = new Przelewy24Generator( $main_gateway );
$icon_generator = $this->core->get_cached_icon_generator();
}
}
foreach ( $to_prep as $id ) {
$total = ( null !== WC()->cart ) ? (int) WC()->cart->total : 0;
if ( ! $total && null !== WC()->cart ) {
// hack for WooCommerce Active Payments pluin.
$total = WC()->cart->get_cart_contents_total() + WC()->cart->get_taxes_total() + WC()->cart->get_shipping_total();
}
if ( ! $this->is_p24_now_allowed( $total, $currency ) && 266 === (int) $id ) {
continue;
}
if ( ! $this->is_oneyraty_now_allowed( $total, $currency ) && 294 === (int) $id ) {
continue;
}
if ( ! $id ) {
continue;
} elseif ( ! isset( $all_banks[ $id ] ) ) {
continue;
}
$icon = $icon_generator->get_icon( $id, true );
if ( ! $icon ) {
/* Fallback. */
$icon = PRZELEWY24_URI . 'logo.png';
}
$this->extra_gateways[] = new P24_Extra_Gateway( $id, $all_banks[ $id ], $generator, $main_gateway, $icon );
}
}
/**
* Check if P24 Now is allowed
*
* @param numeric $amount Amount order.
* @param string $currency Active currency.
*
* @return bool
*/
private function is_p24_now_allowed( $amount, $currency ) {
return $amount > 0 && $amount < 10000 && 'PLN' === $currency;
}
/**
* Check if Oney raty is allowed
*
* @param numeric $amount Amount order.
* @param string $currency Active currency.
*
* @return bool
*/
private function is_oneyraty_now_allowed( $amount, $currency ) {
return $amount >= 150 && $amount <= 30000 && 'PLN' === $currency;
}
/**
* Inject additional gateways.
*
* Used for super first methods.
*
* @param array $gateways Prepared gateways.
* @return array
* @throws LogicException Throws if executed too early.
*/
public function inject_additional_gateways( $gateways ) {
if ( array_key_exists( WC_Gateway_Przelewy24::PAYMENT_METHOD, $gateways ) ) {
if ( ! isset( $this->extra_gateways ) ) {
throw new LogicException( 'The extra getways are not prepared yet.' );
}
foreach ( $this->extra_gateways as $extra ) {
$gateways[ $extra->id ] = $extra;
}
}
return $gateways;
}
/**
* Check gateway name.
*
* @param string $subject The gateway name.
* @return bool
*/
private function check_gateway_name( $subject ) {
$prefix = WC_Gateway_Przelewy24::PAYMENT_METHOD . '_extra_';
$prefix_quoted = preg_quote( $prefix, '/' );
$pattern = '/^' . $prefix_quoted . '\d+$/';
return (bool) preg_match( $pattern, $subject );
}
/**
* Do hack on hidden box.
*
* @param mixed $default We are not interested in changing this variable.
* @param WP_Screen $screen Data about active screen.
* @return mixed Return default value.
*/
public function do_hack_on_hidden_box( $default, WP_Screen $screen ) {
/* Fix refunds */
if ( 'woocommerce' === $screen->parent_base && 'shop_order' === $screen->post_type ) {
/* We have to try to overwrite this global variable. */
global $theorder;
if ( $theorder instanceof \Automattic\WooCommerce\Admin\Overrides\Order ) {
$old_method = $theorder->get_payment_method();
if ( $this->check_gateway_name( $old_method ) ) {
try {
$theorder->set_payment_method( WC_Gateway_Przelewy24::PAYMENT_METHOD );
} catch ( WC_Data_Exception $ex ) {
error_log( __METHOD__ . ' There is an error with unknown plugin.' ); // phpcs:ignore
error_log( __METHOD__ . $ex->getMessage() ); // phpcs:ignore
return $default;
}
}
}
}
/* We are not interested in altering default value. */
return $default;
}
/**
* Hack to fix refund.
*
* @param string $gateway_name The gateway name.
* @param WC_Order $order The order.
* @return string
*/
public function do_hack_to_fix_refund( $gateway_name, WC_Order $order ) {
if ( is_admin() ) {
if ( $this->check_gateway_name( $gateway_name ) ) {
if ( $order instanceof \Automattic\WooCommerce\Admin\Overrides\Order ) {
return WC_Gateway_Przelewy24::PAYMENT_METHOD;
}
}
}
return $gateway_name;
}
/**
* Bind common events.
*/
public function bind_common_events() {
add_filter( 'woocommerce_available_payment_gateways', array( $this, 'inject_additional_gateways' ), 256, 1 );
add_filter( 'default_hidden_meta_boxes', array( $this, 'do_hack_on_hidden_box' ), 5, 2 );
add_filter( 'woocommerce_order_get_payment_method', array( $this, 'do_hack_to_fix_refund' ), 10, 2 );
}
}

View File

@@ -0,0 +1,134 @@
<?php
/**
* File that define P24_Extra_Gateway class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* The class for extra gateway.
*/
class P24_Extra_Gateway extends WC_Payment_Gateway {
/**
* Internal id.
*
* @var string
*/
private $internal_id;
/**
* The id of BLIK method on Przelewy24 page.
*/
const BLIK_METHOD = '181';
/**
* The name of form field on checkout page.
*/
const BLIK_CODE_INPUT_NAME = 'p24-blik-code';
/**
* The key the blik code is stored in the database.
*/
const BLIK_CODE_META_KEY = '_p24_blik_code';
/**
* Generator.
*
* @var Przelewy24Generator
*/
private $generator;
/**
* Main_gateway.
*
* @var WC_Gateway_Przelewy24
*/
private $main_gateway;
/**
* P24_Extra_Gateway constructor.
*
* @param string $id Id of payment method.
* @param string $title Title of payment method.
* @param Przelewy24Generator $generator Przelewy24 generator.
* @param WC_Gateway_Przelewy24 $main_gateway Main Prelewy24 payment gateway.
* @param string $icon Icon url.
*/
public function __construct( $id, $title, $generator, $main_gateway, $icon ) {
$this->internal_id = (string) $id;
$this->id = WC_Gateway_Przelewy24::PAYMENT_METHOD . '_extra_' . $id;
$this->generator = $generator;
$this->main_gateway = $main_gateway;
$this->icon = $icon;
$this->title = (string) $title;
add_action( 'woocommerce_receipt_' . $this->id, array( $this, 'print_receipt' ) );
}
/**
* Get title.
*
* @return mixed
*/
public function get_title() {
return $this->title;
}
/**
* Aditional conntent on print receipt page.
*
* @param int $order_id If of order.
*/
public function print_receipt( $order_id ) {
$order_id = (int) $order_id;
$is_blik = self::BLIK_METHOD === $this->internal_id;
$order = new WC_Order( (int) $order_id );
if ( $is_blik ) {
$blik_code = $order->get_meta( self::BLIK_CODE_META_KEY );
} else {
$blik_code = false;
}
if ( $blik_code ) {
$legacy_auto_submit = false;
} else {
$legacy_auto_submit = true;
}
$ajax_url = add_query_arg( array( 'wc-api' => 'wc_gateway_przelewy24' ), home_url( '/' ) );
echo $this->generator->generate_przelewy24_form( $order, $legacy_auto_submit ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo "<div id='p24-additional-order-data' data-order-id='$order_id' data-ajax-url='$ajax_url'></div>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
if ( $blik_code ) {
echo P24_Blik_Html::get_modal_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
/**
* Process the payment and return the result
*
* @param int $order_id Id of orer.
* @return array
*/
public function process_payment( $order_id ) {
$order = new WC_Order( $order_id );
/* This is the default place to reduce stock levels. It is safe to call function below multiple times. */
wc_maybe_reduce_stock_levels( $order );
wp_verify_nonce( null ); /* There is no nonce in request. */
if ( isset( $_POST[ self::BLIK_CODE_INPUT_NAME ] ) ) {
$blik_code = sanitize_text_field( wp_unslash( $_POST[ self::BLIK_CODE_INPUT_NAME ] ) );
$order->update_meta_data( P24_Core::CHOSEN_TIMESTAMP_META_KEY, time() );
$order->update_meta_data( P24_Core::P24_METHOD_META_KEY, $this->internal_id );
$order->update_meta_data( self::BLIK_CODE_META_KEY, $blik_code );
$order->save_meta_data();
}
do_action( 'wc_extra_gateway_przelewy24_process_payment', $order );
return array(
'result' => 'success',
'redirect' => $order->get_checkout_payment_url( $order ),
);
}
}

View File

@@ -0,0 +1,102 @@
<?php
/**
* File that define P24_Icon_Html_Generator class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* The class for bank icons.
*/
class P24_Icon_Html_Generator {
/**
* Icon generator set.
*
* @var P24_Icon_Svg_Generator $svg_gnerator
*/
private $svg_gnerator;
/**
* P24_Icon_Html_Generator constructor.
*
* @param P24_Icon_Svg_Generator $svg_generator SVG generator.
*/
public function __construct( P24_Icon_Svg_Generator $svg_generator ) {
$this->svg_gnerator = $svg_generator;
}
/**
* Get bank icon html.
*
* @param int $bank_id Bank id.
* @param string $bank_name Bank name.
* @param string $text Bank description.
* @param string $cc_id CC id data.
* @param string $class Additional class.
* @param string $onclick On click JavaScript code.
* @param bool $with_input Generate additional form.
* @return string
*/
public function get_bank_html( $bank_id, $bank_name, $text = '', $cc_id = '', $class = '', $onclick = '', $with_input = false ) {
$bank_id = sanitize_text_field( $bank_id );
$bank_name = sanitize_text_field( $bank_name );
$text = sanitize_text_field( $text );
$cc_id = sanitize_text_field( $cc_id );
$class = sanitize_text_field( $class );
$onclick = sanitize_text_field( $onclick );
$with_input = sanitize_text_field( $with_input );
$css = $this->get_logo_css( $bank_id, true );
return '<a class="bank-box bank-item ' . $class . '" data-id="' . $bank_id . '" data-cc="' . $cc_id . '" onclick="' . $onclick . '">' .
( empty( $cc_id ) ? '' : '<span class="removecc" ' .
' title="' . __( 'Usuń zapamiętaną kartę', 'przelewy24' ) . ' ' . $bank_name . ' ' . $text . '" ' .
' onclick="arguments[0].stopPropagation(); if (confirm(\'' . __( 'Czy na pewno?', 'przelewy24' ) . '\')) removecc(' . $cc_id . ')"></span>' ) .
'<div class="bank-logo" style="' . $css . '">' .
( empty( $text ) ? '' : "<span>{$text}</span>" ) .
'</div><div class="bank-name">' . $bank_name . '</div>' . ( $with_input ? "<input style='display:none;' name='selected_banks[]' value='" . $bank_id . "' type='checkbox'/>" : '' ) . '</a>';
}
/**
* Get pay now html due to lack of proper template machine.
*
* @param int $bank_id The id of a bank.
* @param string $bank_name The name of a bank.
*
* @return string
*/
public function get_pay_now_html( $bank_id = 266, $bank_name = '' ) {
$css = $this->get_logo_css( $bank_id, true );
$logo = sprintf( '<div class="align-center bank-logo" style="%s"></div>', $css );
$text = sprintf( '<div class="bank-name ">%s</div>', $bank_name );
return sprintf(
'<a class="box-wrapper" data-id="%s"><div id="p24-now-box" class="%s">%s%s</div></a>',
$bank_id,
'payments-extra-promoted extra-promoted-box text-center',
$logo,
$text
);
}
/**
* Get logo CSS.
*
* @param int $bank_id The id of a bank.
* @param bool $mobile True if a mobile icon is requested.
* @return string
*/
private function get_logo_css( $bank_id, $mobile ) {
$bg_image = $this->svg_gnerator->get_icon( $bank_id, $mobile );
if ( $bg_image ) {
$css = "background-image: url('$bg_image')";
} else {
$css = '';
}
return $css;
}
}

View File

@@ -0,0 +1,95 @@
<?php
/**
* File that define P24_Icon_Svg_Generator class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* The class for extra gateway.
*/
class P24_Icon_Svg_Generator {
/**
* Icon_set.
*
* @var array|null
*/
private $icon_set = null;
/**
* Config.
*
* @var P24_Config_Accessor
*/
private $config;
/**
* P24_Icon_Svg_Generator constructor.
*
* @param P24_Config_Accessor $config A valid config.
*/
public function __construct( P24_Config_Accessor $config ) {
$this->icon_set = null;
$this->config = clone $config;
$this->config->access_mode_to_strict();
}
/**
* Generate set.
*/
public function generate_set() {
$this->icon_set = array();
$rest_api = new P24_Rest_Common( $this->config );
$res = $rest_api->payment_methods( 'pl' );
if ( isset( $res['data'] ) ) {
foreach ( $res['data'] as $row ) {
$this->icon_set[ $row['id'] ] = array(
'base' => $row['imgUrl'],
'mobile' => $row['mobileImgUrl'],
);
}
}
ksort( $this->icon_set, SORT_NUMERIC );
}
/**
* Get icon.
*
* @param int $id Id of payment method.
* @param bool $mobile True for mobile version.
* @return string|null
*/
public function get_icon( $id, $mobile ) {
if ( ! isset( $this->icon_set ) ) {
$this->generate_set();
}
$id = (int) $id;
if ( array_key_exists( $id, $this->icon_set ) ) {
$type = $mobile ? 'mobile' : 'base';
return $this->icon_set[ $id ][ $type ];
} else {
return null;
}
}
/**
* Get_all.
*
* @return array
*/
public function get_all() {
if ( ! isset( $this->icon_set ) ) {
$this->generate_set();
}
return $this->icon_set;
}
}

View File

@@ -0,0 +1,100 @@
<?php
/**
* File that define P24_Install class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
/**
* Install methods for Przelewy 24 plugin.
*/
class P24_Install {
const P24_INSTALLED_VERSION = 'p24_installed_version';
/**
* Update database.
*/
private static function update_database() {
global $wpdb;
dbDelta(
'
CREATE TABLE ' . $wpdb->prefix . 'woocommerce_p24_data (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
data_type VARCHAR(32) NOT NULL,
data_id INT NOT NULL,
custom_key VARCHAR(32) NOT NULL,
custom_value TEXT,
robik TEXT,
INDEX search_key (data_type, data_id, custom_key),
INDEX get_key (data_type, data_id)
);
'
);
dbDelta(
'
CREATE TABLE ' . $wpdb->prefix . 'woocommerce_p24_order_map (
order_hash VARCHAR(40) UNIQUE NOT NULL PRIMARY KEY,
order_id INT NOT NULL,
INDEX search_hash (order_hash)
);
'
);
dbDelta(
'
CREATE TABLE IF NOT EXISTS ' . $wpdb->prefix . 'woocommerce_p24_subscription(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
valid_to DATETIME NOT NULL,
extend TINYINT NOT NULL,
card_ref TEXT NULL,
last_order_id BIGINT NOT NULL,
last_checked DATETIME NOT NULL,
INDEX (user_id),
INDEX (product_id),
INDEX (last_order_id),
INDEX (valid_to)
);
'
);
if ( $wpdb->get_var( "SHOW TABLES LIKE '" . $wpdb->prefix . "woocommerce_p24_custom_data'" ) === $wpdb->prefix . 'woocommerce_p24_custom_data' && ! $wpdb->get_var( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'woocommerce_p24_data' ) ) {
$wpdb->query(
'
INSERT INTO ' . $wpdb->prefix . 'woocommerce_p24_data
SELECT * FROM ' . $wpdb->prefix . 'woocommerce_p24_custom_data
'
); /* db call ok; no cache ok */
}
}
/**
* Update shedules.
*/
private static function update_shedules() {
if ( ! wp_next_scheduled( 'p24_daily_event' ) ) {
wp_schedule_event( time(), 'daily', 'p24_daily_event' );
}
}
/**
* Check install.
*/
public static function check_install() {
$configured = get_option( self::P24_INSTALLED_VERSION );
$actual = P24_Core::INTERNAL_VERSION;
if ( $configured !== $actual ) {
self::update_database();
self::update_shedules();
update_option( self::P24_INSTALLED_VERSION, $actual, true );
}
}
}

View File

@@ -0,0 +1,299 @@
<?php
/**
* File that define P24_Leaderboards_Controller class. This is code from WooCommerce plugin with overwritten data
* stores. Slightly rebuilt (few texts were moved to constants).
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Leaderboards;
use P24_Categories_Data_Store as CategoriesDataStore;
use P24_Coupons_Data_Store as CouponsDataStore;
use P24_Customers_Data_Store as CustomersDataStore;
use P24_Products_Data_Store as ProductsDataStore;
/**
* Class P24_Leaderbords_Controller.
*/
class P24_Leaderboards_Controller extends Leaderboards {
const LEADERBOARD_ARGUMENT_ORDER_BY = 'orderby';
const LEADERBOARD_ARGUMENT_ORDER = 'order';
const LEADERBOARD_ARGUMENT_AFTER = 'after';
const LEADERBOARD_ARGUMENT_BEFORE = 'before';
const LEADERBOARD_ARGUMENT_PER_PAGE = 'per_page';
const LEADERBOARD_ARGUMENT_EXTENDED_INFO = 'extended_info';
const LEADERBOARD_ARGUMENT_ORDER_AFTER = 'order_after';
const LEADERBOARD_ARGUMENT_ORDER_BEFORE = 'order_before';
/**
* Get the data for the coupons leaderboard.
*
* @param int $per_page Number of rows.
* @param string $after Items after date.
* @param string $before Items before date.
* @param string $persisted_query URL query string.
*
* @return array
*/
public function get_coupons_leaderboard( $per_page, $after, $before, $persisted_query ) {
$coupons_data_store = new CouponsDataStore();
$coupons_data = $per_page > 0 ? $coupons_data_store->get_data(
array(
self::LEADERBOARD_ARGUMENT_ORDER_BY => 'orders_count',
self::LEADERBOARD_ARGUMENT_ORDER => 'desc',
self::LEADERBOARD_ARGUMENT_AFTER => $after,
self::LEADERBOARD_ARGUMENT_BEFORE => $before,
self::LEADERBOARD_ARGUMENT_PER_PAGE => $per_page,
self::LEADERBOARD_ARGUMENT_EXTENDED_INFO => true,
)
)->data : array();
$rows = array();
foreach ( $coupons_data as $coupon ) {
$url_query = wp_parse_args(
array(
'filter' => 'single_coupon',
'coupons' => $coupon['coupon_id'],
),
$persisted_query
);
$coupon_url = wc_admin_url( '/analytics/coupons', $url_query );
$coupon_code = isset( $coupon['extended_info'] ) && isset( $coupon['extended_info']['code'] ) ? $coupon['extended_info']['code'] : '';
$rows[] = array(
array(
'display' => "<a href='{$coupon_url}'>{$coupon_code}</a>",
'value' => $coupon_code,
),
array(
'display' => wc_admin_number_format( $coupon['orders_count'] ),
'value' => $coupon['orders_count'],
),
array(
'display' => wc_price( $coupon['amount'] ),
'value' => $coupon['amount'],
),
);
}
return array(
'id' => 'coupons',
'label' => __( 'Top Coupons - Number of Orders', 'woocommerce' ),
'headers' => array(
array(
'label' => __( 'Coupon Code', 'woocommerce' ),
),
array(
'label' => __( 'Orders', 'woocommerce' ),
),
array(
'label' => __( 'Amount Discounted', 'woocommerce' ),
),
),
'rows' => $rows,
);
}
/**
* Get the data for the categories leaderboard.
*
* @param int $per_page Number of rows.
* @param string $after Items after date.
* @param string $before Items before date.
* @param string $persisted_query URL query string.
*
* @return array
*/
public function get_categories_leaderboard( $per_page, $after, $before, $persisted_query ) {
$categories_data_store = new CategoriesDataStore();
$categories_data = $per_page > 0 ? $categories_data_store->get_data(
array(
self::LEADERBOARD_ARGUMENT_ORDER_BY => 'items_sold',
self::LEADERBOARD_ARGUMENT_ORDER => 'desc',
self::LEADERBOARD_ARGUMENT_AFTER => $after,
self::LEADERBOARD_ARGUMENT_BEFORE => $before,
self::LEADERBOARD_ARGUMENT_PER_PAGE => $per_page,
self::LEADERBOARD_ARGUMENT_EXTENDED_INFO => true,
)
)->data : array();
$rows = array();
foreach ( $categories_data as $category ) {
$url_query = wp_parse_args(
array(
'filter' => 'single_category',
'categories' => $category['category_id'],
),
$persisted_query
);
$category_url = wc_admin_url( '/analytics/categories', $url_query );
$category_name = isset( $category['extended_info'] ) && isset( $category['extended_info']['name'] ) ? $category['extended_info']['name'] : '';
$rows[] = array(
array(
'display' => "<a href='{$category_url}'>{$category_name}</a>",
'value' => $category_name,
),
array(
'display' => wc_admin_number_format( $category['items_sold'] ),
'value' => $category['items_sold'],
),
array(
'display' => wc_price( $category['net_revenue'] ),
'value' => $category['net_revenue'],
),
);
}
return array(
'id' => 'categories',
'label' => __( 'Top Categories - Items Sold', 'woocommerce' ),
'headers' => array(
array(
'label' => __( 'Category', 'woocommerce' ),
),
array(
'label' => __( 'Items Sold', 'woocommerce' ),
),
array(
'label' => __( 'Net Sales', 'woocommerce' ),
),
),
'rows' => $rows,
);
}
/**
* Get the data for the customers leaderboard.
*
* @param int $per_page Number of rows.
* @param string $after Items after date.
* @param string $before Items before date.
* @param string $persisted_query URL query string.
*
* @return array
*/
public function get_customers_leaderboard( $per_page, $after, $before, $persisted_query ) {
$customers_data_store = new CustomersDataStore();
$customers_data = $per_page > 0 ? $customers_data_store->get_data(
array(
self::LEADERBOARD_ARGUMENT_ORDER_BY => 'total_spend',
self::LEADERBOARD_ARGUMENT_ORDER => 'desc',
self::LEADERBOARD_ARGUMENT_ORDER_AFTER => $after,
self::LEADERBOARD_ARGUMENT_ORDER_BEFORE => $before,
self::LEADERBOARD_ARGUMENT_PER_PAGE => $per_page,
)
)->data : array();
$rows = array();
foreach ( $customers_data as $customer ) {
$url_query = wp_parse_args(
array(
'filter' => 'single_customer',
'customers' => $customer['id'],
),
$persisted_query
);
$customer_url = wc_admin_url( '/analytics/customers', $url_query );
$rows[] = array(
array(
'display' => "<a href='{$customer_url}'>{$customer['name']}</a>",
'value' => $customer['name'],
),
array(
'display' => wc_admin_number_format( $customer['orders_count'] ),
'value' => $customer['orders_count'],
),
array(
'display' => wc_price( $customer['total_spend'] ),
'value' => $customer['total_spend'],
),
);
}
return array(
'id' => 'customers',
'label' => __( 'Top Customers - Total Spend', 'woocommerce' ),
'headers' => array(
array(
'label' => __( 'Customer Name', 'woocommerce' ),
),
array(
'label' => __( 'Orders', 'woocommerce' ),
),
array(
'label' => __( 'Total Spend', 'woocommerce' ),
),
),
'rows' => $rows,
);
}
/**
* Get the data for the products leaderboard.
*
* @param int $per_page Number of rows.
* @param string $after Items after date.
* @param string $before Items before date.
* @param string $persisted_query URL query string.
*
* @return array
*/
public function get_products_leaderboard( $per_page, $after, $before, $persisted_query ) {
$products_data_store = new ProductsDataStore();
$products_data = $per_page > 0 ? $products_data_store->get_data(
array(
self::LEADERBOARD_ARGUMENT_ORDER_BY => 'items_sold',
self::LEADERBOARD_ARGUMENT_ORDER => 'desc',
self::LEADERBOARD_ARGUMENT_AFTER => $after,
self::LEADERBOARD_ARGUMENT_BEFORE => $before,
self::LEADERBOARD_ARGUMENT_PER_PAGE => $per_page,
self::LEADERBOARD_ARGUMENT_EXTENDED_INFO => true,
)
)->data : array();
$rows = array();
foreach ( $products_data as $product ) {
$url_query = wp_parse_args(
array(
'filter' => 'single_product',
'products' => $product['product_id'],
),
$persisted_query
);
$product_url = wc_admin_url( '/analytics/products', $url_query );
$product_name = isset( $product[ self::LEADERBOARD_ARGUMENT_EXTENDED_INFO ] )
&& isset( $product[ self::LEADERBOARD_ARGUMENT_EXTENDED_INFO ]['name'] )
? $product[ self::LEADERBOARD_ARGUMENT_EXTENDED_INFO ]['name'] : '';
$rows[] = array(
array(
'display' => "<a href='{$product_url}'>{$product_name}</a>",
'value' => $product_name,
),
array(
'display' => wc_admin_number_format( $product['items_sold'] ),
'value' => $product['items_sold'],
),
array(
'display' => wc_price( $product['net_revenue'] ),
'value' => $product['net_revenue'],
),
);
}
return array(
'id' => 'products',
'label' => __( 'Top Products - Items Sold', 'woocommerce' ),
'headers' => array(
array(
'label' => __( 'Product', 'woocommerce' ),
),
array(
'label' => __( 'Items Sold', 'woocommerce' ),
),
array(
'label' => __( 'Net Sales', 'woocommerce' ),
),
),
'rows' => $rows,
);
}
}

View File

@@ -0,0 +1,210 @@
<?php
/**
* File that define P24_Message_Validator class.
*
* @package Przelewy24
*/
/**
* Class P24_Message_Validator.
*/
class P24_Message_Validator {
/**
* Validate version.
*
* @param string $version Reference to version variable.
* @return bool
*/
private function validate_version( &$version ) {
if ( preg_match( '/^[0-9]+(?:\.[0-9]+)*(?:[\.\-][0-9a-z]+)?$/', $version ) ) {
return true;
}
$version = '';
return false;
}
/**
* Validate email.
*
* @param string $email Reference to email variable.
* @return bool
*/
private function validate_email( &$email ) {
$email = filter_var( $email, FILTER_VALIDATE_EMAIL );
if ( $email ) {
return true;
}
$email = '';
return false;
}
/**
* Validate number.
*
* @param string|float|int $value Reference to value that should be a number.
* @param bool|int $min The minimum allowed value, false for unbound.
* @param bool|int $max The maximum allowed value, false for unbound.
* @return bool
*/
private function validate_number( &$value, $min = false, $max = false ) {
if ( is_numeric( $value ) ) {
$value = (int) $value;
if ( ( false !== $min && $value < $min ) || ( false !== $max && $value > $max ) ) {
return false;
}
return true;
}
$value = ( false !== $min ? $min : 0 );
return false;
}
/**
* Validate string.
*
* @param string $value The reference to string.
* @param int $len The maximum length, 0 for unlimited.
* @return bool
*/
private function validate_string( &$value, $len = 0 ) {
if ( preg_match( '/<[^<]+>/', $value, $m ) === 1 ) {
return false;
}
if ( 0 === $len ^ strlen( $value ) <= $len ) {
return true;
}
$value = '';
return false;
}
/**
* Validate URL.
*
* @param string $url The reference to url.
* @param int $len The maximum length, 0 for unlimited.
* @return bool
*/
private function validate_url( &$url, $len = 0 ) {
if ( 0 === $len ^ strlen( $url ) <= $len ) {
if ( preg_match( '@^https?://[^\s/$.?#].[^\s]*$@iS', $url ) ) {
return true;
}
}
$url = '';
return false;
}
/**
* Validate enum.
*
* @param string $value The reference to value.
* @param array $haystack The list of valid values.
* @return bool
*/
private function validate_enum( &$value, $haystack ) {
if ( in_array( strtolower( $value ), $haystack, true ) ) {
return true;
}
$value = $haystack[0];
return false;
}
/**
* Validate field.
*
* @param string $field The name of field.
* @param mixed $value The reference to value.
* @return boolean
*/
public function validate_field( $field, &$value ) {
$ret = false;
switch ( $field ) {
case 'p24_session_id':
$ret = $this->validate_string( $value, 100 );
break;
case 'p24_description':
$ret = $this->validate_string( $value, 1024 );
break;
case 'p24_address':
$ret = $this->validate_string( $value, 80 );
break;
case 'p24_country':
case 'p24_language':
$ret = $this->validate_string( $value, 2 );
break;
case 'p24_client':
case 'p24_city':
$ret = $this->validate_string( $value, 50 );
break;
case 'p24_merchant_id':
case 'p24_pos_id':
case 'p24_order_id':
case 'p24_amount':
case 'p24_method':
case 'p24_time_limit':
case 'p24_channel':
case 'p24_shipping':
$ret = $this->validate_number( $value );
break;
case 'p24_wait_for_result':
$ret = $this->validate_number( $value, 0, 1 );
break;
case 'p24_api_version':
$ret = $this->validate_version( $value );
break;
case 'p24_sign':
if ( strlen( $value ) === 32 && ctype_xdigit( $value ) ) {
$ret = true;
} else {
$value = '';
}
break;
case 'p24_url_return':
case 'p24_url_status':
$ret = $this->validate_url( $value, 250 );
break;
case 'p24_currency':
$ret = (bool) preg_match( '/^[A-Z]{3}$/', $value );
if ( ! $ret ) {
$value = '';
}
break;
case 'p24_email':
$ret = $this->validate_email( $value );
break;
case 'p24_encoding':
$ret = $this->validate_enum( $value, array( 'iso-8859-2', 'windows-1250', 'urf-8', 'utf8' ) );
break;
case 'p24_transfer_label':
$ret = $this->validate_string( $value, 20 );
break;
case 'p24_phone':
$ret = $this->validate_string( $value, 12 );
break;
case 'p24_zip':
$ret = $this->validate_string( $value, 10 );
break;
default:
if ( strpos( $field, 'p24_quantity_' ) === 0 || strpos( $field, 'p24_price_' ) === 0 || strpos( $field, 'p24_number_' ) === 0 ) {
$ret = $this->validate_number( $value );
} elseif ( strpos( $field, 'p24_name_' ) === 0 || strpos( $field, 'p24_description_' ) === 0 ) {
$ret = $this->validate_string( $value, 127 );
} else {
$value = '';
}
break;
}
return $ret;
}
/**
* Filter value.
*
* @param string $field The name of field.
* @param string|float|int $value The value to test.
* @return bool|string
*/
public function filter_value( $field, $value ) {
return ( $this->validate_field( $field, $value ) ) ? addslashes( $value ) : false;
}
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* File that define P24_Multi_Currency_Menu class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class P24_Multi_Currency_Menu
*
* Update the menu section on admin panel.
*/
class P24_Multi_Currency_Menu {
/**
* The P24_Core instance.
*
* @var P24_Core
*/
private $plugin_core;
/**
* The constructor.
*
* @param P24_Core $plugin_core The P24_Core instance.
*/
public function __construct( P24_Core $plugin_core ) {
$this->plugin_core = $plugin_core;
}
/**
* Generate form to select links to change currency in user mode.
*/
public function nav_menu_link() {
$params = [
'currency_options' => get_przelewy24_multi_currency_options(),
];
$this->plugin_core->render_template( 'currency-menu-generator', $params );
}
/**
* Add box on admin panel to select links.
*/
public function add_menu_box() {
if ( $this->plugin_core->is_internal_multi_currency_active() ) {
add_meta_box(
'p24_menu_box',
__( 'Moduł multi currency', 'przelewy24' ),
[ $this, 'nav_menu_link' ],
'nav-menus',
'side',
'low'
);
}
}
/**
* Check if selected post should be show in menu.
*
* @param WP_Post $item The element to show in menu.
*
* @return bool
*/
private function check_drop_inactive_currency( WP_Post $item ) {
if ( property_exists( $item, 'url' ) ) {
$url = $item->{'url'};
$rx = '/^\\?p24\\_change\\_currency\\=(.+)$/';
if ( preg_match( $rx, $url, $m ) ) {
$currency = $m[1];
$mc = $this->plugin_core->get_multi_currency_instance();
if ( $currency === $mc->get_active_currency() ) {
return true;
} elseif ( ! in_array( $currency, $mc->get_available_currencies(), true ) ) {
return true;
}
}
}
return false;
}
/**
* Filter user menu items.
*
* @param array $items Sorted list of items in menu.
*
* @return array
*/
public function filter_user_menu( $items ) {
$ret = [];
foreach ( $items as $item ) {
$classes = $item->classes;
if ( in_array( 'p24-change-currency', $classes, true ) ) {
if ( ! $this->plugin_core->is_internal_multi_currency_active() ) {
/* If there is no multi currency, drop all links. */
continue;
}
if ( $this->check_drop_inactive_currency( $item ) ) {
continue;
}
}
$ret[] = $item;
}
return $ret;
}
/**
* Bind events.
*/
public function bind_events() {
add_action( 'admin_init', [ $this, 'add_menu_box' ] );
add_filter( 'wp_nav_menu_objects', [ $this, 'filter_user_menu' ] );
}
}

View File

@@ -0,0 +1,733 @@
<?php
/**
* File that define P24_Multi_Currency class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class P24_Multi_Currency
*
* Add elementary functions to support multi currency.
*/
class P24_Multi_Currency implements P24_MC_Interface {
// WooCommerce values - no constants are used in WC libraries for them.
const WOOCOMMERCE_FIELD_DECIMAL_SEPARATOR = 'decimal_separator';
const WOOCOMMERCE_FIELD_THOUSAND_SEPARATOR = 'thousand_separator';
const WOOCOMMERCE_FIELD_DECIMALS = 'decimals';
/**
* Internal name for this implementation of Multi Currency.
*/
const MC_NAME = 'P24_MC_Internal';
/**
* Instance of core of plugin.
*
* @var P24_Core
*/
private $plugin_core;
/**
* The currency to display for users.
*
* @var string|null
*/
private $active_currency;
/**
* P24_Multi_Currency constructor.
*
* @param P24_Core $plugin_core Instance of main plugin.
* @param string|null $active_currency Active currency to set.
*/
public function __construct( P24_Core $plugin_core, $active_currency ) {
$this->plugin_core = $plugin_core;
$this->active_currency = $active_currency;
}
/**
* Check if external multi currency is activated.
*
* If this instance exists, it should be active.
*
* @return bool
*/
public function is_multi_currency_active() {
return true;
}
/**
* Check if multi currency is internal.
*
* @return bool
*/
public function is_internal() {
return true;
}
/**
* Get reports currency.
*
* @param string|null $default Default reports currency.
*
* @return string|null
*/
public static function get_admin_reports_currency( $default = null ) {
if ( ! isset( $_COOKIE['admin_p24_reports_currency'] ) ) {
return $default;
}
return sanitize_text_field( wp_unslash( $_COOKIE['admin_p24_reports_currency'] ) );
}
/**
* Get sql query which filters report data by order currency.
*
* @param string $order_table Name of table with orders (without prefix).
*
* @return string
*/
public static function get_currency_filter_for_reports( $order_table ) {
/**
* Global variable usage suggested in WordPress Documentation:
* https://developer.wordpress.org/reference/classes/wpdb/ .
*
* Unfortunately there does not seem to be any alternative to access db prefix by global variables.
*/
global $wpdb;
$metadata_table = esc_sql( "{$wpdb->prefix}postmeta" );
$currency = esc_sql( self::get_admin_reports_currency( get_woocommerce_currency() ) );
$metadata_alias = 'p24_postmeta';
$order_table = esc_sql( $order_table );
return " JOIN {$metadata_table} as {$metadata_alias} ON (" .
"{$metadata_alias}.meta_key = '_order_currency'" . ' AND ' .
"{$metadata_alias}.meta_value = '" . $currency . "'" . ' AND ' .
"{$metadata_alias}.post_id = {$order_table}.order_id)";
}
/**
* Get active currency.
*
* @return string
*/
public function get_active_currency() {
if ( ! $this->active_currency ) {
$multipliers = $this->get_multipliers();
wp_verify_nonce( null ); /* There is no noce. */
if ( $this->plugin_core->is_in_user_mode() ) {
$this->active_currency = $this->get_active_currency_from_cookie( $multipliers );
} elseif ( $this->plugin_core->is_in_json_mode() ) {
if ( array_key_exists( P24_Request_Support::WP_JSON_GET_KEY_CURRENCY, $_GET ) ) {
$this->active_currency = sanitize_text_field( wp_unslash( $_GET[ P24_Request_Support::WP_JSON_GET_KEY_CURRENCY ] ) );
}
}
if ( ! $this->active_currency || ! array_key_exists( $this->active_currency, $multipliers ) ) {
$this->active_currency = P24_Woo_Commerce_Low_Level_Getter::get_unhooked_currency_form_woocommerce();
}
}
return $this->active_currency;
}
/**
* Get default currency.
*
* It may be different from active currency.
*
* @return string
*/
public function get_default_currency() {
return P24_Woo_Commerce_Low_Level_Getter::get_unhooked_currency_form_woocommerce();
}
/**
* Save active currency to cookie.
*/
public function save_currency_to_cookie() {
wc_setcookie( 'user_p24_currency', $this->active_currency );
}
/**
* Try to get active currency from cookie.
*
* @param array $multipliers Array of valid currencies with multipliers.
* @return string|null
*/
private function get_active_currency_from_cookie( array $multipliers ) {
if ( isset( $_COOKIE['user_p24_currency'] ) ) {
$this->active_currency = sanitize_text_field( wp_unslash( $_COOKIE['user_p24_currency'] ) );
} else {
$this->active_currency = null;
}
if ( ! $this->active_currency || ! array_key_exists( $this->active_currency, $multipliers ) ) {
/* Fix cookie. */
$this->active_currency = P24_Woo_Commerce_Low_Level_Getter::get_unhooked_currency_form_woocommerce();
$this->save_currency_to_cookie();
}
return $this->active_currency;
}
/**
* Get array of multipliers for currencies.
*
* @return array
*/
public function get_multipliers() {
$set = get_option( 'przelewy24_multi_currency_multipliers', array() );
$default = P24_Woo_Commerce_Low_Level_Getter::get_unhooked_currency_form_woocommerce();
$set[ $default ] = 1;
return $set;
}
/**
* Get list of available currencies.
*
* It is based on multipliers.
*
* @return array
*/
public function get_available_currencies() {
$set = $this->get_multipliers();
$keys = array_keys( $set );
return array_combine( $keys, $keys );
}
/**
* Get name.
*
* @return string
*/
public function get_name() {
return self::MC_NAME;
}
/**
* Method for filter that change default currency.
*
* The default value is ignored.
* The wrapped function should always return something.
*
* @param mixed $default Default value provided by filter.
* @return string
*/
public function try_change_default_currency( $default ) {
$active = $this->get_active_currency();
return $active ? $active : $default;
}
/**
* Try change price format.
*
* @param mixed $default Default value.
* @param string $option Name of option.
* @return mixed
*/
private function try_change_price_format( $default, $option ) {
$is_reports_context = $this->plugin_core->get_context_provider()->is_reports_context();
/* Do not change defaults on admin panel except for reports. */
if ( is_admin() && ! $is_reports_context ) {
return $default;
}
$currency = $is_reports_context ? $this->get_admin_reports_currency() : $this->get_active_currency();
if ( null === $currency ) {
return $default;
}
$format = $this->get_przelewy24_multi_currency_format( $currency, $option );
return null !== $format ? $format : $default;
}
/**
* Get price format from multicurrency settings.
*
* @param string $currency Default value.
* @param string $option Name of option.
*
* @return string|null
*/
private function get_przelewy24_multi_currency_format( $currency, $option ) {
$formats = get_option( 'przelewy24_multi_currency_formats', array() );
if ( ! array_key_exists( $currency, $formats ) || ! array_key_exists( $option, $formats[ $currency ] ) ) {
return null;
}
$return = $formats[ $currency ][ $option ];
if ( 'thousand_separator' !== $option && '' === $return ) {
return null;
}
return $return;
}
/**
* Try change thousand separator.
*
* @param string $default Default thousand separator.
* @return string
*/
public function try_change_thousand_separator( $default ) {
return $this->try_change_price_format( $default, 'thousand_separator' );
}
/**
* Try change decimal separator.
*
* @param string $default Default decimal separator.
* @return string
*/
public function try_change_decimal_separator( $default ) {
return $this->try_change_price_format( $default, 'decimal_separator' );
}
/**
* Try change number of fraction digits.
*
* @param mixed $default Default number of fraction digits.
* @return mixed
*/
public function try_change_decimals( $default ) {
return $this->try_change_price_format( $default, 'decimals' );
}
/**
* Try change currency position.
*
* @param string $default Default currency position.
* @return string
*/
public function try_change_currency_pos( $default ) {
return $this->try_change_price_format( $default, 'currency_pos' );
}
/**
* Add scripts used on admin page.
*/
public function add_admin_scripts() {
wp_enqueue_script( 'p24_multi_currency_admin_script', PRZELEWY24_URI . 'assets/js/p24_multi_currency_admin_script.js', array( 'jquery' ), P24_Core::SCRIPTS_VERSION, true );
}
/**
* Add scripts used on user page.
*/
public function add_user_scripts() {
wp_enqueue_style( 'p24_multi_currency_form', PRZELEWY24_URI . 'assets/css/p24_multi_currency_style.css', array(), P24_Core::SCRIPTS_VERSION );
}
/**
* No product class error suppressor.
*
* We have to run this code before find_product_class.
*
* @param string|null $suggested
* @return string
*/
public function no_product_class_error_suppressor( $suggested ) {
if ( ! $suggested || ! class_exists( $suggested ) ) {
return WC_Product_Simple::class;
} else {
return $suggested;
}
}
/**
* Try find name of class for product.
*
* This method has to be run after no_product_class_error_suppressor.
*
* This method works as filter. The suggested class is required to do proper override.
*
* @param string $suggested Suggested product class.
* @param string $type Product type.
* @param string $variation Product variation.
* @param int $product_id Product id.
* @return string
* @throws LogicException If nothing was provided or found.
*/
public function find_product_class( $suggested, $type, $variation, $product_id ) {
$rx1 = '/^WC\\_Product\\_(.+)$/';
$rx2 = '/^P24\\_No\\_MC\\_Product\\_(.+)$/';
if ( preg_match( $rx1, $suggested, $m ) ) {
$class = 'P24_Product_' . $m[1];
} elseif ( preg_match( $rx2, $suggested, $m ) ) {
$class = 'P24_Product_' . $m[1];
} else {
$class = $suggested;
}
if ( class_exists( $class ) ) {
return $class;
} else {
$msg = "The incompatability with multi currency and other plugin occured. Cannot compute price. The required class $class cannot be found. Suggested class was $suggested, type was $type, variation was $variation, id was $product_id.";
throw new LogicException( $msg );
}
}
/**
* Update price hash.
*
* The multiplier for currency is added.
*
* @param array $hash Default hash.
* @param WC_Product $product The product.
* @param string $context The context.
* @return array
* @throws LogicException If the currency is not configured.
*/
public function filter_price_hash( $hash, $product, $context ) {
if ( method_exists( $product, 'get_currency' ) ) {
$currency = $product->get_currency( $context );
$multipliers = $this->get_multipliers();
if ( ! array_key_exists( $currency, $multipliers ) ) {
throw new LogicException( "The requested currency $currency is not configured." );
}
$hash[] = $multipliers[ $currency ];
}
return $hash;
}
/**
* Try override active currency.
*
* The communication with Przelewy24 is quite late.
*
* @param P24_Communication_Parser $parser The P24_Communication_Parser instance.
*/
public function try_override_active_currency( P24_Communication_Parser $parser ) {
if ( $parser->is_valid() ) {
$this->active_currency = $parser->get_currency();
}
}
/**
* Replaces store element.
*
* @param array $results Current stores.
*
* @return array
*/
public static function add_to_store( $results ) {
$p24_stores = array(
'report-orders-stats' => 'P24_Orders_Stats_Data_Store',
'report-revenue-stats' => 'P24_Orders_Stats_Data_Store',
'report-products-stats' => 'P24_Products_Stats_Data_Store',
'report-products' => 'P24_Products_Data_Store',
'report-categories' => 'P24_Categories_Data_Store',
'report-orders' => 'P24_Orders_Data_Store',
'report-variations' => 'P24_Variations_Data_Store',
'report-taxes' => 'P24_Taxes_Data_Store',
'report-taxes-stats' => 'P24_Taxes_Stats_Data_Store',
'report-coupons' => 'P24_Coupons_Data_Store',
'report-coupons-stats' => 'P24_Coupons_Stats_Data_Store',
'report-customers' => 'P24_Customers_Data_Store',
'report-customers-stats' => 'P24_Customers_Stats_Data_Store',
);
return array_merge( $results, $p24_stores );
}
/**
* Compute price in provided currency.
*
* @param mixed $price Price in default currency.
* @param string $currency Provided currency.
* @return mixed
* @throws LogicException If currency is not found.
*/
public function compute_price_in_currency( $price, $currency ) {
if ( ! $price ) {
/* We have to preserve different false values. */
return $price;
}
$multipliers = $this->get_multipliers();
if ( array_key_exists( $currency, $multipliers ) ) {
$multiplier = $multipliers[ $currency ];
} else {
throw new LogicException( "The currency $currency not found in config." );
}
if ( 1.0 === (float) $multiplier ) {
return $price;
} else {
return $price * $multiplier;
}
}
/**
* Convert price between currencies.
*
* @param mixed $price Price in default currency.
* @param string $from From currency.
* @param string $to To currency.
* @return mixed
* @throws LogicException If any currency is not found.
*/
public function convert_price( $price, $from, $to ) {
if ( ! $price ) {
/* We have to preserve different false values. */
return $price;
}
$multipliers = $this->get_multipliers();
if ( array_key_exists( $from, $multipliers ) ) {
$multiplier_from = $multipliers[ $from ];
} else {
throw new LogicException( "The currency $from not found in config." );
}
if ( array_key_exists( $to, $multipliers ) ) {
$multiplier_to = $multipliers[ $to ];
} else {
throw new LogicException( "The currency $to not found in config." );
}
if ( 1.0 === (float) $multiplier_to / $multiplier_from ) {
return $price;
} else {
return $price * $multiplier_to / $multiplier_from;
}
}
/**
* Compute prices for sending package.
*
* @param array $rates The set of rages.
*
* @return array
*/
public function update_package_rates( $rates ) {
$currency = $this->get_active_currency();
$ret = array();
foreach ( $rates as $idx => $rate ) {
$cost = $rate->get_cost();
$cost = $this->compute_price_in_currency( $cost, $currency );
$rate->set_cost( $cost );
$taxes = $rate->get_taxes();
$currencies_map = array_fill_keys( array_keys( $taxes ), $currency );
$taxes_keys = array_keys( $taxes );
$taxes = array_map( array( $this, 'compute_price_in_currency' ), $taxes, $currencies_map );
$rate->set_taxes( array_combine( $taxes_keys, $taxes ) );
$ret[ $idx ] = $rate;
}
return $rates;
}
/**
* Try override one field for multi currency.
*
* @param string $field The name of field in meta table.
* @param array $sql The SQL split into few parts.
*
* @return array
*/
private function sql_override_field( $field, $sql ) {
$rxs = '/^(.*\\S)\\s?SUM\\s*\\(\\s*meta_' . $field . '\\.meta_value\\s*\\)(.*)$/Dis';
$rxj = '/INNER\\s+JOIN\\s+(\\S*postmeta)\\s+AS\\s+(\\S+)\\s+ON\\s*\\([^\\)]*\\.meta_key\\s*\\=\\s*\\\'' . $field . '\\\'[^\\)]*\\)/is';
if ( preg_match( $rxs, $sql['select'], $ms ) && preg_match( $rxj, $sql['join'], $mj ) ) {
$meta_tbl = $mj[1];
$base_tbl = $mj[2];
$our_tbl = $base_tbl . '_p24dc';
$our_field = $field . '_p24dc';
$select_head = $ms[1];
$select_tail = $ms[2];
$sql['select'] = "$select_head SUM(IFNULL($our_tbl.meta_value, $base_tbl.meta_value ) )$select_tail";
$sql['join'] = $sql['join'] . "\n"
. " LEFT JOIN $meta_tbl AS $our_tbl ON (\n"
. " $our_tbl.meta_key = '$our_field'\n"
. " AND $our_tbl.post_id = $base_tbl.post_id\n"
. " )\n";
}
return $sql;
}
/**
* Override SQL to be compatible with multi currency.
*
* @param array $sql The SQL split into few parts.
*
* @return array
*/
public function sql_override( $sql ) {
if ( array_key_exists( 'select', $sql ) && array_key_exists( 'join', $sql ) ) {
$sql = $this->sql_override_field( '_order_total', $sql );
$sql = $this->sql_override_field( '_order_tax', $sql );
$sql = $this->sql_override_field( '_order_shipping', $sql );
$sql = $this->sql_override_field( '_order_shipping_tax', $sql );
$sql = $this->sql_override_field( '_order_discount', $sql );
$sql = $this->sql_override_field( '_order_discount_tax', $sql );
}
return $sql;
}
/**
* Add additional fields to order.
*
* @param WC_Abstract_Order $order The order to save.
*/
public function before_order_save( $order ) {
$dc = $this->get_default_currency();
$oc = $order->get_currency();
if ( $dc !== $order->get_currency() ) {
$multipliers = $this->get_multipliers();
$multiplier = $multipliers[ $oc ];
$total = $order->get_total();
$dc_total = $total / $multiplier;
$tax = $order->get_cart_tax();
$dc_tax = $tax / $multiplier;
$shipping = $order->get_shipping_total();
$dc_shipping = $shipping / $multiplier;
$shipping_tax = $order->get_shipping_tax();
$dc_shipping_tax = $shipping_tax / $multiplier;
$discount = $order->get_discount_total();
$dc_discount = $discount / $multiplier;
$discount_tax = $order->get_discount_tax();
$dc_discount_tax = $discount_tax / $multiplier;
$order->add_meta_data( '_order_total_p24dc', $dc_total, true );
$order->add_meta_data( '_order_tax_p24dc', $dc_tax, true );
$order->add_meta_data( '_order_shipping_p24dc', $dc_shipping, true );
$order->add_meta_data( '_order_shipping_tax_p24dc', $dc_shipping_tax, true );
$order->add_meta_data( '_cart_discount_p24dc', $dc_discount, true );
$order->add_meta_data( '_cart_discount_tax_p24dc', $dc_discount_tax, true );
if ( $order instanceof WC_Order_Refund ) {
$refund = $order->get_amount();
$dc_refund = $refund / $multiplier;
$order->add_meta_data( '_refund_amount_p24dc', $dc_refund, true );
}
}
}
/**
* Update order currency.
*
* The function should be called after nonce verification.
* We have to get the raw data from global variable, though.
*
* @param int|null $id The id of order.
*/
public function update_order_currency( $id ) {
if ( isset( $_POST['p24_order_currency'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Missing
$currency = sanitize_text_field( wp_unslash( $_POST['p24_order_currency'] ) ); //phpcs:ignore WordPress.Security.NonceVerification.Missing
$available = $this->get_available_currencies();
if ( in_array( $currency, $available, true ) ) {
update_metadata( 'post', $id, '_order_currency', $currency );
}
}
}
/**
* Register widget for multi currency.
*/
public function register_widget() {
$widget = new P24_Currency_Selector_Widget( $this->plugin_core );
register_widget( $widget );
}
/**
* Updates admin report rest controllers.
*
* @param array $controllers Rest controllers supplied for reports context.
*
* @return array
*/
public function update_admin_rest_controllers( $controllers ) {
$key = array_search( 'Automattic\WooCommerce\Admin\API\Leaderboards', $controllers, true );
if ( false === $key ) {
return $controllers;
}
$controllers[ $key ] = 'P24_Leaderboards_Controller';
return $controllers;
}
/**
* Update admin wc price format arguments.
*
* @param array $args Currency arguments.
*
* @return array
*/
public function update_wc_price_format_arguments( $args ) {
$currency = isset( $args[ P24_Request_Support::WP_JSON_GET_KEY_CURRENCY ] ) && $args[ P24_Request_Support::WP_JSON_GET_KEY_CURRENCY ]
? $args[ P24_Request_Support::WP_JSON_GET_KEY_CURRENCY ] : get_woocommerce_currency();
foreach ( self::get_multi_currency_format_fields() as $argument ) {
$p24_multi_currency_value = $this->get_przelewy24_multi_currency_format( $currency, $argument );
if ( null !== $p24_multi_currency_value ) {
$args[ $argument ] = $p24_multi_currency_value;
}
}
$args['price_format'] = $this->get_currency_format_for_currency_pos(
$this->get_przelewy24_multi_currency_format( $currency, 'currency_pos' )
);
return $args;
}
/**
* Get multi currency format fields.
*
* @return array
*/
public static function get_multi_currency_format_fields() {
return array(
self::WOOCOMMERCE_FIELD_DECIMAL_SEPARATOR,
self::WOOCOMMERCE_FIELD_THOUSAND_SEPARATOR,
self::WOOCOMMERCE_FIELD_DECIMALS,
);
}
/**
* Get currency format from currency position.
*
* @param string|null $currency_pos Currency position. Allowed values are: left, right, left_space and right_space.
*
* @return string Value for 'left' will be returned by default - just like in WooCommerce.
*/
private function get_currency_format_for_currency_pos( $currency_pos = null ) {
switch ( $currency_pos ) {
case 'right':
return '%2$s%1$s';
case 'left_space':
return '%1$s&nbsp;%2$s';
case 'right_space':
return '%2$s&nbsp;%1$s';
default: // left - like in dollars.
return '%1$s%2$s';
}
}
/**
* Bind events to use multi currency.
*/
public function bind_events() {
add_action( 'wp_enqueue_scripts', array( $this, 'add_user_scripts' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'add_admin_scripts' ) );
add_action( 'widgets_init', array( $this, 'register_widget' ) );
if ( ! is_admin() ) {
add_filter( 'woocommerce_currency', array( $this, 'try_change_default_currency' ) );
add_filter( 'wc_get_price_decimals', array( $this, 'try_change_decimals' ) );
add_action( 'wp_loaded', array( $this, 'save_currency_to_cookie' ) );
add_filter( 'woocommerce_package_rates', array( $this, 'update_package_rates' ) );
}
if ( $this->plugin_core->get_context_provider()->is_reports_context() ) {
add_filter( 'woocommerce_currency', array( $this, 'get_admin_reports_currency' ) );
add_filter( 'woocommerce_data_stores', array( __CLASS__, 'add_to_store' ) );
}
add_filter( 'wc_price_args', array( $this, 'update_wc_price_format_arguments' ) );
add_filter( 'option_woocommerce_currency_pos', array( $this, 'try_change_currency_pos' ) ); /* Core event. */
add_filter( 'wc_get_price_thousand_separator', array( $this, 'try_change_thousand_separator' ) );
add_filter( 'wc_get_price_decimal_separator', array( $this, 'try_change_decimal_separator' ) );
add_filter( 'woocommerce_product_class', array( $this, 'no_product_class_error_suppressor' ), 40, 1 );
add_filter( 'woocommerce_product_class', array( $this, 'find_product_class' ), 60, 4 );
add_action( 'woocommerce_before_order_object_save', array( $this, 'before_order_save' ) );
add_action( 'woocommerce_before_order_refund_object_save', array( $this, 'before_order_save' ), 10, 2 );
add_action( 'woocommerce_process_shop_order_meta', array( $this, 'update_order_currency' ) );
add_filter( 'woocommerce_get_variation_prices_hash', array( $this, 'filter_price_hash' ), 10, 3 );
add_filter( 'woocommerce_reports_get_order_report_query', array( $this, 'sql_override' ), 10, 1 );
add_filter( 'woocommerce_admin_rest_controllers', array( $this, 'update_admin_rest_controllers' ) );
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* File that define P24_Product_Simple class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
*
*
* The product is not aware of multiple currencies.
* We need this class before we have configured multi currency.
*/
class P24_No_Mc_Product_Subscription extends WC_Product {
const TYPE = 'p24_subscription';
/**
* Stores additional product data.
*
* @var array
*/
protected $extra_data = array(
'days' => 1,
);
/**
* P24_Product_Simple constructor.
*
* @param int $product Id of product.
*/
public function __construct( $product = 0 ) {
$this->product_type = self::TYPE;
parent::__construct( $product );
}
/**
* Get days.
*
* @return int
*/
public function get_days() {
$days = (int) $this->get_prop( 'days' );
if ( $days < 1 ) {
$days = 1;
}
return $days;
}
/**
* Set_days.
*
* @param int $days Number of days.
*/
public function set_days( $days ) {
$days = (int) $days;
if ( $days < 1 ) {
$days = 1;
}
$this->set_prop( 'days', $days );
}
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* File that define P24_Payment_Methods_helper class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* The helper for payment methods.
*/
class P24_Payment_Methods_Helper {
/**
* Config.
*
* @var P24_Config_Accessor
*/
private $config;
/**
* Data set.
*
* @var array
*/
private $data_set;
/**
* P24_Icon_Svg_Generator constructor.
*
* @param P24_Config_Accessor $config A valid config.
*/
public function __construct( P24_Config_Accessor $config ) {
$this->config = clone $config;
$this->config->access_mode_to_strict();
}
/**
* Get set.
*
* @return array
*/
private function get_set() {
if ( ! isset( $this->data_set ) ) {
$rest_api = new P24_Rest_Common( $this->config );
$response = $rest_api->payment_methods( 'pl' );
if ( isset( $response['data'] ) ) {
$this->data_set = $response['data'];
} else {
$this->data_set = array();
}
}
return $this->data_set;
}
/**
* Has P24Now.
*
* @return bool
*/
public function has_p24_now() {
$set = $this->get_set();
foreach ( $set as $one ) {
if ( 266 === $one['id'] ) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,27 @@
<?php
/**
* File that define P24_Product_External class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* The class add to parent awareness of multiple currencies.
*/
class P24_Product_External extends WC_Product_External {
use P24_Product_Trait;
/**
* P24_Product_External constructor.
*
* @param int $product The id of product.
*/
public function __construct( $product = 0 ) {
$this->populate_internal_data();
parent::__construct( $product );
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* File that define P24_Product_Grouped class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* The class add to parent awareness of multiple currencies.
*/
class P24_Product_Grouped extends WC_Product_Grouped {
use P24_Product_Trait;
/**
* P24_Product_Grouped constructor.
*
* @param int $product The id of product.
*/
public function __construct( $product = 0 ) {
$this->populate_internal_data();
parent::__construct( $product );
}
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* File that define P24_Product_Keys class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class with keys for overwritten producs.
*/
class P24_Product_Keys {
const KEY_CURRENCY = 'currency';
const KEY_DEFAULT_CURRENCY_PRICE = 'default_currency_price';
const KEY_DEFAULT_CURRENCY_REGULAR_PRICE = 'default_currency_regular_price';
const KEY_DEFAULT_CURRENCY_SALE_PRICE = 'default_currency_sale_price';
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* File that define P24_Product_LP_Course class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* The class fix support of multiple currencies in LearnPress.
*/
class P24_Product_LP_Course extends WC_Product_LP_Course {
/**
* Convert_price.
*
* @param mixed $price The base price in LearnPress base currency.
* @return mixed
*/
private function convert_price( $price ) {
$multi_currency = get_przelewy24_plugin_instance()->get_multi_currency_instance();
$from = learn_press_get_currency();
$to = $multi_currency->get_active_currency();
return $multi_currency->convert_price( $price, $from, $to );
}
/**
* Get_price.
*
* @param string|null $context The name of context.
* @return mixed
*/
public function get_price( $context = 'view' ) {
$native = parent::get_price( $context );
$public = $this->convert_price( $native );
return $public;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* File that define P24_Product_Simple class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* The class add to parent awareness of multiple currencies.
*/
class P24_Product_Simple extends WC_Product_Simple {
use P24_Product_Trait;
/**
* P24_Product_Simple constructor.
*
* @param int $product Id of product.
*/
public function __construct( $product = 0 ) {
$this->populate_internal_data();
parent::__construct( $product );
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* File that define P24_Product_Simple class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
*
*
* The product is aware of multiple currencies.
*/
class P24_Product_Subscription extends P24_No_Mc_Product_Subscription {
use P24_Product_Trait;
/**
* P24_Product_Simple constructor.
*
* @param int $product Id of product.
*/
public function __construct( $product = 0 ) {
$this->populate_internal_data();
parent::__construct( $product );
}
}

View File

@@ -0,0 +1,150 @@
<?php
/**
* File that define P24_Product_Trait trait.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Trait with common methods for overwritten objects.
*/
trait P24_Product_Trait {
/**
* A getter.
*
* Should be defined in parent class of classes including this trait.
*
* @param string $prop The name of prop.
* @param string $context The name of context.
* @return mixed
*/
abstract protected function get_prop( $prop, $context = 'view' );
/**
* A setter for internal variables.
*
* Should be defined in parent class of classes including this trait.
*
* @param string $prop The name of prop.
* @param mixed $value The value of prop.
* @return mixed
*/
abstract protected function set_prop( $prop, $value );
/**
* Common code to run in constructor.
*/
protected function populate_internal_data() {
$this->data[ P24_Product_Keys::KEY_CURRENCY ] = get_woocommerce_currency();
$this->data[ P24_Product_Keys::KEY_DEFAULT_CURRENCY_PRICE ] = '';
$this->data[ P24_Product_Keys::KEY_DEFAULT_CURRENCY_REGULAR_PRICE ] = '';
$this->data[ P24_Product_Keys::KEY_DEFAULT_CURRENCY_SALE_PRICE ] = '';
}
/**
* Compute price native to object.
*
* The object has own currency.
* The false values have special meaning.
*
* @param mixed $price Price in default currency.
* @return mixed
* @throws LogicException If currency is not found.
*/
protected function compute_native_price( $price ) {
$currency = $this->get_currency();
$multi_currency = get_przelewy24_plugin_instance()->get_multi_currency_instance();
return $multi_currency->compute_price_in_currency( $price, $currency );
}
/**
* Get currency of the object.
*
* @param string $context The name of context.
* @return mixed
*/
public function get_currency( $context = 'view' ) {
return $this->get_prop( P24_Product_Keys::KEY_CURRENCY, $context );
}
/**
* Set the product's active price.
*
* @param string $price Price in default currency.
*/
public function set_price( $price ) {
$native_price = $this->compute_native_price( $price );
$this->set_prop( 'price', wc_format_decimal( $native_price ) );
$this->set_prop( 'default_currency_price', wc_format_decimal( $price ) );
}
/**
* Get price.
* It is in base currency for editing.
*
* @param string $context Name of context.
* @return mixed
*/
public function get_price( $context = 'view' ) {
if ( 'edit' === $context ) {
return $this->get_prop( 'default_currency_price', $context );
} else {
return $this->get_prop( 'price', $context );
}
}
/**
* Set the product's regular price.
*
* @param string $price Price in default currency.
*/
public function set_regular_price( $price ) {
$native_price = $this->compute_native_price( $price );
$this->set_prop( 'regular_price', wc_format_decimal( $native_price ) );
$this->set_prop( 'default_currency_regular_price', wc_format_decimal( $price ) );
}
/**
* Get regular price.
* It is in base currency for editing.
*
* @param string $context Name of context.
* @return mixed
*/
public function get_regular_price( $context = 'view' ) {
if ( 'edit' === $context ) {
return $this->get_prop( 'default_currency_regular_price', $context );
} else {
return $this->get_prop( 'regular_price', $context );
}
}
/**
* Set the product's sale price.
*
* @param string $price Price in default currency.
*/
public function set_sale_price( $price ) {
$native_price = $this->compute_native_price( $price );
$this->set_prop( 'sale_price', wc_format_decimal( $native_price ) );
$this->set_prop( 'default_currency_sale_price', wc_format_decimal( $price ) );
}
/**
* Get sale price.
* It is in base currency for editing.
*
* @param string $context Name of context.
* @return mixed
*/
public function get_sale_price( $context = 'view' ) {
if ( 'edit' === $context ) {
return $this->get_prop( 'default_currency_sale_price', $context );
} else {
return $this->get_prop( 'sale_price', $context );
}
}
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* File that define P24_Product_Variable class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* The class add to parent awareness of multiple currencies.
*/
class P24_Product_Variable extends WC_Product_Variable {
use P24_Product_Trait;
/**
* P24_Product_Variable constructor.
*
* @param int $product Id of product.
*/
public function __construct( $product = 0 ) {
$this->populate_internal_data();
parent::__construct( $product );
}
/**
* Get an array of all sale and regular prices from all variations.
*
* @param bool $for_display If true, prices will be adapted for display.
* @return array Array of prices.
*/
public function get_variation_prices( $for_display = false ) {
$prices = parent::get_variation_prices( $for_display );
$new_prices = array();
foreach ( $prices as $key => $set ) {
$new_set = array_map( array( $this, 'compute_native_price' ), $set );
$new_prices[ $key ] = $new_set;
}
return $new_prices;
}
}

View File

@@ -0,0 +1,27 @@
<?php
/**
* File that define P24_Product_Variation class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* The class add to parent awareness of multiple currencies.
*/
class P24_Product_Variation extends WC_Product_Variation {
use P24_Product_Trait;
/**
* P24_Product_Variation constructor.
*
* @param int $product Id of product.
*/
public function __construct( $product = 0 ) {
$this->populate_internal_data();
parent::__construct( $product );
}
}

View File

@@ -0,0 +1,305 @@
<?php
/**
* File that define P24_Request_Support class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class that analyse requests originated from WordPress but WooCommerce.
*
* It supports user mode and admin mode.
* Requests from WooCommerce are supported in different places.
*
* The class interact with $_POST.
*/
class P24_Request_Support {
const WP_JSON_GET_KEY_CURRENCY = 'currency';
const OPTION_KEY_FLAT = 'przelewy24_flat_settings';
const OPTION_KEY_MULTI_CURRENCY_MULTIPLIERS = 'przelewy24_multi_currency_multipliers';
const OPTION_KEY_MULTI_CURRENCY_FORMATS = 'przelewy24_multi_currency_formats';
const OPTION_KEY_COMMON = 'przelewy24_common_settings';
const KEY_CHANGES_CURRENCY = 'currency';
const KEY_NEW_STATUS = 'new_status';
/**
* Set of changes.
*
* @var array
*/
private $changes = array();
/**
* Return changes of active currency.
*
* @return string|null
*/
public function get_currency_changes() {
return ( array_key_exists( self::KEY_CHANGES_CURRENCY, $this->changes ) )
? $this->changes[ self::KEY_CHANGES_CURRENCY ] : null;
}
/**
* Analyse if there is new currency to set.
*
* @param array $data Array of data to analyse.
*/
private function preload_currency_changes( $data ) {
if ( isset( $data['p24_currency'] ) ) {
$this->changes[ self::KEY_CHANGES_CURRENCY ] = $data['p24_currency'];
}
}
/**
* Get changes of format.
*
* @return array|null
*/
public function get_format_changes() {
if ( array_key_exists( 'formats', $this->changes ) ) {
return $this->changes['formats'];
} else {
return null;
}
}
/**
* Analyse if there are new formats to set.
*
* @param array $data Array of data to analyse.
*/
private function preload_format_changes( $data ) {
if ( array_key_exists( 'p24_currency', $data ) && array_key_exists( 'p24_formats', $data ) ) {
$this->changes['formats'] = array( $data['p24_currency'] => $data['p24_formats'] );
}
}
/**
* Get changes of multipliers.
*
* @return array|null
*/
public function get_multipliers_changes() {
if ( array_key_exists( 'p24_multiplers', $this->changes ) ) {
return $this->changes['p24_multiplers'];
} else {
return null;
}
}
/**
* Analyse if there are new multipliers to change.
*
* @param array $data Array of data to analyse.
* @throws LogicException If there is a bug in send data.
*/
private function preload_multipliers_changes( $data ) {
if ( isset( $data['p24_multipliers'] ) ) {
$multipliers = $data['p24_multipliers'];
} else {
$multipliers = array();
}
$default = P24_Woo_Commerce_Low_Level_Getter::get_unhooked_currency_form_woocommerce();
$multipliers[ $default ] = 1;
$multipliers = array_map( 'floatval', $multipliers );
$multipliers = array_filter( $multipliers );
$this->changes['p24_multiplers'] = $multipliers;
}
/**
* Get list of common changes.
*
* @return mixed|null
*/
public function get_common_changes() {
if ( array_key_exists( 'p24_common', $this->changes ) ) {
return $this->changes['p24_common'];
} else {
return null;
}
}
/**
* Get list of flat changes.
*
* @return array
*/
public function get_flat_changes() {
if ( array_key_exists( self::OPTION_KEY_FLAT, $this->changes ) ) {
return $this->changes[ self::OPTION_KEY_FLAT ];
} else {
return array();
}
}
/**
* Get status changes.
*
* @return null|array
*/
public function get_order_status_changes() {
if ( array_key_exists( self::KEY_NEW_STATUS, $this->changes ) ) {
return $this->changes[ self::KEY_NEW_STATUS ];
} else {
return null;
}
}
/**
* Analyse if activation of multi currency is set.
*
* @param array $data Array of data to analyse.
*/
private function preload_multi_currency_changes( $data ) {
$active = array_key_exists( 'p24_multi_currency_active', $data ) && 'yes' === $data['p24_multi_currency_active'] ? 'yes' : 'no';
$this->changes['p24_common']['p24_multi_currency'] = $active;
if ( 'yes' === $active && array_key_exists( 'p24_reports_currency', $data ) ) {
wc_setcookie( 'admin_p24_reports_currency', $data['p24_reports_currency'] );
}
$order_created_notification = array_key_exists( 'p24_notification_order_created', $data ) && 'yes' === $data['p24_notification_order_created'] ? 'yes' : 'no';
$this->changes['p24_common']['p24_notification_order_created'] = $order_created_notification;
}
/**
* Analyse if activation of multi currency is set.
*
* @param array $data Array of data to analyse.
*/
private function preload_activate_statuses( $data ) {
$active = array_key_exists( 'p24_statuses_active', $data ) && $data['p24_statuses_active'];
$value = $active ? 'yes' : 'no';
$this->changes[ self::OPTION_KEY_FLAT ]['p24_statuses_active'] = $value;
}
/**
* Preload add new status.
*
* @param array $data Post data.
*/
private function preload_add_status( $data ) {
if ( isset( $data['p24-status-new-label'] ) && isset( $data['p24-status-new-code'] ) ) {
$this->changes[ self::KEY_NEW_STATUS ] = array(
'code' => $data['p24-status-new-code'],
'label' => $data['p24-status-new-label'],
);
}
}
/**
* Update subscription config.
*
* @param array $data Array of data to analyse.
*/
private function update_subscription_config( $data ) {
$new_keys = P24_Subscription_Config::update_config( $data );
if ( ! array_key_exists( self::OPTION_KEY_FLAT, $this->changes ) ) {
$this->changes[ self::OPTION_KEY_FLAT ] = $new_keys;
} else {
$this->changes[ self::OPTION_KEY_FLAT ] += $new_keys;
}
}
/**
* Process data from GET.
*/
private function check_get() {
wp_verify_nonce( null );
$get = $_GET;
if ( isset( $get['p24_change_currency'] ) ) {
$this->changes[ self::KEY_CHANGES_CURRENCY ] = $get['p24_change_currency'];
}
}
/**
* Validate nonce and return request.
*
* @return null|array
*/
private function get_post_data() {
if ( isset( $_POST['p24_nonce'] ) ) {
$nonce = sanitize_key( $_POST['p24_nonce'] );
if ( wp_verify_nonce( $nonce, 'p24_action' ) ) {
return $_POST;
}
}
return null;
}
/**
* Analyse the whole request.
*
* We need call this action very early.
*/
public function analyse() {
$this->check_get();
$data = $this->get_post_data();
if ( ! $data ) {
return;
}
if ( isset( $data['p24_action_type_field'] ) ) {
$field = $data['p24_action_type_field'];
switch ( $field ) {
case 'change_currency':
$this->preload_currency_changes( $data );
break;
case 'change_formats':
$this->preload_currency_changes( $data );
$this->preload_format_changes( $data );
break;
case 'change_multipliers':
$this->preload_multipliers_changes( $data );
break;
case 'activate_multi_currency':
$this->preload_multi_currency_changes( $data );
break;
case 'activate_statuses':
$this->preload_activate_statuses( $data );
break;
case 'add_status':
$this->preload_add_status( $data );
break;
case 'update_subscription':
$this->update_subscription_config( $data );
break;
}
}
}
/**
* Flush options to the database.
*
* This action should be done later thant analyse.
*/
public function flush_options() {
$set_overwrite = array(
self::OPTION_KEY_MULTI_CURRENCY_MULTIPLIERS => $this->get_multipliers_changes(),
);
$set_merge = array(
self::OPTION_KEY_MULTI_CURRENCY_FORMATS => $this->get_format_changes(),
self::OPTION_KEY_COMMON => $this->get_common_changes(),
);
$set_flat = $this->get_flat_changes();
foreach ( $set_overwrite as $k => $v ) {
if ( $v ) {
update_option( $k, $v );
}
}
foreach ( $set_merge as $k => $v ) {
if ( $v ) {
$v = $v + get_option( $k, array() );
update_option( $k, $v );
}
}
foreach ( $set_flat as $k => $v ) {
if ( $v ) {
update_option( $k, $v );
}
}
}
}

View File

@@ -0,0 +1,223 @@
<?php
/**
* File that define P24_Rest_Server class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Base class for REST API transaction.
*/
class P24_Rest_Server {
/**
* Config factory.
*
* @var callable
*/
protected $config_factory;
/**
* Przelewy24RestAbstract constructor.
*
* @param callable $config_factory Config factory.
*/
public function __construct( $config_factory ) {
$this->config_factory = $config_factory;
}
/**
* Support REST api.
*/
public function support_status() {
$status_payload = $this->get_json_from_body();
$cf = $this->get_config( $status_payload['currency'] );
$reg_session = '/^[0-9a-zA-Z_\.]+$/D';
if ( ! preg_match( $reg_session, $status_payload['sessionId'] ) ) {
return;
}
$session_id = explode( '_', $status_payload['sessionId'] );
$order_id = $session_id[0];
$order = new WC_Order( $order_id );
$verified = $this->verify( $order, $status_payload, $cf );
if ( $verified ) {
/* This value mey be not set yet. */
$order->update_meta_data( P24_Core::ORDER_P24_ID, $status_payload['orderId'] );
$verified = $this->external_verify( $order, $status_payload, $cf );
}
if ( ! $verified ) {
http_response_code( 400 );
$answer = wp_json_encode( array( 'success' => false ) );
exit( esc_js( "\n" . $answer ) );
} else {
$order->add_order_note( __( 'IPN payment completed', 'woocommerce' ) );
$order->payment_complete();
if ( (int) $status_payload['methodId'] ) {
$user_id = $order->get_user_id();
$method_id = (int) $status_payload['methodId'];
Przelewy24Helpers::setCustomData( 'user', $user_id, 'lastmethod', $method_id );
Przelewy24Helpers::setCustomData( 'user', $user_id, 'accept', 1 );
$this->save_reference_id( $status_payload['orderId'], $status_payload['methodId'], $user_id, $cf );
}
$order->update_meta_data( P24_Core::ORDER_SESSION_ID_KEY, $status_payload['sessionId'] );
$order->save_meta_data();
do_action( 'p24_payment_complete', $order, null );
}
$answer = wp_json_encode( array( 'success' => true ) );
exit( esc_js( "\n" . $answer ) );
}
/**
* Save card id reference number (to allow one click payments).
*
* @param int $order_id P24 order id.
* @param int $method_id Method id (in p24).
* @param int $user_id Id of order owner.
* @param P24_Config_Accessor $cf Plugin configuration.
*/
public function save_reference_id( $order_id, $method_id, $user_id, $cf ) {
if ( ! in_array( (int) $method_id, Przelewy24Class::getChannelsCard(), true ) ) {
return;
}
if ( WC_Gateway_Przelewy24::get_cc_forget( $user_id ) ) {
return;
}
if ( ! $cf->get_p24_payinshop() || ! $cf->get_p24_oneclick() ) {
return;
}
$api_rest_card = new P24_Rest_Card( $cf );
$res = $api_rest_card->info( $order_id );
if ( ! isset( $res['data']['refId'] ) ) {
error_log( __METHOD__ . ' brak numeru referencyjnego karty użytkownika' );
return;
}
$ref = $res['data']['refId'];
$expires = substr( $res['data']['cardDate'], 2 ) . substr( $res['data']['cardDate'], 0, 2 );
if ( date( 'Ym' ) > $expires ) {
error_log( __METHOD__ . ' termin ważności ' . var_export( $expires, true ) );
return;
}
$key = md5( $res['data']['mask'] . '|' . $res['data']['cardType'] . '|' . substr( $expires, 2 ) );
Przelewy24Helpers::setCustomData(
'user_cards',
$user_id,
$key,
array(
'ref' => $ref,
'exp' => substr( $expires, 2 ),
'mask' => $res['data']['mask'],
'type' => $res['data']['cardType'],
'time' => date( 'Y-m-d H:i.s' ),
)
);
}
/**
* Verify payload.
*
* @param WC_Order $order Order.
* @param array $payload Payload.
* @param P24_Config_Accessor $config Config accessor.
* @return bool
*/
private function verify( $order, $payload, $config ) {
$total_amount = number_format( $order->get_total() * 100, 0, '', '' );
$saved_p24_order_id = $order->get_meta( P24_Core::ORDER_P24_ID );
if ( $payload['merchantId'] !== (int) $config->get_merchant_id() ) {
return false;
} elseif ( $payload['posId'] !== (int) $config->get_shop_id() ) {
return false;
} elseif ( (string) $payload['amount'] !== $total_amount ) {
return false;
} elseif ( $payload['currency'] !== $config->get_currency() ) {
return false;
} elseif ( $saved_p24_order_id && (int) $saved_p24_order_id !== (int) $payload['orderId'] ) {
return false;
} elseif ( $this->sign( $payload, $config ) !== $payload['sign'] ) {
return false;
}
return true;
}
/**
* External_verify.
*
* @param WC_Order $order Order.
* @param array $data Additional data.
* @param P24_Config_Accessor $config Config accessor.
*
* @return bool
*/
private function external_verify( $order, $data, $config ) {
$rest_transaction = new P24_Rest_Transaction( $config );
$payload = array(
'merchantId' => (int) $config->get_merchant_id(),
'posId' => (int) $config->get_shop_id(),
'sessionId' => $data['sessionId'],
'amount' => (int) number_format( $order->get_total() * 100, 0, '', '' ),
'currency' => $config->get_currency(),
'orderId' => (int) $order->get_meta( P24_Core::ORDER_P24_ID ),
);
return $rest_transaction->verify_bool( $payload );
}
/**
* Sign
*
* @param array $payload Payload.
* @param P24_Config_Accessor $config Config accessor.
* @return string
*/
private function sign( $payload, $config ) {
unset( $payload['sign'] );
$payload['crc'] = $config->get_salt();
$string = wp_json_encode( $payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
$sign = hash( 'sha384', $string );
return $sign;
}
/**
* Get JSON from body.
*
* @return array
*/
private function get_json_from_body() {
$body = file_get_contents( 'php://input' );
$json = json_decode( $body, true );
if ( ! is_array( $json ) ) {
$json = (array) $json;
}
return $json;
}
/**
* Get_config.
*
* @param string|null $currency Currency.
* @return P24_Config_Accessor Config accessor.
*/
private function get_config( $currency = null ) {
$factory = $this->config_factory;
$cf = $factory( $currency );
$cf->access_mode_to_strict();
return $cf;
}
}

View File

@@ -0,0 +1,58 @@
<?php
/**
* File that define P24_Settings_Helper.
*
* @package Przelewy24
*/
/**
* Helper to access config.
*
* There is some legacy code for this purpose in WC_Gateway_Przelewy24 too.
*/
class P24_Settings_Helper {
const OPTION_KEY_COMMON = 'przelewy24_common_settings';
const OPTION_KEY_CURRENCY_TEMPLATE = 'woocommerce_przelewy24_%s_settings';
/**
* Convert common arrays to config holder.
*
* @param array $array The config as array.
* @return P24_Config_Holder
*/
public static function map_array_to_config_holder( $array ) {
$config_holder = new P24_Config_Holder();
foreach ( $array as $k => $v ) {
if ( property_exists( $config_holder, $k ) ) {
$config_holder->{$k} = $v;
} elseif ( 'CRC_key' === $k ) {
$config_holder->salt = $v;
} elseif ( 'p24_testmod' === $k ) {
$config_holder->p24_operation_mode = $v;
}
}
return $config_holder;
}
/**
* Get config for currency in object.
*
* @param string $currency The currency.
* @return P24_Config_Accessor|null
*/
public static function load_settings( $currency ) {
$common_options = get_option( self::OPTION_KEY_COMMON, array() );
if ( ! array_key_exists( 'enabled', $common_options ) ) {
return null;
} elseif ( 'yes' !== $common_options['enabled'] ) {
return null;
}
$key = sprintf( self::OPTION_KEY_CURRENCY_TEMPLATE, $currency );
$array = get_option( $key, array() );
$config_holder = self::map_array_to_config_holder( $array );
return new P24_Config_Accessor( $currency, $config_holder );
}
}

View File

@@ -0,0 +1,78 @@
<?php
/**
* File that define P24_Status_Decorator_Db class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class to help decorate statuses with access to a database.
*/
class P24_Status_Decorator_Db {
/**
* Escape strings in array and make it in comma separated list.
*
* @param array $input Array of string.
* @return string
*/
private static function implode_strings( $input ) {
$mapper = function ( $in ) {
return "'" . esc_sql( $in ) . "'";
};
$mapped = array_map( $mapper, $input );
return implode( ', ', $mapped );
}
/**
* Cancel unpaid orders that has custom Przelewy24 status.
*
* @param string $pending_status Status for pending Przelewy24 payments.
*/
public static function cancel_unpaid_p24_orders( $pending_status ) {
$held_duration = (int) get_option( P24_Woo_Commerce_Internals::HOLD_STOCK_MINUTES );
/* We have to copy these two conditions from wc_cancel_unpaid_orders function. */
if ( $held_duration < 1 || 'yes' !== get_option( P24_Woo_Commerce_Internals::MANAGE_STOCK ) ) {
return;
}
$date = new DateTime( $held_duration . ' minutes ago', wp_timezone() );
$escaped_post_types = self::implode_strings( wc_get_order_types() );
/*
* The code below is formatted after WC_Order_Data_Store_CPT::get_unpaid_orders.
* It is not possible to make it follow standards.
*/
// @codingStandardsIgnoreStart
global $wpdb;
$unpaid_orders = $wpdb->get_col(
$wpdb->prepare(
"SELECT posts.ID
FROM {$wpdb->posts} AS posts
WHERE posts.post_type IN ({$escaped_post_types})
AND posts.post_status = '%s'
AND posts.post_modified < %s",
$pending_status,
$date->format( 'Y-m-d H:i:s' )
)
);
// @codingStandardsIgnoreEnd
/* The code fragment below is copied from wc_cancel_unpaid_orders function. */
if ( $unpaid_orders ) {
foreach ( $unpaid_orders as $unpaid_order ) {
$order = wc_get_order( $unpaid_order );
if ( apply_filters( 'woocommerce_cancel_unpaid_order', 'checkout' === $order->get_created_via(), $order ) ) {
$order->update_status( 'cancelled', __( 'Unpaid order cancelled - time limit reached.', 'woocommerce' ) );
}
}
}
}
}

View File

@@ -0,0 +1,510 @@
<?php
/**
* File that define P24_Status_Decorator class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class to decorate order statuses.
*/
class P24_Status_Decorator {
/**
* Suffix to use for status for the database.
* The length is very limited.
*/
const STATUS_SUFFIX = '-p24';
/**
* Suffix to use for status for humans.
*/
const STATUS_SUFFIX_HUMAN = ' P24';
/**
* Config factory.
*
* @var callable
*/
private $config_factory;
/**
* In_decoration_mode.
*
* @var bool
*/
private $in_decoration_mode = false;
/**
* Status provider.
*
* @var P24_Status_Provider
*/
private $status_provider;
/**
* Core of this plugin.
*
* @var P24_Core
*/
private $plugin_core;
/**
* P24_Status_Decorator constructor.
*
* @param callable $config_factory The config factory.
* @param P24_Status_Provider $status_provider Status provider.
* @param P24_Core $plugin_core Core of this plugin.
*/
public function __construct( $config_factory, $status_provider, $plugin_core ) {
$this->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;
}
/**
* Check if from Przelewy24.
*
* @param WC_Order $order The order from client.
*/
private function check_if_from_przelewy24( $order ) {
/* We have to support two types of gateways: main and extra. */
$rx = '/^przelewy24(\_extra\_\d+)?$/';
$method = $order->get_payment_method();
return preg_match( $rx, $method );
}
/**
* Add pending status.
*
* @param WC_Order $order The order.
* @param array $data Additional order data.
*/
public function try_set_custom_pending_status( $order, $data ) {
if ( $this->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->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 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 $default Default args.
* @param array $extra Extra data.
* @return array
*/
public function fix_statuses_in_args( $default, $extra ) {
/* Used on my orders list. */
$ret = $default;
if ( isset( $default['post_status'] ) && is_array( $default['post_status'] ) ) {
$statuses = $default['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 <span class="count">(%s)</span>', 'Pending payment <span class="count">(%s)</span>', $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 <span class="count">(%s)</span>', '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 $default Default need.
* @param WC_Order $order The order.
* @param array $statuses List of statuses.
* @return bool
*/
public function check_need_of_payment( $default, $order, $statuses ) {
if ( ! $this->check_if_from_przelewy24( $order ) ) {
return $default;
} elseif ( $default ) {
$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 );
}
}
/**
* 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 );
}
}

View File

@@ -0,0 +1,231 @@
<?php
/**
* File that define P24_Status_Decorator class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class to add additional order statuses.
*/
class P24_Status_Provider {
const ADDITIONAL_STATUSES_KEY = 'woocommerce_przelewy24_additional_statuses';
/**
* Adding_error.
*
* @var string|null
*/
private $adding_error;
/**
* Proposed_values.
*
* @var array|null
*/
private $proposed_values;
/**
* Get config for internal use.
*
* @return array
*/
private static function get_config() {
$data = get_option( self::ADDITIONAL_STATUSES_KEY );
if ( $data && is_array( $data ) ) {
return $data;
} else {
return array();
}
}
/**
* Get formatted config.
*
* @return array
*/
public static function get_formatted_config() {
$data = self::get_config();
$ret = array();
foreach ( $data as $one ) {
if ( isset( $one['code'] ) && isset( $one['label'] ) ) {
$ret[] = $one;
}
}
return $ret;
}
/**
* Get config for select.
*
* @param string $base_status Base status.
* @return array
*/
public static function get_config_for_select( $base_status ) {
/* The _x function do not accept variables. We have to use this switch. */
switch ( $base_status ) {
case 'Pending payment':
$default = _x( 'Pending payment', 'Order status', 'woocommerce' );
break;
case 'Processing':
$default = _x( 'Processing', 'Order status', 'woocommerce' );
break;
default:
$default = 'No translation for ' . $base_status;
}
$data = self::get_formatted_config();
$ret = array(
'' => $default,
);
foreach ( $data as $one ) {
$ret[ $one['code'] ] = $one['label'];
}
return $ret;
}
/**
* Try add new status.
*
* @param array $status New array with status.
*/
public function try_add_new( $status ) {
if ( ! $status ) {
$this->adding_error = null;
} elseif ( ! $status['code'] || ! $status['label'] ) {
/* Someone has hand crafted request. No need for better description. */
$this->adding_error = __( 'Błąd przy dodawaniu nowego statusu.' );
$this->proposed_values = $status;
} elseif ( preg_match( '/^wc-/', $status['code'] ) ) {
$this->adding_error = __( 'Prefiks wc- dla kodu jest niedozwolony.' );
$this->proposed_values = $status;
} elseif ( ! preg_match( '/^[a-z\\-]+$/', $status['code'] ) ) {
$this->adding_error = __( 'Kod powinien składać się tylko z małych liter, bez znaków diakrytycznych.' );
$this->proposed_values = $status;
} elseif ( preg_match( '/^pending|processing|on-hold|completed|cancelled|refunded|failed$/', $status['code'] ) ) {
$this->adding_error = __( 'Kod jest używany wewnętrznie przez WooCommerce, nie można go użyć.' );
$this->proposed_values = $status;
} else {
$data = self::get_formatted_config();
$data[] = $status;
update_option( self::ADDITIONAL_STATUSES_KEY, $data );
}
}
/**
* Get additional valid statuses.
*
* @param string $prefix Optional prefix.
* @return array
*/
public function get_additional_valid_statuses( $prefix ) {
$statuses = array();
$data = $this->get_config();
foreach ( $data as $one ) {
if ( ! isset( $one['code'] ) || ! isset( $one['label'] ) ) {
continue;
}
$statuses[ $prefix . $one['code'] ] = $one['label'];
}
return $statuses;
}
/**
* Get additional valid statuse codes.
*
* @param string $prefix Optional prefix.
* @return array
*/
public function get_additional_valid_statuse_codes( $prefix ) {
$full = $this->get_additional_valid_statuses( $prefix );
return array_keys( $full );
}
/**
* Add description for status.
*
* @param array $defaults Default WooCommerce statuses.
* @return array
*/
public function status_description_list( $defaults ) {
$new = array();
$data = $this->get_config();
foreach ( $data as $one ) {
if ( ! isset( $one['code'] ) || ! isset( $one['label'] ) ) {
continue;
}
$new[ $one['code'] ] = $this->status_description( $one, $defaults );
}
return $new;
}
/**
* Prep_status_description.
*
* @param array $one One record from P24 status config.
* @param array $defaults Default sttuses.
* @return array
*/
public function status_description( $one, $defaults ) {
$new = $defaults['wc-processing'];
$new['label'] = $one['label'];
$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 ] = $one['label'] . ' ' . $m[1];
} else {
$new_label_count[ $k ] = $v;
}
}
$new['label_count'] = $new_label_count;
return $new;
}
/**
* Get adding error.
*
* @return string
*/
public function get_adding_error() {
return (string) $this->adding_error;
}
/**
* Get proposed code if error.
*
* @return string
*/
public function get_proposed_code_if_error() {
if ( $this->adding_error ) {
return $this->proposed_values['code'];
} else {
return '';
}
}
/**
* Get proposed label if error.
*
* @return string
*/
public function get_proposed_label_if_error() {
if ( $this->adding_error ) {
return $this->proposed_values['label'];
} else {
return '';
}
}
}

View File

@@ -0,0 +1,118 @@
<?php
/**
* File that define P24_Sub_Generator.
*
* @package Przelewy24
*/
/**
* Class tat generate data to generate orders.
*
* It has some interaction with WC_Gateway_Przelewy24 .
*/
class P24_Sub_Generator {
/**
* Find_saved_card.
*
* @param string $key Kay of card, it is not reference id for Przelewy24.
* @param int $user_id User id.
* @return array|null
*/
public static function find_saved_card( $key, $user_id ) {
$cards = WC_Gateway_Przelewy24::get_all_cards( $user_id );
foreach ( $cards as $card ) {
if ( $card->custom_key === $key ) {
return $card->custom_value;
}
}
return null;
}
/**
* Generate order description.
*
* @param WC_Order $order The existing order.
*/
public static function generate_order_description( $order ) {
$currency = $order->get_currency();
$config = P24_Settings_Helper::load_settings( $currency );
$config->access_mode_to_strict();
$description_order_id = $order->get_order_number();
/* Modifies order number if Sequential Order Numbers Pro plugin is installed. */
if ( class_exists( 'WC_Seq_Order_Number_Pro' ) ) {
$seq = new WC_Seq_Order_Number_Pro();
$description_order_id = $seq->get_order_number( $description_order_id, $order );
} elseif ( class_exists( 'WC_Seq_Order_Number' ) ) {
$seq = new WC_Seq_Order_Number();
$description_order_id = $seq->get_order_number( $description_order_id, $order );
}
$now = new DateTime();
$short_date = $now->format( 'Ymdhi' );
/* Description depends on operation mode. */
$prefix = $config->is_p24_operation_mode( 'sandbox' ) ? __( 'Transakcja testowa', 'przelewy24' ) . ', ' : '';
$suffix = $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() . ', ' . $short_date;
$desc = $prefix . __( 'Zamówienie nr', 'przelewy24' ) . ': ' . $description_order_id . ', ' . $suffix;
return $desc;
}
/**
* Generate payload for REST transaction.
*
* @param WC_Order $order The existing order.
* @return array|null
*/
public static function generate_payload_for_rest( $order ) {
$currency = $order->get_currency();
$config = P24_Settings_Helper::load_settings( $currency );
if ( ! $config ) {
return null;
}
/* We need a plain integer to generate session id. */
$order_id = (int) $order->get_id();
if ( ! $order_id ) {
return null;
}
$amount = (int) round( $order->get_total() * 100 );
$shipping = (int) round( $order->get_shipping_total() * 100 );
$session_id = addslashes( $order_id . '_' . uniqid( md5( wp_rand() ), true ) );
$status_page = add_query_arg(
array(
'wc-api' => 'WC_Gateway_Przelewy24',
'status' => 'REST',
),
home_url( '/' )
);
$return_page = WC_Gateway_Przelewy24::getReturnUrlStatic( $order );
global $locale;
$localization = ! empty( $locale ) ? explode( '_', $locale ) : 'pl';
return array(
'merchantId' => (int) $config->get_merchant_id(),
'posId' => (int) $config->get_shop_id(),
'sessionId' => $session_id,
'amount' => $amount,
'currency' => $currency,
'description' => self::generate_order_description( $order ),
'email' => filter_var( $order->get_billing_email(), FILTER_SANITIZE_EMAIL ),
'client' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
'address' => $order->get_billing_address_1(),
'zip' => $order->get_billing_postcode(),
'city' => $order->get_billing_city(),
'country' => $order->get_billing_country(),
'language' => filter_var( $localization[0], FILTER_SANITIZE_STRING ),
'urlReturn' => filter_var( $return_page, FILTER_SANITIZE_URL ),
'urlStatus' => filter_var( $status_page, FILTER_SANITIZE_URL ),
'shipping' => $shipping,
'encoding' => 'UTF-8',
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* File that define P24_Woo_Commerce_Internals class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class that defines few constants used by Woo Commerce.
*/
class P24_Woo_Commerce_Internals {
const CURRENCY = 'woocommerce_currency';
const CURRENCY_POS = 'woocommerce_currency_pos';
const HOLD_STOCK_MINUTES = 'woocommerce_hold_stock_minutes';
const MANAGE_STOCK = 'woocommerce_manage_stock';
const PRICE_THOUSAND_SEP = 'woocommerce_price_thousand_sep';
const PRICE_DECIMAL_SEP = 'woocommerce_price_decimal_sep';
const PRICE_NUM_DECIMALS = 'woocommerce_price_num_decimals';
const PROCESSING_STATUS = 'wc-processing';
const TRANSLATION_DOMAIN = 'woocommerce';
}

View File

@@ -0,0 +1,27 @@
<?php
/**
* File that define P24_Woo_Commerce_Low_Level_Getter class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class that let access low level variables of Woo Commerce.
*
* It should be used with caution.
*/
class P24_Woo_Commerce_Low_Level_Getter
{
/**
* Get currency from configuration of Woo Commerce.
*
* Try to bypass as many Woo Commerce hooks as possible.
*
* @return string
*/
public static function get_unhooked_currency_form_woocommerce() {
return (string) get_option( P24_Woo_Commerce_Internals::CURRENCY );
}
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* File that define P24_Woo_Commerce_Strings class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class that defines few strings used by Woo Commerce.
*/
class P24_Woo_Commerce_Strings {
const PENDING_PAYMENT_WITH_COUNT = 'Pending payment <span class="count">(%s)</span>';
const PROCESSING_PAYMENT_WITH_COUNT = 'Processing <span class="count">(%s)</span>';
}

View File

@@ -0,0 +1,350 @@
<?php
/**
* Przelewy24 comunication class
*
* @author Przelewy24 Sp. z o.o.
* @copyright DialCom24 Sp. z o.o.
* @version 1.1
* @since 2014-04-29
*/
/**
*
* Communication protol version
* @var double
*/
define('P24_VERSION', '3.2');
if (class_exists('Przelewy24Class', false)!=true) {
class Przelewy24Class {
/**
* Config.
* @var P24_Config_Accessor
*/
private $config;
/**
* Live system URL address
* @var string
*/
private static $hostLive = 'https://secure.przelewy24.pl/';
/**
* Sandbox system URL address
* @var string
*/
private static $hostSandbox = 'https://sandbox.przelewy24.pl/';
/**
* Use Live (false) or Sandbox (true) enviroment
* @var bool
*/
private $testMode = false;
/**
* Merchant Id
* @var int
*/
private $merchantId = 0;
/**
* Merchant posId
* @var int
*/
private $posId = 0;
/**
* API Key (from P24 panel)
* @var string
*/
private $api = '';
/**
* Array of POST data
* @var array
*/
private $postData = array();
/**
* The class to validate messages.
*
* @var P24_Message_Validator
*/
private $message_validator;
/**
* Przelewy24Class constructor.
* @param P24_Config_Accessor $config
*/
public function __construct( P24_Config_Accessor $config ) {
$this->config = clone $config;
$this->config->access_mode_to_strict();
#TODO Refactor this out.
$this->message_validator = new P24_Message_Validator();
$config->access_mode_to_strict();
$this->posId = (int) trim( $this->config->get_shop_id() );
$this->merchantId = (int) trim( $this->config->get_merchant_id() );
if ($this->merchantId === 0) {
$this->merchantId = $this->posId;
}
$this->testMode = $this->config->is_p24_operation_mode( 'sandbox' );
$this->addValue('p24_merchant_id', $this->merchantId);
$this->addValue('p24_pos_id', $this->posId);
$this->addValue('p24_api_version', P24_VERSION);
$this->api = $this->config->get_p24_api();
return true;
}
/**
* Returns host URL
*/
public function getHost() {
return self::getHostStatic($this->testMode);
}
public static function getHostStatic($testMode) {
if ($testMode) return self::$hostSandbox;
return self::$hostLive;
}
/**
* Add value do post request
*
* @param string $name Argument name
* @param mixed $value Argument value
*/
public function addValue($name, $value) {
if ($this->validateField($name, $value))
$this->postData[$name] = $value;
}
/**
* Redirects or returns URL to a P24 payment screen
*
* @param string $token Token
* @param bool $redirect If set to true redirects to P24 payment screen. If set to false function returns URL to redirect to P24 payment screen
* @return string URL to P24 payment screen
*/
public function trnRequest($token, $redirect = true) {
$url=$this->getHost().'trnRequest/'.$token;
if($redirect) {
header('Location: '.$url);
return '';
}
return $url;
}
/**
* Verify rest transaction.
*
* @return bool
*/
private function trn_verify_rest() {
$payload = array(
'merchantId' => (int) $this->merchantId,
'posId' => (int) $this->posId,
'sessionId' => $this->postData['p24_session_id'],
'amount' => (int) $this->postData['p24_amount'],
'currency' => $this->postData['p24_currency'],
'orderId' => (int) $this->postData['p24_order_id'],
);
$api_rest = new P24_Rest_Transaction( $this->config );
return $api_rest->verify_bool( $payload );
}
/**
* @param string $field
* @param mixed &$value
* @return boolean
*/
public function validateField($field, &$value) {
return $this->message_validator->validate_field($field, $value);
}
/**
* Filter value.
*
* @param string $field The name of field.
* @param string|float|int $value The value to test.
* @return bool|string
*/
private function filterValue($field, $value) {
return $this->message_validator->filter_value($field, $value);
}
/**
* Check if mandatory fields are set.
*
* @param $fieldsArray
*
* @return bool
* @throws Exception
*/
public static function checkMandatoryFieldsForAction($fieldsArray) {
$keys = array_keys($fieldsArray);
static $mandatory=array(
'p24_merchant_id','p24_pos_id','p24_api_version','p24_session_id','p24_amount',//all
'p24_currency','p24_description','p24_country','p24_url_return','p24_currency','p24_email');//register/direct
for ($i=0; $i<count($mandatory); $i++) {
if(!in_array($mandatory[$i], $keys)) {
throw new Exception('Field '.$mandatory[$i].' is required for request!');
}
}
return true;
}
/**
* Parse and validate POST response data from Przelewy24
* @return array|false
*/
public function parseStatusResponse() {
if (isset($_POST['p24_session_id'], $_POST['p24_order_id'], $_POST['p24_merchant_id'], $_POST['p24_pos_id'], $_POST['p24_amount'], $_POST['p24_currency'], $_POST['p24_method']/*, $_POST['p24_statement']*/, $_POST['p24_sign'])) {
$session_id = $this->filterValue('p24_session_id', $_POST['p24_session_id']);
$merchant_id = $this->filterValue('p24_merchant_id', $_POST['p24_merchant_id']);
$pos_id = $this->filterValue('p24_pos_id', $_POST['p24_pos_id']);
$order_id = $this->filterValue('p24_order_id', $_POST['p24_order_id']);
$amount = $this->filterValue('p24_amount', $_POST['p24_amount']);
$currency = $this->filterValue('p24_currency', $_POST['p24_currency']);
$method = $this->filterValue('p24_method', $_POST['p24_method']);
if ($merchant_id!=$this->merchantId || $pos_id!=$this->posId) return false;
return array(
'p24_session_id' => $session_id,
'p24_order_id' => $order_id,
'p24_amount' => $amount,
'p24_currency' => $currency,
'p24_method' => $method,
);
}
return null;
}
public function trn_verify_ex_rest( $data = null ) {
$response = $this->parseStatusResponse();
if ($response === null) return null;
elseif ($response) {
if ($data!=null) {
foreach ($data as $field => $value) {
if ($response[$field]!=$value) return false;
}
}
$this->postData=array_merge($this->postData,$response);
return $this->trn_verify_rest();
}
return false;
}
/**
* Zwraca listę kanałów płatności, którymi można płacić inną walutą niż PLN
*/
public static function getChannelsNonPln() {
return array(66,92,124,140,145,152,218);
}
/**
* Zwraca listę kanałów płatności ratalnej
*/
public static function getChannelsRaty() {
return array(72,129,136);
}
/**
* Zwraca minimalną kwotę dla płatności ratalnych
*/
public static function getMinRatyAmount() {
return 300;
}
/**
* Zwraca listę kanałów płatności kartą
*
*/
public static function getChannelsCard(): array {
return array(140,142,145,218);
}
/**
* Zwraca listę kanałów płatności [id => etykieta,]
*
* @param bool $only24at7 płatności, które są w tej chwili aktywne - usuwa z wyników te nienatychmiastowe
* @param string $currency ogranicza listę metod płatności do dostępnych dla wskazanej waluty
* @param string $lang Etykiety kanałów płatności w wybranym języku
* @return bool
*/
public function availablePaymentMethods($only24at7 = true, $currency = 'PLN', $lang = 'pl')
{
if (empty($this->api)) {
return false;
}
$rest_api = new P24_Rest_Common( $this->config );
$res = $rest_api->payment_methods( $lang );
if ( isset( $res['data'] ) ) {
$banks = $res['data'];
if ($only24at7) {
$there_is_218 = false;
foreach ($banks as $key => $bank) {
if (218 === $bank['id']) {
$there_is_218 = true;
}
if (!$bank['status'] || 1000 === $bank['id']) {
unset($banks[$key]);
}
}
}
if ($currency !== 'PLN') {
foreach ($banks as $key => $bank) {
if (!isset($there_is_218) && 218 === $bank['id']) {
$there_is_218 = true;
}
if (!in_array($bank['id'], $this->getChannelsNonPln())) {
unset($banks[$key]);
}
}
if (!isset($there_is_218)) {
$there_is_218 = false;
}
}
if (!isset($there_is_218)) {
$there_is_218 = false;
foreach ($banks as $bank) {
if (218 === $bank['id']) {
$there_is_218 = true;
break;
}
}
}
// filter method 142 and 145 when there is 218
if ($there_is_218) {
foreach ($banks as $key => $bank) {
if (in_array($bank['id'], array(142, 145))) {
unset($banks[$key]);
}
}
}
return $banks;
}
return false;
}
public function availablePaymentMethodsSimple($only24at7 = true, $currency = 'PLN', $lang = 'pl') {
$all = $this->availablePaymentMethods($only24at7, $currency, $lang);
$result = array();
if (is_array($all) && sizeof($all) > 0) {
foreach ($all as $item) {
$result[$item['id']] = $item['name'];
}
} else {
$result = $all;
}
return $result;
}
}
}

View File

@@ -0,0 +1,68 @@
<?php
class Przelewy24OneClickHelper
{
public static function getCardPaymentIds()
{
return array(140, 142, 145, 218);
}
public static function updateCustomerRememberCard($customerId, $remember = 0)
{
return Db::getInstance()->Execute("REPLACE INTO " . _DB_PREFIX_ . "przelewy24_customersettings (`customer_id`, `card_remember`) " .
"VALUES (" . (int)$customerId . ", '" . (int)$remember . "')");
}
public static function rememberCardForCustomer($customerId)
{
$rememberRow = Db::getInstance()->getRow('SELECT `card_remember` FROM ' . _DB_PREFIX_ . 'przelewy24_customersettings WHERE customer_id=' . (int)$customerId);
if (!isset($rememberRow['card_remember'])) {
// if empty, then set default value: 1
return (bool)self::updateCustomerRememberCard($customerId, 1);
}
return (bool)($rememberRow['card_remember'] > 0);
}
public static function saveCard($customerId, $refId, $expires, $mask, $cardType)
{
Db::getInstance()->Execute("REPLACE INTO " . _DB_PREFIX_ . "przelewy24_recuring (`website_id`, `customer_id`, `reference_id`, `expires`, `mask`, `card_type`) " .
"VALUES (1, " . (int)$customerId . ", '" . pSQL($refId) . "', '" . pSQL($expires) . "', '" . pSQL($mask) . "', '" . pSQL($cardType) . "')");
}
public static function escape($string)
{
$string = trim($string);
return htmlspecialchars($string);
}
public static function getCustomerCards($customerId)
{
$results = Db::getInstance()->ExecuteS(
' SELECT * ' . ' FROM ' . _DB_PREFIX_ . 'przelewy24_recuring WHERE customer_id=' . (int)$customerId
);
return $results;
}
public static function deleteCustomerCard($customerId, $cardId)
{
Db::getInstance()->Execute(
' DELETE FROM ' . _DB_PREFIX_ . 'przelewy24_recuring ' .
' WHERE customer_id=' . (int)$customerId . ' AND id=' . (int)$cardId
);
}
public static function isOneClickEnable($sufix = "")
{
$soap = new Przelewy24Soap($sufix);
if ($soap->checkCardRecurrency() && (int)Configuration::get('P24_ONECLICK_ENABLE') === 1) {
return true;
}
return false;
}
public static function getOneclickOrderId($orderId){
$result = Db::getInstance()->getRow('SELECT * FROM ' . _DB_PREFIX_ . 'przelewy24_oneclick WHERE p24_order_id = ' . (int)$orderId);
return $result;
}
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* File that define P24_External_Multi_Currency class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class with support for external multi currency.
*/
class P24_MC_External_None implements P24_MC_Interface {
/**
* Check if external multi currency is activated.
*
* This one is always inactive.
*
* @return bool
*/
public function is_multi_currency_active() {
return false;
}
/**
* Check if multi currency is internal.
*
* @return bool
*/
public function is_internal() {
return false;
}
/**
* Get list of available currencies.
*
* @return array
*/
public function get_available_currencies() {
return array();
}
/**
* Get name.
*
* @return string
*/
public function get_name() {
return '';
}
}

View File

@@ -0,0 +1,84 @@
<?php
/**
* File that define P24_External_Multi_Currency class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class with support for external multi currency.
*/
class P24_MC_External_WPML implements P24_MC_Interface {
/**
* Get wpml settings.
*
* @return array
*/
private static function get_wpml_settings() {
global $woocommerce_wpml;
if ( $woocommerce_wpml ) {
if ( isset( $woocommerce_wpml->settings['currencies_order'] ) ) {
return $woocommerce_wpml->settings['currencies_order'];
}
}
return array();
}
/**
* Try create instance.
*
* @return null|P24_MC_External_WPML
*/
public static function try_create() {
$settings = self::get_wpml_settings();
if ( $settings ) {
return new self();
} else {
return null;
}
}
/**
* Check if external multi currency is activated.
*
* @return bool
*/
public function is_multi_currency_active() {
$settings = self::get_wpml_settings();
return (bool) $settings;
}
/**
* Check if multi currency is internal.
*
* @return bool
*/
public function is_internal() {
return false;
}
/**
* Get list of available currencies.
*
* @return array
*/
public function get_available_currencies() {
$settings = self::get_wpml_settings();
return array_combine( $settings, $settings );
}
/**
* Get name.
*
* @return string
*/
public function get_name() {
return 'WPML';
}
}

View File

@@ -0,0 +1,42 @@
<?php
/**
* File that define P24_External_Multi_Currency class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class with support for external multi currency.
*/
interface P24_MC_Interface {
/**
* Check if external multi currency is activated.
*
* @return bool
*/
public function is_multi_currency_active();
/**
* Check if multi currency is internal.
*
* @return bool
*/
public function is_internal();
/**
* Get list of available currencies.
*
* @return array
*/
public function get_available_currencies();
/**
* Get name of multi currency implementation.
*
* @return string
*/
public function get_name();
}

View File

@@ -0,0 +1,152 @@
<?php
/**
* File that define P24_MC_Pool class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class that pool all multi currency support.
*/
class P24_MC_Pool {
/**
* Instance of core of plugin.
*
* @var P24_Core
*/
private $plugin_core;
/**
* External multi currency proxy.
*
* @var P24_MC_Interface|null
*/
private $external = null;
/**
* Active currency.
*
* @var string|null
*/
private $active_currency = null;
/**
* P24_MC_Pool constructor.
*
* @param P24_Core $plugin_core Instance of main plugin.
*/
public function __construct( P24_Core $plugin_core ) {
$this->plugin_core = $plugin_core;
}
/**
* Set_active_currency.
*
* @param string $currency Currency.
*/
public function set_active_currency( $currency ) {
$this->active_currency = $currency;
}
/**
* Get external Multi Currency proxy.
*
* @return P24_MC_Interface
*/
public function get_external_mc() {
if ( ! $this->external ) {
$wpml = P24_MC_External_WPML::try_create();
if ( $wpml && $wpml->is_multi_currency_active() ) {
$this->external = $wpml;
} else {
$this->external = new P24_MC_External_None();
}
}
return $this->external;
}
/**
* Get preffered Multi Currency proxy.
*
* @return P24_MC_Interface|null
*/
public function get_preffered_mc() {
if ( $this->plugin_core->is_internal_multi_currency_active() ) {
$mc = $this->plugin_core->get_multi_currency_instance();
} else {
$mc = $this->get_external_mc();
}
return $mc;
}
/**
* Method for filter that change default currency.
*
* The default value is ignored.
* The wrapped function should always return something.
*
* @param string|null $default Default value provided by filter.
* @return string|null
*/
public function check_admin_currency( $default ) {
if ( ! $this->active_currency ) {
$mc = $this->get_preffered_mc();
$available = $mc->get_available_currencies();
wp_verify_nonce( null ); /* There is no noce. */
if ( $this->plugin_core->is_in_json_mode() ) {
if ( array_key_exists( P24_Request_Support::WP_JSON_GET_KEY_CURRENCY, $_GET ) ) {
$this->active_currency = sanitize_text_field( wp_unslash( $_GET[ P24_Request_Support::WP_JSON_GET_KEY_CURRENCY ] ) );
}
} else {
if ( isset( $_COOKIE['admin_p24_currency'] ) ) {
$this->active_currency = sanitize_text_field( wp_unslash( $_COOKIE['admin_p24_currency'] ) );
}
}
if ( ! $this->active_currency || ! array_key_exists( $this->active_currency, $available ) ) {
$this->active_currency = P24_Woo_Commerce_Low_Level_Getter::get_unhooked_currency_form_woocommerce();
}
}
return $this->active_currency ? $this->active_currency : $default;
}
/**
* Get list of available currencies.
*
* It is based on multipliers.
*
* @return array
*/
public function get_available_currencies() {
return $this->get_preffered_mc()->get_available_currencies();
}
/**
* An AJAX method to change currency for admin.
*/
public function admin_ajax_change_currency() {
$mc = $this->get_preffered_mc();
if ( $mc->is_multi_currency_active() ) {
header( 'Content-Type: text/plain; charset=utf-8' );
wc_setcookie( 'admin_p24_currency', $this->check_admin_currency( '' ) );
echo 'Ok';
wp_die();
}
}
/**
* Bind events to use multi currency.
*/
public function bind_events() {
add_action( 'wp_ajax_p24_change_currency', array( $this, 'admin_ajax_change_currency' ) );
add_filter( 'przelewy24_multi_currency_admin_currency', array( $this, 'check_admin_currency' ) );
add_filter( 'przelewy24_multi_currency_options', array( $this, 'get_available_currencies' ) );
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* Autoload classes of Przelewy24 Plugin.
*
* The class has 3 requirements:
* 1. The class should start (case insensitive) from P24_.
* 2. The file has to reside in includes directory.
* 3. The file should be prefixed with class-.
* 4. The extension should be php.
* 5. The underscores should be replaced by hyphens.
*/
defined( 'ABSPATH' ) || exit;
spl_autoload_register(
function( $class ) {
if ( preg_match( '/^p24_[a-z][a-z0-9\\_]+/i', $class ) ) {
$normalised = strtolower( strtr( $class, array( '_' => '-' ) ) );
$directories = array(
__DIR__,
__DIR__ . '/subscription',
__DIR__ . '/report-data-stores',
__DIR__ . '/rest_api',
__DIR__ . '/multi_currency',
);
foreach ( $directories as $directory ) {
$path_class = $directory . '/class-' . $normalised . '.php';
if ( is_readable( $path_class ) ) {
require_once $path_class;
return;
}
}
}
}
);

View File

@@ -0,0 +1,36 @@
<?php
/**
* Categories data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Categories\DataStore;
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrdersDataStore;
/**
* Class P24_Categories_Data_Store.
*/
class P24_Categories_Data_Store extends DataStore {
/**
* Return the database query with parameters used for Categories report: time span and order status.
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function add_sql_query_params( $query_args ) {
parent::add_sql_query_params( $query_args );
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( OrdersDataStore::get_db_table_name() );
$this->subquery->add_sql_clause( 'join', $metadata_join );
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Coupons data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Coupons\DataStore;
/**
* Class P24_Coupons_Data_Store.
*/
class P24_Coupons_Data_Store extends DataStore {
/**
* Updates the database query with parameters used for Products report: categories and order status.
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function add_sql_query_params( $query_args ) {
parent::add_sql_query_params( $query_args );
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( self::get_db_table_name() );
$this->subquery->add_sql_clause( 'join', $metadata_join );
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* Coupons stats data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Coupons\Stats\DataStore;
/**
* Class P24_Coupons_Stats_Data_Store.
*/
class P24_Coupons_Stats_Data_Store extends DataStore {
/**
* Updates the database query with parameters used for Products Stats report: categories and order status.
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function update_sql_query_params( $query_args ) {
parent::update_sql_query_params( $query_args );
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( self::get_db_table_name() );
$this->interval_query->add_sql_clause( 'join', $metadata_join );
$this->total_query->add_sql_clause( 'join', $metadata_join );
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Customers data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore;
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrdersDataStore;
/**
* Class P24_Customers_Data_Store.
*/
class P24_Customers_Data_Store extends DataStore {
/**
* Updates the database query with parameters used for Customers report: categories and order status.
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function add_sql_query_params( $query_args ) {
parent::add_sql_query_params( $query_args );
$query_statement = $this->subquery->get_query_statement();
$order_table = OrdersDataStore::get_db_table_name();
if ( false === strpos( $query_statement, $order_table ) ) {
return;
}
$metadata_alias = 'p24_postmeta';
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( $order_table );
$this->subquery->add_sql_clause( 'left_join', $metadata_join );
$this->subquery->add_sql_clause(
'where',
"AND {$metadata_alias}.meta_key = '_order_currency'"
);
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Customers stats data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Customers\Stats\DataStore;
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrdersDataStore;
/**
* Class P24_Customers_Stats_Data_Store.
*/
class P24_Customers_Stats_Data_Store extends DataStore {
/**
* Updates the database query with parameters used for Customers report: categories and order status.
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function add_sql_query_params( $query_args ) {
parent::add_sql_query_params( $query_args );
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( OrdersDataStore::get_db_table_name() );
$this->subquery->add_sql_clause( 'join', $metadata_join );
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Orders data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore;
/**
* Class P24_Orders_Data_Store.
*/
class P24_Orders_Data_Store extends DataStore {
/**
* Updates the database query with parameters used for orders report: coupons and products filters.
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function add_sql_query_params( $query_args ) {
parent::add_sql_query_params( $query_args );
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( self::get_db_table_name() );
$this->subquery->add_sql_clause( 'join', $metadata_join );
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Orders stats data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Orders\Stats\DataStore;
/**
* Class P24_Orders_Stats_Data_Store.
*/
class P24_Orders_Stats_Data_Store extends DataStore {
/**
* Updates the totals and intervals database queries with parameters used for Orders report: categories, coupons and order status.
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function orders_stats_sql_filter( $query_args ) {
parent::orders_stats_sql_filter( $query_args );
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( self::get_db_table_name() );
$this->total_query->add_sql_clause( 'join', $metadata_join );
$this->interval_query->add_sql_clause( 'join', $metadata_join );
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* Products data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Products\DataStore;
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrdersDataStore;
/**
* Class P24_Products_Data_Store.
*/
class P24_Products_Data_Store extends DataStore {
/**
* Updates the database query with parameters used for Products report: categories and order status.
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function add_sql_query_params( $query_args ) {
parent::add_sql_query_params( $query_args );
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( OrdersDataStore::get_db_table_name() );
$this->subquery->add_sql_clause( 'join', $metadata_join );
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Products data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Products\Stats\DataStore;
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrdersDataStore;
/**
* Class P24_Products_Stats_Data_Store.
*/
class P24_Products_Stats_Data_Store extends DataStore {
/**
* Updates the database query with parameters used for Products Stats report: categories and order status.
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function update_sql_query_params( $query_args ) {
parent::update_sql_query_params( $query_args );
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( OrdersDataStore::get_db_table_name() );
$this->interval_query->add_sql_clause( 'join', $metadata_join );
$this->total_query->add_sql_clause( 'join', $metadata_join );
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Taxes data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Taxes\DataStore;
/**
* Class P24_Taxes_Data_Store.
*/
class P24_Taxes_Data_Store extends DataStore {
/**
* Updates the totals and intervals database queries with parameters used for Orders report: categories, coupons and order status.
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function add_sql_query_params( $query_args ) {
parent::add_sql_query_params( $query_args );
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( self::get_db_table_name() );
$this->subquery->add_sql_clause( 'join', $metadata_join );
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* Taxes stats data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Taxes\Stats\DataStore;
/**
* Class P24_Taxes_Stats_Data_Store.
*/
class P24_Taxes_Stats_Data_Store extends DataStore {
/**
* Updates the database query with parameters used for Taxes Stats report
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function update_sql_query_params( $query_args ) {
parent::update_sql_query_params( $query_args );
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( self::get_db_table_name() );
$this->total_query->add_sql_clause( 'join', $metadata_join );
$this->interval_query->add_sql_clause( 'join', $metadata_join );
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Variations data store.
*
* @package Przelewy24
*/
use Automattic\WooCommerce\Admin\API\Reports\Variations\DataStore;
/**
* Class P24_Variations_Data_Store.
*/
class P24_Variations_Data_Store extends DataStore {
/**
* Updates the database query with parameters used for Products report: categories and order status.
*
* @param array $query_args Query arguments supplied by the user.
*/
protected function add_sql_query_params( $query_args ) {
parent::add_sql_query_params( $query_args );
$metadata_join = P24_Multi_Currency::get_currency_filter_for_reports( self::get_db_table_name() );
$this->subquery->add_sql_clause( 'join', $metadata_join );
}
/**
* Get cache key.
*
* @param array $params Parameters.
*
* @return string
*/
protected function get_cache_key( $params ) {
return parent::get_cache_key( $params ) . '_' . P24_Multi_Currency::get_admin_reports_currency();
}
}

View File

@@ -0,0 +1,89 @@
<?php
/**
* File that define P24_Rest_Abstract class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Base class for REST API transaction.
*/
class P24_Rest_Abstract {
const URL_SECURE = 'https://secure.przelewy24.pl/api/v1';
const URL_SANDBOX = 'https://sandbox.przelewy24.pl/api/v1';
/**
* Url.
*
* @var string|null
*/
protected $url;
/**
* Config accessor.
*
* @var P24_Config_Accessor
*/
protected $cf;
/**
* Przelewy24RestAbstract constructor.
*
* @param P24_Config_Accessor $cf
*/
public function __construct( P24_Config_Accessor $cf ) {
$this->cf = clone $cf;
$this->cf->access_mode_to_strict();
if ( $this->cf->is_p24_operation_mode( 'sandbox' ) ) {
$this->url = self::URL_SANDBOX;
} else {
$this->url = self::URL_SECURE;
}
}
/**
* Call rest command
*
* @param string $path Api path.
* @param array|object|null $payload Method call parameters.
* @param string $method Method name.
*
* @return array
*/
protected function call( $path, $payload, $method ) {
$credentials = $this->cf->get_shop_id() . ':' . $this->cf->get_p24_api();
$json_style = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
$options = array(
CURLOPT_USERPWD => $credentials,
CURLOPT_URL => $this->url . $path,
CURLOPT_RETURNTRANSFER => true,
);
if ( 'PUT' === $method ) {
$options[ CURLOPT_CUSTOMREQUEST ] = 'PUT';
}
if ( 'GET' !== $method ) {
$headers = array(
'Content-Type: application/json',
);
$options[ CURLOPT_POST ] = true;
$options[ CURLOPT_HTTPHEADER ] = $headers;
$options[ CURLOPT_POSTFIELDS ] = wp_json_encode( $payload, $json_style );
}
$h = curl_init();
curl_setopt_array( $h, $options );
$ret = curl_exec( $h );
curl_close( $h );
$decoded = json_decode( $ret, true );
if ( ! is_array( $decoded ) ) {
$decoded = array();
}
return $decoded;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* File that define P24_Rest_Blik class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class that support card API.
*/
class P24_Rest_Blik extends P24_Rest_Abstract {
/**
* Charge by code
*
* @param string $token Przelewy24 transaction token.
* @param string $blik_code Blik code.
*
* @return array
*/
public function charge_by_code( $token, $blik_code ) {
$path = '/paymentMethod/blik/chargeByCode';
$payload = array(
'token' => $token,
'blikCode' => $blik_code,
);
$ret = $this->call( $path, $payload, 'POST' );
return $ret;
}
}

View File

@@ -0,0 +1,72 @@
<?php
/**
* File that define P24_Rest_Card class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class that support card API.
*/
class P24_Rest_Card extends P24_Rest_Abstract {
/**
* Charge with 3ds.
*
* @param string $token Przelewy24 transaction token.
* @return array
*/
public function chargeWith3ds( $token ) {
$path = '/card/chargeWith3ds';
$payload = array(
'token' => $token,
);
$ret = $this->call( $path, $payload, 'POST' );
return $ret;
}
/**
* Charge without 3ds.
*
* @param string $token Przelewy24 transaction token.
* @return array
*/
public function chargeWithout3ds( $token ) {
$path = '/card/charge';
$payload = array(
'token' => $token,
);
$ret = $this->call( $path, $payload, 'POST' );
return $ret;
}
/**
* Pay.
*
* @param array $payload Array with transaction data required to make card payment.
*
* @return array
*/
public function pay( $payload ) {
$path = '/card/pay';
$ret = $this->call( $path, $payload, 'POST' );
return $ret;
}
/**
* Info.
*
* @param string $order_id Order id used to collect card data with.
*
* @return array
*/
public function info( $order_id ) {
return $this->call( '/card/info/' . $order_id, null, 'GET' );
}
}

View File

@@ -0,0 +1,57 @@
<?php
/**
* File that define P24_Rest_Common class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class that support card API.
*/
class P24_Rest_Common extends P24_Rest_Abstract {
/**
* Test access.
*
* @return array
*/
public function test_access() {
$path = '/testAccess';
$ret = $this->call( $path, null, 'GET' );
return $ret;
}
/**
* Test access bool.
*
* @return bool
*/
public function test_access_bool() {
$data = $this->test_access();
return isset( $data['error'] ) && empty( $data['error'] );
}
/**
* Payment_methods.
*
* @param string $lang One of supported languages (only 'pl' and 'en' for now).
*
* @return array
*
* @throws LogicException When wrong language is provided.
*/
public function payment_methods( $lang ) {
if ( ! in_array( $lang, array( 'pl', 'en' ), true ) ) {
throw new LogicException( 'The lang ' . $lang . ' is not supported.' );
}
$path = '/payment/methods/' . $lang;
$ret = $this->call( $path, null, 'GET' );
return $ret;
}
}

View File

@@ -0,0 +1,146 @@
<?php
/**
* File that define P24_Rest_Transaction class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class that support transaction API.
*/
class P24_Rest_Transaction extends P24_Rest_Abstract {
/**
* Register.
*
* @param array $payload
* @return array
*/
public function register( $payload ) {
$path = '/transaction/register';
$payload['sign'] = $this->sign_sha_384_register( $payload );
return $this->call( $path, $payload, 'POST' );
}
/**
* Register raw token.
*
* @param array $payload Array with payload data.
*
* @return string|null
*/
public function register_raw_token( $payload ) {
$res = $this->register( $payload );
if ( isset( $res['data']['token'] ) ) {
return $res['data']['token'];
} else {
return null;
}
}
/**
* Register.
*
* @param array $payload
* @return array
*/
public function verify( $payload ) {
$path = '/transaction/verify';
$payload['sign'] = $this->sign_sha_384_verify( $payload );
return $this->call( $path, $payload, 'PUT' );
}
/**
* Register.
*
* @param array $payload Array with optional data -> status field.
*
* @return bool
*/
public function verify_bool( $payload ) {
$res = $this->verify( $payload );
if ( isset( $res['data']['status'] ) ) {
$status = $res['data']['status'];
} else {
$status = '';
}
return 'success' === $status;
}
/**
* Register.
*
* @param array $payload Array with transaction refund data.
*
* @return array
*/
public function refund( $payload ) {
$path = '/transaction/refund';
return $this->call( $path, $payload, 'POST' );
}
/**
* By_session_id.
*
* @param string $session_id Session id of transaction to search for by REST api.
*
* @return array
*
* @throws InvalidArgumentException When invalid session id is provided.
*/
public function by_session_id( $session_id ) {
/* RFC 3986 unreserved characters. */
if ( ! preg_match( '/^[a-zA-Z0-9\\_\\.\\-\\~]+$/', $session_id ) ) {
/* We do not support other than unreserved characters in $session_id. */
throw new InvalidArgumentException( 'Invalid session id provided.' );
}
$path = '/transaction/by/sessionId/' . $session_id;
return $this->call( $path, null, 'GET' );
}
/**
* Sign sha384.
*
* @param array $payload
* @return string
*/
private function sign_sha_384_register( $payload ) {
$data = array(
'sessionId' => $payload['sessionId'],
'merchantId' => $payload['merchantId'],
'amount' => $payload['amount'],
'currency' => $payload['currency'],
'crc' => $this->cf->get_salt(),
);
$string = json_encode( $data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
$sign = hash( 'sha384', $string );
return $sign;
}
/**
* Sign sha384.
*
* @param array $payload
* @return string
*/
private function sign_sha_384_verify( $payload ) {
$data = array(
'sessionId' => $payload['sessionId'],
'orderId' => $payload['orderId'],
'amount' => $payload['amount'],
'currency' => $payload['currency'],
'crc' => $this->cf->get_salt(),
);
$string = json_encode( $data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
$sign = hash( 'sha384', $string );
return $sign;
}
}

View File

@@ -0,0 +1,12 @@
# Change Log #
## [Zencard] - 2016-11-10 ##
- Has coupon field.
## [Przelewy24Product] - 2016-10-13 ##
- Init.
- Added descriptions, doc.

View File

@@ -0,0 +1,8 @@
# Zbiór wspólnych bibliotek/klas dla wszystkich wtyczek sklepowych Przelewy24 #
### Minimalne wymagania ###
- PHP 5.2+
- SOAP
- cURL

View File

@@ -0,0 +1,9 @@
<?php
if (!defined('PRZELEWY24_LIB_ROOT')) {
define('PRZELEWY24_LIB_ROOT', dirname(__FILE__));
}
require_once PRZELEWY24_LIB_ROOT . DIRECTORY_SEPARATOR . 'interfaces' . DIRECTORY_SEPARATOR . 'Przelewy24Interface.php';
require_once PRZELEWY24_LIB_ROOT . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'Przelewy24Product.php';
require_once PRZELEWY24_LIB_ROOT . DIRECTORY_SEPARATOR . 'installer' . DIRECTORY_SEPARATOR . 'Przelewy24Installer.php';

View File

@@ -0,0 +1,79 @@
<?php
if (!class_exists('Przelewy24Product', false)) {
class Przelewy24Product implements Przelewy24Interface
{
private $translations;
public function __construct(array $translations = array())
{
$this->setTranslations($translations);
}
/**
* Prepare cart items for form trnRegister.
*
* Read more: /docs/przelewy24product.md
*/
public function prepareCartItems($amount, array $items = array(), $shipping = 0)
{
$cartItems = array();
if (empty($items)) {
return $cartItems;
}
$amount = (int)$amount;
$shipping = (int)$shipping;
$number = 0;
$sumProductsPrice = 0;
$joinName = '';
foreach ($items as $item) {
$number++;
$cartItems['p24_name_' . $number] = substr(strip_tags($item['name']), 0, 127);
$cartItems['p24_description_' . $number] = substr(strip_tags($item['description']), 0, 127);
$cartItems['p24_quantity_' . $number] = (int)$item['quantity'];
$cartItems['p24_price_' . $number] = (int)$item['price'];
$cartItems['p24_number_' . $number] = (int)$item['number'];
$joinName .= strip_tags($item['name']) . ', ';
$sumProductsPrice += ((int)$item['quantity'] * (int)$item['price']);
}
if ($amount > $shipping + $sumProductsPrice) {
$number++;
$cartItems['p24_name_' . $number] = $this->translations['virtual_product_name'];
$cartItems['p24_description_' . $number] = '';
$cartItems['p24_quantity_' . $number] = 1;
$cartItems['p24_price_' . $number] = $amount - ($shipping + $sumProductsPrice);
$cartItems['p24_number_' . $number] = 0;
} else if ($amount < $shipping + $sumProductsPrice) {
$cartItems = array();
$number = 1;
$joinName = $this->translations['cart_as_product'] . ' [' . trim($joinName, ', ') . ']';
$cartItems['p24_name_' . $number] = substr($joinName, 0, 127);
$cartItems['p24_description_' . $number] = '';
$cartItems['p24_quantity_' . $number] = 1;
$cartItems['p24_price_' . $number] = $amount - $shipping;
$cartItems['p24_number_' . $number] = 0;
}
// when is correct
return $cartItems;
}
public function setTranslations(array $translations = array())
{
$this->translations = $translations;
// set default values
if (empty($this->translations['virtual_product_name'])) {
$this->translations['virtual_product_name'] = 'Różnica';
}
if (empty($this->translations['cart_as_product'])) {
$this->translations['cart_as_product'] = 'Zamówienie';
}
}
}
}

View File

@@ -0,0 +1,124 @@
<?php
if (!class_exists('Przelewy24Installer', false)) {
class Przelewy24Installer implements Przelewy24Interface
{
private $translations;
private $sliderEnabled = true;
private $pages = array();
public function __construct($sliderEnabled = true, array $translations = array())
{
$this->sliderEnabled = $sliderEnabled;
$this->setTranslations($translations);
}
public function setTranslations(array $translations = array())
{
$this->translations = $translations;
// set default values
if (empty($this->translations['php_version'])) {
$this->translations['php_version'] = 'Wersja PHP min. 5.2';
}
if (empty($this->translations['curl_version'])) {
$this->translations['curl_enabled'] = 'Włączone rozszerzenie PHP cURL (php_curl.dll)';
}
if (empty($this->translations['soap_enabled'])) {
$this->translations['soap_enabled'] = 'Włączone rozszerzenie PHP SOAP (php_soap.dll)';
}
if (empty($this->translations['merchant_id'])) {
$this->translations['merchant_id'] = 'ID sprzedawcy';
}
if (empty($this->translations['shop_id'])) {
$this->translations['shop_id'] = 'ID sklepu';
}
if (empty($this->translations['crc_key'])) {
$this->translations['crc_key'] = 'Klucz CRC';
}
if (empty($this->translations['api_key'])) {
$this->translations['api_key'] = 'Klucz API';
}
}
public function addPages(array $pages = array())
{
$this->pages = array_values($pages);
}
public function renderInstallerSteps()
{
if (!$this->sliderEnabled || empty($this->pages) || !is_array($this->pages)) {
return '';
}
$requirements = $this->checkRequirements();
$params = array(
'requirements' => $requirements,
'translations' => $this->translations
);
$maxSteps = 0;
$data = array(
'steps' => array()
);
foreach ($this->pages as $page) {
$page = (int)$page;
if ($page > 0) {
$step = $this->loadStep($page, $params);
$data['steps'][$page] = $step;
$maxSteps++;
}
}
if ($maxSteps === 0) {
return '';
}
$data['maxSteps'] = $maxSteps;
return $this->loadTemplate('installer', $data);
}
private function loadStep($number, $params = null)
{
$step = $this->loadTemplate('step' . $number, $params);
$step = $this->removeNewLines($step);
return $step;
}
private function removeNewLines($string)
{
return trim(str_replace(PHP_EOL, ' ', $string));
}
private function loadTemplate($view, $data = null)
{
extract(array("content" => $data));
ob_start();
$viewFile = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'theme' . DIRECTORY_SEPARATOR . "$view.tpl.php";
if (file_exists($viewFile)) {
include $viewFile;
} else {
throw new Exception('View not exist in ' . get_class($this));
}
$content = ob_get_clean();
return $content;
}
private function checkRequirements()
{
$data = array(
'php' => array(
'test' => (version_compare(PHP_VERSION, '5.2.0') > 0),
'label' => $this->translations['php_version']
),
'curl' => array(
'test' => function_exists('curl_version'),
'label' => $this->translations['curl_enabled']
),
);
return $data;
}
}
}

View File

@@ -0,0 +1,181 @@
<style type="text/css">
.p24-admin-main-config {
display: none;
}
.p24-step {
height: 300px;
background: #eee;
}
.p24-step-1 {
}
.p24-inputs-group p {
display: inline-block;
width: 100%;
}
.p24-installer-container label.p24-required span::after {
color: red;
content: "*";
}
.p24-installer-container label.p24-required.p24-error input {
border: 1px solid red;
}
</style>
<script type="text/javascript">
(function ($) {
/**
* Global settings.
*/
var currentStep = 1;
var sliderSpeed = 300;
var stepsDiv = '.p24-installer-steps';
var maxSteps = <?php print $content['maxSteps']; ?>;
function contentStep(number) {
if (number == undefined || number < 1) {
number = 1
}
var html = '';
switch (number) {
<?php $i = 0; ?>
<?php foreach ($content['steps'] as $step): ?>
case <?php print ++$i; ?>:
html = '<?php print $step; ?>';
break;
<?php endforeach; ?>
}
return html;
}
function loadStep(step) {
var content = contentStep(step);
jQuery(stepsDiv).fadeOut(sliderSpeed, function () {
jQuery(this).html(content);
jQuery(this).fadeIn(sliderSpeed);
updateStepCounter();
});
}
function skip() {
jQuery('.p24-installer-container').fadeOut(sliderSpeed, function () {
jQuery('.p24-admin-main-config').fadeIn(sliderSpeed);
});
}
function saveInputs() {
var validInputs = true;
jQuery('.p24-inputs-group input').each(function () {
var name = jQuery(this).attr('name');
var val = jQuery(this).val();
var valid = true;
if (jQuery(this).hasClass('p24-valid-crc')) {
valid = crcValidator(val);
}
if (jQuery(this).hasClass('p24-valid-number')) {
valid = numberValidator(val);
}
if (valid) {
jQuery('.p24-admin-main-config input.' + name).val(val);
jQuery(this).parents('label').removeClass('p24-error');
} else {
validInputs = false;
jQuery(this).parents('label').addClass('p24-error');
}
});
return validInputs;
}
function numberValidator(text) {
if (text == "" || text == undefined) {
return false;
}
if (!isNumeric(text)) {
return false;
}
var length = text.trim().length;
if (length < 4 || length > 6) {
return false;
}
return true;
}
function crcValidator(text) {
if (text == "" || text == undefined) {
return false;
}
return true;
}
function isNumeric(input) {
var test = ((input - 0) == input && ('' + input).trim().length > 0);
return test;
}
function updateStepCounter() {
var wrapper = '.p24-step-counter';
jQuery(wrapper).find('.p24-step-current').text(currentStep);
jQuery(wrapper).find('.p24-step-all').text(maxSteps);
}
$(document).ready(function () {
loadStep(currentStep);
jQuery('.p24-installer-container a.p24-a').click(function () {
if (jQuery(this).hasClass('p24-a-next')) {
var valid = saveInputs();
if (!valid) {
return false;
}
currentStep++;
} else if (jQuery(this).hasClass('p24-a-back')) {
currentStep--;
} else {
skip();
return false;
}
if (currentStep < 1) {
currentStep = 1;
return false;
}
if (currentStep > maxSteps) {
currentStep = maxSteps;
skip();
return false;
}
loadStep(currentStep);
return false;
});
});
})(jQuery);
</script>
<div class="p24-installer-container">
<div class="p24-step-counter">
<span class="p24-step-current"></span>
/
<span class="p24-step-all"></span>
</div>
<div class="p24-installer-steps">
</div>
<div class="p24-installer-nav">
<a class="p24-a p24-a-back" href="#">
Back
</a>
<a class="p24-a p24-a-next" href="#">
Next
</a>
<a class="p24-a p24-a-skip" href="#">
Skip
</a>
</div>
</div>

View File

@@ -0,0 +1,22 @@
<div class="p24-step p24-step-1">
<p>
Instalator - sprawdzenie wymagań wtyczki Przelewy24
</p>
<p>
Proin nibh augue, suscipit a, scelerisque sed, lacinia
in, mi. Cras vel lorem. Etiam pellentesque aliquet tellus.
</p>
<div class="">
<?php foreach ($content['requirements'] as $key => $requirement): ?>
<p>
<?php print $requirement['label']; ?>
-
<?php if ($requirement['test']): ?>
<span class="">TAK</span>
<?php else: ?>
<span class="">NIE</span>
<?php endif; ?>
</p>
<?php endforeach; ?>
</div>
</div>

View File

@@ -0,0 +1,38 @@
<div class="p24-step p24-step-2">
<p>
Autoryzacja
</p>
<p>
Proin nibh augue, suscipit a, scelerisque sed, lacinia
in, mi. Cras vel lorem. Etiam pellentesque aliquet tellus. Phasellus pharetra nulla ac diam. Quisque semper
justo at risus. Donec venenatis, turpis vel hendrerit interdum, dui ligula ultricies purus, sed posuere libero
dui id orci. Nam congue, pede vitae dapibus aliquet, elit magna vulputate arcu, vel tempus metus leo non est.
Etiam sit amet lectus quis est congue mollis.
</p>
<div class="p24-inputs-group">
<p>
<label class="p24-required">
<span>
<?php print $content['translations']['merchant_id']; ?>
</span>
<input name="p24_merchant_id" value="12345" class="p24-valid-number" type="text"/>
</label>
</p>
<p>
<label class="p24-required">
<span>
<?php print $content['translations']['shop_id']; ?>
</span>
<input name="p24_shop_id" value="12345" class="p24-valid-number" type="text"/>
</label>
</p>
<p>
<label class="p24-required">
<span>
<?php print $content['translations']['crc_key']; ?>
</span>
<input name="p24_crc_key" value="testtest" class="p24-valid-crc" type="text"/>
</label>
</p>
</div>
</div>

View File

@@ -0,0 +1,39 @@
<div class="p24-step p24-step-3">
<p>
Klucz API - dodatkowe funkcje
</p>
<p>
Jakie dodatkowe funkcje i korzyści daje nam wtyczka Przelewy24 po wprowadzeniu klucza API?
</p>
<b>Oneclick</b>
<p>
Najwygodniejszy dla klienta sposób zakupu produktów, usług lub subskrypcji w Internecie za pomocą jednego
kliknięcia, bez konieczności zakładania konta w systemie operatora i każdorazowego uzupełniania danych karty.
</p>
<b>
Wybór metody płatności w sklepie
</b>
<p>
Możliwość personalizacji procesu płatności, dowolność ingerencji w kwestie graficzne i funkcjonalne modułu.
Wybór płatności bezpośrednio na stronie partnera.
</p>
<b>
IVR
</b>
<p>
Obsługa płatności przez telefon za pośrednictwem automatycznego operatora. Usługa ma zastosowanie m.in w
serwisach, które posiadają własne CallCenter sprzedażowe lub doradcze. Klient w procesie płatności bezpiecznie
uzupełnia dane swojej karty przy pomocy klawiatury własnego urządzenia.
</p>
<div class="p24-inputs-group">
<p>
<label class="">
<span>
<?php print $content['translations']['api_key']; ?>
</span>
<input name="p24_api_key" value="" class="" type="text"/>
</label>
</p>
</div>
</div>

View File

@@ -0,0 +1,11 @@
<div class="p24-step p24-step-4">
<p>
Dodatkowe informacje
</p>
<p>
Proin nibh augue, suscipit a, scelerisque sed, lacinia
in, mi. Cras vel lorem. Etiam pellentesque aliquet tellus.
Proin nibh augue, suscipit a, scelerisque sed, lacinia
in, mi. Cras vel lorem. Etiam pellentesque aliquet tellus.
</p>
</div>

View File

@@ -0,0 +1,19 @@
<div class="p24-step p24-step-5">
<p>
Podsumowanie
</p>
<p>
To już wszystko!
</p>
<p>
Phasellus ornare, ante vitae consectetuer consequat, purus sapien ultricies dolor, et mollis pede metus eget
nisi. Praesent sodales velit quis augue. Cras suscipit, urna at aliquam rhoncus, urna quam viverra nisi, in
interdum massa nibh nec erat.
Proin nibh augue, suscipit a, scelerisque sed, lacinia
in, mi. Cras vel lorem. Etiam pellentesque aliquet tellus.
Proin nibh augue, suscipit a, scelerisque sed, lacinia
in, mi. Cras vel lorem. Etiam pellentesque aliquet tellus.
Nam congue, pede vitae dapibus aliquet, elit magna vulputate arcu, vel tempus metus leo non est. Etiam sit amet
lectus quis est congue mollis. Phasellus congue lacus eget neque.
</p>
</div>

View File

@@ -0,0 +1,6 @@
<?php
interface Przelewy24Interface
{
public function setTranslations();
}

View File

@@ -0,0 +1,146 @@
<?php
/**
* File that define P24_Subscription_Admin class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class P24_Subscription_Admin
*/
class P24_Subscription_Admin {
/**
* The P24_Core instance.
*
* @var P24_Core
*/
private $plugin_core;
/**
* The constructor.
*
* @param P24_Core $plugin_core The P24_Core instance.
*/
public function __construct( P24_Core $plugin_core ) {
$this->plugin_core = $plugin_core;
}
/**
* Try serve csv.
*/
public function try_serve_csv() {
/* User credenitals should be checked and high enough. */
wp_verify_nonce( null );
if ( isset( $_GET['p24'] ) && isset( $_GET['subscription_csv'] ) ) {
header( 'Content-Type: text/csv; charset=utf-8' );
header( 'Content-Disposition: attachment; filename=p24_subscriptions.csv' );
$header = array(
__( 'Użytkownik' ),
__( 'E-Mail' ),
__( 'Ważna do' ),
__( 'Subskrypcje' ),
);
$list = P24_Subscription_Db::get_active_list();
$stdout = fopen( 'php://output', 'w' );
fputcsv( $stdout, $header );
foreach ( $list as $one ) {
$array = (array) $one;
fputcsv( $stdout, $array );
}
exit();
}
}
/**
* Add P24 subscription tab.
*
* @param array $tabs Provided tabs.
* @return array Extended tabs.
*/
public function add_subscription_tab( $tabs ) {
$new_tabs = array(
/* This one has to be first. */
'general' => $tabs['general'],
'p24_subscription' => array(
'label' => __( 'Ustawienia subskrypcji' ),
'target' => 'p24_subscription_options',
'class' => ( 'show_if_p24_subscription' ),
),
);
return $new_tabs + $tabs;
}
/**
* Parse cancellation request.
*/
public static function parse_cancellation_request() {
$ok = wp_verify_nonce( isset( $_POST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ) : null, 'p24_subscription' );
if ( $ok ) {
self::parse_cancellation_request_internal( $_POST );
}
}
/**
* Parse cancellation request internal.
*
* @param array $data The post data.
*/
private static function parse_cancellation_request_internal( $data ) {
if ( ! isset( $data['displayed'] ) ) {
/* Nothing to do. */
return;
}
$a = $data['displayed'];
if ( isset( $data['preserve'] ) ) {
$b = $data['preserve'];
} else {
$b = array();
}
$todel = array_diff( $a, $b );
foreach ( $todel as $one ) {
$one = (int) $one;
if ( $one ) {
$ok = P24_Subscription_Db::end_subscription( $one );
if ( $ok ) {
$data = P24_Subscription_Db::get_extended_data_for_single( $one );
self::send_email_about_cancellation( $data );
}
}
}
}
/**
* Send email about cancellation.
*
* @param array $data Data from database.
*/
private static function send_email_about_cancellation( $data ) {
if ( ! $data ) {
return;
}
$mailer = WC()->mailer();
$subject = __( 'Twoja subskrypcja została anulowana', 'przelewy24' );
$args = array(
'email_heading' => $subject,
'subscription_title' => $data['subscription_title'],
'email' => $mailer,
);
$headers = 'Content-Type: text/html';
$dir = __DIR__ . '/../../emails/';
$content = wc_get_template_html( 'subscription-cancellation.php', $args, $dir, $dir );
$mailer->send( $data['user_email'], $subject, $content, $headers );
}
/**
* Bind events.
*/
public function bind_core_events() {
add_filter( 'woocommerce_product_data_tabs', array( $this, 'add_subscription_tab' ) );
add_action( 'admin_init', array( $this, 'try_serve_csv' ) );
}
}

View File

@@ -0,0 +1,89 @@
<?php
/**
* File that define P24_Subscription_Api class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class P24_Subscription_Api
*/
class P24_Subscription_Api {
/**
* Query db.
*
* @param int|null $for_user User id.
* @param int|null $subscription Subcription (product) id.
* @return array
*/
private static function query_db( $for_user, $subscription ) {
global $wpdb;
$now = new DateTime();
$for_user = (int) $for_user;
$subscription = (int) $subscription;
$list = $wpdb->get_results(
$wpdb->prepare(
"
SELECT
u.ID AS user_id,
u.user_nicename,
u.user_email,
s.valid_to,
p.ID AS subscription_id,
p.post_title AS subscription_title
FROM {$wpdb->prefix}woocommerce_p24_subscription AS s
INNER JOIN {$wpdb->prefix}posts AS p ON p.ID = s.product_id
INNER JOIN {$wpdb->prefix}users AS u ON u.ID = s.user_id
WHERE s.valid_to > %s
AND (u.ID = %d OR 0 = %d)
AND (p.ID = %d OR 0 = %d)
ORDER BY p.post_title, u.user_email, s.id
;
",
array(
$now->format( 'Y-m-d H:i:s' ),
$for_user, /* The variable is used twice. */
$for_user,
$subscription, /* The variable is used twice. */
$subscription,
)
)
); /* db call ok; no cache ok */
return $list;
}
/**
* Try serve JSON.
*/
public function try_serve() {
/* User credentials should be checked and high enough. */
wp_verify_nonce( null );
if ( isset( $_GET['p24'] ) && isset( $_GET['subscription_get'] ) ) {
if ( isset( $_GET['user'] ) ) {
$for_user = (int) $_GET['user'];
} else {
$for_user = null;
}
if ( isset( $_GET['subscription'] ) ) {
$subscription = (int) $_GET['subscription'];
} else {
$subscription = null;
}
header( 'Content-Type: application/json' );
$list = self::query_db( $for_user, $subscription );
echo wp_json_encode( $list );
exit();
}
}
/**
* Bind events.
*/
public function bind_core_events() {
add_action( 'admin_init', array( $this, 'try_serve' ) );
}
}

View File

@@ -0,0 +1,144 @@
<?php
/**
* File that define P24_Subscription_Config class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class P24_Subscription_Config
*/
class P24_Subscription_Config {
/**
* Days to renew.
*
* @return int
*/
public static function days_to_renew() {
$ret = get_option( 'przelewy24_subscriptions_days' );
if ( ! isset( $ret ) ) {
return 1;
} else {
return (int) $ret;
}
}
/**
* Is active.
*
* @return bool
*/
public static function is_active() {
$ret = get_option( 'przelewy24_subscriptions_active' );
if ( ! isset( $ret ) ) {
return false;
} else {
return 'yes' === $ret;
}
}
/**
* Get page id.
*
* @return int|null
*/
public static function page_id() {
$page_id = (int) get_option( 'p24_subscription_page_id', 0 );
return $page_id ? $page_id : null;
}
/**
* Set page id.
*
* @param int|null $page_id Id of page, null to unset.
*/
public static function set_page_id( $page_id ) {
$page_id = (int) $page_id;
$page_id = $page_id ? $page_id : null;
update_option( 'p24_subscription_page_id', $page_id );
}
/**
* Set page for user.
*/
public static function set_page() {
$page_id = self::page_id();
if ( $page_id ) {
$subscription_page = get_post( $page_id );
if ( ! $subscription_page ) {
$page_id = null;
}
}
if ( ! $page_id ) {
$page_id = wp_insert_post(
array(
'post_title' => 'P24 Subskrypcje',
'post_name' => 'p24-subscription',
'post_type' => 'page',
'post_content' => '<!-- wp:shortcode -->[p24_user_subscription]<!-- /wp:shortcode -->',
'post_status' => 'publish',
)
);
self::set_page_id( $page_id );
}
return $page_id;
}
/**
* Update page.
*
* @param string $action Name of action.
*/
private static function update_page( $action ) {
switch ( $action ) {
case 'delete':
self::set_page_id( null );
break;
case 'force':
self::set_page_id( null );
self::set_page();
break;
case 'generate':
self::set_page();
break;
case 'nothing':
default:
break;
}
}
/**
* Update config.
*
* @param array $data Provided data.
* @return array
*/
public static function update_config( $data ) {
if ( array_key_exists( 'p24_subscriptions_active', $data ) ) {
$active = (bool) $data['p24_subscriptions_active'];
} else {
$active = false;
}
if ( array_key_exists( 'p24_subscriptions_days', $data ) ) {
$days = (int) $data['p24_subscriptions_days'];
}
if ( ! isset( $days ) || $days < 1 ) {
$days = 1;
}
if ( array_key_exists( 'p24_subscription_page', $data ) ) {
self::update_page( $data['p24_subscription_page'] );
}
$ret = array(
'przelewy24_subscriptions_active' => $active ? 'yes' : 'no',
'przelewy24_subscriptions_days' => $days,
);
return $ret;
}
}

View File

@@ -0,0 +1,371 @@
<?php
/**
* File that define P24_Subscription_Db class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class P24_Subscription_Db
*/
class P24_Subscription_Db {
/**
* Extend or add subscription.
*
* @param P24_No_Mc_Product_Subscription $subscription Subcription product.
* @param int $quantity Quantity of subscriptions.
* @param WP_User $user Buyer.
* @param WC_Order $order Current order.
*/
public static function extend_subscription( $subscription, $quantity, $user, $order ) {
global $wpdb;
$user_id = (int) $user->ID;
$subscription_id = (int) $subscription->get_id();
/* We need a plain integer for database relations. */
$order_id = (int) $order->get_id();
$data = $wpdb->get_row(
$wpdb->prepare(
"SELECT id, valid_to FROM {$wpdb->prefix}woocommerce_p24_subscription WHERE user_id = %d AND product_id = %d;",
array( $user_id, $subscription_id )
)
); /* db call ok; no cache ok */
$now = new DateTime();
$days = (int) ( $subscription->get_days() * $quantity );
if ( $data ) {
$id = (int) $data->id;
$alt_date = new DateTime( "$days days" );
try {
$date = new DateTime( $data->valid_to );
$date->modify( "$days days" );
/* If the subscription is too old. */
if ( $date < $alt_date ) {
$date = $alt_date;
}
} catch ( Exception $ex ) {
/* The best fall back we can do. */
$date = $alt_date;
}
$wpdb->update(
"{$wpdb->prefix}woocommerce_p24_subscription",
array(
'valid_to' => $date->format( 'Y-m-d H:i:s' ),
'last_order_id' => $order_id,
'last_checked' => $now->format( 'Y-m-d H:i:s' ),
),
array( 'id' => $id ), /* The NULL is not SQL compatible. */
array( '%s', '%d', '%s' ),
array( '%d' )
); /* db call ok; no cache ok */
} else {
$date = new DateTime( "$days days" );
$data = array(
'user_id' => $user_id,
'product_id' => $subscription_id,
'valid_to' => $date->format( 'Y-m-d H:i:s' ),
'extend' => 0,
'last_order_id' => $order_id,
'last_checked' => $now->format( 'Y-m-d H:i:s' ),
);
$formats = array( '%d', '%d', '%s', '%d', '%d', '%s' );
$wpdb->insert( "{$wpdb->prefix}woocommerce_p24_subscription", $data, $formats ); /* db call ok */
}
}
/**
* Add card reference.
*
* @param WC_Order $order Order.
* @param string $card_ref Card reference.
*/
public static function add_card_reference( $order, $card_ref ) {
global $wpdb;
/* We need a plain integer for database relations. */
$last_order_id = (int) $order->get_id();
$now = new DateTime();
$wpdb->update(
"{$wpdb->prefix}woocommerce_p24_subscription",
array(
'extend' => 1,
'card_ref' => $card_ref,
'last_checked' => $now->format( 'Y-m-d H:i:s' ),
),
array( 'last_order_id' => $last_order_id ), /* The NULL is not SQL compatible. */
array( '%d', '%s', '%s' ),
array( '%d' )
); /* db call ok; no cache ok */
}
/**
* Update card reference.
*
* @param int $subcription_id Subcription id.
* @param string $card_ref Card reference.
*/
public static function update_card_reference( $subcription_id, $card_ref ) {
global $wpdb;
$now = new DateTime();
$wpdb->update(
"{$wpdb->prefix}woocommerce_p24_subscription",
array(
'extend' => 1,
'card_ref' => $card_ref,
'last_checked' => $now->format( 'Y-m-d H:i:s' ),
),
array( 'id' => (int) $subcription_id ), /* The NULL is not SQL compatible. */
array( '%d', '%s', '%s' ),
array( '%d' )
); /* db call ok; no cache ok */
}
/**
* Clear card reference.
*
* @param int $subcription_id Subcription id.
*/
public static function clear_card_reference( $subcription_id ) {
global $wpdb;
$wpdb->update(
"{$wpdb->prefix}woocommerce_p24_subscription",
array(
'extend' => 0,
'card_ref' => null,
),
array( 'id' => (int) $subcription_id ), /* The NULL is not SQL compatible. */
array( '%d', '%s' ),
array( '%d' )
); /* db call ok; no cache ok */
}
/**
* End subscription.
*
* @param int $subscription_id Subscription id.
* @return bool True on success.
*/
public static function end_subscription( $subscription_id ) {
global $wpdb;
$yesterday = new DateTime( 'yesterday' );
$ok = $wpdb->update(
"{$wpdb->prefix}woocommerce_p24_subscription",
array(
'extend' => 0,
'card_ref' => null,
'valid_to' => $yesterday->format( 'Y-m-d H:i:s' ),
),
array( 'id' => (int) $subscription_id ), /* The NULL is not SQL compatible. */
array( '%d', '%s', '%s' ),
array( '%d' )
); /* db call ok; no cache ok */
return (bool) $ok;
}
/**
* Get active list.
*
* @return array|object|null
*/
public static function get_active_list() {
global $wpdb;
$now = new DateTime();
$list = $wpdb->get_results(
$wpdb->prepare(
"
SELECT
u.user_nicename,
u.user_email,
s.valid_to,
p.post_title AS subscription_title,
s.id AS record_id
FROM {$wpdb->prefix}woocommerce_p24_subscription AS s
INNER JOIN {$wpdb->prefix}posts AS p ON p.ID = s.product_id
INNER JOIN {$wpdb->prefix}users AS u ON u.ID = s.user_id
WHERE s.valid_to > %s
ORDER BY p.post_title, u.user_email, s.id
;
",
array( $now->format( 'Y-m-d H:i:s' ) )
)
); /* db call ok; no cache ok */
return $list;
}
/**
* Get inactive list.
*
* @return array|object|null
*/
public static function get_inactive_list() {
global $wpdb;
$now = new DateTime();
$list = $wpdb->get_results(
$wpdb->prepare(
"
SELECT
u.user_nicename,
u.user_email,
s.valid_to,
p.post_title AS subscription_title
FROM {$wpdb->prefix}woocommerce_p24_subscription AS s
INNER JOIN {$wpdb->prefix}posts AS p ON p.ID = s.product_id
INNER JOIN {$wpdb->prefix}users AS u ON u.ID = s.user_id
WHERE s.valid_to < %s
ORDER BY p.post_title, u.user_email, s.id
;
",
array( $now->format( 'Y-m-d H:i:s' ) )
)
); /* db call ok; no cache ok */
return $list;
}
/**
* Get active list for user.
*
* @return array|object|null
* @param WP_User $user User of interest.
*/
public static function get_active_list_for_user( $user ) {
global $wpdb;
$user_id = $user->ID;
$now = new DateTime();
$list = $wpdb->get_results(
$wpdb->prepare(
"
SELECT
s.id AS record_id,
s.valid_to,
s.card_ref,
p.ID AS product_id,
p.post_title AS subscription_title
FROM {$wpdb->prefix}woocommerce_p24_subscription AS s
INNER JOIN {$wpdb->prefix}posts AS p ON p.ID = s.product_id
WHERE s.valid_to > %s
AND s.user_id = %d
ORDER BY p.post_title, s.id
;
",
array( $now->format( 'Y-m-d H:i:s' ), $user_id )
)
); /* db call ok; no cache ok */
return $list;
}
/**
* Get inactive list for user.
*
* @return array|object|null
* @param WP_User $user User of interest.
*/
public static function get_inactive_list_for_user( $user ) {
global $wpdb;
$user_id = $user->ID;
$now = new DateTime();
$list = $wpdb->get_results(
$wpdb->prepare(
"
SELECT
s.id AS record_id,
p.ID AS product_id,
p.post_title AS subscription_title
FROM {$wpdb->prefix}woocommerce_p24_subscription AS s
INNER JOIN {$wpdb->prefix}posts AS p ON p.ID = s.product_id
WHERE s.valid_to < %s
AND s.user_id = %d
ORDER BY p.post_title, s.id
;
",
array( $now->format( 'Y-m-d H:i:s' ), $user_id )
)
); /* db call ok; no cache ok */
return $list;
}
/**
* Mark checked.
*
* @param int $id Id of subscription.
*/
public static function mark_checked( $id ) {
global $wpdb;
$id = (int) $id;
$now = new DateTime();
$wpdb->update(
"{$wpdb->prefix}woocommerce_p24_subscription",
array(
'last_checked' => $now->format( 'Y-m-d H:i:s' ),
),
array( 'id' => $id ), /* The NULL is not SQL compatible. */
array( '%s' ),
array( '%d' )
); /* db call ok; no cache ok */
}
/**
* Find_subscription_to_extends.
*
* @param DateTimeInterface $critical_date The date of subscription.
*/
public static function find_subscription_to_extends( $critical_date ) {
global $wpdb;
$critical_date_string = $critical_date->format( 'Y-m-d H:i:s' );
$cool_down = new DateTime( '- 1 hour' );
$cool_down_string = $cool_down->format( 'Y-m-d H:i:s' );
$data = $wpdb->get_results(
$wpdb->prepare(
"
SELECT id, product_id, user_id, last_order_id, card_ref
FROM {$wpdb->prefix}woocommerce_p24_subscription
WHERE valid_to < %s AND extend <> 0 AND card_ref IS NOT NULL AND last_checked < %s
;
",
array( $critical_date_string, $cool_down_string )
)
); /* db call ok; no cache ok */
return $data;
}
/**
* Get extended data for single record.
*
* @param int $subscription_id Subsription id.
* @return array|null
*/
public static function get_extended_data_for_single( $subscription_id ) {
$subscription_id = (int) $subscription_id;
global $wpdb;
$data = $wpdb->get_results(
$wpdb->prepare(
"
SELECT
u.user_nicename,
u.user_email,
p.post_title AS subscription_title
FROM {$wpdb->prefix}woocommerce_p24_subscription AS s
INNER JOIN {$wpdb->prefix}posts AS p ON p.ID = s.product_id
INNER JOIN {$wpdb->prefix}users AS u ON u.ID = s.user_id
WHERE s.id = %d
;
",
array( $subscription_id )
)
); /* db call ok; no cache ok */
if ( $data ) {
return (array) reset( $data );
} else {
return null;
}
}
}

View File

@@ -0,0 +1,218 @@
<?php
/**
* File that define P24_Subscription_User class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class P24_Subscription_User
*/
class P24_Subscription_User {
/**
* The P24_Core instance.
*
* @var P24_Core
*/
private $plugin_core;
/**
* The constructor.
*
* @param P24_Core $plugin_core The P24_Core instance.
*/
public function __construct( P24_Core $plugin_core ) {
$this->plugin_core = $plugin_core;
}
/**
* Extend nav.
*
* @param array $endpoints Default endpoints.
* @param array $descriptions Additional endpoints description.
* @return array
*/
public function extend_nav( $endpoints, $descriptions ) {
$endpoints['p24-subscriptions-user'] = __( 'Subskrypcje P24' );
return $endpoints;
}
/**
* Set nav url.
*
* @param string $url Proposed url.
* @param string $endpoint Endpoint name.
* @param string $value Unused in our context.
* @param string $permalink Unused in our context.
* @return string
*/
public function set_nav_url( $url, $endpoint, $value, $permalink ) {
if ( 'p24-subscriptions-user' === $endpoint ) {
$post = get_post( P24_Subscription_Config::page_id() );
if ( $post ) {
$url = get_post_permalink( $post );
}
}
return $url;
}
/**
* Get post data.
*
* There are problems with arrays in $_POST. This is workaround.
*/
private function get_post() {
/* We are forced to verify nonce in this place. */
if ( isset( $_POST['p24_nonce'] ) ) {
$nonce = sanitize_key( $_POST['p24_nonce'] );
if ( ! wp_verify_nonce( $nonce, 'p24_action' ) ) {
return array();
}
}
return $_POST;
}
/**
* Process form.
*
* @param WP_User $user The active user.
* @param array $cards The user cards.
*/
private function process_form( $user, $cards ) {
$valid_keys = array_map(
function ( $card ) {
return $card->custom_key;
},
$cards
);
$post = $this->get_post();
if ( ! $post ) {
return;
}
if ( ! array_key_exists( 'p24_action_type_field', $post ) ) {
return;
} elseif ( 'user_subscriptions' !== $post['p24_action_type_field'] ) {
return;
} elseif ( ! array_key_exists( 'card_for_subscription', $post ) ) {
return;
}
$cards_for_subscription = wp_unslash( $post['card_for_subscription'] );
foreach ( $cards_for_subscription as $subscription_id => $card_ref ) {
if ( in_array( $card_ref, $valid_keys, true ) ) {
P24_Subscription_Db::update_card_reference( (int) $subscription_id, $card_ref );
} else {
P24_Subscription_Db::clear_card_reference( (int) $subscription_id );
}
}
}
/**
* Render.
*/
public function render() {
$user = wp_get_current_user();
if ( $user->ID ) {
$cards = WC_Gateway_Przelewy24::get_all_cards( (int) $user->ID );
$this->process_form( $user, $cards );
$subscriptions = P24_Subscription_Db::get_active_list_for_user( $user );
$files = $this->get_all_files_for_user( $user );
$inactive = P24_Subscription_Db::get_inactive_list_for_user( $user );
} else {
$cards = array();
$subscriptions = array();
$files = array();
$inactive = array();
}
$data = compact( 'user', 'subscriptions', 'cards', 'files', 'inactive' );
$this->plugin_core->render_template( 'subscriptions-user', $data );
}
/**
* Find file.
*
* @param WP_User $user Use of interest.
* @param int $subscription_id Subscription id.
* @param string $file_name File name.
* @return array|null
*/
private function find_file( $user, $subscription_id, $file_name ) {
$subscription_id = (int) $subscription_id;
$file_name = (string) $file_name;
$subscriptions = P24_Subscription_Db::get_active_list_for_user( $user );
foreach ( $subscriptions as $subscription ) {
if ( (int) $subscription->record_id === $subscription_id ) {
$files = P24_Subscription::files_for_subscription( $subscription->product_id );
foreach ( $files as $file ) {
if ( $file['name'] === $file_name ) {
return $file;
}
}
return null;
}
}
return null;
}
/**
* Get all files for user.
*
* @param WP_User $user Use of interest.
* @return array
*/
private function get_all_files_for_user( $user ) {
$all_files = array();
$subscriptions = P24_Subscription_Db::get_active_list_for_user( $user );
foreach ( $subscriptions as $subscription ) {
$files = P24_Subscription::files_for_subscription( $subscription->product_id );
array_walk(
$files,
function ( &$record ) use ( $subscription ) {
$record['parent_id'] = $subscription->record_id;
$record['name_url'] = rawurlencode( $record['name'] );
}
);
$all_files = array_merge( $all_files, $files );
}
return $all_files;
}
/**
* Try download.
*
* @throws LogicException The callee should finish script.
*/
public function try_download() {
global $current_user;
if ( ! $current_user || ! $current_user->ID ) {
return;
}
wp_verify_nonce( null );
if ( isset( $_GET['subscription_id'] ) && isset( $_GET['file_name'] ) && isset( $_GET['p24'] ) && isset( $_GET['download'] ) ) {
$subscription_id = sanitize_text_field( wp_unslash( $_GET['subscription_id'] ) );
$file_name = sanitize_text_field( wp_unslash( $_GET['file_name'] ) );
$file = $this->find_file( $current_user, $subscription_id, $file_name );
if ( $file ) {
WC_Download_Handler::download_file_xsendfile( $file['url'], $file['name'] );
exit();
}
}
}
/**
* Bind events.
*/
public function bind_core_events() {
add_filter( 'woocommerce_account_menu_items', array( $this, 'extend_nav' ), 10, 2 );
add_filter( 'woocommerce_get_endpoint_url', array( $this, 'set_nav_url' ), 10, 4 );
add_action( 'init', array( $this, 'try_download' ) );
add_shortcode( 'p24_user_subscription', array( $this, 'render' ) );
}
}

View File

@@ -0,0 +1,337 @@
<?php
/**
* File that define P24_Subscription class.
*
* @package Przelewy24
*/
defined( 'ABSPATH' ) || exit;
/**
* Class P24_Subscription
*/
class P24_Subscription {
/**
* The P24_Core instance.
*
* @var P24_Core
*/
private $plugin_core;
/**
* The P24_Core instance.
*
* @var P24_Subscription_User
*/
private $for_user;
/**
* The P24_Core instance.
*
* @var P24_Subscription_Admin
*/
private $for_admin;
/**
* The P24_Subscription_Api instance.
*
* @var P24_Subscription_Api
*/
private $api;
/**
* The constructor.
*
* @param P24_Core $plugin_core The P24_Core instance.
*/
public function __construct( P24_Core $plugin_core ) {
$this->plugin_core = $plugin_core;
$this->for_user = new P24_Subscription_User( $plugin_core );
$this->for_admin = new P24_Subscription_Admin( $plugin_core );
$this->api = new P24_Subscription_Api();
}
/**
* Register subcription product type
*
* @param array $types Provided types.
* @return array Extended types.
*/
public function register_product_type( $types ) {
$types[ P24_No_Mc_Product_Subscription::TYPE ] = __( 'Subskrypcja P24' );
return $types;
}
/**
* Detect subcription product class.
*
* @param string $classname Default classname.
* @param string $product_type Product type.
* @return string
*/
public function subscription_class_detector( $classname, $product_type ) {
if ( P24_No_Mc_Product_Subscription::TYPE === $product_type ) {
$classname = P24_No_Mc_Product_Subscription::class;
}
return $classname;
}
/**
* Render subscription panel.
*/
public function render_subscription_panel() {
global $post;
$post_id = (int) $post->ID;
$data = array(
'files' => self::files_for_subscription( $post_id ),
);
$this->plugin_core->render_template( 'subscriptions-product', $data );
}
/**
* Save subscription fields.
*
* @param int $post_id Id of post.
* @param WP_Post $post The post itself.
*/
public function save_subscription_fields( $post_id, $post ) {
if ( isset( $_POST['_wpnonce'] ) ) {
wp_verify_nonce( sanitize_textarea_field( wp_unslash( $_POST['_wpnonce'] ) ), 'update-post_' . $post->ID );
}
if ( isset( $_POST['product-type'] ) ) {
$product_type = sanitize_text_field( wp_unslash( $_POST['product-type'] ) );
if ( P24_No_Mc_Product_Subscription::TYPE !== $product_type ) {
/* Different product type, nothing sane to do. */
return;
}
}
if ( isset( $_POST['_subscription_price'] ) ) {
/* Update two metas with the same value. For better compatibility. */
$price = sanitize_text_field( wp_unslash( $_POST['_subscription_price'] ) );
update_post_meta( $post_id, '_subscription_price', $price );
update_post_meta( $post_id, '_price', $price );
}
/* The WordPress standards allow only the simplest for lops. */
$i = 0;
$files_to_save = array();
while ( array_key_exists( $i, $_POST['_p24_sub_file_urls'] ) ) {
$url = sanitize_text_field( wp_unslash( $_POST['_p24_sub_file_urls'][ $i ] ) );
$name = 'file_' . $i;
if ( array_key_exists( $i, $_POST['_p24_sub_file_names'] ) ) {
$provided_name = sanitize_text_field( wp_unslash( $_POST['_p24_sub_file_names'][ $i ] ) );
if ( '' !== $provided_name ) {
$name = $provided_name;
}
}
$files_to_save[] = compact( 'name', 'url' );
$i++;
}
update_post_meta( $post_id, 'p24_sub_files', $files_to_save );
if ( isset( $_POST['_days'] ) ) {
$days = (int) sanitize_text_field( wp_unslash( $_POST['_days'] ) );
if ( $days < 1 ) {
$days = 1;
}
update_post_meta( $post_id, '_days', $days );
}
}
/**
* Output the simple product add to cart area.
*/
public function render_subscription_buy_form() {
$nonce_action = 'p24_add_subscription';
if ( isset( $_POST['_wpnonce'] ) ) {
wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), $nonce_action );
$post_data = $_POST;
} else {
$post_data = array();
}
$data = compact( 'post_data', 'nonce_action' );
$this->plugin_core->render_template( 'add-subscription-to-cart', $data );
}
/**
* Check for subscriptions.
*
* This code should execute only if order is paid and saved.
*
* @param int $order_id The id of existing order.
* @throws LogicException If the function is misused.
*/
public function check_for_subscriptions_in_order( $order_id ) {
$order_id = (int) $order_id;
if ( ! $order_id ) {
throw new LogicException( 'Order should be present before call to this function.' );
}
$order = new WC_Order( $order_id );
if ( ! $order->is_paid() ) {
throw new LogicException( 'Order should be paid before call to this function.' );
}
$user = $order->get_user();
if ( ! $user ) {
/* If there is no user, the subscription cannot be created. */
return;
}
$items = $order->get_items();
foreach ( $items as $item ) {
if ( ! $item instanceof WC_Order_Item_Product ) {
continue;
}
$subscription = $item->get_product();
if ( $subscription instanceof P24_No_Mc_Product_Subscription ) {
$quantity = (int) $item->get_quantity();
P24_Subscription_Db::extend_subscription( $subscription, $quantity, $user, $order );
}
}
}
/**
* Add_card_ref.
*
* @param WC_Order $order Order.
* @param string|null $cart_ref Kay of card, it is not reference id for Przelewy24.
*/
public function add_card_ref( $order, $cart_ref ) {
if ( $cart_ref ) {
P24_Subscription_Db::add_card_reference( $order, $cart_ref );
}
}
/**
* Charge_card.
*
* @param WC_Order $order Order to pay.
* @param string $card_ref Kay of card, it is not reference id for Przelewy24.
* @return bool
*/
private function charge_card( $order, $card_ref ) {
$data = P24_Sub_Generator::generate_payload_for_rest( $order );
if ( ! $data ) {
return false;
}
$card = P24_Sub_Generator::find_saved_card( $card_ref, $order->get_user_id() );
if ( ! $card ) {
return false;
}
$config_accessor = P24_Settings_Helper::load_settings( $order->get_currency() );
$data['regulationAccept'] = true;
$rest_transaction = new P24_Rest_Transaction( $config_accessor );
$data['methodRefId'] = $card['ref'];
$transaction_info = $rest_transaction->register( $data );
$token = $transaction_info['data']['token'];
if ( ! $token ) {
return false;
}
$rest_card = new P24_Rest_Card( $config_accessor );
$payment_info = $rest_card->chargeWithout3ds( $token );
if ( isset( $payment_info['data']['orderId'] ) ) {
$order_id = $payment_info['data']['orderId'];
$order->update_meta_data( P24_Core::ORDER_P24_ID, $order_id );
$order->save_meta_data();
}
return true;
}
/**
* Create subscription.
*
* @param int $product_id Product id.
* @param int $user_id User id.
* @param int $last_order_id Last order id.
* @param string $card_ref Kay of card, it is not reference id for Przelewy24.
*
* @throws LogicException This error is not expected.
*/
private function create_subscription( $product_id, $user_id, $last_order_id, $card_ref ) {
$user_id = (int) $user_id;
$product_id = (int) $product_id;
$product = wc_get_product( $product_id );
$last_order = wc_get_order( $last_order_id );
$order = wc_create_order();
$order->add_product( $product );
$order->set_address( $last_order->get_address( 'billing' ), 'billing' );
try {
$order->set_currency( $last_order->get_currency() );
$order->set_customer_id( $user_id );
} catch ( WC_Data_Exception $ex ) {
$msg = 'The function shuld not be called if conditions above cannot be satisfied.';
throw new LogicException( $msg, 0, $ex );
}
$order->calculate_totals();
$this->charge_card( $order, $card_ref );
}
/**
* Files_for_subscription.
*
* @param int $subscription_id Subscription id.
* @return array
*/
public static function files_for_subscription( $subscription_id ) {
$subscription_id = (int) $subscription_id;
$files = get_post_meta( $subscription_id, 'p24_sub_files', true );
if ( $files ) {
return $files;
} else {
return array();
}
}
/**
* Check subscription to extend.
*/
public function check_subscription_to_extend() {
$critical_date = new DateTime( P24_Subscription_Config::days_to_renew() . ' days' );
$todo = P24_Subscription_Db::find_subscription_to_extends( $critical_date );
$one = array_shift( $todo );
if ( $one ) {
$this->create_subscription( $one->product_id, $one->user_id, $one->last_order_id, $one->card_ref );
P24_Subscription_Db::mark_checked( $one->id );
}
if ( $todo ) {
wp_schedule_single_event( time() + 60, 'p24_extra_do_subscription' );
}
}
/**
* Bind events.
*/
public function bind_core_events() {
if ( ! P24_Subscription_Config::is_active() ) {
/* Do not bind any events. */
return;
}
add_filter( 'product_type_selector', array( $this, 'register_product_type' ) );
add_filter( 'woocommerce_product_class', array( $this, 'subscription_class_detector' ), 10, 2 );
add_action( 'woocommerce_product_data_panels', array( $this, 'render_subscription_panel' ) );
add_action( 'woocommerce_process_product_meta', array( $this, 'save_subscription_fields' ), 20, 2 );
add_action( 'woocommerce_p24_subscription_add_to_cart', array( $this, 'render_subscription_buy_form' ), 30 );
add_action( 'woocommerce_payment_complete', array( $this, 'check_for_subscriptions_in_order' ), 10, 1 );
add_action( 'p24_payment_complete', array( $this, 'add_card_ref' ), 10, 2 );
add_action( 'p24_daily_event', array( $this, 'check_subscription_to_extend' ) );
add_action( 'p24_extra_do_subscription', array( $this, 'check_subscription_to_extend' ) );
$this->for_user->bind_core_events();
$this->for_admin->bind_core_events();
$this->api->bind_core_events();
}
}