[MIG] pos_pax: Rewrite for Odoo 14.0 + Owl

This commit is contained in:
Jared Kipe
2020-11-15 15:07:02 -08:00
parent ad2f9393ab
commit afbdd85c70
18 changed files with 1179 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
.pos .paymentline.selected.o_pos_pax_txn_pending, .pos .paymentline.o_pos_pax_txn_pending {
background: rgb(239, 153, 65);
}
.pos .col-tendered.edit.o_pos_pax_txn_pending {
color: rgb(239, 153, 65);
box-shadow: 0px 0px 0px 3px rgb(239, 153, 65);
}
.pos .paymentline .pax-send-transaction-button {
cursor: pointer !important;
border: 1px solid rgba(255, 255, 255, 0.5);
background-color: rgba(255,255,255, 0.2);
display: block;
text-align: center;
margin: 6px 0 0 0;
padding: 2px 5px;
}

View File

@@ -0,0 +1,183 @@
odoo.define('pos_pax.PAXPaymentScreen', function (require) {
'use strict';
// Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
const { _t } = require('web.core');
const PaymentScreen = require('point_of_sale.PaymentScreen');
const Registries = require('point_of_sale.Registries');
const { useListener } = require('web.custom_hooks');
const PAX = require('pos_pax.pax_device');
PAX.mDestinationIP = '';
const PAXPaymentScreen = (PaymentScreen) =>
class extends PaymentScreen {
constructor() {
super(...arguments);
// tempting to use 'send-payment-request',
// but method implements things that don't seem to exist yet (payment_method.payment_terminal)
useListener('pax-send-payment-request', this._sendPAXPaymentRequest);
}
async _sendPAXPaymentRequest({ detail: line }) {
this.pax_credit_transaction(line);
}
pax_credit_transaction(line) {
var order = this.env.pos.get_order();
if(this.env.pos.getPAXOnlinePaymentJournals().length === 0) {
return;
}
var self = this;
var transaction = {};
var purchase_amount = line.get_amount();
var transactionType = '01'; // SALE
if (purchase_amount < 0.0) {
purchase_amount = -purchase_amount;
transactionType = '02'; // RETURN
}
transaction = {
command: 'T00',
version: '1.28',
transactionType: transactionType,
amountInformation: {
TransactionAmount: (purchase_amount * 100) | 0, // cast to integer
},
cashierInformation: {
ClerkID: this.env.pos.user.name,
},
traceInformation: {
ReferenceNumber: self.env.pos.get_order().uid,
// InvoiceNumber: self.env.pos.get_order().uid,
},
}
var def = new $.Deferred();
// show the transaction popup.
// the transaction deferred is used to update transaction status
self.showPopup('PAXPaymentTransactionPopup', {
transaction: def
});
def.notify({
message: _t('Handling transaction...'),
});
PAX.mDestinationIP = self.env.pos.config.pax_endpoint;
PAX.DoCredit(transaction, function (response) {
console.log(response);
var parsed_response = self.env.pos.decodePAXResponse(response);
if (parsed_response.fail) {
def.resolve({message: parsed_response.fail})
return;
}
if (parsed_response.success) {
line.paid = true;
line.pax_card_number = parsed_response.card_num;
line.pax_txn_id = parsed_response.txn_id;
line.pax_approval = parsed_response.approval;
line.pax_txn_pending = false;
line.set_credit_card_name();
order.trigger('change', order);
self.render();
def.resolve({message: 'Approval ' + parsed_response.approval, auto_close: true})
}
def.resolve({message: _t('Unknown response.')})
}, function (fail){
def.resolve({message: _t('Communication Failure: ') + fail});
});
}
pax_do_reversal(line) {
var def = new $.Deferred();
var self = this;
var transaction = {};
// show the transaction popup.
// the transaction deferred is used to update transaction status
this.showPopup('PAXPaymentTransactionPopup', {
transaction: def
});
def.notify({
message: 'Sending reversal...',
});
transaction = {
command: 'T00',
version: '1.28',
transactionType: (line.get_amount() > 0) ? '17' : '18', // V/SALE, V/RETURN
cashierInformation: {
ClerkID: this.env.pos.user.name,
},
traceInformation: {
ReferenceNumber: this.env.pos.get_order().uid,
InvoiceNumber: '',
AuthCode: line.pax_approval,
TransactionNumber: line.pax_txn_id,
},
}
PAX.mDestinationIP = self.env.pos.config.pax_endpoint;
PAX.DoCredit(transaction, function (response) {
var parsed_response = self.env.pos.decodePAXResponse(response);
if (parsed_response.fail) {
def.resolve({message: parsed_response.fail})
return;
}
if (parsed_response.success) {
def.resolve({
message: _t('Reversal succeeded.'),
auto_close: true,
});
self.remove_paymentline_by_ref(line);
return;
}
def.resolve({message: _t('Unknown response.')})
}, function (fail){
def.resolve({message: _t('Communication Failure: ') + fail});
});
}
remove_paymentline_by_ref(line) {
this.env.pos.get_order().remove_paymentline(line);
this.render();
}
/**
* @override
*/
deletePaymentLine(event) {
const { cid } = event.detail;
const line = this.paymentLines.find((line) => line.cid === cid);
if (line.pax_txn_id) {
this.pax_do_reversal(line);
} else {
super.deletePaymentLine(event);
}
}
/**
* @override
*/
addNewPaymentLine({ detail: paymentMethod }) {
const order = this.env.pos.get_order();
const res = super.addNewPaymentLine(...arguments);
if (res && paymentMethod.use_payment_terminal == 'pax') {
order.selected_paymentline.pax_txn_pending = true;
order.trigger('change', order);
this.render();
}
}
};
Registries.Component.extend(PaymentScreen, PAXPaymentScreen);
return PAXPaymentScreen;
});

View File

@@ -0,0 +1,32 @@
odoo.define('pos_pax.PAXPaymentScreenPaymentLines', function (require) {
'use strict';
// Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
const PaymentScreenPaymentLines = require('point_of_sale.PaymentScreenPaymentLines');
const Registries = require('point_of_sale.Registries');
const PAXPaymentLines = (PaymentScreenPaymentLines) =>
class extends PaymentScreenPaymentLines {
/**
* @override
*/
selectedLineClass(line) {
return Object.assign({}, super.selectedLineClass(line), {
o_pos_pax_txn_pending: line.pax_txn_pending,
});
}
/**
* @override
*/
unselectedLineClass(line) {
return Object.assign({}, super.unselectedLineClass(line), {
o_pos_pax_txn_pending: line.pax_txn_pending,
});
}
};
Registries.Component.extend(PaymentScreenPaymentLines, PAXPaymentLines);
return PAXPaymentLines;
});

View File

@@ -0,0 +1,39 @@
odoo.define('pos_pax.PAXPaymentTransactionPopup', function(require) {
'use strict';
// Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
const { useState } = owl.hooks;
const AbstractAwaitablePopup = require('point_of_sale.AbstractAwaitablePopup');
const Registries = require('point_of_sale.Registries');
class PAXPaymentTransactionPopup extends AbstractAwaitablePopup {
constructor() {
super(...arguments);
this.state = useState({ message: '', confirmButtonIsShown: false });
this.props.transaction.then(data => {
if (data.auto_close) {
setTimeout(() => {
this.confirm();
}, 2000)
} else {
this.state.confirmButtonIsShown = true;
}
this.state.message = data.message;
}).progress(data => {
this.state.message = data.message;
})
}
}
PAXPaymentTransactionPopup.template = 'PAXPaymentTransactionPopup';
PAXPaymentTransactionPopup.defaultProps = {
confirmText: 'Ok',
cancelText: 'Cancel',
title: 'PAX Online Payment',
body: '',
};
Registries.Component.add(PAXPaymentTransactionPopup);
return PAXPaymentTransactionPopup;
});

133
pos_pax/static/src/js/jquery_base64.js vendored Normal file
View File

@@ -0,0 +1,133 @@
odoo.define('pos_pax.jquery_base64', function (require) {
"use strict";
// Hibou Corp. © 2020 - Wrapped library for PAX Device
var jQuery = window.jQuery;
/*!
* jquery.base64.js 0.1 - https://github.com/yckart/jquery.base64.js
* Makes Base64 en & -decoding simpler as it is.
*
* Based upon: https://gist.github.com/Yaffle/1284012
*
* Copyright (c) 2012 Yannick Albert (http://yckart.com)
* Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php).
* 2013/02/10
**/
;(function ($) {
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
a256 = '',
r64 = [256],
r256 = [256],
i = 0;
var UTF8 = {
/**
* Encode multi-byte Unicode string into utf-8 multiple single-byte characters
* (BMP / basic multilingual plane only)
*
* Chars in range U+0080 - U+07FF are encoded in 2 chars, U+0800 - U+FFFF in 3 chars
*
* @param {String} strUni Unicode string to be encoded as UTF-8
* @returns {String} encoded string
*/
encode: function (strUni) {
// use regular expressions & String.replace callback function for better efficiency
// than procedural approaches
var strUtf = strUni.replace(/[\u0080-\u07ff]/g, // U+0080 - U+07FF => 2 bytes 110yyyyy, 10zzzzzz
function (c) {
var cc = c.charCodeAt(0);
return String.fromCharCode(0xc0 | cc >> 6, 0x80 | cc & 0x3f);
})
.replace(/[\u0800-\uffff]/g, // U+0800 - U+FFFF => 3 bytes 1110xxxx, 10yyyyyy, 10zzzzzz
function (c) {
var cc = c.charCodeAt(0);
return String.fromCharCode(0xe0 | cc >> 12, 0x80 | cc >> 6 & 0x3F, 0x80 | cc & 0x3f);
});
return strUtf;
},
/**
* Decode utf-8 encoded string back into multi-byte Unicode characters
*
* @param {String} strUtf UTF-8 string to be decoded back to Unicode
* @returns {String} decoded string
*/
decode: function (strUtf) {
// note: decode 3-byte chars first as decoded 2-byte strings could appear to be 3-byte char!
var strUni = strUtf.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars
function (c) { // (note parentheses for precence)
var cc = ((c.charCodeAt(0) & 0x0f) << 12) | ((c.charCodeAt(1) & 0x3f) << 6) | (c.charCodeAt(2) & 0x3f);
return String.fromCharCode(cc);
})
.replace(/[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars
function (c) { // (note parentheses for precence)
var cc = (c.charCodeAt(0) & 0x1f) << 6 | c.charCodeAt(1) & 0x3f;
return String.fromCharCode(cc);
});
return strUni;
}
};
while (i < 256) {
var c = String.fromCharCode(i);
a256 += c;
r256[i] = i;
r64[i] = b64.indexOf(c);
++i;
}
function code(s, discard, alpha, beta, w1, w2) {
s = String(s);
var buffer = 0,
i = 0,
length = s.length,
result = '',
bitsInBuffer = 0;
while (i < length) {
var c = s.charCodeAt(i);
c = c < 256 ? alpha[c] : -1;
buffer = (buffer << w1) + c;
bitsInBuffer += w1;
while (bitsInBuffer >= w2) {
bitsInBuffer -= w2;
var tmp = buffer >> bitsInBuffer;
result += beta.charAt(tmp);
buffer ^= tmp << bitsInBuffer;
}
++i;
}
if (!discard && bitsInBuffer > 0) result += beta.charAt(buffer << (w2 - bitsInBuffer));
return result;
}
var Plugin = $.base64 = function (dir, input, encode) {
return input ? Plugin[dir](input, encode) : dir ? null : this;
};
Plugin.btoa = Plugin.encode = function (plain, utf8encode) {
plain = Plugin.raw === false || Plugin.utf8encode || utf8encode ? UTF8.encode(plain) : plain;
plain = code(plain, false, r256, b64, 8, 6);
return plain + '===='.slice((plain.length % 4) || 4);
};
Plugin.atob = Plugin.decode = function (coded, utf8decode) {
coded = String(coded).split('=');
var i = coded.length;
do {
--i;
coded[i] = code(coded[i], true, r64, a256, 6, 8);
} while (i > 0);
coded = coded.join('');
return Plugin.raw === false || Plugin.utf8decode || utf8decode ? UTF8.decode(coded) : coded;
};
}(jQuery));
return jQuery;
});

View File

@@ -0,0 +1,479 @@
odoo.define('pos_pax.pax_device', function (require) {
"use strict";
var $ = require('pos_pax.jquery_base64');
// Hibou Corp. © 2020 - Wrapped library for PAX Device
// Additions and Fixes:
// 2020-11-12 Fixed variable i and ii in getLRC
// 2020-11-12 Fixed/added 'fail' mechanisms for XHR
//HEX TO BASE64
function hexToBase64(str) {
return $.base64.btoa(String.fromCharCode.apply(null,
str.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" "))
);
}
//BASE64 TO HEX
function base64ToHex(str) {
for (var i = 0, bin = $.base64.atob(str), hex = []; i < bin.length; ++i) {
var tmp = bin.charCodeAt(i).toString(16);
if (tmp.length === 1) tmp = "0" + tmp;
hex[hex.length] = tmp;
}
return hex.join(" ");
}
function StringToHex(response){
var responseHex = "";
for(var i=0; i<response.length; i++){
if(responseHex == "")
responseHex = response.charCodeAt(i).toString(16).length<2?'0'+response.charCodeAt(i).toString(16):response.charCodeAt(i).toString(16);
else
responseHex += response.charCodeAt(i).toString(16).length<2?" " + '0'+response.charCodeAt(i).toString(16):" " + response.charCodeAt(i).toString(16);
}
return responseHex;
}
function HexToString(response){
var responseHex = "";
var arr = response.split(" ");
for(var i=0; i<arr.length; i++){
if(arr[i] == "")
continue;
responseHex += String.fromCharCode(parseInt(arr[i],16));
}
return responseHex;
}
var PAX = {
//IP of the POS
mDestinationIP : "http://127.0.0.1:10009", // - OLD "http://192.167.2.100:10009"; //http://112.199.49.146:8181
mStx : {
hex: 0x02,
code: "02"
},
mFS : {
hex : 0x1c,
code : "1c"
},
mEtx : {
hex : 0x03,
code : "03"
},
mUS : {
hex : 0x1F,
code : "1F"
},
//var _this : this;
customData : '',
timeout : {
"Initialize":120*1000,
"GetSignature":120*1000,
"DoSignature":120*1000,
"DoCredit":120*1000
},
//Set ip and port
Settings : function(ip,port){
this.mDestinationIP = "http://" + ip + ":" + port;
console.log("New service address: "+this.mDestinationIP);
},
AjaxTimeOut : function(command,timeout){
this.timeout[command]= timeout;
},
SetCustomData : function(custom_data){
this.customData = custom_data;
console.log(custom_data);
},
//Get LRC
getLRC : function(params){
var lrc = 0;
for(var i=1; i< params.length; i++){
var type_of = typeof(params[i]);
if(type_of == "string"){
var element = params[i].split("");
for(var ii=0; ii<element.length; ii++){
lrc ^= element[ii].charCodeAt(0);
}
}else{
lrc ^= params[i];
}
}
return (lrc>0)?String.fromCharCode(lrc):0;
},
//Connect to the server
HttpCommunication : function(commandType,url,callback,timeout,fail){
var xhr = null;
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
try{
xhr = new ActiveXObject('Microsoft.XMLHttp');
}catch(e){
xhr = new ActiveXObject('msxml2.xmlhttp');
}
}
//get
xhr.open("GET", url,true);
xhr.onreadystatechange=function(){
if(xhr.readyState==4) {
//alert(xhr.status);
if(xhr.status==200) {
var response = xhr.responseText;
console.log("Raw response: "+response);
var checkParams = StringToHex(response).split(" ").pop();
var RedundancyCheck = StringToHex(response).split(" ").pop().substring(1);
var check = PAX.getLRC(checkParams);
if(check == RedundancyCheck){
//get package detail info
var packetInfo = [];
var len = StringToHex(response).indexOf("03");
var hex = StringToHex(response).slice(0,len).split(/02|1c/);
console.log(hex);
if(commandType == "DoCredit"){
var subHex=[], subPacketInfo=[];
for(var i=0; i<hex.length; i++){
if(hex[i] != ""){
if(hex[i].indexOf("1f")>0){
subHex = hex[i].split("1f");
console.log(subHex);
subPacketInfo = [];
for(var j=0; j<subHex.length; j++){
if(subHex[j]!=''){
subPacketInfo.push(HexToString(subHex[j]));
}
}
console.log(subPacketInfo);
packetInfo.push(subPacketInfo);
}else{
packetInfo[i] = HexToString(hex[i]);
}
}
}
}else{
for(var i=0; i<hex.length; i++){
if(hex[i] != ""){
packetInfo[i] = HexToString(hex[i]);
}
}
}
console.log("Separate package info: ");
console.log(packetInfo);
callback(packetInfo);
}
} else {
if(fail) {
fail(xhr.status);
}
}
}
};
xhr.send(null);
},
Initialize : function(initialInfo,callback,fail){
var params = [this.mStx.hex,initialInfo.command,this.mFS.hex, initialInfo.version, this.mEtx.hex];
//[02]A08[1c]1.28[1c]0[1c]90000[03]
//var params = [0x02,"A08",0x1c,"1.28",0x1c, "0", 0x1c,"90000",0x03];
var lrc = this.getLRC(params);
var command_hex = base64ToHex($.base64.btoa(initialInfo.command));
var version_hex = base64ToHex($.base64.btoa(initialInfo.version));
//var elements = [this.mStx, command_hex, this.mFS, version_hex, this.mEtx, base64ToHex($.base64.btoa(lrc))];
var elements = [this.mStx.code, command_hex, this.mFS.code, version_hex, this.mEtx.code, base64ToHex($.base64.btoa(lrc))];
var final_string = elements.join(" ");
//console.log("final_string: " + final_string);
var final_b64 = hexToBase64(final_string);
console.log("LRC: " + lrc);
console.log("Base64: " + final_b64);
var url = this.mDestinationIP + '?' + final_b64;
console.log("URL: " + url);
this.HttpCommunication('Initialize',url,function(response){
callback(response);
},PAX.timeout.Initialize,fail);
},
//GET SIGNATURE
GetSignature : function(getSignatureInfo,callback,fail){
var params = [this.mStx.hex,getSignatureInfo.command,this.mFS.hex,getSignatureInfo.version,this.mFS.hex, getSignatureInfo.offset, this.mFS.hex,getSignatureInfo.requestlength,this.mEtx.hex];
var lrc = this.getLRC(params);
//prepare for base64 encoding.
var command_hex = base64ToHex($.base64.btoa(getSignatureInfo.command));
var version_hex = base64ToHex($.base64.btoa(getSignatureInfo.version));
var offset_hex = base64ToHex($.base64.btoa(getSignatureInfo.offset));
var requestlength_hex = base64ToHex($.base64.btoa(getSignatureInfo.requestlength));
//var elements = [this.mStx.code, command_hex, this.mFS.code, version_hex, this.mFS.code, offset_hex, this.mFS.code, requestlength_hex, this.mEtx.code, base64ToHex($.base64.btoa(lrc))];
var elements = [this.mStx.code];
elements.push(command_hex);
elements.push(this.mFS.code);
elements.push(version_hex);
elements.push(this.mFS.code);
if(offset_hex != ''){
elements.push(offset_hex);
}
elements.push(this.mFS.code);
if(requestlength_hex != ''){
elements.push(requestlength_hex);
}
elements.push(this.mEtx.code);
elements.push(base64ToHex($.base64.btoa(lrc)));
var final_string = elements.join(" ");
var final_b64 = hexToBase64(final_string);
console.log("LRC: " + lrc);
console.log("Base64: " + final_b64);
var url = this.mDestinationIP + '?' + final_b64;
console.log("URL: " + url);
this.HttpCommunication('GetSignature',url,function(response){
callback(response);
},PAX.timeout.GetSignature,fail);
},
//DO SIGNATURE
DoSignature : function(doSignatureInfo,callback,fail){
var params = [this.mStx.hex,doSignatureInfo.command, this.mFS.hex, doSignatureInfo.version, this.mFS.hex, doSignatureInfo.uploadFlag, this.mFS.hex,doSignatureInfo.hostReferenceNumber, this.mFS.hex, doSignatureInfo.edcType, this.mFS.hex, doSignatureInfo.timeout, this.mEtx.hex];
var lrc = this.getLRC(params);
//prepare for base64 encoding.
var command_hex = base64ToHex($.base64.btoa(doSignatureInfo.command));
var version_hex = base64ToHex($.base64.btoa(doSignatureInfo.version));
var uploadFlag_hex = base64ToHex($.base64.btoa(doSignatureInfo.uploadFlag));
var hostReferenceNumber_hex = base64ToHex($.base64.btoa(doSignatureInfo.hostReferenceNumber));
var edcType_hex = base64ToHex($.base64.btoa(doSignatureInfo.edcType));
var timeout_hex = base64ToHex($.base64.btoa(doSignatureInfo.timeout));
var elements = [this.mStx.code];
elements.push(command_hex);
elements.push(this.mFS.code);
elements.push(version_hex);
elements.push(this.mFS.code);
if(uploadFlag_hex != ''){
elements.push(uploadFlag_hex);
}
elements.push(this.mFS.code);
if(hostReferenceNumber_hex != ''){
elements.push(hostReferenceNumber_hex);
}
elements.push(this.mFS.code);
if(edcType_hex != ''){
elements.push(edcType_hex);
}
elements.push(this.mFS.code);
if(timeout_hex != ''){
elements.push(timeout_hex);
}
elements.push(this.mEtx.code);
elements.push(base64ToHex($.base64.btoa(lrc)));
var final_string = elements.join(" ");
var final_b64 = hexToBase64(final_string);
console.log("LRC: " + lrc);
console.log("Base64: " + final_b64);
var url = this.mDestinationIP + '?' + final_b64;
console.log("URL: " + url);
this.HttpCommunication('DoSignature',url,function(response){
callback(response);
},PAX.timeout.DoSignature,fail);
},
PushParams : function(params,type,objectInfo){
var empty = 0;
var arr = [];
arr = arr.concat(params);
for(name in objectInfo){
if(objectInfo[name] == '' && type!="additionalInformation")
{
arr.push(this.mUS.hex);
continue;
}
if(type == "additionalInformation"){
if(objectInfo[name] == ''){
continue;
}
empty++;
arr.push(name+"="+objectInfo[name].toString());
}else{
empty++;
arr.push(objectInfo[name].toString());
}
arr.push(this.mUS.hex);
}
arr.pop();
if(empty==0 && type!="additionalInformation"){
arr = params;
}
if(empty==0 && type=="additionalInformation"){
arr.push(this.mFS.hex);
}
//console.log(params);
return arr;
},
AddBase64 : function(elements,type,objectInfo){
//console.log(objectInfo);
var empty = 0;
var arr = [];
arr = arr.concat(elements);
for(name in objectInfo){
if(objectInfo[name] == '' && type!="additionalInformation")
{
arr.push(this.mUS.code);
continue;
}
if(type == "additionalInformation"){
if(objectInfo[name] == '')
continue;
empty++;
arr.push(base64ToHex($.base64.btoa(name+"="+objectInfo[name].toString())));
}else{
empty++;
arr.push(base64ToHex($.base64.btoa(objectInfo[name].toString())));
}
arr.push(this.mUS.code);
}
arr.pop();
if(empty==0 && type!="additionalInformation"){
arr = elements;
}
if(empty==0 && type=="additionalInformation"){
arr.push(this.mFS.code);
}
//console.log(arr);
return arr;
},
//DO Credit
DoCredit : function(doCreditInfo,callback,fail){
var amountInformation,accountInformation,traceInformation,avsInformation,cashierInformation,commercialInformation,motoEcommerce,additionalInformation;
var params = [this.mStx.hex,doCreditInfo.command, this.mFS.hex, doCreditInfo.version];
params.push(this.mFS.hex);
if(doCreditInfo.transactionType != ''){
params.push(doCreditInfo.transactionType);
}
params.push(this.mFS.hex);
params = this.PushParams(params,"amountInformation",doCreditInfo.amountInformation);
params.push(this.mFS.hex);
params = this.PushParams(params,"accountInformation",doCreditInfo.accountInformation);
params.push(this.mFS.hex);
params = this.PushParams(params,"traceInformation",doCreditInfo.traceInformation);
params.push(this.mFS.hex);
params = this.PushParams(params,"avsInformation",doCreditInfo.avsInformation);
params.push(this.mFS.hex);
params = this.PushParams(params,"cashierInformation",doCreditInfo.cashierInformation);
params.push(this.mFS.hex);
params = this.PushParams(params,"commercialInformation",doCreditInfo.commercialInformation);
params.push(this.mFS.hex);
params = this.PushParams(params,"motoEcommerce",doCreditInfo.motoEcommerce);
params.push(this.mFS.hex);
params = this.PushParams(params,"additionalInformation",doCreditInfo.additionalInformation);
params.push(this.mEtx.hex);
var lrc = this.getLRC(params);
console.log(params);
//prepare for base64 encoding.
var command_hex = base64ToHex($.base64.btoa(doCreditInfo.command));
var version_hex = base64ToHex($.base64.btoa(doCreditInfo.version));
var transactionType_hex = base64ToHex($.base64.btoa(doCreditInfo.transactionType));
var amountInformation_hex = base64ToHex($.base64.btoa(doCreditInfo.amountInformation));
var accountInformation_hex = base64ToHex($.base64.btoa(doCreditInfo.accountInformation));
var traceInformation_hex = base64ToHex($.base64.btoa(doCreditInfo.traceInformation));
var avsInformation_hex = base64ToHex($.base64.btoa(doCreditInfo.avsInformation));
var cashierInformation_hex = base64ToHex($.base64.btoa(doCreditInfo.cashierInformation));
var commercialInformation_hex = base64ToHex($.base64.btoa(doCreditInfo.commercialInformation));
var motoEcommerce_hex = base64ToHex($.base64.btoa(doCreditInfo.motoEcommerce));
var additionalInformation_hex = base64ToHex($.base64.btoa(doCreditInfo.additionalInformation));
//var elements = [this.mStx.code, command_hex, this.mFS.code, version_hex, this.mFS.code, uploadFlag_hex, this.mFS.code, timeout, this.mEtx.code, base64ToHex($.base64.btoa(lrc))];
var elements = [this.mStx.code];
elements.push(command_hex);
elements.push(this.mFS.code);
elements.push(version_hex);
elements.push(this.mFS.code);
if(transactionType_hex != ''){
elements.push(transactionType_hex);
}
elements.push(this.mFS.code);
elements = this.AddBase64(elements,"amountInformation",doCreditInfo.amountInformation);
elements.push(this.mFS.code);
elements = this.AddBase64(elements,"accountInformation",doCreditInfo.accountInformation);
elements.push(this.mFS.code);
elements = this.AddBase64(elements,"traceInformation",doCreditInfo.traceInformation);
elements.push(this.mFS.code);
elements = this.AddBase64(elements,"avsInformation",doCreditInfo.avsInformation);
elements.push(this.mFS.code);
elements = this.AddBase64(elements,"cashierInformation",doCreditInfo.cashierInformation);
elements.push(this.mFS.code);
elements = this.AddBase64(elements,"commercialInformation",doCreditInfo.commercialInformation);
elements.push(this.mFS.code);
elements = this.AddBase64(elements,"motoEcommerce",doCreditInfo.motoEcommerce);
elements.push(this.mFS.code);
elements = this.AddBase64(elements,"additionalInformation",doCreditInfo.additionalInformation);
elements.push(this.mEtx.code);
elements.push(base64ToHex($.base64.btoa(lrc)));
console.log("elements");
console.log(elements);
var final_string = elements.join(" ");
var final_b64 = hexToBase64(final_string);
console.log("LRC: " + lrc);
console.log("Base64: " + final_b64);
// if(customData != ''){
// final_b64 = hexToBase64(final_string+"&custom_data=<PAX>"+customData+"</PAX>");
// }
var url = this.mDestinationIP + '?' + final_b64;
console.log("URL: " + url);
this.HttpCommunication('DoCredit',url,function(response){
callback(response);
},PAX.timeout.DoCredit,fail);
}
};
return PAX;
});

View File

@@ -0,0 +1,71 @@
odoo.define('pos_pax.pos_pax', function (require) {
"use strict";
// Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
const pos_model = require('point_of_sale.models');
pos_model.PosModel = pos_model.PosModel.extend({
getPAXOnlinePaymentJournals: function () {
var online_payment_methods = [];
$.each(this.payment_methods, function (i, payment_method) {
if (payment_method.use_payment_terminal == 'pax') {
online_payment_methods.push({label: payment_method.name, item: payment_method.id});
}
});
return online_payment_methods;
},
decodePAXResponse: function (data) {
if (data[5] == 'ABORTED') {
return {fail: 'Transaction Aborted'};
} else if (data[5] == 'OK') {
return {
success: true,
approval: data[6][2],
txn_id: data[10][0],
card_num: '***' + data[9][0],
}
}
return {fail: 'Unknown Response. ' + data};
},
});
var _paylineproto = pos_model.Paymentline.prototype;
pos_model.Paymentline = pos_model.Paymentline.extend({
init_from_JSON: function (json) {
_paylineproto.init_from_JSON.apply(this, arguments);
this.paid = json.paid;
this.pax_txn_pending = json.pax_txn_pending;
this.pax_card_number = json.pax_card_number;
this.pax_approval = json.pax_approval;
this.pax_txn_id = json.pax_txn_id;
this.set_credit_card_name();
},
export_as_JSON: function () {
return _.extend(_paylineproto.export_as_JSON.apply(this, arguments), {
paid: this.paid,
pax_txn_pending: this.pax_txn_pending,
pax_card_number: this.pax_card_number,
pax_approval: this.pax_approval,
pax_txn_id: this.pax_txn_id,
});
},
set_credit_card_name: function () {
if (this.pax_card_number) {
this.name = this.pax_card_number;
}
},
});
var _order_super = pos_model.Order.prototype;
pos_model.Order = pos_model.Order.extend({
electronic_payment_in_progress: function() {
var res = _order_super.electronic_payment_in_progress.apply(this, arguments);
return res || this.get_paymentlines().some(line => line.pax_txn_pending);
},
});
});

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="pos_pax.OrderReceipt" t-inherit="point_of_sale.OrderReceipt" t-inherit-mode="extension" owl="1">
<xpath expr="//t[@t-foreach='receipt.paymentlines']" position="inside">
<t t-if="line.pax_approval">
<div class="pos-receipt-left-padding">
<span>APPROVAL CODE: </span>
<span>
<t t-esc="line.pax_approval" />
</span>
</div>
</t>
</xpath>
</t>
</templates>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="pos_pax.PaymentScreenPaymentLines" t-inherit="point_of_sale.PaymentScreenPaymentLines" t-inherit-mode="extension" owl="1">
<xpath expr="//div[hasclass('paymentline')]//t[@t-esc='line.payment_method.name']" position="replace">
<t t-if="line.pax_txn_pending">
<span>WAITING FOR TXN</span>
<div class="pax-send-transaction-button"
t-on-click="trigger('pax-send-payment-request', line)"
aria-label="Send Transaction" title="Send Transaction">
<span>Send</span>
</div>
</t>
<t t-else="">
<t t-esc="line.payment_method.name" />
<t t-esc="line.name" />
</t>
</xpath>
</t>
</templates>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<templates id="template" xml:space="preserve">
<t t-name="PAXPaymentTransactionPopup" owl="1">
<div role="dialog" class="modal-dialog">
<div class="popup">
<p class="title">
<t t-esc="props.title"></t>
</p>
<p class="body">
<t t-esc="state.message"></t>
</p>
<div t-if="state.confirmButtonIsShown" class="footer">
<div class="button cancel" t-on-click="confirm">
<t t-esc="props.confirmText"></t>
</div>
</div>
</div>
</div>
</t>
</templates>