tappay_v5_24 #1

Merged
warrenchen merged 2 commits from tappay_v5_24 into master 2025-12-10 08:56:33 +00:00
2 changed files with 207 additions and 129 deletions
Showing only changes of commit ce18a5eb1c - Show all commits

View File

@ -15,6 +15,7 @@ using Nop.Services.Payments;
using Nop.Services.Plugins;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace Nop.Plugin.Payments.TapPay;
@ -89,10 +90,30 @@ public class TapPayPaymentProcessor : BasePlugin, IPaymentMethod
var customer = await _customerService.GetCustomerByIdAsync(processPaymentRequest.CustomerId);
var customerBillingAddress = await _customerService.GetCustomerBillingAddressAsync(customer);
string GetCustomValue(string key)
{
if (processPaymentRequest.CustomValues.TryGetValue(key, out var value) && value != null)
return value.ToString().Trim();
return string.Empty;
}
var prime = GetCustomValue("Prime");
if (string.IsNullOrEmpty(prime))
{
result.AddError("TapPay prime is missing.");
return result;
}
var cardholderEmail = GetCustomValue("CardholderEmail");
var cardholderPhone = GetCustomValue("CardholderPhoneNumber");
var cardholderPhoneCode = GetCustomValue("CardholderPhoneNumberCountryCode");
var cardholderNameEn = GetCustomValue("CardholderNameEn");
var requestBody = JsonSerializer.Serialize(
new {
partner_key = _tapPayPaymentSettings.PartnerKey,
prime = ((Newtonsoft.Json.Linq.JArray)processPaymentRequest.CustomValues["Prime"])[0].ToString(),
prime = prime,
amount = (int)processPaymentRequest.OrderTotal,
merchant_id = _tapPayPaymentSettings.Merchant.ToString(),
order_number = processPaymentRequest.OrderGuid.ToString(),
@ -105,11 +126,13 @@ public class TapPayPaymentProcessor : BasePlugin, IPaymentMethod
},
details = "AI Hardware / APP",
cardholder = new {
phone_number = customerBillingAddress.PhoneNumber,
name = customerBillingAddress.LastName + customerBillingAddress.FirstName,
email = customerBillingAddress.Email,
zip_code = customerBillingAddress.ZipPostalCode,
address = customerBillingAddress.City + customerBillingAddress.Address1 + customerBillingAddress.Address2,
phone_number = cardholderPhone,
phone_number_country_code = string.IsNullOrWhiteSpace(cardholderPhoneCode) ? "886" : cardholderPhoneCode,
name_en = cardholderNameEn,
name = (customerBillingAddress?.LastName ?? string.Empty) + (customerBillingAddress?.FirstName ?? string.Empty),
email = cardholderEmail,
zip_code = customerBillingAddress?.ZipPostalCode,
address = (customerBillingAddress?.City ?? string.Empty) + (customerBillingAddress?.Address1 ?? string.Empty) + (customerBillingAddress?.Address2 ?? string.Empty),
member_id = processPaymentRequest.CustomerId.ToString()
}
}
@ -367,7 +390,11 @@ public class TapPayPaymentProcessor : BasePlugin, IPaymentMethod
public Task<ProcessPaymentRequest> GetPaymentInfoAsync(IFormCollection form)
{
var paymentRequest = new ProcessPaymentRequest();
paymentRequest.CustomValues.Add("Prime", form["Prime"]);
paymentRequest.CustomValues.Add("Prime", form["Prime"].ToString());
paymentRequest.CustomValues.Add("CardholderEmail", form["CardholderEmail"].ToString());
paymentRequest.CustomValues.Add("CardholderPhoneNumber", form["CardholderPhoneNumber"].ToString());
paymentRequest.CustomValues.Add("CardholderPhoneNumberCountryCode", form["CardholderPhoneNumberCountryCode"].ToString());
paymentRequest.CustomValues.Add("CardholderNameEn", form["CardholderNameEn"].ToString());
return Task.FromResult(paymentRequest);
}
@ -482,4 +509,4 @@ public class TapPayPaymentProcessor : BasePlugin, IPaymentMethod
public bool SkipPaymentInfo => false;
#endregion
}
}

View File

@ -3,8 +3,6 @@
}
@model Nop.Plugin.Payments.TapPay.Models.PaymentInfoModel
@* <!script async src="https://js.tappaysdk.com/tpdirect/v5.1.0"></!script> *@
<input type="hidden" asp-for="AppId" />
<input type="hidden" asp-for="AppKey" />
<input type="hidden" asp-for="ServerType" />
@ -35,137 +33,190 @@
<div class="form-control ccv" style="height: 20px"></div>
</td>
</tr>
<tr>
<td>
<label>@T("Payment.CardHolderName"):</label>
</td>
<td>
<input type="text" id="CardholderNameEn" name="CardholderNameEn" maxlength="45" placeholder="@T("Payment.CardHolderName")"/>
</td>
</tr>
<tr>
<td>
<label>@T("Payment.CardHolderEmail"):</label>
</td>
<td>
<input type="text" id="CardholderEmail" name="CardholderEmail" maxlength="40" placeholder="@T("Payment.CardHolderEmail")"/>
</td>
</tr>
<tr id="phone_group">
<td>
<label>@T("Payment.CardHolderPhone"):</label>
</td>
<td>
<div style="display: flex">
+<input type="tel" id="CardholderPhoneNumberCountryCode" name="CardholderPhoneNumberCountryCode" minlength="1" maxlength="3" placeholder="886" value="886"/>
<input type="tel" id="CardholderPhoneNumber" name="CardholderPhoneNumber" maxlength="16" placeholder="912345678"/>
</div>
</td>
</tr>
</table>
<script asp-location="Footer">
//$(document).ready(function() {
$.getScript("https://js.tappaysdk.com/tpdirect/v5.1.0", function() {
TPDirect.setupSDK($('#AppId').val(), $('#AppKey').val(), $('#ServerType').val());
$('.button-1.payment-info-next-step-button').attr('disabled', true);
$('.button-1.payment-info-next-step-button').removeAttr('onclick');
$('.button-1.payment-info-next-step-button').off('click');
$('.button-1.payment-info-next-step-button').click(function() {
event.preventDefault();
// fix keyboard issue in iOS device
forceBlurIos();
const tappayStatus = TPDirect.card.getTappayFieldsStatus();
console.log(tappayStatus);
$.ajax({
url: "https://js.tappaysdk.com/sdk/tpdirect/v5.24.0",
dataType: "script",
cache: true,
success: function() {
TPDirect.setupSDK($('#AppId').val(), $('#AppKey').val(), $('#ServerType').val());
$('.button-1.payment-info-next-step-button').attr('disabled', true);
$('.button-1.payment-info-next-step-button').removeAttr('onclick');
$('.button-1.payment-info-next-step-button').off('click');
$('.button-1.payment-info-next-step-button').click(function() {
event.preventDefault();
// fix keyboard issue in iOS device
forceBlurIos();
const tappayStatus = TPDirect.card.getTappayFieldsStatus();
console.log(tappayStatus);
// Check TPDirect.card.getTappayFieldsStatus().canGetPrime before TPDirect.card.getPrime
if (tappayStatus.canGetPrime === false) {
alert('can not get prime');
return;
}
TPDirect.card.getPrime(function (result) {
if (result.status !== 0) {
alert('get prime error ' + result.msg);
// Check TPDirect.card.getTappayFieldsStatus().canGetPrime before TPDirect.card.getPrime
if (tappayStatus.canGetPrime === false) {
alert('can not get prime');
return;
}
$('#Prime').val(result.card.prime);
if(typeof PaymentInfo !== 'undefined')
{
PaymentInfo.save();
}
else
{
$("form[action='/checkout/paymentinfo'").submit();
TPDirect.card.getPrime(function (result) {
if (result.status !== 0) {
alert('get prime error ' + result.msg);
return;
}
$('#Prime').val(result.card.prime);
if(typeof PaymentInfo !== 'undefined')
{
PaymentInfo.save();
}
else
{
$("form[action='/checkout/paymentinfo'").submit();
}
});
});
TPDirect.card.setup({
fields: {
number: {
element: '.form-control.card-number',
placeholder: '**** **** **** ****'
},
expirationDate: {
element: '.form-control.expiration-date',
placeholder: 'MM / YY'
},
ccv: {
element: '.form-control.ccv',
placeholder: '後三碼'
}
},
@* cardholder: {
name_en: {
element: document.getElementById('name_en'),
placeholder: '持卡人姓名'
},
email: {
element: document.getElementById('email'),
placeholder: 'Email'
},
phone: {
country_code: {
element: document.getElementById('phone_country_code'),
placeholder: '886'
},
number: {
element: document.getElementById('phone_number'),
placeholder: '912345678'
}
}
}, *@
styles: {
'input': {
'color': 'gray'
},
'input.ccv': {
// 'font-size': '16px'
},
':focus': {
'color': 'black'
},
'.valid': {
'color': 'green'
},
'.invalid': {
'color': 'red'
}
},
// 此設定會顯示卡號輸入正確後,會顯示前六後四碼信用卡卡號
isMaskCreditCardNumber: true,
maskCreditCardNumberRange: {
beginIndex: 6,
endIndex: 11
}
});
});
TPDirect.card.setup({
fields: {
number: {
element: '.form-control.card-number',
placeholder: '**** **** **** ****'
},
expirationDate: {
element: '.form-control.expiration-date',
placeholder: 'MM / YY'
},
ccv: {
element: '.form-control.ccv',
placeholder: '後三碼'
// listen for TapPay Field
TPDirect.card.onUpdate(function (update) {
/* Disable / enable submit button depend on update.canGetPrime */
/* ============================================================ */
// update.canGetPrime === true
// --> you can call TPDirect.card.getPrime()
// const submitButton = document.querySelector('button[type="submit"]')
if (update.canGetPrime) {
// submitButton.removeAttribute('disabled')
$('.button-1.payment-info-next-step-button').removeAttr('disabled');
} else {
// submitButton.setAttribute('disabled', true)
$('.button-1.payment-info-next-step-button').attr('disabled', true);
}
},
styles: {
'input': {
'color': 'gray'
},
'input.ccv': {
// 'font-size': '16px'
},
':focus': {
'color': 'black'
},
'.valid': {
'color': 'green'
},
'.invalid': {
'color': 'red'
/* Change card type display when card type change */
/* ============================================== */
// cardTypes = ['visa', 'mastercard', ...]
var newType = update.cardType === 'unknown' ? '' : update.cardType.toUpperCase();
$('#cardtype').text(newType);
/* Change form-group style when tappay field status change */
/* ======================================================= */
// number 欄位是錯誤的
if (update.status.number === 2) {
setNumberFormGroupToError('.card-number-group');
} else if (update.status.number === 0) {
setNumberFormGroupToSuccess('.card-number-group');
} else {
setNumberFormGroupToNormal('.card-number-group');
}
},
// 此設定會顯示卡號輸入正確後,會顯示前六後四碼信用卡卡號
isMaskCreditCardNumber: true,
maskCreditCardNumberRange: {
beginIndex: 6,
endIndex: 11
}
});
// listen for TapPay Field
TPDirect.card.onUpdate(function (update) {
/* Disable / enable submit button depend on update.canGetPrime */
/* ============================================================ */
if (update.status.expiry === 2) {
setNumberFormGroupToError('.expiration-date-group');
} else if (update.status.expiry === 0) {
setNumberFormGroupToSuccess('.expiration-date-group');
} else {
setNumberFormGroupToNormal('.expiration-date-group');
}
// update.canGetPrime === true
// --> you can call TPDirect.card.getPrime()
// const submitButton = document.querySelector('button[type="submit"]')
if (update.canGetPrime) {
// submitButton.removeAttribute('disabled')
$('.button-1.payment-info-next-step-button').removeAttr('disabled');
} else {
// submitButton.setAttribute('disabled', true)
$('.button-1.payment-info-next-step-button').attr('disabled', true);
}
/* Change card type display when card type change */
/* ============================================== */
// cardTypes = ['visa', 'mastercard', ...]
var newType = update.cardType === 'unknown' ? '' : update.cardType.toUpperCase();
$('#cardtype').text(newType);
/* Change form-group style when tappay field status change */
/* ======================================================= */
// number 欄位是錯誤的
if (update.status.number === 2) {
setNumberFormGroupToError('.card-number-group');
} else if (update.status.number === 0) {
setNumberFormGroupToSuccess('.card-number-group');
} else {
setNumberFormGroupToNormal('.card-number-group');
}
if (update.status.expiry === 2) {
setNumberFormGroupToError('.expiration-date-group');
} else if (update.status.expiry === 0) {
setNumberFormGroupToSuccess('.expiration-date-group');
} else {
setNumberFormGroupToNormal('.expiration-date-group');
}
if (update.status.ccv === 2) {
setNumberFormGroupToError('.ccv-group');
} else if (update.status.ccv === 0) {
setNumberFormGroupToSuccess('.ccv-group');
} else {
setNumberFormGroupToNormal('.ccv-group');
}
});
if (update.status.ccv === 2) {
setNumberFormGroupToError('.ccv-group');
} else if (update.status.ccv === 0) {
setNumberFormGroupToSuccess('.ccv-group');
} else {
setNumberFormGroupToNormal('.ccv-group');
}
});
}
});
function setNumberFormGroupToError(selector) {