Skip to content

Commit

Permalink
Add QR expires count down for promptpay (#408)
Browse files Browse the repository at this point in the history
* add expires in count down for promptpay QR

* add test for promptpay qr expires at

* separate class for file get contents

* fix error on test

* remove unused function
  • Loading branch information
ajzkk committed Oct 17, 2023
1 parent 3cbd9d5 commit 8722d96
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 6 deletions.
43 changes: 43 additions & 0 deletions assets/javascripts/omise-promptpay-count-down.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
(function () {
let countDownInterval;

function calculateCountdown() {
const currentDateTime = new Date();
const expiresAtDateTime = new Date(omise.qr_expires_at);
const difference = expiresAtDateTime - currentDateTime;
const hours = Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((difference % (1000 * 60)) / 1000);
return { hours, minutes, seconds };
}

function padZero(num) {
return num.toString().padStart(2, '0');
}

function updateCountdown(fromInterval = true) {
const countdownDisplay = document.getElementById('countdown');
if(!countdownDisplay) {
return;
}

const { hours, minutes, seconds } = calculateCountdown();

if (hours + minutes + seconds < 0) {
// To prevent infinite loading, we need to reload and clear interval
// only when it is from setInterval function.
if (fromInterval) {
clearInterval(countDownInterval)
window.location.reload()
}
return;
}

countdownDisplay.innerHTML = `${padZero(hours)}:${padZero(minutes)}:${padZero(seconds)}`;
if (!countDownInterval) {
countDownInterval = setInterval(updateCountdown, 1000);
}
}

updateCountdown(false)
})()
30 changes: 25 additions & 5 deletions includes/gateway/class-omise-payment-promptpay.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ private function register_omise_promptpay_scripts() {
);
}

/**
* register scripts for count down
*/
private function register_omise_promptpay_count_down_script($expiresAt) {
wp_enqueue_script(
'omise-promptpay-count-down',
plugins_url( '../assets/javascripts/omise-promptpay-count-down.js', dirname( __FILE__ ) ),
array(),
WC_VERSION,
true
);
wp_localize_script('omise-promptpay-count-down', 'omise', [
// Format `c` is used to format as ISO string
'qr_expires_at' => $expiresAt->format('c')
]);
}

/**
* @see WC_Settings_API::init_form_fields()
* @see woocommerce/includes/abstracts/abstract-wc-settings-api.php
Expand Down Expand Up @@ -79,7 +96,7 @@ public function init_form_fields() {
* @param string $id Value to be added in the id attribute of the svg element
*/
private function load_qr_svg_to_DOM($url, $id = null) {
$svg_file = file_get_contents($url);
$svg_file = File_Get_Contents_Wrapper::get_contents($url);

$find_string = '<svg';
$position = strpos($svg_file, $find_string);
Expand Down Expand Up @@ -119,7 +136,7 @@ public function display_qrcode( $order, $context = 'view' ) {
}

$charge = OmiseCharge::retrieve( $this->get_charge_id_from_order() );
if ( self::STATUS_PENDING !== $charge['status'] ) {
if ( $this->get_pending_status() !== $charge['status'] ) {
return;
}

Expand All @@ -128,6 +145,10 @@ public function display_qrcode( $order, $context = 'view' ) {
$expires_datetime = new WC_DateTime( $charge['expires_at'], new DateTimeZone( 'UTC' ) );
$expires_datetime->set_utc_offset( wc_timezone_offset() );

if ( 'view' === $context ) {
$this->register_omise_promptpay_count_down_script($expires_datetime);
}

$nonce = wp_create_nonce( OmisePluginHelperWcOrder::get_order_key_by_id( $order ) );

if ( 'view' === $context ) : ?>
Expand All @@ -139,9 +160,8 @@ public function display_qrcode( $order, $context = 'view' ) {
</div>
<a id="omise-download-promptpay-qr" class="omise-download-promptpay-qr" href="<?php echo $qrcode ?>" download="qr_code.svg">Download QR</a>
<div>
<?php echo __( 'Payment expires at: ', 'omise' ); ?>
<?php echo wc_format_datetime( $expires_datetime, wc_date_format() ); ?>
<?php echo wc_format_datetime( $expires_datetime, wc_time_format() ); ?>
<?php echo __( 'Payment expires in: ', 'omise' ); ?>
<span id="countdown"></span>
</div>

<div id="omise-offline-payment-timeout" style="margin-top: 2em; display: none;">
Expand Down
10 changes: 10 additions & 0 deletions includes/gateway/class-omise-payment.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,16 @@ public function protectMetadata($protected, $metadataKeys)
return $protected;
}

/**
* get pending status
*
* This function is crate to get value for pending status,
* since we cannot mock constant values for unit test.
*/
public function get_pending_status() {
return self::STATUS_PENDING;
}

/**
* Register all required javascripts
*/
Expand Down
1 change: 1 addition & 0 deletions includes/libraries/omise-plugin/Omise.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
require_once dirname(__FILE__).'/helpers/request.php';
require_once dirname(__FILE__).'/helpers/token.php';
require_once dirname(__FILE__).'/helpers/RedirectUrl.php';
require_once dirname(__FILE__).'/helpers/file_get_contents_wrapper.php';
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

/**
* file_get_contents wrapper class
*
* Since we cannot mock global function,
* we have to create a wrapper for file_get_contents.
*/
class File_Get_Contents_Wrapper
{
public static function get_contents($url)
{
return file_get_contents($url);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require_once __DIR__ . '/bootstrap-test-setup.php';

class Omise_Payment_Offline_Test extends Bootstrap_Test_Setup
abstract class Omise_Payment_Offline_Test extends Bootstrap_Test_Setup
{
public function setUp(): void
{
Expand Down
80 changes: 80 additions & 0 deletions tests/unit/includes/gateway/class-omise-payment-promptpay-test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

use Mockery\Mock;

class Omise_Payment_Promptpay_Test extends Omise_Payment_Offline_Test
{
public $mockOrder;
public $mockWcDateTime;
public $mockLocalizeScript;
public $mockOmisePluginHelper;
public $mockOmisePaymentOffline;
public $mockOmiseCharge;
public $mockFileGetContent;

public function setUp(): void
{
function wc_timezone_offset() {}
function wp_create_nonce() {}
function admin_url() {}

$this->mockOrder = Mockery::mock();
$this->mockLocalizeScript = Mockery::mock();
$this->mockWcDateTime = Mockery::mock('overload:WC_DateTime');
$this->mockOmisePluginHelper = Mockery::mock('overload:OmisePluginHelperWcOrder')->shouldIgnoreMissing();
$this->mockOmisePaymentOffline = Mockery::mock('overload:Omise_Payment_Offline');
$this->mockOmiseCharge = Mockery::mock('overload:OmiseCharge');
$this->mockFileGetContent = Mockery::mock('overload:File_Get_Contents_Wrapper');

require_once __DIR__ . '/../../../../includes/gateway/class-omise-payment-promptpay.php';
}

/**
* @test
*/
public function textExpiresAtFieldIsPassedToJavascript()
{
$expiresAt = '2023-11-22T14:48:00.000Z';

$this->mockFileGetContent->shouldReceive('get_contents')->once()->andReturn('<svg></svg>');

$this->mockOmisePaymentOffline->shouldReceive('init_settings');
$this->mockOmisePaymentOffline->shouldReceive('get_option');
$this->mockOmisePaymentOffline->shouldReceive('load_order')->andReturn(true);
$this->mockOmisePaymentOffline->shouldReceive('get_charge_id_from_order')->andReturn('charge_xxx');
$this->mockOmisePaymentOffline->shouldReceive('get_pending_status')->andReturn('pending');
$this->mockOmisePaymentOffline->shouldReceive('file_get_contents')->andReturn('');

$this->mockWcDateTime->shouldReceive('set_utc_offset');
$this->mockWcDateTime->shouldReceive('format')->with('c')->andReturn($expiresAt);

$this->mockOmiseCharge->shouldReceive('retrieve')->andReturn([
'status' => 'pending',
'expires_at' => $expiresAt,
'source' => [
'scannable_code' => [
'image' => [
'id' => 1,
'download_uri' => '',
]
]
]
]);

// check that qr_expires_at is passed to `omise-promptpay-count-down` script with omise object
$this->mockLocalizeScript->shouldReceive('call')
->with('omise-promptpay-count-down', 'omise', [
'qr_expires_at' => $expiresAt
]);

$GLOBALS['mock_wp_localize_script'] = $this->mockLocalizeScript;

function wp_localize_script($scriptName, $object, $params) {
return $GLOBALS['mock_wp_localize_script']->call($scriptName, $object, $params);
}

$obj = new Omise_Payment_Promptpay();
$result = $obj->display_qrcode($this->mockOrder, 'view');
$this->assertNull($result);
}
}

0 comments on commit 8722d96

Please sign in to comment.