blob: 23169d86226442f730c017ece2dcac38f37bbc64 [file] [log] [blame]
<!--
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
-->
<!DOCTYPE html>
<html>
<head>
<title>Sample: Payment Records Processor</title>
<style>
body, td, div, span, p {
font-family:arial,sans-serif;
}
body {
padding:0px;
margin:0px;
}
.payment-processor-shadow {
filter: alpha(opacity=30);
-moz-opacity:.3;
opacity:0.3;
background-color:#000;
width:690px;
height:390px;
margin:5px 0px 0px 5px;
position:absolute;
z-index:100;
}
.payment-processor-border1 {
background-color:#E5ECF9;
width:690px;
height:390px;
position:absolute;
z-index:200;
}
.payment-processor-border2 {
background-color:#FFF;
margin:5px;
height:380px;
}
.payment-processor-content {
padding:20px;
font-size:13px;
}
.payment-processor-content #loading-tab {
color:#777;
}
.caption {
font-weight:bold;
width:80px;
display:inline;
}
.desc {
color:#007F00;
}
.head {
font-weight:bold;
}
</style>
<script type="text/javascript">
/**
* @static
* @class A sample records processor panel provides the UI and logic for the real records fetching
* and fixing requests to container api server.
*
* NOTE:
*
* All functions or logics or names in this page are customizable. Indeed containers have
* to customize them to make the UI consistent. This sample panel page is embeded in the
* parent container page as an iframe for better code structure, but indeed it is not
* necessary. It can be on the same page as container page.
*
* You can implement their processor panel page using this file but replace the UI and
* mock codes, or use your completely own codes. If you use your own page, just to make
* sure <code>shindig.paymentprocessor.initPaymentRecords</code> function is called with
* necessary callbacks (open and close event handlers) passed in when initializing the
* page.
*
*/
var myRecordsProcessorPanel = (function() {
/** Element which holding this processor panel page in parent window. */
var parentDiv;
/** Just a reference to <code>shindig.paymentprocessor</code> object, which holding necessary
parameters needed in the payment process */
var processor;
/**
* Called by <code>shindig.paymentprocessor</code> when the counter
* panel is closing.
*/
function closeEvent() {
// Set the div in the parent window to invisible.
parentDiv.style.display = 'none';
};
/**
* Draws the pay counter panel UI itself.
* (NOTE that this page is a iframe in its parent container window);
* Assigns the submit callback and cancel callback to the buttons.
* So from this panel, submit or cancel actions can be made.
*
* @param {Object} paymentJson The payment parameters.
* @param {Object} extraParams The extra parameters for the payment
* procedure, including handler url, app title and spec.
* @param {Function} submitCallback The submit callback in
* <code>shindig.paymentprocessor</code>.
* @param {Function} cancelCallback The cancel callback in
* <code>shindig.paymentprocessor</code>.
*/
function openEvent() {
// Set the div in the parent window to visible.
parentDiv.style.display = 'block';
document.getElementById('payment-appname').innerHTML = processor.getParam('appTitle');
document.getElementById('payment-appspec').innerHTML = processor.getParam('appSpec');
document.getElementById('payment-records-close').onclick = cancelHandler;
// The requestData is going to post to server.
var requestData = {
'appSpec' : processor.getParam('appSpec'),
'appTitle' : processor.getParam('appTitle'),
'st' : processor.getParam('stoken'), // or other security token if needed
'params' : processor.getParam('reqParams'),
'sandbox': processor.getParam('reqParams.sandbox')
};
//////////////////////////////////////////////////////////////////////////////////////
// Here the logic should be on container sever for fetching payment records. //
// See the proposal doc Rivision#4. //
//////////////////////////////////////////////////////////////////////////////////////
var sendFetchPaymentRecordsRequest = function(ajaxCallback) {
// The Server will fetch data from it's own database then response.
// Here is just a fake call. You should replace these codes with actual ajax.
// Wait 1 second to simulate the network connection.
window.setTimeout(function() {
// Get the payment records in database by querying with appSpec. Here uses mock data.
var mockData = [
{
'orderId' : 'ORDER_ID_FROM_APP_' + Math.round(Math.random() * 10000),
'items': [
{'skuId':'1234', 'price':'10', 'count': 5, 'description':'this is fake.'},
{'skuId':'2345', 'price':'11', 'count': 7, 'description':'this is fake2.'}
],
'amount': 127,
'message': 'Fake message',
'paymentType': 'payment',
'orderedTime': new Date().getTime(),
'submittedTime': new Date().getTime(),
'executedTime': new Date().getTime(),
'responseCode': 'OK',
'responseMessage': 'Payment done.',
'paymentComplete': true,
'sandbox': !!requestData['sandbox']
}, {
'orderId' : 'ORDER_ID_FROM_APP_' + Math.round(Math.random() * 10000),
'items': [
{'skuId':'3456', 'price':'5', 'count': 30, 'description':'this is fake3.'},
{'skuId':'6789', 'price':'100', 'count': 1, 'description':'this is fake4.'}
],
'amount': 250,
'message': 'Fake message2',
'paymentType': 'payment',
'orderedTime': new Date().getTime(),
'submittedTime': new Date().getTime(),
'executedTime': new Date().getTime(),
'responseCode': 'APP_LOGIC_ERROR',
'responseMessage': 'Payment failed on app.',
'paymentComplete': false,
'sandbox': !!requestData['sandbox']
}, {
'orderId' : 'ORDER_ID_FROM_APP_' + Math.round(Math.random() * 10000),
'items': [
{'skuId':'abcd', 'price':'3', 'count': 3, 'description':'this is fake5.'},
{'skuId':'efgh', 'price':'12', 'count': 4, 'description':'this is fake6.'}
],
'amount': 57,
'message': 'Fake message3',
'paymentType': 'payment',
'orderedTime': new Date().getTime(),
'submittedTime': new Date().getTime(),
'executedTime': new Date().getTime(),
'responseCode': 'PAYMENT_ERROR',
'responseMessage': 'Payment failed on container.',
'paymentComplete': false,
'sandbox': !!requestData['sandbox']
}
];
var max = Number(requestData['params']['max']);
if (!max) {
max = 3 // If not set or incorrectly set, set default value.
}
ajaxCallback(mockData.slice(0, max));
}, 1000);
};
////////////////////////////////////////////////////////////////////////////////////
// Send ajax request
document.getElementById('loading-tab').style.display = 'block';
sendFetchPaymentRecordsRequest(function(responseData) {
document.getElementById('loading-tab').style.display = 'none';
var records = processor.getParam('records.payments');
var incompleteIds = [];
// Generate the payment records table UI
var html = '<table border=1><tbody><tr class="head">' +
'<td>Amount</td><td>Message</td><td>SubmittedTime</td>' +
'<td>ResponseCode</td><td>ExecutedTime</td>'+
'</tr>';
for (var i = 0; i < responseData.length; i++) {
var paymentJson = responseData[i];
var orderId = paymentJson['orderId'];
html += '<tr><td>' + paymentJson['amount'] + '</td>' +
'<td>' + paymentJson['message'] + '</td>' +
'<td>' + new Date(paymentJson['submittedTime']).toLocaleString() + '</td>' +
'<td>' + paymentJson['responseCode'] + '</td>' +
'<td id=\'td_' + orderId + '\'>';
if (!paymentJson['paymentComplete']) {
// Show a 'FixIt' button for non-complete payment with ID equals orderId.
html += '<button id=\'' + orderId + '\'>FixIt</button>';
// Add the incompletes to records.
records[orderId] = paymentJson;
incompleteIds.push(orderId);
} else {
html += new Date(paymentJson['executedTime']).toLocaleString();
}
html += '</td></tr>';
}
html += '</tbody></table>';
document.getElementById('payment-records').innerHTML = html;
// Assign onclick handler's for incomplete payments.
for (var j = 0; j < incompleteIds.length; j++) {
document.getElementById(incompleteIds[j]).onclick = submitHandler;
}
});
};
/**
* Called by submit button clicked by the user.
*
* This function should send the payment fixing request to container virtual currency
* api with Ajax POST.
*/
function submitHandler() {
var orderId = this.id;
var requestData = {
'appSpec' : processor.getParam('appSpec'),
'appTitle' : processor.getParam('appTitle'),
'st' : processor.getParam('stoken'), // or other security token
'orderId' : orderId,
'sandbox': processor.getParam('reqParams.sandbox')
};
//////////////////////////////////////////////////////////////////////////////////////
// Here the logic should be on container sever for updating an incomplete payment. //
// See the proposal doc Rivision#4. //
//////////////////////////////////////////////////////////////////////////////////////
var sendFixPaymentRecordRequest = function(ajaxCallback) {
// The Server will communicate with App Backend Server then response.
// Here is just a fake call.
// Wait 1 second to simulate the network connection.
window.setTimeout(function() {
// let say it will always succeed.
var responseData = {};
// Simulate success response.
responseData['paymentComplete'] = true;
responseData['executedTime'] = new Date().getTime();
responseData['responseCode'] = 'OK';
if (!!requestData['sandbox']) {
responseData['responseMessage'] = 'Fake success response in sandbox!';
} else {
responseData['responseMessage'] = 'Fake success response!';
}
ajaxCallback(responseData);
}, 1000);
};
/////////////////////////////////////////////////////////////////////////////////////
// Send ajax request
document.getElementById('loading-tab').style.display = 'block';
sendFixPaymentRecordRequest(function(responseData) {
document.getElementById('loading-tab').style.display = 'none';
if (responseData['responseCode'] != 'OK') {
// something fail, display exception message and let user try again.
document.getElementById(orderId).innerHTML = 'Try again';
return;
}
// If fixing request succeeded, replay the button with payment executed time.
document.getElementById('td_' + orderId).innerHTML =
new Date(responseData['executedTime']).toLocaleString();
// Updates the payment json object in the records.
var paymentJson = processor.getParam('records.payments.' + orderId);
paymentJson['paymentComplete'] = true;
paymentJson['executedTime'] = responseData['executedTime'];
paymentJson['responseCode'] = responseData['responseCode'];
paymentJson['responseMessage'] = responseData['responseMessage'];
});
};
/**
* Invoked when cancel button clicked by user. Closes the processor.
*/
function cancelHandler() {
// You can also show a message to say the order is canceled.
// Here just call the callback and return.
processor.setParam('records.responseCode', 'OK');
processor.closePaymentRecords();
};
return {
/**
* Initializes the counter module. It can be called by this page's <code>body.onload()</code>
* function or in other initializing steps.
* Note the <code>shindig.paymentprocessor</code> object is passed from the parent window.
*/
init: function() {
// Store the parent node in which there is an iframe holding this page.
parentDiv = window.frameElement.parentNode;
processor = parent.shindig.paymentprocessor;
// Initialize the paymentprocessor module with four events.
// The container need to fully implement these event functions for
// UI/Backend interaction.
processor.initPaymentRecords(openEvent, closeEvent);
}
};
})();
</script>
</head>
<body onload="myRecordsProcessorPanel.init();">
<!-- Customize the UI -->
<div class="payment-processor-shadow"></div>
<div class="payment-processor-border1">
<div class="payment-processor-border2">
<div class="payment-processor-content">
<p class="desc">
This panel is in an iframe from another page in the same container domain:<br>
<b><script>document.write(window.location.href);</script></b>
</p>
<div class="caption">App Name: </div><span id="payment-appname"></span><br>
<div class="caption">App Spec: </div><span id="payment-appspec"></span><br>
<p id="payment-records"></p>
<div id="button-tab">
<button id="payment-records-close">Close</button>
</div>
<div id="loading-tab" style="display:none">Please wait...</div>
</div>
</div>
</div>
</body>
</html>