Added QRResult and null guard for qr code
This commit is contained in:
@@ -14,8 +14,8 @@ namespace Darkmatter.Fonepay
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class FonepayApiClient
|
internal sealed class FonepayApiClient
|
||||||
{
|
{
|
||||||
private const string QrPath = "merchant/merchantDetailsForThirdParty/thirdPartyDynamicQrDownload";
|
private const string QrPath = "merchant/merchantDetailsForThirdParty/thirdPartyDynamicQrDownload";
|
||||||
private const string StatusPath = "merchant/merchantDetailsForThirdParty/thirdPartyDynamicQrGetStatus";
|
private const string StatusPath = "merchant/merchantDetailsForThirdParty/thirdPartyDynamicQrGetStatus";
|
||||||
private const string TaxRefundPath = "merchant/merchantDetailsForThirdParty/taxRefund";
|
private const string TaxRefundPath = "merchant/merchantDetailsForThirdParty/taxRefund";
|
||||||
|
|
||||||
private readonly FonepayConfigSO _config;
|
private readonly FonepayConfigSO _config;
|
||||||
@@ -29,27 +29,28 @@ namespace Darkmatter.Fonepay
|
|||||||
|
|
||||||
// ── public API ────────────────────────────────────────────────────
|
// ── public API ────────────────────────────────────────────────────
|
||||||
|
|
||||||
internal Task<QrResponse> PostQRAsync(QrRequest request, CancellationToken ct)
|
internal async Task<QrResult> PostQRAsync(QrRequest request, CancellationToken ct)
|
||||||
{
|
{
|
||||||
var amountStr = request.amount.ToString("0.00", CultureInfo.InvariantCulture);
|
var amountStr = request.amount.ToString("0.00", CultureInfo.InvariantCulture);
|
||||||
var payload = new QrRequestPayload
|
var payload = new QrRequestPayload
|
||||||
{
|
{
|
||||||
amount = request.amount,
|
amount = request.amount,
|
||||||
prn = request.prn,
|
prn = request.prn,
|
||||||
remarks1 = request.remarks1,
|
remarks1 = request.remarks1,
|
||||||
remarks2 = request.remarks2,
|
remarks2 = request.remarks2,
|
||||||
pm = request.pm,
|
pm = request.pm,
|
||||||
merchantCode = _config.MerchantCode,
|
merchantCode = _config.MerchantCode,
|
||||||
username = _config.Username,
|
username = _config.Username,
|
||||||
password = _config.GetPassword(),
|
password = _config.GetPassword(),
|
||||||
dataValidation = _signer.SignQrRequest(
|
dataValidation = _signer.SignQrRequest(
|
||||||
amountStr, request.prn, _config.MerchantCode,
|
amountStr, request.prn, _config.MerchantCode,
|
||||||
request.remarks1, request.remarks2),
|
request.remarks1, request.remarks2),
|
||||||
};
|
};
|
||||||
return SendPostAsync<QrResponse>(QrPath, payload, ct);
|
var response = await SendPostAsync<QrResponse>(QrPath, payload, ct);
|
||||||
|
return MapToQrResult(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Task<QrResponse> GetStatusAsync(string prn, CancellationToken ct)
|
internal async Task<QrResult> GetStatusAsync(string prn, CancellationToken ct)
|
||||||
{
|
{
|
||||||
var sig = _signer.SignStatusCheck(prn, _config.MerchantCode);
|
var sig = _signer.SignStatusCheck(prn, _config.MerchantCode);
|
||||||
var url = $"{_config.ResolveBaseUrl()}{StatusPath}" +
|
var url = $"{_config.ResolveBaseUrl()}{StatusPath}" +
|
||||||
@@ -58,24 +59,26 @@ namespace Darkmatter.Fonepay
|
|||||||
$"&dataValidation={UnityWebRequest.EscapeURL(sig)}" +
|
$"&dataValidation={UnityWebRequest.EscapeURL(sig)}" +
|
||||||
$"&username={UnityWebRequest.EscapeURL(_config.Username)}" +
|
$"&username={UnityWebRequest.EscapeURL(_config.Username)}" +
|
||||||
$"&password={UnityWebRequest.EscapeURL(_config.GetPassword())}";
|
$"&password={UnityWebRequest.EscapeURL(_config.GetPassword())}";
|
||||||
return SendAsync<QrResponse>(url, UnityWebRequest.kHttpVerbGET, null, ct);
|
var response = await SendAsync<QrResponse>(url, UnityWebRequest.kHttpVerbGET, null, ct);
|
||||||
|
return MapToQrResult(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal Task<TaxRefundResponse> PostTaxRefundAsync(TaxRefundRequest r, CancellationToken ct)
|
internal Task<TaxRefundResponse> PostTaxRefundAsync(TaxRefundRequest r, CancellationToken ct)
|
||||||
{
|
{
|
||||||
var invoiceDate = r.invoiceDate.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
|
var invoiceDate = r.invoiceDate.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
|
||||||
var amountStr = r.transactionAmount.ToString("0.00", CultureInfo.InvariantCulture);
|
var amountStr = r.transactionAmount.ToString("0.00", CultureInfo.InvariantCulture);
|
||||||
var payload = new TaxRefundRequestPayload
|
var payload = new TaxRefundRequestPayload
|
||||||
{
|
{
|
||||||
fonepayTraceId = r.fonepayTraceId,
|
fonepayTraceId = r.fonepayTraceId,
|
||||||
merchantPRN = r.merchantPRN,
|
merchantPRN = r.merchantPRN,
|
||||||
invoiceNumber = r.invoiceNumber,
|
invoiceNumber = r.invoiceNumber,
|
||||||
invoiceDate = invoiceDate,
|
invoiceDate = invoiceDate,
|
||||||
transactionAmount = r.transactionAmount,
|
transactionAmount = r.transactionAmount,
|
||||||
merchantCode = _config.MerchantCode,
|
merchantCode = _config.MerchantCode,
|
||||||
username = _config.Username,
|
username = _config.Username,
|
||||||
password = _config.GetPassword(),
|
password = _config.GetPassword(),
|
||||||
dataValidation = _signer.SignTaxRefund(
|
dataValidation = _signer.SignTaxRefund(
|
||||||
r.fonepayTraceId, r.merchantPRN, r.invoiceNumber,
|
r.fonepayTraceId, r.merchantPRN, r.invoiceNumber,
|
||||||
invoiceDate, amountStr, _config.MerchantCode),
|
invoiceDate, amountStr, _config.MerchantCode),
|
||||||
};
|
};
|
||||||
@@ -86,7 +89,7 @@ namespace Darkmatter.Fonepay
|
|||||||
|
|
||||||
private Task<T> SendPostAsync<T>(string relativePath, object body, CancellationToken ct)
|
private Task<T> SendPostAsync<T>(string relativePath, object body, CancellationToken ct)
|
||||||
{
|
{
|
||||||
var url = _config.ResolveBaseUrl() + relativePath;
|
var url = _config.ResolveBaseUrl() + relativePath;
|
||||||
var json = JsonUtility.ToJson(body);
|
var json = JsonUtility.ToJson(body);
|
||||||
return SendAsync<T>(url, UnityWebRequest.kHttpVerbPOST, json, ct);
|
return SendAsync<T>(url, UnityWebRequest.kHttpVerbPOST, json, ct);
|
||||||
}
|
}
|
||||||
@@ -103,11 +106,22 @@ namespace Darkmatter.Fonepay
|
|||||||
req.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(jsonBody));
|
req.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(jsonBody));
|
||||||
req.SetRequestHeader("Content-Type", "application/json");
|
req.SetRequestHeader("Content-Type", "application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
req.SetRequestHeader("Accept", "application/json");
|
req.SetRequestHeader("Accept", "application/json");
|
||||||
|
|
||||||
CancellationTokenRegistration reg = default;
|
CancellationTokenRegistration reg = default;
|
||||||
if (ct.CanBeCanceled)
|
if (ct.CanBeCanceled)
|
||||||
reg = ct.Register(() => { try { req.Abort(); } catch { /* ignored */ } });
|
reg = ct.Register(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
req.Abort();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
/* ignored */
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var op = req.SendWebRequest();
|
var op = req.SendWebRequest();
|
||||||
op.completed += _ =>
|
op.completed += _ =>
|
||||||
@@ -135,13 +149,17 @@ namespace Darkmatter.Fonepay
|
|||||||
|
|
||||||
var text = req.downloadHandler.text ?? string.Empty;
|
var text = req.downloadHandler.text ?? string.Empty;
|
||||||
T result;
|
T result;
|
||||||
try { result = JsonUtility.FromJson<T>(text); }
|
try
|
||||||
|
{
|
||||||
|
result = JsonUtility.FromJson<T>(text);
|
||||||
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
tcs.TrySetException(new FonepayError(0,
|
tcs.TrySetException(new FonepayError(0,
|
||||||
$"JSON parse failed: {e.Message}. Body: {text}", url));
|
$"JSON parse failed: {e.Message}. Body: {text}", url));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcs.TrySetResult(result);
|
tcs.TrySetResult(result);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -152,5 +170,21 @@ namespace Darkmatter.Fonepay
|
|||||||
};
|
};
|
||||||
return tcs.Task;
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private QrResult MapToQrResult(QrResponse response)
|
||||||
|
{
|
||||||
|
return new QrResult
|
||||||
|
{
|
||||||
|
message = response.message,
|
||||||
|
qrCode = string.IsNullOrEmpty(response.qrMessage)
|
||||||
|
? null
|
||||||
|
: FonepayQRGenerator.GenerateTexture(response.qrMessage),
|
||||||
|
status = response.status,
|
||||||
|
statusCode = response.statusCode,
|
||||||
|
success = response.success,
|
||||||
|
thirdpartyQrWebSocketUrl = response.thirdpartyQrWebSocketUrl,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ namespace Darkmatter.Fonepay
|
|||||||
/// <param name="req"></param>
|
/// <param name="req"></param>
|
||||||
/// <param name="ct"></param>
|
/// <param name="ct"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<QrResponse> PostQRAsync(QrRequest req, CancellationToken ct = default)
|
public Task<QrResult> PostQRAsync(QrRequest req, CancellationToken ct = default)
|
||||||
=> _api.PostQRAsync(req, ct);
|
=> _api.PostQRAsync(req, ct);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -36,7 +36,7 @@ namespace Darkmatter.Fonepay
|
|||||||
/// <param name="prn"></param>
|
/// <param name="prn"></param>
|
||||||
/// <param name="ct"></param>
|
/// <param name="ct"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<QrResponse> GetStatusAsync(string prn, CancellationToken ct = default)
|
public Task<QrResult> GetStatusAsync(string prn, CancellationToken ct = default)
|
||||||
=> _api.GetStatusAsync(prn, ct);
|
=> _api.GetStatusAsync(prn, ct);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,9 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Darkmatter.Fonepay
|
namespace Darkmatter.Fonepay
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public struct QrResponse
|
public struct QrResult
|
||||||
|
{
|
||||||
|
public string message;
|
||||||
|
public Texture2D qrCode;
|
||||||
|
public string status;
|
||||||
|
public int statusCode;
|
||||||
|
public bool success;
|
||||||
|
public string thirdpartyQrWebSocketUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
internal struct QrResponse
|
||||||
{
|
{
|
||||||
public string message;
|
public string message;
|
||||||
public string qrMessage;
|
public string qrMessage;
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ namespace Darkmatter.Fonepay
|
|||||||
|
|
||||||
public static bool[,] GenerateMatrix(string text, EccLevel ecc = EccLevel.M)
|
public static bool[,] GenerateMatrix(string text, EccLevel ecc = EccLevel.M)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
|
throw new System.ArgumentException("QR text must be non-empty", nameof(text));
|
||||||
byte[] data = System.Text.Encoding.UTF8.GetBytes(text);
|
byte[] data = System.Text.Encoding.UTF8.GetBytes(text);
|
||||||
var (version, ecBlocks) = ChooseVersion(data.Length, ecc);
|
var (version, ecBlocks) = ChooseVersion(data.Length, ecc);
|
||||||
byte[] codewords = BuildCodewords(data, version, ecc, ecBlocks);
|
byte[] codewords = BuildCodewords(data, version, ecc, ecBlocks);
|
||||||
|
|||||||
Reference in New Issue
Block a user