-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathwoocommerce-yellow.php
496 lines (416 loc) · 21.2 KB
/
woocommerce-yellow.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
<?php
/*
Plugin Name: Yellow for WooCommerce
Plugin URI: https://yellowpay.co
Description: Enable your WooCommerce store to accept Bitcoin with Yellow.
Author: Yellow
Author URI: https://yellowpay.co
Version: 1.0.1
License: Copyright 2015 Yellow Inc., MIT License
GitHub Plugin URI: https://github.com/YellowPay/yellow-wordpress
*/
// Exit if accessed directly
if (false === defined('ABSPATH')) {
exit;
}
$autoloader_param = __DIR__.'/vendor/autoload.php';
// Load up the Yellow library
if (true === file_exists($autoloader_param) &&
true === is_readable($autoloader_param))
{
require_once $autoloader_param;
} else {
throw new \Exception('The Yellow payment plugin was not installed correctly or the files are corrupt. Please reinstall the plugin. If this message persists after a reinstall, contact [email protected] with this message.');
}
use Yellow\Bitcoin\Invoice;
// Ensures WooCommerce is loaded before initializing the Yellow plugin
add_action('plugins_loaded', 'woocommerce_yellow_init', 0);
register_activation_hook(__FILE__, 'woocommerce_yellow_activate');
function woocommerce_yellow_init()
{
if (true === class_exists('WC_Gateway_Yellow')) {
return;
}
if (false === class_exists('WC_Payment_Gateway')) {
return;
}
class WC_Gateway_Yellow extends WC_Payment_Gateway {
private $is_initialized = false;
public function __construct() {
// General
$this->id = 'yellow';
$this->has_fields = false;
$this->title = 'Pay with Bitcoin (<a href="http://yellowpay.co/what-is-bitcoin/" target="_blank">what is bitcoin?</a>)';
$this->backend_title = 'Bitcoin Payment';
$this->description = 'Bitcoin is digital cash. Make online payments even if you don\'t have a credit card!';
$this->method_title = 'Yellow';
$this->method_description = 'To accept bitcoin payment, register through <a target="_blank" href="http://merchant.yellowpay.co/">Yellow merchants website</a>, then paste your API key and secret below';
// Load the settings.
$this->init_form_fields();
$this->init_settings();
// Define Yellow settings
$this->api_key = $this->get_option('api_key');
$this->api_secret = $this->get_option('api_secret');
$this->debug = 'yes' === $this->get_option('debug', 'no');
// Actions
add_action('woocommerce_update_options_payment_gateways_'.$this->id, array($this, 'process_admin_options'));
add_action('woocommerce_receipt_'.$this->id, array($this, 'order_invoice'));
// Valid for use and IPN Callback
if (false === $this->is_valid_for_use() || !$this->get_option('enabled') ) {
$this->enabled = 'no';
} else {
$this->enabled = 'yes';
add_action('woocommerce_api_wc_gateway_yellow', array($this, 'ipn_callback'));
}
$this->is_initialized = true;
}
public function is_valid_for_use()
{
// Check that API credentials are set
if (true === is_null($this->api_key) ||
true === is_null($this->api_secret))
{
return false;
}
return true;
}
/**
* Initialise Gateway Settings Form Fields
*/
public function init_form_fields()
{
$log_file = 'yellow-' . sanitize_file_name( wp_hash( 'yellow' ) ) . '-log';
$logs_href = get_bloginfo('wpurl') . '/wp-admin/admin.php?page=wc-status&tab=logs&log_file=' . $log_file;
$this->form_fields = array(
'enabled' => array(
'title' => __('Enable/Disable', 'Yellow'),
'type' => 'checkbox',
'label' => __('Enable Bitcoin Payments via Yellow', 'Yellow'),
'default' => 'yes',
),
'api_key' => array(
'type' => 'api_key',
'title' => __('API Key', 'Yellow'),
),
'api_secret' => array(
'title' => __('API Secret', 'Yellow'),
'type' => 'api_secret',
'type' => 'password',
),
'debug' => array(
'title' => __('Debug Log', 'Yellow'),
'type' => 'checkbox',
'label' => sprintf(__('Enable logging <a href="%s" class="button">View Logs</a>', 'Yellow'), $logs_href),
'default' => 'no',
'description' => sprintf(__('Log Yellow events, such as IPN requests, inside <code>%s</code>', 'Yellow'), wc_get_log_file_path('Yellow')),
'desc_tip' => true,
),
);
}
/**
* Process the payment and return the result
*
* @param int $order_id
* @return array
*/
public function process_payment($order_id)
{
if (true === empty($order_id)) {
throw new \Exception('The Yellow payment plugin was called to process a payment but the order_id was missing. Cannot continue!');
}
$order = wc_get_order($order_id);
if (false === $order) {
throw new \Exception('The Yellow payment plugin was called to process a payment but could not retrieve the order details for order_id '.$order_id.'. Cannot continue!');
}
// session_start();
if( !session_id() )
session_start();
$order_invoice_url_variable = 'yellow_order_'.$order_id.'_invoice_url';
if( !isset($_SESSION[$order_invoice_url_variable]) || $order->get_status() == "failed" ){
try {
$yellow = new Invoice($this->api_key, $this->api_secret);
$amount = (float)$order->order_total;
$currency = get_woocommerce_currency();
$callback = WC()->api_request_url('WC_Gateway_Yellow');
$type = 'cart';
$order_number = (string)$order->get_order_number();
$payload = array(
'base_price'=> $amount,
'base_ccy' => $currency,
'callback' => $callback,
'type' => $type,
'order' => $order_number,
);
$invoice = $yellow->createInvoice( $payload );
$this->log('Invoice created with payload: '.json_encode($payload).', response: '.json_encode($invoice));
if (false === isset($invoice) || true === empty($invoice) || true === is_object($invoice)) {
throw new \Exception('The Yellow payment plugin was called to process a payment but could not instantiate an invoice object. Cannot continue!');
}
if( $order->get_status() != "failed" ){ //new order
$order->add_order_note(__('Order created with Yellow invoice of ID: '.$invoice["id"], 'yellow'));
// Reduce stock levels
$order->reduce_order_stock();
// Remove cart
WC()->cart->empty_cart();
}else{ //failed order with new invoice
$order->add_order_note(__('New Yellow invoice created of ID: '.$invoice["id"], 'yellow'));
$order->update_status('pending');
}
$_SESSION[$order_invoice_url_variable] = $invoice["url"];
} catch (\Exception $e) {
error_log($e->getMessage());
return array(
'result' => 'success',
'messages' => "We're sorry, an error has occurred while completing your request. Please resubmit the shopping cart and try again. If the error persists, please send us an email at <a href='mailto:[email protected]' target='_blank'>[email protected]</a>"
);
}
}
// Redirect the customer to the Yellow invoice
return array(
'result' => 'success',
'redirect' => $order->get_checkout_payment_url( true ),
);
}
/**
* Output for the order invoice.
*/
public function order_invoice($order_id) {
if( !session_id() )
session_start();
$order = wc_get_order($order_id);
$order_invoice_url_variable = 'yellow_order_'.$order_id.'_invoice_url';
$order_invoice_url = $_SESSION[$order_invoice_url_variable];
$order_return_url = $this->get_return_url($order);
echo "<script> \n";
echo " function invoiceListener(event) { \n";
echo " switch (event.data) { \n";
echo " case \"authorizing\": \n";
echo " // Handle the invoice status update \n";
echo " window.location = \"".$order_return_url."\" \n";
echo " break; \n";
echo " } \n";
echo " } \n";
echo " // Attach the message listener \n";
echo " if (window.addEventListener) { \n";
echo " addEventListener(\"message\", invoiceListener, false) \n";
echo " } else { \n";
echo " attachEvent(\"onmessage\", invoiceListener) \n";
echo " } \n";
echo "</script>";
echo 'Invoice payment details:';
echo '<iframe src="'.$order_invoice_url.'" style="width:393px; height:220px; overflow:hidden; border:none; margin:auto; display:block;" scrolling="no" allowtransparency="true" frameborder="0"></iframe>';
}
public function ipn_callback()
{
$yellow = new Invoice($this->api_key, $this->api_secret);
$body = file_get_contents("php://input") ;
$url = $yellow->getCurrentUrl();
$sign = $_SERVER["HTTP_API_SIGN"];
$api_key = $_SERVER["HTTP_API_KEY"];
$nonce = $_SERVER["HTTP_API_NONCE"];
$isValidIPN = $yellow->verifyIPN($url,$sign,$api_key,$nonce,$body); //bool
if( $isValidIPN ){
$this->log('Valid IPN call: '.json_encode($body));
}else{
$this->log('Invalid IPN call: '.json_encode($body));
wp_die('Invalid IPN call');
}
// Fetch the invoice from Yellow's server to update the order
$invoice = json_decode($body);
$order_id = $invoice->order;
if (false === isset($order_id) && true === empty($order_id)) {
throw new \Exception('The Yellow payment plugin was called to process an IPN message but could not obtain the order ID from the invoice. Cannot continue!');
}
// Creating a new WooCommerce Order object with $order_id
$order = wc_get_order($order_id);
if (false === isset($order) && true === empty($order)) {
throw new \Exception('The Yellow payment plugin was called to process an IPN message but could not retrieve the order details for order_id '.$order_id.'. Cannot continue!');
}
$current_status = $order->get_status();
if (false === isset($current_status) && true === empty($current_status)) {
throw new \Exception('The Yellow payment plugin was called to process an IPN message but could not obtain the current status from the order. Cannot continue!');
}
$checkStatus = $invoice->status;
if (false === isset($checkStatus) && true === empty($checkStatus)) {
throw new \Exception('The Yellow payment plugin was called to process an IPN message but could not obtain the current status from the invoice. Cannot continue!');
}
// Based on the payment status parameter for this
// IPN, we will update the current order status.
switch ($checkStatus) {
// The "authorizing" IPN message is received when the invoice is paid but still not authorized.
case 'authorizing':
if( $current_status == 'pending' || $current_status == 'on-hold' ) {
$order->update_status('processing');
$order->add_order_note(__('Yellow invoice paid. Awaiting network confirmation and payment completed status.', 'yellow'));
}
break;
// The "paid" IPN message is received when the invoice got authorized.
case 'paid':
if( $current_status == 'processing' ) {
$order->payment_complete();
$order->add_order_note(__('Yellow invoice payment confirmed. The order is awaiting fulfillment.', 'yellow'));
}
break;
// The "refund_owed" IPN message is received when the invoice under paid or over paid.
case 'refund_owed':
if( $current_status != 'processing' || $current_status != 'completed' ) {
$order->update_status('failed');
$order->add_order_note(__('Yellow invoice needs refund.', 'yellow'));
}
break;
// The "refund_paid" IPN message is received when the invoice got refunded.
case 'refund_paid':
if( $current_status != 'processing' || $current_status != 'completed' ) {
$order->update_status('refunded');
$order->add_order_note(__('Yellow invoice refunded.', 'yellow'));
}
break;
// The "expired" IPN message is received after the 10 minutes passes on the invoice without payment.
case 'expired':
if( $current_status == 'pending' || $current_status == 'on-hold' ) {
$order->update_status('failed');
$order->add_order_note(__('Yellow invoice expired.', 'yellow'));
}
break;
}
}
public function log($message)
{
if (true === isset($this->debug) && 'yes' == $this->debug) {
if (false === isset($this->logger) || true === empty($this->logger)) {
$this->logger = new WC_Logger();
}
$this->logger->add('yellow', $message);
}
}
/*
* over riding get_title function to return title without html in the backend
*/
public function get_title()
{
$trace=debug_backtrace();
if( isset($trace[1]) &&
isset($trace[1]['args']) &&
isset($trace[1]['args'][0]) ){
$caller_url = $trace[1]['args'][0];
$find1 = 'payment-method.php';
$find2 = 'form-pay.php';
if( is_string($caller_url) &&
(substr_compare($caller_url, $find1, strlen($caller_url)-strlen($find1), strlen($find1)) === 0 ||
substr_compare($caller_url, $find2, strlen($caller_url)-strlen($find2), strlen($find2)) === 0) ){
return $this->title;
}
}
return $this->backend_title;
}
}
/**
* Add Yellow Payment Gateway to WooCommerce
**/
add_filter('woocommerce_payment_gateways', 'wc_add_yellow');
function wc_add_yellow($methods)
{
$methods[] = 'WC_Gateway_Yellow';
return $methods;
}
/**
* Add Settings link to the plugin entry in the plugins menu
**/
add_filter('plugin_action_links', 'yellow_plugin_action_links', 10, 2);
function yellow_plugin_action_links($links, $file)
{
static $this_plugin;
if (false === isset($this_plugin) || true === empty($this_plugin)) {
$this_plugin = plugin_basename(__FILE__);
}
if ($file == $this_plugin) {
$log_file = 'yellow-'.sanitize_file_name( wp_hash( 'yellow' ) ).'-log';
$settings_link = '<a href="'.get_bloginfo('wpurl').'/wp-admin/admin.php?page=wc-settings&tab=checkout§ion=wc_gateway_yellow">Settings</a>';
$logs_link = '<a href="'.get_bloginfo('wpurl').'/wp-admin/admin.php?page=wc-status&tab=logs&log_file='.$log_file.'">Logs</a>';
array_unshift($links, $settings_link, $logs_link);
}
return $links;
}
/**
* Add message to apppear instead of the default message after the plugin activation
**/
add_filter('gettext',
function( $translated_text, $untranslated_text, $domain )
{
$old = array(
"Plugin <strong>activated</strong>.",
"Selected plugins <strong>activated</strong>."
);
$settings_link = '<a href="'.get_bloginfo('wpurl').'/wp-admin/admin.php?page=wc-settings&tab=checkout§ion=wc_gateway_yellow">settings page</a>';
$new = 'To start accepting Bitcoin payments, visit the '.$settings_link.' to connect your site to your Yellow account';
if ( in_array( $untranslated_text, $old, true ) )
$translated_text = substr($untranslated_text, 0, -1).', '.$new;
return $translated_text;
}
, 99, 3);
}
function woocommerce_yellow_failed_requirements()
{
global $wp_version;
global $woocommerce;
$errors = array();
// PHP 5.4+ required
if (true === version_compare(PHP_VERSION, '5.4.0', '<')) {
$errors[] = 'Your PHP version is too old. The Yellow payment plugin requires PHP 5.4 or higher to function. Please contact your web server administrator for assistance.';
}
// Wordpress 3.9+ required
if (true === version_compare($wp_version, '3.9', '<')) {
$errors[] = 'Your WordPress version is too old. The Yellow payment plugin requires Wordpress 3.9 or higher to function. Please contact your web server administrator for assistance.';
}
// WooCommerce required
if (true === empty($woocommerce)) {
$errors[] = 'The WooCommerce plugin for WordPress needs to be installed and activated. Please contact your web server administrator for assistance.';
}elseif (true === version_compare($woocommerce->version, '2.2', '<')) {
$errors[] = 'Your WooCommerce version is too old. The Yellow payment plugin requires WooCommerce 2.2 or higher to function. Your version is '.$woocommerce->version.'. Please contact your web server administrator for assistance.';
}
// GMP or BCMath required
if (false === extension_loaded('gmp') && false === extension_loaded('bcmath')) {
$errors[] = 'The Yellow payment plugin requires the GMP or BC Math extension for PHP in order to function. Please contact your web server administrator for assistance.';
}
// Curl required
if (false === extension_loaded('curl')) {
$errors[] = 'The Yellow payment plugin requires the Curl extension for PHP in order to function. Please contact your web server administrator for assistance.';
}
if (false === empty($errors)) {
return implode("<br>\n", $errors);
} else {
return false;
}
}
// Activating the plugin
function woocommerce_yellow_activate()
{
// Check for Requirements
$failed = woocommerce_yellow_failed_requirements();
$plugins_url = admin_url('plugins.php');
// Requirements met, activate the plugin
if ($failed === false) {
// Deactivate any older versions that might still be present
$plugins = get_plugins();
foreach ($plugins as $file => $plugin) {
if ('Yellow Woocommerce' === $plugin['Name'] && true === is_plugin_active($file)) {
deactivate_plugins(plugin_basename(__FILE__));
wp_die('Yellow for WooCommerce requires that the old plugin, <b>Yellow Woocommerce</b>, is deactivated and deleted.<br><a href="'.$plugins_url.'">Return to plugins screen</a>');
}
}
// Fix transaction_speed from older versions
$settings = get_option('woocommerce_Yellow');
if (true === isset($settings) && true === is_string($settings)) {
$settings_array = @unserialize($settings);
if (false !== $settings_array && true === isset($settings_array['transactionSpeed'])) {
$settings_array['transaction_speed'] = $settings_array['transactionSpeed'];
unset($settings_array['transactionSpeed']);
update_option('woocommerce_Yellow', serialize($settings));
}
}
update_option('woocommerce_Yellow_version', '1.0.0');
} else {
// Requirements not met, return an error message
wp_die($failed.'<br><a href="'.$plugins_url.'">Return to plugins screen</a>');
}
}