網購業者收款確認的事一向是最煩鎖的事,若有公司營業登記,可以向國泰世華申請ATM虛擬帳號,就可以發給買家匯款指定的帳號,等入帳後再使用銀行提供的即時對帳API(存取頻率最低3分鐘)作查稽。
國泰世華發行的虛擬帳號長度有11, 14及16字長,前2者可以使用臨櫃匯款的方式繳納(匯款單的帳號長度是14長)。若有限繳時間的檢查及訂單編號的綁定,則使用16字長編碼才夠。
編號原則: 16位編碼 = 企業代碼[4] + 限繳日期MMDDHH[6] + 自訂編碼[5] + 檢核查[1]
送交銀行的申請表單勾核選項如下:
使用國泰ATM虛擬帳號不需要事先在銀行開立允許列表,只要符合其編碼原則文件規範即可。
發現這虛擬帳號的檢核碼規則,跟台灣身份字號的最後1碼是邏輯相同,只差別在於權數不同而己。我的程式應用是採用16位帳號+限繳日期yyymmhh+交易金額+檢核碼的驗證方式,最後2組檢核碼相加須要取餘數,這點官方文件沒提到。
分享我的國泰世華16位虛擬帳號的C#源碼下:
void Main()
{
MyVirtualAccount provider = new MyVirtualAccount();
// 限繳日期設定
DateTime expDate = new DateTime(2015, 08, 31, 12, 00, 00);
// 產生10筆16位長編碼
for (int i = 1; i <= 10; i++)
{
var s = provider.CreateAccount16(
prefix4: "9999"
, expDate: expDate
, billNo5: i.ToString().PadLeft(5, '0')
, amount: 4);
s.Dump();
}
}
///
/// 國泰世華-虛擬帳號產碼類別
///
/// Author: Tomex Ou
/// Update: 2015-08-25 13:56:30
public class MyVirtualAccount
{
///
/// Creates Len=16 Account
///
/// Customer ID (Len=4), 公司編碼="9999"
/// Expired Date (GetNextFullHour)取下個整時刻
/// Bill No (Len=5, 左補0)
/// Amount value金額
///
public string CreateAccount16(string prefix4, DateTime expDate, string billNo5, decimal amount)
{
// -------------------------------------------------------------
// Arguments Validating.
// -------------------------------------------------------------
if (prefix4.Length != 4)
throw new Exception("The length of Customer ID must be 4.");
if (billNo5.Length != 5)
throw new Exception("The length of Bill No. must be 5.");
int accCheck, amtCheck, value;
// -------------------------------------------------------------
// accCheck for Account
// -------------------------------------------------------------
string strAccount = prefix4 + this.GetNextFullHour(expDate).ToString("MMddHH") + billNo5;
int[] accWeights = { 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // Len=15
int accSum = 0;
for (int i = 0; i < accWeights.Length; i++)
{
value = (int)Char.GetNumericValue(strAccount[i]); // char '0' to int32.
accSum += (value * accWeights[i]) % 10;
}
accCheck = this.GetCheckValue(accSum);
// -------------------------------------------------------------
// amtCheck for Amount
// -------------------------------------------------------------
int[] amtWeights = { 8, 7, 6, 5, 4, 3, 2, 1 };
int[] amtIntArray = this.CreateAmountIntArray(amount, amtWeights.Length);
int amtSum = 0;
for (int i = 0; i < amtWeights.Length; i++)
{
value = amtIntArray[i];
amtSum += (value * amtWeights[i]) % 10;
}
amtCheck = this.GetCheckValue(amtSum);
// -------------------------------------------------------------
// Full check
// -------------------------------------------------------------
int fullCheck = (accCheck + amtCheck) % 10;
return strAccount + fullCheck;
}
///
/// 取得Sum值的檢核碼
///
private int GetCheckValue(int sum)
{
int d0 = sum % 10; // 個位數
return (d0 == 0) ? 0 : 10 - d0;
}
///
/// 限繳日期的下一個整點時刻
///
public DateTime GetNextFullHour(DateTime theDate)
{
double nextFullHour = Math.Ceiling(theDate.TimeOfDay.TotalHours);
return theDate.Date.AddHours(nextFullHour);
}
///
/// 金額的int陣列 (8位長)
///
private int[] CreateAmountIntArray(decimal amount, int totalWidth = 8)
{
// 1200.00 => 1200 => ["00001200"]
string strAmount = decimal.ToInt32(amount).ToString().PadLeft(totalWidth, '0');
if (strAmount.Length != 8)
throw new Exception("The length of amount must <= 8.");
int[] intArray = new int[strAmount.Length];
for (int i = 0; i < strAmount.Length; i++)
{
intArray[i] = (int)Char.GetNumericValue(strAmount[i]); // char '0' to int32
}
return intArray;
}
}
發行的虛擬帳號在轉帳時,必須符合限繳時間+交易金額+檢核碼的規則,否則轉帳時會出現錯誤,無法入帳。