Hacked By AnonymousFox
<?php
/**
* YOCO Payment Gateway
* @class KKART_Gateway_Yoco
* @package Kkart
* @version 1.0.0
* @category Payment Gateways
* @author Kkart
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
define( 'KKART_GATEWAY_YOCO_VERSION', KKART_VERSION );
define( 'KKART_GATEWAY_YOCO_URL', untrailingslashit( plugin_dir_url(__FILE__) ) );
define( 'KKART_YOCO_ONLINE_CHECKOUT_URL', 'https://payments.yoco.com/api/checkouts' );
class KKART_Gateway_Yoco extends KKART_Payment_Gateway {
/**
* Version
*
* @var string
*/
public $version;
public $mode;
/**
* Constructor
*/
public function __construct() {
//NOTE:: Update payment method description according to supported payment methods
$this->version = KKART_GATEWAY_YOCO_VERSION;
$this->credentials = $this->get_credential();
$this->id = 'yoco';
$this->enabled = $this->get_option( 'enabled' );
$this->icon = KKART_GATEWAY_YOCO_URL . '/assets/yoco-2024.svg';
$this->has_fields = false;
$this->init_form_fields();
$this->init_settings();
// Supported functionality.
$this->supports = array( 'products', 'pre-orders', 'refunds');
$this->title = $this->get_option( 'title', esc_html__( 'Yoco', 'kkart' ) );
$this->description = $this->get_option( 'description', esc_html__( 'Pay securely using a credit/debit card or other payment methods via Yoco.', 'kkart' ) );
$this->mode = $this->get_option( 'mode' );
$this->method_title = esc_html__( 'Yoco', 'kkart' );
$this->method_description = esc_html__( 'Yoco redirects customers to PayPal to enter their payment information.', 'kkart' );
$this->available_currencies = (array)apply_filters('kkart_gateway_payfast_available_currencies', array( 'ZAR' ) );
add_action( 'kkart_update_options_payment_gateways_' . $this->id, array( &$this, 'process_admin_options' ) );
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
add_action( 'yoco_payment_gateway/checkout/created', array( $this, 'updateOrderCheckoutMeta' ), 10, 2 );
add_action( 'yoco_payment_gateway/order/refunded', array( $this, 'updateOrderRefundId' ), 10, 2 );
}
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', 'kkart' ),
'label' => __( 'Enable Yoco Payments', 'kkart' ),
'type' => 'checkbox',
'description' => '',
'default' => 'no',
),
'title' => array(
'title' => __( 'Title', 'kkart' ),
'type' => 'text',
'description' => __( 'This controls the title which the user sees during checkout.', 'kkart' ),
'default' => __( 'Yoco', 'kkart' ),
'desc_tip' => true,
),
'description' => array(
'title' => __( 'Description', 'kkart' ),
'type' => 'text',
'description' => __( 'This controls the description which the user sees during checkout.', 'kkart' ),
'default' => __( 'Pay securely using a credit/debit card or other payment methods via Yoco.', 'kkart' ),
'css' => 'max-width:400px;',
),
'mode' => array(
'title' => __( 'Mode', 'kkart' ),
'label' => __( 'Mode', 'kkart' ),
'type' => 'select',
'description' => __( 'Test mode allow you to test the plugin without processing money.<br>Set the plugin to Live mode and click on "Save changes" for real customers to use it.', 'kkart' ),
'default' => 'Test',
'options' => array(
'live' => 'Live',
'test' => 'Test',
),
),
'live_secret_key' => array(
'title' => __( 'Live Secret Key', 'kkart' ),
'type' => 'password',
'description' => __( 'Live Secret Key', 'kkart' ),
'class' => 'input password-input',
),
'test_secret_key' => array(
'title' => __( 'Test Secret Key', 'kkart' ),
'type' => 'password',
'description' => __( 'Test Secret Key', 'kkart' ),
'class' => 'input password-input',
),
);
}
public function process_payment( $order_id ): ?array {
$order = kkart_get_order( $order_id );
try {
$checkoutUrl = $order->get_meta( 'kkart_yoco_order_checkout_url', true, 'kkart' );
if( ! empty( $checkoutUrl ) ){
return $this->createSuccessRedirectResponse( $checkoutUrl );
}
$response = $this->send($order, 'payment');
if( ! in_array( (int) $response['code'], array( 200, 201, 202 ), true )){
$error_message = isset( $response['body']['errorMessage'] ) ? $response['body']['errorMessage'] : '';
$error_code = isset( $response['body']['errorCode'] ) ? $response['body']['errorCode'] : '';
$response_message = isset( $response['message'] ) ? $response['message'] : '';
throw new Exception( sprintf( 'Failed to request checkout. %s', $response_message ) );
}
do_action( 'yoco_payment_gateway/checkout/created', $order, $response['body']);
return $this->createSuccessRedirectResponse( $response['body']['redirectUrl'] );
} catch ( \Throwable $th ){
kkart_add_notice( __( 'Your order could not be processed by Yoco - please try again later.', 'kkart' ), 'error' );
return null;
}
}
public function get_icon() {
$icon = '<img class="yoco-payment-method-icon" style="max-height:1em;width:100%;" alt="' . esc_attr( $this->title ) . '" width="100" height="24" src="' . esc_url( $this->icon ) . '"/>';
return apply_filters( 'kkart_gateway_icon', $icon, $this->id );
}
public function process_refund( $order_id, $amount = null, $reason = '' ){
$order = kkart_get_order( $order_id );
try{
$response = $this->send($order, 'refund');
if ( isset( $response['body']['description'] ) ) {
return new WP_Error( 400, $response['body']['description'] );
}
if ( isset( $response['body']['status'] ) && 'successful' === $response['body']['status'] ) {
do_action( 'yoco_payment_gateway/order/refunded', $order, $response['body'] );
}
return new WP_Error( 200, $response['body']['message'] ?? '' );
}catch( \Throwable $th ){
return new WP_Error( $th->getCode(), $th->getMessage() );
}
}
private function createSuccessRedirectResponse( string $redirectUrl ): array {
return array(
'result' => 'success',
'redirect' => $redirectUrl,
);
}
public function send($order, string $request_type): array {
try {
$url = $this->getUrl($order, $request_type);
$args = $this->getArgs($order,$request_type);
return $this->post( $url, $args );
} catch ( \Throwable $th ) {
throw $th;
}
}
public function updateOrderCheckoutMeta( KKART_Order $order, array $data ): void {
$this->updateOrderMeta( $order, 'kkart_yoco_order_checkout_id', $data['id'] );
$this->updateOrderMeta( $order, 'kkart_yoco_order_checkout_mode', $data['processingMode'] );
$this->updateOrderMeta( $order, 'kkart_yoco_order_checkout_url', $data['redirectUrl'] );
}
public function updateOrderPaymentId( KKART_Order $order, $payload ): void {
$this->updateOrderMeta( $order, 'kkart_yoco_order_payment_id', $payload->getPaymentId() );
}
public function updateOrderRefundId( KKART_Order $order, array $data ): void {
$this->updateOrderMeta( $order, 'kkart_yoco_order_refund_id', $data['refundId'] );
}
public function updateOrderMeta( KKART_Order $order, string $key, string $value ): void {
$order->update_meta_data( $key, $value );
$order->save_meta_data();
}
private function getUrl($order, string $request_type): string {
if($request_type === 'refund'){
$url = $this->getCheckoutApiUrl();
return trailingslashit( $url ) . $this->getOrderCheckoutId($order) . '/refund';
}
return $this->getCheckoutApiUrl();
}
public function getCheckoutApiUrl(): ?string {
if(! defined( 'KKART_YOCO_ONLINE_CHECKOUT_URL' ) ){
return '';
}
return KKART_YOCO_ONLINE_CHECKOUT_URL;
}
public function getOrderCheckoutId( KKART_Order $order ): string {
return $this->getOrderMeta( $order, 'kkart_yoco_order_checkout_id' );
}
public function getOrderMeta( KKART_Order $order, string $key ): string {
$meta = $order->get_meta( $key, true, 'yoco' );
return is_string( $meta ) ? $meta : '';
}
private function getArgs($order, string $request_type): array {
if($request_type === 'refund'){
return array(
'headers' => $this->getHeaders($request_type),
);
}
return array(
'headers' => $this->getHeaders($request_type),
'body' => $this->getBody($order)
);
}
public function getHeaders($request_type) {
$headers = array(
'Content-Type' => 'application/json',
'Authorization' => $this->getApiBearer(),
'X-Product' => 'kkart',
);
if($request_type === 'refund'){
return apply_filters( 'yoco_payment_gateway/refund/request/headers', $headers );
}
return apply_filters( 'yoco_payment_gateway/payment/request/headers', $headers );
}
public function getHeadersForMode($order) {
$headers = array(
'Content-Type' => 'application/json',
'Authorization' => $this->getApiBearer( $order->get_meta( 'kkart_yoco_order_payment_mode', true ) ),
'X-Product' => 'kkart',
);
return apply_filters( 'yoco_payment_gateway/payment/request/headers', $headers );
}
public function getApiBearer( string $mode = '' ): string {
return 'Bearer ' . $this->getSecretKey( $mode );
}
public function getSecretKey( string $mode = '' ) {
$mode = ( 'live' === $mode || 'test' === $mode ) ? $mode : $this->mode;
return $this->get_option($mode . '_secret_key' ) ? $this->get_option($mode . '_secret_key' ) : '';
}
public function getBody($order) {
$body = $this->buildPayload($order);
$body = apply_filters( 'yoco_payment_gateway/payment/request/body', $body );
return json_encode( $body, JSON_UNESCAPED_SLASHES );
}
public function getOrderCheckoutPaymentUrl( string $status, $order ): string {
return add_query_arg(
array(
'kkart_yoco_checkout_status' => $status,
),
$order->get_checkout_order_received_url()
);
}
// This function checked move on to the next
public function buildPayload($order){
$payload = array();
$payload['amount'] = $this->format($order->get_total());
$payload['currency'] = $order->get_currency();
$payload['successUrl'] = $order->get_checkout_order_received_url();
$payload['cancelUrl'] = $order->get_checkout_payment_url();
$payload['failureUrl'] = $this->getOrderCheckoutPaymentUrl( 'failed', $order );
$payload['totalDiscount'] = $order->get_total_discount();
$payload['totalTaxAmount'] = $order->get_total_tax();
$payload['subtotalAmount'] = $order->get_subtotal();
if (!isset($payload['metadata'])) {
$payload['metadata'] = array();
}
$metadata = $this->buildMetadata($order);
$payload['metadata'] = array_merge($payload['metadata'], $metadata);
$payload['productType'] = 'kkart';
return $payload;
}
public function buildMetadata( KKART_Order $order ){
$custom_info = array();
$note = join(' ',
array(
__( 'order', 'kkart' ),
$order->get_id(),
__( 'from', 'kkart' ),
$order->get_billing_first_name(),
$order->get_billing_last_name(),
'(' . $order->get_billing_email() . ')',
)
);
$custom_info['billNote'] = $note;
$custom_info['customerEmailAddress'] = $order->get_billing_email();
$custom_info['customerLastName'] = $order->get_billing_last_name();
$custom_info['customerFirstName'] = $order->get_billing_first_name();
return $custom_info;
}
public function post( string $url, array $args ){
if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) {
throw new Exception( __( 'Invalid URL for POST request.', 'yoco_wc_payment_gateway' ) );
}
$response = wp_remote_post( $url, $args );
if ( is_wp_error( $response ) ) {
throw new Exception( $response->get_error_message(), 0 );
}
$code = wp_remote_retrieve_response_code( $response );
//start from here
$message = wp_remote_retrieve_response_message( $response );
$body = wp_remote_retrieve_body( $response );
return array(
'code' => $code,
'message' => $message,
'body' => (array) json_decode( $body ),
);
}
public function format( $value, array $options = array() ): int {
$options = wp_parse_args(
$options,
array(
'decimals' => 2,
'rounding_mode' => PHP_ROUND_HALF_UP,
)
);
$decimals = absint( $options['decimals'] );
$rounding_mode = min( absint( $options['rounding_mode'] ), 4 );
return intval( round( ( (float) kkart_format_decimal( $value ) ) * ( 10 ** $decimals ), 0, $rounding_mode ) );
}
public function get_credential(){
$cred_arr = array();
$cred_arr['livePublic'] = $this->mode === "live" ? $this->get_option( 'live_public_key', '' ) : '';
$cred_arr['liveSecret'] = $this->mode === "live" ? $this->get_option( 'live_secret_key', '' ) : '';
$cred_arr['testPublic'] = $this->mode === "test" ? $this->get_option( 'test_public_key', '' ) : '';
$cred_arr['testSecret'] = $this->mode === "test" ? $this->get_option( 'test_secret_key', '' ) : '';
return $cred_arr;
}
public function check_requirements() {
$errors = [];
// Check if the store currency is supported by YOCO
if (!in_array(get_kkart_currency(), $this->available_currencies)) {
$errors[] = 'kkart-gateway-yoco-error-invalid-currency';
}
if ($this->mode === 'live' && empty($this->get_option('live_secret_key'))) {
$errors[] = 'kkart-gateway-yoco-error-missing-livekey';
}
if ($this->mode === 'test' && empty($this->get_option('test_secret_key'))) {
$errors[] = 'kkart-gateway-yoco-error-missing-testkey';
}
if ($this->mode === 'test' && !preg_match('/^sk_test/', $this->get_option('test_secret_key'))) {
$errors[] = 'kkart-gateway-yoco-error-wrong-testkey';
}
if ($this->mode === 'live' && !preg_match('/^sk_live/', $this->get_option('live_secret_key'))) {
$errors[] = 'kkart-gateway-yoco-error-wrong-livekey';
}
if($this->is_rest_api_enabled() === false){
$errors[] = 'rest-api-disabled';
}
return array_filter( $errors );
}
public function is_rest_api_enabled(){
$rest_api = get_option('sitepad_rest_api');
if(empty($rest_api)){
return false;
}
return true;
}
public function is_available() {
if ( 'yes' === $this->enabled ) {
$errors = $this->check_requirements();
return 0 === count( $errors );
}
return parent::is_available();
}
public function admin_notices() {
// Get requirement errors.
$errors_to_show = $this->check_requirements();
// If everything is in place, don't display it.
if( ! count( $errors_to_show ) ){
return;
}
// If the gateway isn't enabled, don't show it.
if ( "no" === $this->enabled ) {
return;
}
// Use transients to display the admin notice once after saving values.
if ( ! get_transient( 'kkart-gateway-YOCO-admin-notice-transient' ) ) {
set_transient( 'kkart-gateway-YOCO-admin-notice-transient', 1, 1);
echo '<div class="notice notice-error is-dismissible"><p>'
. __( 'To use YOCO as a payment provider, you need to fix the problems below:', 'kkart' ) . '</p>'
. '<ul style="list-style-type: disc; list-style-position: inside; padding-left: 2em;">'
. array_reduce( $errors_to_show, function( $errors_list, $error_item ) {
$errors_list = $errors_list . PHP_EOL . ( '<li>' . $this->get_error_message($error_item) . '</li>' );
return $errors_list;
}, '' )
. '</ul></p></div>';
}
}
public function get_error_message( $key ) {
$error_msg = '';
switch ( $key ) {
case 'kkart-gateway-yoco-error-invalid-currency':
$error_msg = __( 'Your store uses a currency that YOCO doesnt support yet.', 'kkart' );
break;
case 'kkart-gateway-yoco-error-missing-livekey':
$error_msg = __( 'You forgot to fill your live key.', 'kkart' );
break;
case 'kkart-gateway-yoco-error-missing-testkey':
$error_msg = __( 'You forgot to fill your test key.', 'kkart' );
break;
case 'kkart-gateway-yoco-error-wrong-testkey':
$error_msg = __( 'Check the formatting for the test key.', 'kkart' );
break;
case 'rest-api-disabled' :
$error_msg = sprintf(
__('SitePad REST API is disabled. Please <a href="%s">enable</a> it first.', 'kkart'),
esc_url(admin_url('options-general.php'))
);
break;
case 'kkart-gateway-yoco-error-wrong-livekey':
$error_msg = __( 'Check the formatting for the live key.', 'kkart' );
break;
}
return $error_msg;
}
public function process_admin_options() {
parent::process_admin_options();
$mode = $this->get_option('mode', 'test');
$secret_key_option = $mode === 'live' ? 'live_secret_key' : 'test_secret_key';
$secret_key = $this->get_option($secret_key_option);
if (!empty($secret_key)) {
$this->register_yoco_webhook($secret_key);
}
}
public function register_yoco_webhook($secret_key) {
$webhook_url = get_rest_url(null, 'kkart/v3/webhook');
$mode = $this->get_option('mode', 'test');
$payload = array(
'name' => 'kkart-yoco-webhook',
'url' => $webhook_url,
);
$args = array(
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $secret_key,
),
'body' => json_encode($payload),
);
$response = wp_remote_post('https://payments.yoco.com/api/webhooks', $args);
$response_params= wp_remote_retrieve_body( $response );
$response_data = json_decode($response_params, true);
if(is_wp_error($response)){
$error_message = $response->get_error_message();
error_log('Yoco Webhook Registration Error: ' . $error_message);
}else{
$response_code = wp_remote_retrieve_response_code($response);
if($response_code === 200 || $response_code === 201){
$key = 'live' === $mode ? 'yoco_payment_gateway_live_webhook_secret' : 'yoco_payment_gateway_test_webhook_secret';
$current_secret = get_option( $key );
if ( $current_secret === $response_data['secret'] ) {
return;
}
update_option( $key, $response_data['secret']);
}else{
error_log('Yoco Webhook Registration Failed: ' . wp_remote_retrieve_body($response));
}
}
}
}
Hacked By AnonymousFox1.0, Coded By AnonymousFox