經銷商 MYPAY LINK 直接交易
修改歷程
版本 | 異動日期 | 修訂內容 | 位置 |
---|---|---|---|
1.0 | 2021.01.01 | 新版文件 | |
1.0.1 | 2023.04.07 | 新增開發前請先閱讀 | 20230407_01 |
1.0.2 | 2023.07.26 | 新增特約商店可用支付工具 | 20230726_01 |
開發前請先閱讀
金鑰的注意事項
Q:金鑰的有效期限
A:MyPay的金鑰有效期限只有一年,如果要延長,請自行至金鑰管理系統延長
Q:金鑰可以在什麼時候延長
A:到期日7天前,都可以延長(不包含第7天),一但超過,系統自動產生新金鑰後,即不可再延長
Q:金鑰即將到期前7天時,系統新發的金鑰是否會於信件中夾帶
A:會
Q:金鑰在到期前何時會發信通知
A:定期發送金鑰到期通知的頻率為:60天/30天/20天,若 貴司皆無動作,則系統會於到期前七天產製新金鑰並發送email到 貴司技術窗口信箱,此時舊的金鑰,因還未過期還可以使用,一旦過期,貴司仍使用舊金鑰則會無法交易
交易結果的告知
Q:何時會給予交易結果
A:當mypay接收到交易的http request後,會立即回應交易結果於http response body,除此之外,MyPay也會由附錄三這邊的設定,背景主動發動通知商家
Q:當我接到MyPay通知時該做什麼
A:請直接回應8888,如沒有回應,MyPay會通知5次,若5次內均得不到8888,系統會寄發信件給予商家的技術人員以及附錄三而外設定的人員
行動支付測試
Q:那些行動支付工具可以做測試
A:目前除了line pay外,其餘行動支付,因上游無提供測試資料,皆無法進行測試
直接交易設計概要
安全性設計
所有的付費要求發動都僅能從經銷商的網頁伺服器發出請求,將傳輸的資料以AES加密,再透過HTTPS加密傳輸。交易資料不由消費者端送出,可確保資料不被消費者竄改。所有付費資訊經過MYPAY Link匝道進行轉送處理,經銷商不需要處理消費者的付費流程以及安全控管。
資料驗證
交易參數中有一組由雜湊函式運算出的驗証碼,作為資料驗証用,以確保資料正確性。 大部分交易模式,經銷商以導頁的方式處理付費流程,經銷商只需確保與MYPAY LINK連線正常,即可確保交易安全以及確保資料安全。
系統架構
所有的交易請求與查詢只能透過伺服器發動,由經銷商的網頁伺服器利用伺服端服務程式發動交易,以避免交易資料被消費者竄改或攔截。為確保交易安全,MYPAY Link僅能接受 https connection,注意僅接受TLS1.2以上協定。
MYPAY LINK 目前提供之服務與格式
MYPAY LINK 提供多種交易與應用方式,應用情境如下:
(1)虛擬帳號交易請求:產生一組虛擬帳號,可透過ATM轉帳。
(2)超商代碼交易請求:產生ibon、FamiPort、Hi-Life等繳費代碼或繳費條碼自行產生條碼後供超商掃碼繳費。
(3)WebATM交易請求:產生指定金額之導頁網頁資料到銀行WebATM做交易。
(30)後付款交易請求:提交消費者與出貨資訊給後付款。
(31)後付款請款請求:提交貨運資訊給後付款確認請款。
(32)後付款更正出貨請求:未請款前,更正出貨的資訊。
(33)後付款查詢出貨請求:查詢後付款出貨相關資訊。
(34)電票交易請求:發動電子票證交易,消費者透過感應卡機進行付款消費。
(35)電票查詢卡號請求:查詢電子票證之卡號資訊。
(36)電票查詢餘額請求:查詢電子票證餘額。
(37)電票退款請求:發動電子票證交易之退款,消費者透過感應卡機退回電子票證。
(38)eACH交易請求:當消費者申請eDDA電子化授權核印通過後,可發動此交易請求做交易動作。
(39)超商條碼繳費:消費至超商或繳費單位使用條碼繳費。
(40)全支付線上交易請求:商家串接MyPay,直接取得付款網址或開啟APP。
(41)全支付線下交易請求:消費者提供PXPay plus支付碼供設備進行掃碼做交易動作。
(42)LINE Pay線上交易請求:商家串接MyPay,直接取得付款網址或開啟APP。
(43)LINE Pay線下交易請求:消費者提供LINE Pay支付碼供設備進行掃碼做交易動作。
(44)Pi線上交易請求:商家串接MyPay,直接取得付款網址或開啟APP。
(45)Pi線下交易請求:消費者提供Pi支付碼供設備進行掃碼做交易動作。
(46)微信線下交易請求:消費者提供微信支付碼供設備進行掃碼做交易動作。
(47)街口線下交易請求:商家串接MyPay,直接取得付款網址或開啟APP。
(48)街口線下交易請求:消費者提供街口支付碼供設備進行掃碼做交易動作。
(49)Apple Pay線下交易請求:消費者提供Apple Pay支付碼供設備進行掃碼做交易動作。
(50)Google Pay線下交易請求:消費者提供Google Pay支付碼供設備進行掃碼做交易動作。
(51)悠遊付線下交易請求:消費者提供悠遊付支付碼供設備進行掃碼做交易動作。
(52)支付寶線下交易請求:消費者提供支付寶支付碼供設備進行掃碼做交易動作。
(53)自行收款交易請求:商店自行向消費者收款時,可發動此交易請求,將收款記錄在MYPAY
(54)直接交易查詢:向系統發動,若未接收到交易結果回報,可透過此方法確認交易狀況。
(55)交易退款:金流交易退款,支援即時退款且未超過退款期限內之支付方式皆可使用此方式發動退款。
(56)全盈支付線上交易請求:商家串接MyPay,直接取得付款網址或開啟APP。
(57)全盈支付線下交易請求:消費者提供全盈支付碼供設備進行掃碼做交易動作。
我們提供介接方式是透過https連線,只接受POST方式傳送交易資料。
介接網址
經銷商模式
位置 | API介接網址 |
---|---|
測試區 | https://pay.usecase.cc/api/agent |
正式區 | https://ka.mypay.tw/api/agent |
Client模式(限定功能)
位置 | API介接網址 |
---|---|
測試區 | https://pay.usecase.cc/api/open |
正式區 | https://ka.mypay.tw/api/open |
資料加密方式
AES 256編碼 + base64編碼(附錄四資料加密方式)
加密金鑰
金鑰會透過mail發送,也可從管理後台取得
文字編碼
一律使用UTF-8相容編碼
虛擬帳號交易
<?php
/**
* 經銷商串接-直接交易-虛擬帳號
*/
final class AgentECollection
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "E_COLLECTION";
$rawData['limit_pay_days'] = 7;
$rawData['supplier_code'] = "B2";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentECollection = new AgentECollection();
$AgentECollection->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-虛擬帳號
/// </summary>
public class AgentECollection {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentECollection simulator = new AgentECollection();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = "10";
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1"; // 此為消費者IP,會做為驗證用
rawData.pfn = "E_COLLECTION";
rawData.limit_pay_days = "7";
rawData.supplier_code = "B2";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-虛擬帳號
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentECollection {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentECollection simulator = new AgentECollection();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", "10");
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1"); // 此為消費者IP,會做為驗證用
rawData.put("pfn", "E_COLLECTION");
rawData.put("limit_pay_days", "7");
rawData.put("supplier_code", "B2");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-虛擬帳號
*/
function AgentECollection() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentECollection.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}],
cost: "10",
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "E_COLLECTION",
limit_pay_days: 7,
supplier_code: "B2"
};
};
/**
* 取得服務位置
*/
AgentECollection.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentECollection.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentECollection.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentECollection.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentECollection.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentECollection = new AgentECollection();
AgentECollection.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-超商代碼
"""
class AgentCStoreCode:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}],
'cost': "10",
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "CSTORECODE",
'limit_pay_days': "3",
'supplier_code': "S0"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentCStoreCode = AgentCStoreCode()
AgentCStoreCode.run()
回傳 JSON 結構如下:
{
"code": "270",
"msg": "執行成功。",
"uid": 75568,
"key": "3bb205d8f2c315d073fc62c5de8d9761",
"finishtime": "",
"cardno": "",
"acode": "",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "E_COLLECTION",
"trans_type": 1,
"result_type": 4,
"result_content": "{\n \"PinCode\": \"1255100349000018\",\n \"LimitDate\": \"20201214113117\",\n \"BankCode\": \"006\"\n}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
發動交易後,得到一組銀行代號與繳費帳號,讓消費者透過ATM或臨櫃作繳費動作。
經銷商『虛擬帳號交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『虛擬帳號交易』欄位參考 JSON格式,AES256加密資料 |
『虛擬帳號交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | 必填 『付款方式』值參考 |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_address | string(255) | 消費者帳單地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | string | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
supplier_code | string | 金融供應商代碼(依合約設定之支援金融供應商) | 必填 『金流供應商代碼』值參考 |
limit_pay_days | string | 繳費有效天數(如無此資料以系統設定為預設) |
『虛擬帳號』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 交易回傳碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content | string(1000) | 回傳結果 | 『虛擬帳號回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
超商代碼交易
<?php
/**
* 經銷商串接-直接交易-超商代碼
*/
final class AgentCStoreCode
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "CSTORECODE";
$rawData['limit_pay_days'] = 3;
$rawData['supplier_code'] = "S0";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentCStoreCode = new AgentCStoreCode();
$AgentCStoreCode->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-虛擬帳號
/// </summary>
public class AgentCStoreCode {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentCStoreCode simulator = new AgentCStoreCode();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = "10";
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1"; // 此為消費者IP,會做為驗證用
rawData.pfn = "CSTORECODE";
rawData.limit_pay_days = "3";
rawData.supplier_code = "S0";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-超商代碼
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentCStoreCode {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentCStoreCode simulator = new AgentCStoreCode();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", "10");
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1"); // 此為消費者IP,會做為驗證用
rawData.put("pfn", "CSTORECODE");
rawData.put("limit_pay_days", "3");
rawData.put("supplier_code", "S0");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-超商代碼
*/
function AgentCStoreCode() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentCStoreCode.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}],
cost: "10",
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "CSTORECODE",
limit_pay_days: "3",
supplier_code: "S0"
};
};
/**
* 取得服務位置
*/
AgentCStoreCode.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentCStoreCode.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentCStoreCode.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentCStoreCode.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentCStoreCode.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentCStoreCode = new AgentCStoreCode();
AgentCStoreCode.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-虛擬帳號
"""
class AgentECollection:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}],
'cost': "10",
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "E_COLLECTION",
'limit_pay_days': 7,
'supplier_code': "B2"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentECollection = AgentECollection()
AgentECollection.run()
回傳 JSON 結構如下:
{
"code": "260",
"msg": "執行成功。",
"uid": 75569,
"key": "0696b3e97553b8b2d4bdd845e2663aec",
"finishtime": "",
"cardno": "",
"acode": "",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "CSTORECODE",
"trans_type": 1,
"result_type": 4,
"result_content": "{\n \"PinCode\": \"201231V0000156\",\n \"BarCode1\": \"091207KK1\",\n \"BarCode2\": \"00201231V0000156\",\n \"BarCode3\": \"114332000000010\",\n \"LimitDate\": \"20201210113252\"\n}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
發動交易後,會依超商不同而得到不同的繳費代碼或繳費條碼。依規格產生相關的Qrcode或Barcode,提供消費者至超商作掃碼繳費動作。
經銷商『超商代碼交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『超商代碼交易』欄位參考 JSON格式,AES256加密資料 |
『超商代碼交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | 必填 『付款方式』值參考 |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 (如supplier_code = T2,此欄位有填,黑貓Pay發出E-Mail會有此資訊) |
|
user_zipcode | string(10) | 消費者郵遞區號 (如supplier_code = T2,此欄位有填,黑貓Pay發出E-Mail會有此資訊) |
|
user_address | string(255) | 消費者地址 (如supplier_code = T2,此欄位有填,黑貓Pay發出E-Mail會有此資訊) |
|
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 (如supplier_code = T2,此欄位有填,會由黑貓Pay發出簡訊通知。註:測試環境黑貓Pay也可能會發送簡訊,勿隨意填) |
|
user_email | string(80) | 消費者 E-Mail (如supplier_code = T2,此欄位有填,則會由黑貓Pay發出E-Mail通知到這裡) |
|
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | string | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
supplier_code | string | 金融供應商代碼(依合約設定之支援金融供應商) | 必填 『金流供應商代碼』值參考 |
limit_pay_days | string | 繳費有效天數(如無此資料以系統設定為預設),FamiPort有限定3日內 |
『超商代碼交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 交易回傳碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content | string(1000) | 回傳結果 | 『ibon』值參考 『FamiPort』值參考 『Hi Life』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
WebATM交易
<?php
/**
* 經銷商串接-直接交易-WebATM
*/
final class AgentWebATM
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "WEBATM";
$rawData['supplier_code'] = "B2";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentWebATM = new AgentWebATM();
$AgentWebATM->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-WebATM
/// </summary>
public class AgentWebATM {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentWebATM simulator = new AgentWebATM();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = "10";
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1"; // 此為消費者IP,會做為驗證用
rawData.pfn = "WEBATM";
rawData.supplier_code = "B2";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-WebATM
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentWebATM {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentWebATM simulator = new AgentWebATM();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", "10");
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1"); // 此為消費者IP,會做為驗證用
rawData.put("pfn", "WEBATM");
rawData.put("supplier_code", "B2");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-WebATM
*/
function AgentWebATM() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentWebATM.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}],
cost: "10",
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "WEBATM",
supplier_code: "B2"
};
};
/**
* 取得服務位置
*/
AgentWebATM.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentWebATM.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentWebATM.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentWebATM.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentWebATM.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentWebATM = new AgentWebATM();
AgentWebATM.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-WebATM
"""
class AgentWebATM:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}],
'cost': "10",
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "WEBATM",
'supplier_code': "B2"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentWebATM = AgentWebATM()
AgentWebATM.run()
回傳 JSON 結構如下:
{
"code": "280",
"msg": "執行成功。",
"uid": 75570,
"key": "e79ddd457c540d12b8b09cd7790cf614",
"finishtime": "",
"cardno": "",
"acode": "",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "WEBATM",
"trans_type": 1,
"result_type": 2,
"result_content": "<!DOCTYPE html>\r\n<html>\r\n<form action='http:\/\/eatms.tcb-bank.com.tw\/fShop' method='POST' id='form1' name='form1' >\r\n<input type='hidden' name='CardBillRq' value='PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iYmlnNSI\/Pg0KPENhcmRCaWxsUnEgeG1sbnM6eHNkPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSI+DQogIDxTZW5kU2VxTm8+MjAyMDEyMDcxMDAwMDAwNzU1NzA8L1NlbmRTZXFObz4NCiAgPFR4VHlwZT4yNTYwPC9UeFR5cGU+DQogIDxQQVlOTz4wMDYyODkxNTE4ODUzMDE8L1BBWU5PPg0KICA8UGF5VHlwZT41OTk5OTwvUGF5VHlwZT4NCiAgPFVzZXJEYXRhPj8\/Pz88L1VzZXJEYXRhPg0KICA8T05PPjc1NTcwPC9PTk8+DQogIDxBY2N0SWRUbz4xMjU1MTAwMzQ1MDAwMDE2PC9BY2N0SWRUbz4NCiAgPEN1ckFtdD4xMDwvQ3VyQW10Pg0KICA8UGF5RHQ+MjAyMDEyMTA8L1BheUR0Pg0KICA8TUFDPmw0MlVaL3EwUkg1M0l5a21kczJGb1lGRG01eXJ4a3pCPC9NQUM+DQogIDxSc1VSTD5odHRwczovL3Rndy5teXBheS50dy9hcGkvd2ViYXRtL0V4dGVybmFsVGNiQ2xvc2VDYXNlPC9Sc1VSTD4NCjwvQ2FyZEJpbGxScT4='><!-- 帳號-->\r\n<input id='sub' type='submit' value='submit' style='display:none' \/>\r\n<script>\r\n document.getElementById('sub').click();\r\n<\/script>\r\n<\/form>\r\n<\/html>\r\n",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
當發動交易後,會得到一個轉址網頁資訊,透過網頁導頁方式,將消費者操作頁面導頁到銀行WebATM做交易。
經銷商『WebATM交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『WebATM交易』欄位參考 JSON格式,AES256加密資料 |
『WEBATM交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | 必填 『付款方式』值參考 |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_address | string(255) | 消費者帳單地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | string | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
supplier_code | string | 金融供應商代碼(依合約設定之支援金融供應商) | 必填 『金流供應商代碼』值參考 |
success_returl | string(255) | 交易成功導頁網址 | |
failure_returl | string(255) | 交易失敗導頁網址 |
『WEBATM交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 交易回傳碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content | string(1000) | 回傳結果 | |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
後付款交易
<?php
/**
* 經銷商串接-直接交易-後付款
*/
final class AgentAfp
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '1000',
'amount' => '1',
'total' => '1000']];
$rawData['cost'] = 1000;
$rawData['user_id'] = "phper";
$rawData['user_real_name'] = "金城武";
$rawData['user_zipcode'] = "407";
$rawData['user_address'] = "台中市西屯區市政路402號5樓之1";
$rawData['user_cellphone'] = "0900000123";
$rawData['user_email'] = "[email protected]";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "AFP";
$rawData['shipping_info'] = ['shipment_type' => 2,
'name' => "金城武",
'tel' => '0900000123',
'zip_code' => '432',
'ship_address' => '台中市大肚區磺溪里15號'];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentAfp = new AgentAfp();
$AgentAfp->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-後付款
/// </summary>
public class AgentAfp {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentAfp simulator = new AgentAfp();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "1000";
item.amount = "1";
item.total = "1000";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = "1000";
rawData.user_id = "phper";
rawData.user_real_name = "金城武";
rawData.user_zipcode = "407";
rawData.user_address = "台中市西屯區市政路402號5樓之1";
rawData.user_cellphone = "0900000123";
rawData.user_email = "[email protected]";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1"; // 此為消費者IP,會做為驗證用
rawData.pfn = "AFP";
dynamic info = new ExpandoObject();
info.shipment_type = "2";
info.name = "金城武";
info.tel = "0900000123";
info.zip_code = "432";
info.ship_address = "台中市大肚區磺溪里15號";
rawData.shipping_info = info;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-後付款
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentAfp {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentAfp simulator = new AgentAfp();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "1000");
item.put("amount", "1");
item.put("total", "1000");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", "1000");
rawData.put("user_id", "phper");
rawData.put("user_real_name", "金城武");
rawData.put("user_zipcode", "407");
rawData.put("user_address", "台中市西屯區市政路402號5樓之1");
rawData.put("user_cellphone", "0900000123");
rawData.put("user_email", "[email protected]");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1"); // 此為消費者IP,會做為驗證用
rawData.put("pfn", "AFP");
Map<Object, Object> info = new HashMap<Object, Object>();
info.put("shipment_type", "2");
info.put("name", "金城武");
info.put("tel", "0900000123");
info.put("zip_code", "432");
info.put("ship_address", "台中市大肚區磺溪里15號");
rawData.put("shipping_info", info);
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-後付款
*/
function AgentAfp() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentAfp.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [{
'id': "1",
'name': "商品名稱",
'cost': "1000",
'amount': "1",
'total': "1000"
}],
cost: "1000",
user_id: "phper",
user_real_name: "金城武",
user_zipcode: "407",
user_address: "台中市西屯區市政路402號5樓之1",
user_cellphone: "0900000123",
user_email: "[email protected]",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "AFP",
shipping_info : {'shipment_type': 2,
'name': "金城武",
'tel': '0900000123',
'zip_code': '432',
'ship_address': '台中市大肚區磺溪里15號'
}
};
};
/**
* 取得服務位置
*/
AgentAfp.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentAfp.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentAfp.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentAfp.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentAfp.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentAfp = new AgentAfp();
AgentAfp.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-後付款
"""
class AgentAfp:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [{
'id': "1",
'name': "商品名稱",
'cost': "1000",
'amount': "1",
'total': "1000"
}],
'cost': "1000",
'user_id': "phper",
'user_real_name': "金城武",
'user_zipcode': "407",
'user_address': "台中市西屯區市政路402號5樓之1",
'user_cellphone': "0900000123",
'user_email': "[email protected]",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "AFP",
'shipping_info': {
'shipment_type': "2",
'name': "金城武",
'tel': "0900000123",
'zip_code': "432",
'ship_address': '台中市大肚區磺溪里15號'
}
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentAfp = AgentAfp()
AgentAfp.run()
回傳 JSON 結構如下:
{
"code": "284",
"msg": "執行成功。線上訂單成立待出貨-未付款",
"uid": 80998,
"key": "2b4a8cef072c2b8a0b0805d54f54275f",
"finishtime": "",
"cardno": "",
"acode": "",
"order_id": "1234567890",
"user_id": "phper",
"cost": 1000,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "AFP",
"trans_type": 1,
"result_type": 4,
"result_content": "{\n \"OrderTotalCost\": \"1000\",\n \"TradeNo\": \"OD2100070580\",\n \"TradeDate\": \"20210225173152\"\n}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
「先擁有,後付款」網路購物新態度! 消費者收到繳費通知,九天內至全省四大超商、ATM繳費,消費者確認繳費資訊,再進行繳費。
經銷商『後付款交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『後付款交易』欄位參考 JSON格式,AES256加密資料 |
『後付款交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | 必填 |
user_zipcode | string(10) | 消費者郵遞區號 | 必填 |
user_address | string(255) | 消費者地址 | 必填 |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | 必填 |
user_email | string(80) | 消費者 E-Mail | 必填 |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | string | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
shipping_info | object | 送貨資訊 | 必填 『後付款送貨資訊』欄位參考 |
『後付款』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 交易回傳碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content | string(1000) | 回傳結果 | 『後付款交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
後付款請款
<?php
/**
* 經銷商串接-直接交易-後付款請款
*/
final class AgentAfpShipment
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['uid'] = "80747";
$rawData['key'] = "42e46576add74966278a81faf53f732f";
$rawData['shipment_no'] = "9876543210";
$rawData['delivery_code'] = "1";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/afpshipment'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentAfpShipment = new AgentAfpShipment();
$AgentAfpShipment->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-後付款請款
/// </summary>
public class AgentAfpShipment {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentAfpShipment simulator = new AgentAfpShipment();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.uid = "80747";
rawData.key = "42e46576add74966278a81faf53f732f";
rawData.shipment_no = "9876543210";
rawData.delivery_code = "1";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/afpshipment";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-後付款請款
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentAfpShipment {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentAfpShipment simulator = new AgentAfpShipment();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("uid", "80747");
rawData.put("key", "42e46576add74966278a81faf53f732f");
rawData.put("shipment_no", "9876543210");
rawData.put("delivery_code", "1");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/afpshipment");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-後付款請款
*/
function AgentAfpShipment() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentAfpShipment.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
uid: "80747",
key: "42e46576add74966278a81faf53f732f",
shipment_no: "9876543210",
delivery_code: "1"
};
};
/**
* 取得服務位置
*/
AgentAfpShipment.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/afpshipment"
};
};
/**
* AES 256 加密
*/
AgentAfpShipment.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentAfpShipment.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentAfpShipment.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentAfpShipment.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentAfpShipment = new AgentAfpShipment();
AgentAfpShipment.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-後付款請款
"""
class AgentAfpShipment:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'uid': "80747",
'key': "42e46576add74966278a81faf53f732f",
'shipment_no': "9876543210",
'delivery_code': "1"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/afpshipment'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentAfpShipment = AgentAfpShipment()
AgentAfpShipment.run()
回傳 JSON 結構如下:
{
"code": "250",
"msg": "執行成功。",
"uid": 80998,
"key": "2b4a8cef072c2b8a0b0805d54f54275f",
"finishtime": "20210225173326",
"cardno": "OD2100070580",
"acode": "",
"order_id": "1234567890",
"user_id": "phper",
"cost": 1000,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "AFP",
"trans_type": 1,
"result_type": 4,
"result_content": "{\n \"OrderTotalCost\": 1000,\n \"TradeDate\": \"20210225173326\",\n \"TradeNo\": \"OD2100070580\"\n}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
發動後付款交易後,特約商店確認已經出貨給消費者後,即可以發動請款請求。
經銷商『後付款請款』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/afpshipment"} JSON格式,AES256加密資料 |
encry_data | text | 『後付款請款』欄位參考 JSON格式,AES256加密資料 |
『後付款請款』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | |
key | string | 特約商店驗證碼 | |
uid | string | 訂單編號(UID) | |
shipment_no | string | 出貨編號 | |
delivery_code | integer | 貨運商家編號 | 『貨運商家編號』值參考 |
『後付款請款』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 交易回傳碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content | string(1000) | 回傳結果 | 『後付款請款交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
後付款更正出貨
<?php
/**
* 經銷商串接-直接交易-後付款更正出貨
*/
final class AgentAfpShipmentUpdate
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['uid'] = "80747";
$rawData['key'] = "42e46576add74966278a81faf53f732f";
$rawData['shipping_info'] = ['shipment_type' => 2,
'name' => "金城武",
'tel' => '0900000123',
'zip_code' => '432',
'ship_address' => '台中市大肚區磺溪里16號'];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/afpshipmentupdate'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentAfpShipmentUpdate = new AgentAfpShipmentUpdate();
$AgentAfpShipmentUpdate->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-後付款更正出貨
/// </summary>
public class AgentAfp {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentAfp simulator = new AgentAfp();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.uid = "80747";
rawData.key = "42e46576add74966278a81faf53f732f";
dynamic info = new ExpandoObject();
info.shipment_type = "2";
info.name = "金城武";
info.tel = "0900000123";
info.zip_code = "432";
info.ship_address = "台中市大肚區磺溪里16號";
rawData.shipping_info = info;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/afpshipmentupdate";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-後付款更正出貨
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentAfpShipmentUpdate {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentAfpShipmentUpdate simulator = new AgentAfpShipmentUpdate();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("uid", "80747");
rawData.put("key", "42e46576add74966278a81faf53f732f");
Map<Object, Object> info = new HashMap<Object, Object>();
info.put("shipment_type", "2");
info.put("name", "金城武");
info.put("tel", "0900000123");
info.put("zip_code", "432");
info.put("ship_address", "台中市大肚區磺溪里16號");
rawData.put("shipping_info", info);
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/afpshipmentupdate");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-後付款更正出貨
*/
function AgentAfpShipmentUpdate() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentAfpShipmentUpdate.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
uid: "80747",
key: "42e46576add74966278a81faf53f732f",
shipping_info: {
shipment_type: "2",
name: "金城武",
tel: "0900000123",
zip_code: "432",
ship_address: "台中市大肚區磺溪里16號"
}
};
};
/**
* 取得服務位置
*/
AgentAfpShipmentUpdate.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/afpshipmentupdate"
};
};
/**
* AES 256 加密
*/
AgentAfpShipmentUpdate.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentAfpShipmentUpdate.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentAfpShipmentUpdate.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentAfpShipmentUpdate.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentAfpShipmentUpdate = new AgentAfpShipmentUpdate();
AgentAfpShipmentUpdate.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-後付款更正出貨
"""
class AgentAfpShipmentUpdate:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'uid': "80747",
'key': "42e46576add74966278a81faf53f732f",
'shipping_info': {
'shipment_type': "2",
'name': "金城武",
'tel': "0900000123",
'zip_code': "432",
'ship_address': "台中市大肚區磺溪里16號"
}
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/afpshipmentupdate'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentAfpShipmentUpdate = AgentAfpShipmentUpdate()
AgentAfpShipmentUpdate.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功"
}
發動後付款交易後,在後付款請款發動之前,如出貨資訊資訊不正確,可以發動更正出貨修正出貨資訊。
經銷商『後付款更正出貨』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/afpshipmentupdate"} JSON格式,AES256加密資料 |
encry_data | text | 『後付款更正出貨』欄位參考 JSON格式,AES256加密資料 |
『後付款更正出貨』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | |
key | string | 特約商店驗證碼 | |
uid | string | 訂單編號(UID) | |
shipping_info | object | 送貨資訊 (後付款為必填) | 『後付款送貨資訊』欄位參考 |
『後付款更正出貨』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 回傳碼 | |
msg | string(500) | 回傳訊息 |
後付款查詢出貨
<?php
/**
* 經銷商串接-直接交易-後付款查詢出貨
*/
final class AgentAfpShipmentQuery
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['uid'] = "80685";
$rawData['key'] = "35aeb13990e4d57c3735467498e51b6f";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/afpshipmentquery'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentAfpShipmentQuery = new AgentAfpShipmentQuery();
$AgentAfpShipmentQuery->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-後付款查詢出貨
/// </summary>
public class AgentAfpShipmentQuery {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentAfpShipmentQuery simulator = new AgentAfpShipmentQuery();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.uid = "80747";
rawData.key = "42e46576add74966278a81faf53f732f";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/afpshipmentquery";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-後付款查詢出貨
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentAfpShipmentQuery {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentAfpShipmentQuery simulator = new AgentAfpShipmentQuery();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("uid", "80747");
rawData.put("key", "42e46576add74966278a81faf53f732f");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/afpshipmentquery");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-後付款查詢出貨
*/
function AgentAfpShipmentQuery() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentAfpShipmentQuery.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
uid: "80747",
key: "42e46576add74966278a81faf53f732f"
};
};
/**
* 取得服務位置
*/
AgentAfpShipmentQuery.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/afpshipmentquery"
};
};
/**
* AES 256 加密
*/
AgentAfpShipmentQuery.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentAfpShipmentQuery.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentAfpShipmentQuery.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentAfpShipmentQuery.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentAfpShipmentQuery = new AgentAfpShipmentQuery();
AgentAfpShipmentQuery.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-後付款查詢出貨
"""
class AgentAfpShipmentQuery:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'uid': "80747",
'key': "42e46576add74966278a81faf53f732f"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/afpshipmentquery'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentAfpShipmentQuery = AgentAfpShipmentQuery()
AgentAfpShipmentQuery.run()
回傳 JSON 結構如下:
{
"uid": 80998,
"key": "2b4a8cef072c2b8a0b0805d54f54275f",
"code": "250",
"msg": "付款完成",
"finishtime": "20210225173326",
"trade_no": "OD2100070580",
"order_id": "1234567890",
"user_id": "phper",
"user_real_name": "金城武",
"user_zipcode": "407",
"user_address": "台中市西屯區市政路402號5樓之1",
"user_cellphone": "0900000123",
"user_email": "[email protected]",
"shipping_info": {
"shipment_type": 2,
"company_name": null,
"department_name": null,
"name": "金城武",
"cvs": 0,
"cvs_store": null,
"cvs_store_name": null,
"zip_code": "432",
"ship_address": "台中市大肚區磺溪里15號",
"tel": "0900000123"
},
"shipment_no": "9876543210",
"delivery_code": 1,
"cost": 1000,
"currency": "TWD",
"actual_cost": 1000,
"actual_currency": "TWD",
"pfn": "AFP",
"refund_order": [],
"invoice_state": 0,
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_amount": "0",
"invoice_sales_amount": "0",
"invoice_tax_amount": "0",
"invoice_order_detail": "[]",
"invoice_ratetype": 1,
"invoice_input_type": null,
"invoice_allowance": [],
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
查詢發動後付款交易後的流程,當時候最新的訂單的相關資訊。
經銷商『後付款查詢出貨』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/afpshipmentquery"} JSON格式,AES256加密資料 |
encry_data | text | 『後付款查詢出貨』欄位參考 JSON格式,AES256加密資料 |
『後付款查詢出貨』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | |
uid | string | 訂單編號(UID) | |
key | string | 特約商店驗證碼 |
『後付款查詢出貨』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 訂單編號(UID) | |
key | string(50) | 交易驗証碼 | |
code | string | 交易狀態碼 | |
msg | string | 交易狀態訊息 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
trade_no | string | 後付款訂單編號 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
shipping_info | object | 送貨資訊 | 『後付款送貨資訊』欄位參考 |
shipment_no | string | 出貨編號 | |
delivery_code | integer | 貨運商家編號 | 『貨運商家編號』值參考 |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | |
refund_order | array | 退款訂單資訊(多筆格式) | 每筆『後付款出貨查詢-退款資訊』欄位參考 |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_date | string | 發票開立日期(YYYYMMDD) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | integer | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_allowance | array | 電子發票折讓資訊 | 每筆『電子發票折讓資訊』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
電票交易
<?php
/**
* 經銷商串接-直接交易-電票交易
*/
final class AgentEsvc
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['device_id'] = "01304161";
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '1',
'amount' => '1',
'total' => '1']];
$rawData['cost'] = "1";
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1";
$rawData['pfn'] = 'ESVC';
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentEsvc = new AgentEsvc();
$AgentEsvc->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-電票交易
/// </summary>
public class AgentEsvc {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentEsvc simulator = new AgentEsvc();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.device_id = "01304161";
rawData.items = items;
rawData.cost = "10";
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1";
rawData.pfn = "ESVC";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-電票交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentEsvc {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentEsvc simulator = new AgentEsvc();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "1");
item.put("amount", "1");
item.put("total", "1");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("device_id", "01304161");
rawData.put("items", items);
rawData.put("cost", "1");
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "ESVC");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-電票交易
*/
function AgentEsvc() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentEsvc.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
device_id: "01304161",
items: [{
'id': "1",
'name': "商品名稱",
'cost': "1",
'amount': "1",
'total': "1"
}],
cost: "1",
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "ESVC"
};
};
/**
* 取得服務位置
*/
AgentEsvc.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentEsvc.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentEsvc.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentEsvc.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentEsvc.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentEsvc = new AgentEsvc();
AgentEsvc.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-電票交易
"""
class AgentEsvc:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'device_id': "01304161",
'items': [{
'id': "1",
'name': "商品名稱",
'cost': "1",
'amount': "1",
'total': "1"
}],
'cost': "1",
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "ESVC"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentEsvc = AgentEsvc()
AgentEsvc.run()
回傳 JSON 結構如下:
{
"code": "250",
"msg": "執行成功。",
"uid": 83254,
"key": "c6a40103f46c113217e9d631ccfffa05",
"finishtime": "20210331160416",
"cardno": "",
"acode": "",
"order_id": "1234567890",
"user_id": "phper",
"cost": 1,
"currency": "TWD",
"actual_cost": 1,
"actual_currency": "TWD",
"pfn": "EASYCARD",
"trans_type": 1,
"result_type": 4,
"result_content": "{\n \"OrderTotalCost\": \"1\",\n \"TradeDate\": \"20210331160410\",\n \"PaymentType\": \"06\",\n \"Balance\": \"93\",\n \"BeforeBalance\": \"94\",\n \"AutoTopUpAmount\": \"0\",\n \"CardId\": \"658355957\"\n}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
請消費者將電子票證放於置讀卡上,然後發動電票交易,即可進行讀卡完成交易。
經銷商直接交易查詢參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『電票交易』欄位參考 JSON格式,AES256加密資料 |
『電票交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | (ESVC) |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | string | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
device_id | string | 電子票證設備ID |
『電票交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 交易回傳碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『電票類型』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content | string(1000) | 回傳結果 | 『電票交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
電票查詢卡號
<?php
/**
* 經銷商串接-直接交易-電票查詢卡號
*/
final class AgentEsvcQueryCardid
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['device_id'] = "01304161";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/esvcquerycardid'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentEsvcQueryCardid = new AgentEsvcQueryCardid();
$AgentEsvcQueryCardid->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-電票查詢卡號
/// </summary>
public class AgentEsvcQueryCardid {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentEsvcQueryCardid simulator = new AgentEsvcQueryCardid();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.device_id = "01304161";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/esvcquerycardid";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-電票查詢卡號
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentEsvcQueryCardid {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentEsvcQueryCardid simulator = new AgentEsvcQueryCardid();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("device_id", "01304161");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/esvcquerycardid");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-電票查詢卡號
*/
function AgentEsvcQueryCardid() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentEsvcQueryCardid.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
device_id: "01304161"
};
};
/**
* 取得服務位置
*/
AgentEsvcQueryCardid.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/esvcquerycardid"
};
};
/**
* AES 256 加密
*/
AgentEsvcQueryCardid.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentEsvcQueryCardid.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentEsvcQueryCardid.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentEsvcQueryCardid.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentEsvcQueryCardid = new AgentEsvcQueryCardid();
AgentEsvcQueryCardid.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-電票查詢卡號
"""
class AgentEsvcQueryCardid:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'device_id': "01304161"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/esvcquerycardid'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentEsvcQueryCardid = AgentEsvcQueryCardid()
AgentEsvcQueryCardid.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"cardid": "658355957"
}
請消費者將電子票證放於置讀卡上,然後發動電票查詢卡號,即可進行讀取卡號資訊。
經銷商電票查詢卡號參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/esvcquerycardid"} JSON格式,AES256加密資料 |
encry_data | text | 『電票查詢卡號』欄位參考 JSON格式,AES256加密資料 |
『電票查詢卡號』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店商務代號 | |
device_id | string | 設備編號 |
『電票查詢卡號』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 回傳碼 | |
msg | string(500) | 回傳訊息 | |
cardid | string | 電票卡號 |
電票查詢餘額
<?php
/**
* 經銷商串接-直接交易-電票查詢餘額
*/
final class AgentEsvcQueryBalance
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['device_id'] = "01304161";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/esvcquerybalance'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentEsvcQueryBalance = new AgentEsvcQueryBalance();
$AgentEsvcQueryBalance->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-電票查詢餘額
/// </summary>
public class AgentEsvcQueryBalance {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentEsvcQueryBalance simulator = new AgentEsvcQueryBalance();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.device_id = "01304161";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/esvcquerybalance";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-電票查詢餘額
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentEsvcQueryBalance {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentEsvcQueryBalance simulator = new AgentEsvcQueryBalance();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("device_id", "01304161");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/esvcquerybalance");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-電票查詢餘額
*/
function AgentEsvcQueryBalance() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentEsvcQueryBalance.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
device_id: "01304161"
};
};
/**
* 取得服務位置
*/
AgentEsvcQueryBalance.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/esvcquerybalance"
};
};
/**
* AES 256 加密
*/
AgentEsvcQueryBalance.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentEsvcQueryBalance.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentEsvcQueryBalance.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentEsvcQueryBalance.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentEsvcQueryBalance = new AgentEsvcQueryBalance();
AgentEsvcQueryBalance.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-電票查詢餘額
"""
class AgentEsvcQueryBalance:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'device_id': "01304161"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/esvcquerybalance'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentEsvcQueryBalance = AgentEsvcQueryBalance()
AgentEsvcQueryBalance.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"balance": 93,
"cardid": "658355957",
"cardbrand": "EASYCARD"
}
請消費者將電子票證放於置讀卡上,然後發動電票查詢餘額,即可進行讀取電子票證之餘額以及卡別資訊。
經銷商電票查詢餘額參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/esvcquerycardid"} JSON格式,AES256加密資料 |
encry_data | text | 『電票查詢餘額』欄位參考 JSON格式,AES256加密資料 |
『電票查詢餘額』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店商務代號 | |
device_id | string | 設備編號 |
『電票查詢餘額』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 回傳碼 | |
msg | string(500) | 回傳訊息 | |
balance | float | 餘額 | |
cardid | string | 電票卡號 | |
cardbrand | string | 電票類型 | 『電票類型』值參考 |
電票退款
<?php
/**
* 經銷商串接-直接交易-電票退款
*/
final class AgentEsvcRefund
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['device_id'] = "01304161";
$rawData['uid'] = "83091";
$rawData['key'] = "f4823bd2c2a462eaece7b7c25d0f4470";
$rawData['cost'] = 1;
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/esvcrefund'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentEsvcRefund = new AgentEsvcRefund();
$AgentEsvcRefund->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-電票退款
/// </summary>
public class AgentEsvcRefund {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentEsvcRefund simulator = new AgentEsvcRefund();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.device_id = "01304161";
rawData.uid = "83091";
rawData.key = "f4823bd2c2a462eaece7b7c25d0f4470";
rawData.cost = 1;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/esvcrefund";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-電票退款
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentEsvcRefund {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentEsvcRefund simulator = new AgentEsvcRefund();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("device_id", "01304161");
rawData.put("uid", "83091");
rawData.put("key", "f4823bd2c2a462eaece7b7c25d0f4470");
rawData.put("cost", 1);
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/esvcrefund");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-電票退款
*/
function AgentEsvcRefund() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentEsvcRefund.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
device_id: "01304161",
uid: "83091",
key: "f4823bd2c2a462eaece7b7c25d0f4470",
cost: 1
};
};
/**
* 取得服務位置
*/
AgentEsvcRefund.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/esvcrefund"
};
};
/**
* AES 256 加密
*/
AgentEsvcRefund.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentEsvcRefund.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentEsvcRefund.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentEsvcRefund.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentEsvcRefund = new AgentEsvcRefund();
AgentEsvcRefund.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-電票退款
"""
class AgentEsvcRefund:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'device_id': "01304161",
'uid': "83091",
'key': "f4823bd2c2a462eaece7b7c25d0f4470",
'cost': '1'
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/esvcrefund'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentEsvcRefund = AgentEsvcRefund()
AgentEsvcRefund.run()
回傳 JSON 結構如下:
{
"key": "f4823bd2c2a462eaece7b7c25d0f4470",
"uid": "83091",
"code": "B500",
"msg": "線上退款失敗,原因為:退款密碼錯誤。",
"row_data": null
}
請消費者將電子票證放於置讀卡上,然後發動電票退款,即可進行退款。
經銷商電票退款參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/esvcquerycardid"} JSON格式,AES256加密資料 |
encry_data | text | 『電票退款』欄位參考 JSON格式,AES256加密資料 |
『電票退款』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | |
device_id | string | 設備編號 | |
key | string(50) | 交易驗証碼 | |
uid | string | 訂單編號(UID) | |
cost | string | 退款金額(可部分退款) | |
invoice_state | integer | 若有開立電子發票,指定電子發票使用作廢或折讓 注意:跨發票月份無法作廢 |
『電子發票退款時使用作廢或折讓』值參考 |
items | array | 退款項目 若使用電子發票,此欄位必填 退款項目必須和交易時之產品項目名稱相同 項目總金額必須與退款金額一致 |
每筆『商品項目』欄位參考 |
『電票退款』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
key | string | 特約商店驗證碼 | |
uid | string | 訂單編號(UID) | |
code | string | 處理狀態 B200 或 B500 | |
msg | string(500) | 回傳訊息 | |
row_data | object | 退款資訊(退款成功才有此資訊) | 『電票交易退款完成資訊』欄位參考 |
eACH交易
<?php
/**
* 經銷商串接-直接交易-eACH
*/
final class AgentEach
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1";
$rawData['pfn'] = "EACH";
$rawData['each_code'] = "560";
$rawData['bank_uid'] = "461";
$rawData['bank_account'] = "00551234567890";
$rawData['user_cellphone_code'] = "886";
$rawData['user_cellphone'] = "924123312";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentEach = new AgentEach();
$AgentEach->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-eACH
/// </summary>
public class AgentEach {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentEach simulator = new AgentEach();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = "10";
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1";
rawData.pfn = "EACH";
rawData.each_code = "560";
rawData.bank_uid = "461";
rawData.bank_account = "00551234567890";
rawData.user_cellphone_code = "886";
rawData.user_cellphone = "924123312";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-eACH
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentEach {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentEach simulator = new AgentEach();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", "10");
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "EACH");
rawData.put("each_code", "560");
rawData.put("bank_uid", "461");
rawData.put("bank_account", "00551234567890");
rawData.put("user_cellphone_code", "886");
rawData.put("user_cellphone", "924123312");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-eACH
*/
function AgentEach() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentEach.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}],
cost: "10",
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "EACH",
each_code: "560",
bank_uid: "461",
bank_account: "00551234567890",
user_cellphone_code: "886",
user_cellphone: "924123312"
};
};
/**
* 取得服務位置
*/
AgentEach.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentEach.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentEach.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentEach.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentEach.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentEach = new AgentEach();
AgentEach.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-eACH
"""
class AgentEach:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}],
'cost': "10",
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "EACH",
'each_code': "560",
'bank_uid': "461",
'bank_account': "00551234567890",
'user_cellphone_code': "886",
'user_cellphone': "924123312"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentEach = AgentEach()
AgentEach.run()
回傳 JSON 結構如下:
{
"code": "300",
"msg": "執行失敗,交易失敗,原因:非EACH參加行。",
"uid": 85390,
"key": "9373b656ff1538a53c9845c1e30f1a8d",
"finishtime": "",
"cardno": "",
"acode": "",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "EACH",
"trans_type": 1,
"result_type": 4,
"result_content_type": "EACH",
"result_content": "{\n \"TradeNo\": \"20210507853900\"\n}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
消費者透過網銀或金融卡申請eDDA電子化授權後,透過授權後的相關資訊,可發動eACH交易。
經銷商eACH交易參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『eACH交易』欄位參考 JSON格式,AES256加密資料 |
『eACH交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | 必填 |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | string | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
each_code | string | 交易代碼(eDDA授權資訊) | 必填 |
user_cellphone_code | string(6) | 手機區碼(eDDA授權資訊) | 必填 |
user_cellphone | string(20) | 手機號碼(eDDA授權資訊) | 必填 |
bank_uid | string | 扣款銀行代碼(eDDA授權資訊) | 必填 |
bank_account | string | 扣款銀行帳號(eDDA授權資訊) | 必填 |
『eACH交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 交易回傳碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
超商條碼繳費
<?php
/**
* 經銷商串接-直接交易-超商條碼繳費
*/
final class AgentBarcode
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [
[
'id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10'
]
];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1";
$rawData['pfn'] = "BARCODE";
$rawData['limit_pay_days'] = 40;
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentBarcode = new AgentBarcode();
$AgentBarcode->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-超商條碼繳費
/// </summary>
public class AgentBarcode {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentBarcode simulator = new AgentBarcode();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1";
rawData.pfn = "BARCODE";
rawData.limit_pay_days = 40;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-超商條碼繳費
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentBarcode {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentBarcode simulator = new AgentBarcode();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "BARCODE");
rawData.put("limit_pay_days", 40);
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-超商條碼繳費
*/
function AgentBarcode() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentBarcode.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': '1',
'name': '商品名稱',
'cost': '10',
'amount': '1',
'total': '10'
}
],
cost: 10,
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "BARCODE",
limit_pay_days: 40,
};
};
/**
* 取得服務位置
*/
AgentBarcode.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentBarcode.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentBarcode.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentBarcode.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentBarcode.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentBarcode = new AgentBarcode();
AgentBarcode.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-超商條碼繳費
"""
class AgentBarcode:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': '1',
'name': '商品名稱',
'cost': '10',
'amount': '1',
'total': '10'
}
],
'cost': 10,
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "BARCODE",
'limit_pay_days': 40,
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentBarcode = AgentBarcode()
AgentBarcode.run()
回傳 JSON 結構如下:
{
"code": "260",
"msg": "執行成功。交易成功",
"uid": 87071,
"key": "1f4a2db6abd0131ae52de3af6a363594",
"finishtime": "",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "新光銀行",
"supplier_code": "B0",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "BARCODE",
"trans_type": 1,
"result_type": 4,
"result_content_type": "BARCODE",
"result_content": "{\n \"BarCode1\": \"1007106V6\",\n \"BarCode2\": \"0073711910000563\",\n \"BarCode3\": \"071048000000010\",\n \"LimitDate\": \"20210710235959\"\n}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
發動交易後,得到三組條碼資料,產生Barcode後讓消費者透過超商或臨櫃作繳費動作。
條碼品質及規則建議:
經銷商超商條碼繳費交易參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『超商條碼繳費』欄位參考 JSON格式,AES256加密資料 |
『超商條碼繳費』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | 必填 『付款方式』值參考 |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | string | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
limit_pay_days | string | 繳費有效天數(如無此資料以系統設定為預設) |
『超商條碼繳費』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 交易回傳碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | string | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『超商條碼繳費』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
全支付線上交易
商家發動後會根據回應資料內容result_content中,依據使用裝置,開啟相對應的連結
因上游無提供測試資料,皆無法進行測試
<?php
/**
* 經銷商串接-全支付線上交易
*/
final class AgentPxpayon
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880011";
/**
* 串接交易位置
* @var string
*/
public $url = "http://pay.k20-mypay.tw/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [
[
'id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10'
]
];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "O20240618120110";
$rawData['ip'] = "127.0.0.1";
$rawData['pfn'] = "PXPAYON";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPxpayon = new AgentPxpayon();
$AgentPxpayon->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-全支付線上交易
/// </summary>
public class AgentPxpayon {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880011";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "http://pay.k20-mypay.tw/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPxpayon simulator = new AgentPxpayon();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item1 = new ExpandoObject();
item1.id = "1";
item1.name = "商品名稱";
item1.cost = "10";
item1.amount = "1";
item1.total = "10";
items.Add(item1);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "O20240618120110";
rawData.ip = "127.0.0.1";
rawData.pfn = "PXPAYON";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-全支付線上交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPxpayon {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880011";
/**
* 串接交易位置
*/
String url = "http://pay.k20-mypay.tw/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPxpayon simulator = new AgentPxpayon();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item1 = new HashMap<Object, Object>();
item1.put("id", "1");
item1.put("name", "商品名稱");
item1.put("cost", "10");
item1.put("amount", "1");
item1.put("total", "10");
items.add(item1);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "O20240618120110");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "PXPAYON");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-全支付線上交易
*/
function AgentPxpayon() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880011";
// 串接交易位置
this.url = "http://pay.k20-mypay.tw/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPxpayon.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: 10,
user_id: "phper",
order_id: "O20240618120110",
ip: "127.0.0.1",
pfn: "PXPAYON",
};
};
/**
* 取得服務位置
*/
AgentPxpayon.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentPxpayon.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPxpayon.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPxpayon.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPxpayon.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPxpayon = new AgentPxpayon();
AgentPxpayon.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-全支付線上交易
"""
class AgentPxpayon:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880011"
# 串接交易位置
url = "http://pay.k20-mypay.tw/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': 10,
'user_id': "phper",
'order_id': "O20240618120110",
'ip': "127.0.0.1",
'pfn': "PXPAYON",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPxpayon = AgentPxpayon()
AgentPxpayon.run()
回傳 JSON 結構如下:
{
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_seller_name": "",
"invoice_buyer_ban": "",
"invoice_buyer_name": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 2,
"invoice_print_device": 1,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_tax_rate": "",
"invoice_remark": "",
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_tax_title": "",
"invoice_natural_person": "",
"invoice_m_post_zone": "",
"invoice_m_address": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
"code": "280",
"msg": "執行成功。",
"uid": 194591,
"key": "68d2a09c31643660f29172d80dbaf9ef",
"finishtime": "",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"is_agent_charge": 0,
"transaction_mode": "1",
"supplier_name": "全支付",
"supplier_code": "W8",
"order_id": "O20240618120152",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "PXPAYON",
"actual_pay_mode": "",
"trans_type": 1,
"result_type": 4,
"result_content_type": "PXPAYON",
"result_content": "{\"Web\":\"https:\\\/\\\/uat.pxpayplus.com\\\/pxplus_ec\\\/page_redirect?data=aHR0cHM6Ly91YXQucHhwYXlwbHVzLmNvbS9xcmNvZGUvZWM%2FZGF0YT1hZ0dGQlJ0UkU3bHZrOEhOU0llRFZxMzJXNTZZbFNPZ2h4ZjJmSkx6Z1JoUFgyVTZ2SWd0cWZjM0VvYXo5SXRjbSUyZnZvcmVZd0tKdWoxN1YyUHJjaDRRJTNkJTNk&destination=PxPlus\",\"QRCodeUrl\":\"https:\\\/\\\/uat.pxpayplus.com\\\/qrcode\\\/ec?data=agGFBRtRE7lvk8HNSIeDVq32W56YlSOghxf2fJLzgRhPX2U6vIgtqfc3Eoaz9Itcm%2fvoreYwKJuj17V2Prch4Q%3d%3d\"}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"sys_echo": ""
}
經銷商『全支付線上交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『全支付線上交易』欄位參考 JSON格式,AES256加密資料 |
『全支付線上交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string | 特約商店代碼 | 必填 |
cost | string | 訂單總金額 | 必填 |
currency | string | 預設交易幣別(預設為TWD新台幣) | |
order_id | string | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 | |
pfn | string | 付費方法 (PXPAYON) | 必填 |
discount | string | 折價金額 (預設0) | |
shipping_fee | string | 運費 | |
user_id | string | 消費者帳號 | |
user_name | string | 消費者姓名 | |
user_real_name | string | 消費者真實姓名 | |
user_english_name | string | 消費者英文名稱 | |
user_zipcode | string | 消費者郵遞區號 | |
user_address | string | 消費者地址 | |
user_sn_type | string | 證號類型 | 『證號類型』值參考 |
user_sn | string | 付款人身分證/統一證號/護照號碼 | |
user_phone | string | 消費者家用電話 | |
user_cellphone_code | string | 消費者行動電話國碼 | |
user_cellphone | string | 消費者行動電話 | |
user_email | string | 消費者 E-Mail | |
user_birthday | string | 消費者生日 | |
ip | string | 消費者來源 IP | |
issue_invoice_state | integer | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_m_post_zone | string | EMail 紙本寄送郵遞區號 | 當invoice_cloud_type為4,此欄位才有效,非必須 |
invoice_m_address | string | EMail 紙本寄送住址 | 當invoice_cloud_type為4,此欄位才有效,非必須 |
invoice_love_code | string | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
interface | string | 消費者操作介面類型 pc/app | |
agent_sms_fee_type | integer | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string | 經銷商代收費 | |
is_agent_charge | integer | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
『全支付線上交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 交易狀態代碼 | |
msg | string | 回傳訊息 | |
uid | string | Payment Hub之交易流水號 | |
key | string | 交易驗証碼 | |
finishtime | string | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string | 銀行端口回傳碼 | |
acode | string | 授權碼 | |
card_type | integer | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string | 發卡行 | |
issuing_bank_uid | string | 發卡銀行代碼 | |
is_agent_charge | int | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string | 交易之金融服務商 | |
supplier_code | string | 交易之金融服務商代碼 | |
order_id | string | 貴特店系統的訂單編號 | |
user_id | string | 消費者帳號 | |
cost | string | 總交易金額 | |
currency | string | 原交易幣別 | |
actual_cost | string | 實際交易金額 | |
actual_currency | string | 實際交易幣別 | |
pfn | string | 付費方法 | 『回傳付款方式』值參考 |
actual_pay_mode | string | 實際支付方式 (當pfn為CASH-自行收款時,告知系統實際收款方式) |
『自行收款付款方式』值參考 |
trans_type | integer | 交易類型 | 『交易類型定義』值參考 |
result_type | string | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string | 回傳結果 | 『全支付線上交易回傳欄位』值參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 | |
invoice_state | integer | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string | 發票開立狀態訊息 | |
invoice_date | string | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string | 發票字軌 | |
invoice_number | string | 發票號碼 | |
invoice_rand_code | string | 電子發票隨機碼 | |
invoice_seller_ban | string | 賣方統一編號 | |
invoice_seller_name | string | 賣方名稱 | |
invoice_buyer_ban | string | 買方統一編號 | |
invoice_buyer_name | string | 買方名稱 | |
invoice_left_qrcode | string | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string | 電子發票右邊QrCode內容 | |
invoice_title_type | integer | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string | 電子發票列印標題格式 | |
invoice_print_type | integer | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string | 電子發票銷售總額 | |
invoice_sales_amount | string | 電子發票銷售額 | |
invoice_tax_amount | string | 電子發票稅額 | |
invoice_order_detail | string | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_tax_title | string | 當invoice_cloud_type為2時紀錄的買受人公司名稱 | |
invoice_natural_person | string | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_m_post_zone | string | 當invoice_cloud_type為4時紀錄中獎時紙本發票郵遞區號 | |
invoice_m_address | string | 當invoice_cloud_type為4時紀錄中獎時紙本發票收件住址 | |
invoice_love_code | string | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string | 當invoice_input_type為3時紀錄的發票地址 |
全支付線下交易
消費者提供PXPay plus支付碼供設備進行掃碼做交易動作。
因上游無提供測試資料,皆無法進行測試
<?php
/**
* 經銷商串接-直接交易-全支付線下交易
*/
final class AgentPxpayoff
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [
[
'id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10'
]
];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "O20211203114630";
$rawData['ip'] = "127.0.0.1";
$rawData['pfn'] = "PXPAYOFF";
$rawData['data_json'] = "{\"pxCode\":\"P1M281A4C00B2JOO1N\",\"posId\":\"1\",\"posTradeTime\":\"20211203114630\",\"remark\":\"交易註記\"}";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPxpayoff = new AgentPxpayoff();
$AgentPxpayoff->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-全支付線下交易
/// </summary>
public class AgentPxpayoff {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPxpayoff simulator = new AgentPxpayoff();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "O20211203114630";
rawData.ip = "127.0.0.1";
rawData.pfn = "PXPAYOFF";
rawData.data_json = "{\"pxCode\":\"P1M281A4C00B2JOO1N\",\"posId\":\"1\",\"posTradeTime\":\"20211203114630\",\"remark\":\"交易註記\"}";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-全支付線下交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPxpayoff {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPxpayoff simulator = new AgentPxpayoff();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "O20211203114630");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "PXPAYOFF");
rawData.put("data_json", "{\"pxCode\":\"P1M281A4C00B2JOO1N\",\"posId\":\"1\",\"posTradeTime\":\"20211203114630\",\"remark\":\"交易註記\"}");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-全支付線下交易
*/
function AgentPxpayoff() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPxpayoff.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: 10,
user_id: "phper",
order_id: "O20211203114630",
ip: "127.0.0.1",
pfn: "PXPAYOFF",
data_json: "{\"pxCode\":\"P1M281A4C00B2JOO1N\",\"posId\":\"1\",\"posTradeTime\":\"20211203114630\",\"remark\":\"交易註記\"}",
};
};
/**
* 取得服務位置
*/
AgentPxpayoff.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentPxpayoff.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPxpayoff.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPxpayoff.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPxpayoff.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPxpayoff = new AgentPxpayoff();
AgentPxpayoff.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-全支付線下交易
"""
class AgentPxpayoff:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': 10,
'user_id': "phper",
'order_id': "O20211203114630",
'ip': "127.0.0.1",
'pfn': "PXPAYOFF",
'data_json': "{\"pxCode\":\"P1M281A4C00B2JOO1N\",\"posId\":\"1\",\"posTradeTime\":\"20211203114630\",\"remark\":\"交易註記\"}",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPxpayoff = AgentPxpayoff()
AgentPxpayoff.run()
回傳 JSON 結構如下:
{
"code": "250",
"msg": "執行成功。",
"uid": 98432,
"key": "7f8a2b459ae296a9d3fe8fffd0d7f8d2",
"finishtime": "20211203114635",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "全支付",
"supplier_code": "W8",
"order_id": "O20211203114630",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 10,
"actual_currency": "TWD",
"pfn": "PXPAYOFF",
"trans_type": 1,
"result_type": 4,
"result_content_type": "PXPAYOFF",
"result_content": "{\n \"PosID\": \"121212\",\n \"PosTradeTime\": \"20220101235959\",\n \"Remark\": \"\",\n \"TradeNo\": \"123\",\n \"OrderTotalCost\": \"100\",\n \"TradeDate\": \"20220101235959\",\n \"DebitAmount\": \"100\",\n \"InvoiceVehicle\": \"/MFX844T\",\n \"MerMemToken\": \"TX916173531933310976\",\n \"Pan\": \"******013000****\",\n \"IsControversy\": \"0\"}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 0,
"invoice_print_device": 0,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": ""
}
經銷商全支付線下交易參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『全支付線下交易』欄位參考 JSON格式,AES256加密資料 |
『直接交易-全支付線下交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
data_json | string(500) | 全支付線下資訊輸入(JSON格式) | 『全支付線下資料』值參考 |
『直接交易-全支付線下交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(500) | 回傳結果 | 『全支付線下交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
LINEPay線上交易
商家發動後會根據回應資料內容result_content中,依據使用裝置,開啟相對應的連結
<?php
/**
* 經銷商串接-直接交易-LINEPay線上
*/
final class AgentLinepayon
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "A1234567891002";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "LINEPAYON";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentLinepayon = new AgentLinepayon();
$AgentLinepayon->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 特約商店串接-Pi錢包線下交易
/// </summary>
public class AgentLinepayon {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentLinepayon simulator = new AgentLinepayon();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1";
rawData.pfn = "LINEPAYON";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.storeKey, IV);
var svr_encode = Encrypt(svr_json, this.storeKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-Pi錢包線下交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentLinepayon {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentLinepayon simulator = new AgentLinepayon();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "LINEPAYON");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-Pi錢包線下交易
*/
function AgentLinepayon() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentLinepayon.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: 10,
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "LINEPAYON"
};
};
/**
* 取得服務位置
*/
AgentLinepayon.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentLinepayon.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentLinepayon.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentLinepayon.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentLinepayon.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentLinepayon = new AgentLinepayon();
AgentLinepayon.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-Pi錢包線下交易
"""
class AgentLinepayon:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': 10,
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "LINEPAYON"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentLinepayon = AgentLinepayon()
AgentLinepayon.run()
回傳 JSON 結構如下:
{
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_seller_name": "",
"invoice_buyer_ban": "",
"invoice_buyer_name": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 2,
"invoice_print_device": 1,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_tax_rate": "",
"invoice_remark": "",
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_tax_title": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
"code": "280",
"msg": "執行成功。",
"uid": 156364,
"key": "56075c95f08a5729251af655e6315013",
"finishtime": "",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"is_agent_charge": 0,
"transaction_mode": "1",
"supplier_name": "台灣連線股份有限公司",
"supplier_code": "W2",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "LINEPAYON",
"actual_pay_mode": "",
"trans_type": 1,
"result_type": 4,
"result_content_type": "LINEPAYON",
"result_content": "{\"Web\":\"https:\\\/\\\/sandbox-web-pay.line.me\\\/web\\\/payment\\\/wait?transactionReserveId=T1RrZlpNakorU0M0MHFMdTBCditnZU9RSjBtMXNOWlM4RUdVQlFnMnN5L1ppeDBBQnVTSlpsMURlK3ZzQVcwYQ&locale=zh-TW_LP\",\"App\":\"line:\\\/\\\/pay\\\/payment\\\/T1RrZlpNakorU0M0MHFMdTBCditnZU9RSjBtMXNOWlM4RUdVQlFnMnN5L1ppeDBBQnVTSlpsMURlK3ZzQVcwYQ\",\"TradeNo\":\"2023112002042370710\"}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"sys_echo": ""
}
經銷商『LINEPay線上交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『LINEPay線上交易』欄位參考 JSON格式,AES256加密資料 |
『LINEPay線上交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float(5) | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string(70) | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
success_returl | string(255) | 交易成功導頁網址(導頁式交易有效) | |
failure_returl | string(255) | 交易失敗導頁網址(導頁式交易有效) |
『LINEPay線上交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
actual_pay_mode | string(20) | 實際支付方式 (當pfn為CASH-自行收款時,告知系統實際收款方式) |
『自行收款付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『Line Pay線上交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
LINE Pay線下交易
消費者提供LINE Pay支付碼供設備進行掃碼做交易動作。
<?php
/**
* 經銷商串接-直接交易-LINEPay線下
*/
final class AgentLinepayoff
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "LINEPAYOFF";
$rawData['data_json'] = json_encode(['linepayCode' => '314818461832250045'], JSON_UNESCAPED_UNICODE);
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentLinepayoff = new AgentLinepayoff();
$AgentLinepayoff->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-LINEPay線下
/// </summary>
public class AgentLinepayoff {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentLinepayoff simulator = new AgentLinepayoff();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "O20211203114630";
rawData.ip = "127.0.0.1";
rawData.pfn = "LINEPAYOFF";
rawData.data_json = "{\"linepayCode\":\"314818461832250045\"}";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-LINEPay線下
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentLinepayoff {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentLinepayoff simulator = new AgentLinepayoff();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "O20211203114630");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "LINEPAYOFF");
rawData.put("data_json", "{\"linepayCode\":\"314818461832250045\"}");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-錢包被掃交易-LINEPay線下
*/
function AgentLinepayoff() {
// 特約商店商務代號
this.agentUid = "518169081001";
// 特約商店金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentLinepayoff.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: "10",
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "LINEPAYOFF",
data_json: "{\"linepayCode\":\"314818461832250045\"}",
};
};
/**
* 取得服務位置
*/
AgentLinepayoff.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentLinepayoff.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentLinepayoff.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentLinepayoff.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentLinepayoff.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentLinepayoff = new AgentLinepayoff();
AgentLinepayoff.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-錢包被掃交易-LINEPay線下
"""
class AgentLinepayoff:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': "10",
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "LINEPAYOFF",
'data_json': "{\"linepayCode\":\"314818461832250045\"}",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentLinepayoff = AgentLinepayoff()
AgentLinepayoff.run()
> 回傳 JSON 結構如下:
```json
{
"code": "250",
"msg": "執行成功。",
"uid": 106658,
"key": "970f6eb5c70e3a7582e825d67cc6a289",
"finishtime": "20220419174739",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "台灣連線股份有限公司",
"supplier_code": "W2",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 10,
"actual_currency": "TWD",
"pfn": "LINEPAYOFF",
"trans_type": 1,
"result_type": 4,
"result_content_type": "LINEPAYOFF",
"result_content": "{\n \"TradeNo\": \"2022041900711036410\",\n \"OrderTotalCost\": \"10\",\n \"TradeDate\": \"20220419174739\",\n \"InvoiceVehicle\": \"/MZA588U\",\n \"RedeemAmount\": \"10\",\n \"RedeemType\": \"1\",\n \"OrderRealCost\": \"10\",\n \"PaymentType\": \"\",\n \"CreditAmt\": \"0\",\n \"IsControversy\": \"0\"}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 0,
"invoice_print_device": 0,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
}
經銷商LINE Pay線下交易參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『LINE Pay線下交易』欄位參考 JSON格式,AES256加密資料 |
『直接交易-LINE Pay線下交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | 必填 |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | 必填 |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
data_json | string(500) | LINE Pay線下資訊輸入(JSON格式) | 『Line Pay線下資料』值參考 |
『直接交易-LINE Pay線下交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『Line Pay線下交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
Pi線上交易
商家發動後會根據回應資料內容result_content中,依據使用裝置,開啟相對應的連結
因上游無提供測試資料,皆無法進行測試
<?php
/**
* 經銷商串接-直接交易-Pi錢包線上
*/
final class AgentPion
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "A1234567891002";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "PION";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPion = new AgentPion();
$AgentPion->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-Pi錢包線下交易
/// </summary>
public class AgentPion {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPion simulator = new AgentPion();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1";
rawData.pfn = "PIOFF";
rawData.data_json = "{\"piCode\":\"PI24456862cukoY9JD\"}";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-Pi錢包線下交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPion {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPion simulator = new AgentPion();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "PIOFF");
rawData.put("data_json", "{\"piCode\":\"PI24456862cukoY9JD\"}");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-Pi錢包線下交易
*/
function AgentPion() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPion.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: 10,
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "PIOFF",
data_json: "{\"piCode\":\"PI24456862cukoY9JD\"}",
};
};
/**
* 取得服務位置
*/
AgentPion.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentPion.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPion.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPion.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPion.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPion = new AgentPion();
AgentPion.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-Pi錢包線下交易
"""
class AgentPion:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': 10,
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "PIOFF",
'data_json': "{\"piCode\":\"PI24456862cukoY9JD\"}",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPion = AgentPion()
AgentPion.run()
回傳 JSON 結構如下:
{
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_seller_name": "",
"invoice_buyer_ban": "",
"invoice_buyer_name": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 2,
"invoice_print_device": 1,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_tax_rate": "",
"invoice_remark": "",
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_tax_title": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
"code": "280",
"msg": "執行成功。",
"uid": 156448,
"key": "70e2119e054c78b1e1bcd8a7159021d5",
"finishtime": "",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"is_agent_charge": 0,
"transaction_mode": "1",
"supplier_name": "拍付國際資訊",
"supplier_code": "W9",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "PION",
"actual_pay_mode": "",
"trans_type": 1,
"result_type": 4,
"result_content_type": "PION",
"result_content": "{\"Web\":\"https:\\\/\\\/ap-test-wp.piapp.com.tw\\\/partner_qrcode\\\/v1\\\/payment\\\/select\\\/655b25584fe59\",\"App\":\"intent:\\\/\\\/www.piapp.com.tw?type=partner_qrcode&qrcode_url=https%3A%2F%2Fap-test.p
iapp.com.tw%2Fpartner_qrcode%2Fv1%2Fbill%2F655b25584fe59&browser=com.android.chrome#Intent;package=tw.com.pchome.android.pi.partner;scheme=pi;end;\",\"AppIOS\":\"https:\\\/\\\/ap-test.piapp.com.tw\\\/app\\\/download?type=partner_qrcode&qrcode_url=https%3A%2F%2Fap-test.piapp.com.tw%2Fpartner_qrcode%2Fv1%2Fbill%2F655b25584fe59&browser=com.android.chrome\",\"ExpiredTime\":\"20231120182232\"}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"sys_echo": ""
}
特約商店『Pi線上交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『Pi線上交易』欄位參考 JSON格式,AES256加密資料 |
『Pi線上交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float(5) | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string(70) | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
success_returl | string(255) | 交易成功導頁網址(導頁式交易有效) | |
failure_returl | string(255) | 交易失敗導頁網址(導頁式交易有效) |
『Pi線上交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
actual_pay_mode | string(20) | 實際支付方式 (當pfn為CASH-自行收款時,告知系統實際收款方式) |
『自行收款付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『Pi線上資料回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
Pi線下交易
消費者提供Pi支付碼供設備進行掃碼做交易動作。
因上游無提供測試資料,皆無法進行測試
<?php
/**
* 經銷商串接-直接交易-Pi錢包線下
*/
final class AgentPioff
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "PIOFF";
$rawData['data_json'] = json_encode(['piCode' => 'PI7E3A60BD8C8F23F6'], JSON_UNESCAPED_UNICODE);
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPioff = new AgentPioff();
$AgentPioff->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-Pi錢包線下
/// </summary>
public class AgentPioff {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPioff simulator = new AgentPioff();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "O20211203114630";
rawData.ip = "127.0.0.1";
rawData.pfn = "PIOFF";
rawData.data_json = "{\"piCode\":\"PI7E3A60BD8C8F23F6\"}";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-Pi錢包線下
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPioff {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPioff simulator = new AgentPioff();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "O20211203114630");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "PIOFF");
rawData.put("data_json", "{\"piCode\":\"PI7E3A60BD8C8F23F6\"}");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-錢包被掃交易-Pi錢包線下
*/
function AgentPioff() {
// 特約商店商務代號
this.agentUid = "518169081001";
// 特約商店金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPioff.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: "10",
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "PIOFF",
data_json: "{\"piCode\":\"PI7E3A60BD8C8F23F6\"}",
};
};
/**
* 取得服務位置
*/
AgentPioff.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentPioff.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPioff.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPioff.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPioff.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPioff = new AgentPioff();
AgentPioff.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-錢包被掃交易-Pi錢包線下
"""
class AgentPioff:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': "10",
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "PIOFF",
'data_json': "{\"piCode\":\"PI7E3A60BD8C8F23F6\"}",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPioff = AgentPioff()
AgentPioff.run()
回傳 JSON 結構如下:
{
"code": "250",
"msg": "執行成功。",
"uid": 106658,
"key": "970f6eb5c70e3a7582e825d67cc6a289",
"finishtime": "20220419174739",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "台灣連線股份有限公司",
"supplier_code": "W2",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 10,
"actual_currency": "TWD",
"pfn": "PIOFF",
"trans_type": 1,
"result_type": 4,
"result_content_type": "PIOFF",
"result_content": "{\n \"TradeNo\": \"TX2226274154701960\",\n \"OrderTotalCost\": \"10\",\n \"TradeDate\": \"20220419174739\",\n \"CarrierCode\": \"/VXXP-O2\"\n}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 0,
"invoice_print_device": 0,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
}
經銷商Pi線下交易參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『Pi線下交易』欄位參考 JSON格式,AES256加密資料 |
『直接交易-Pi線下交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | 必填 |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | 必填 |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
data_json | string(500) | Pi線下資訊輸入(JSON格式) | 『Pi線下資料』值參考 |
『直接交易-Pi線下交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『Pi線下交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
微信線下交易
消費者提供微信支付碼供設備進行掃碼做交易動作。
因上游無提供測試資料,皆無法進行測試
<?php
/**
* 經銷商串接-直接交易-微信線下
*/
final class AgentWechatoff
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "WECHATOFF";
$rawData['data_json'] = json_encode(['wechatCode' => '134507721102798524'], JSON_UNESCAPED_UNICODE);
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentWechatoff = new AgentWechatoff();
$AgentWechatoff->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-微信線下
/// </summary>
public class AgentWechatoff {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentWechatoff simulator = new AgentWechatoff();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "O20211203114630";
rawData.ip = "127.0.0.1";
rawData.pfn = "WECHATOFF";
rawData.data_json = "{\"wechatCode\":\"134507721102798524\"}";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-微信線下
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentWechatoff {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentWechatoff simulator = new AgentWechatoff();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "O20211203114630");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "WECHATOFF");
rawData.put("data_json", "{\"wechatCode\":\"134507721102798524\"}");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-錢包被掃交易-微信線下
*/
function AgentWechatoff() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentWechatoff.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: "10",
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "WECHATOFF",
data_json: "{\"wechatCode\":\"134507721102798524\"}",
};
};
/**
* 取得服務位置
*/
AgentWechatoff.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentWechatoff.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentWechatoff.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentWechatoff.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentWechatoff.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentWechatoff = new AgentWechatoff();
AgentWechatoff.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-錢包被掃交易-微信線下
"""
class AgentWechatoff:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': "10",
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "WECHATOFF",
'data_json': "{\"wechatCode\":\"134507721102798524\"}",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentWechatoff = AgentWechatoff()
AgentWechatoff.run()
回傳 JSON 結構如下:
{
"code": "250",
"msg": "執行成功。",
"uid": 106658,
"key": "970f6eb5c70e3a7582e825d67cc6a289",
"finishtime": "20220419174739",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "台灣連線股份有限公司",
"supplier_code": "W2",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 10,
"actual_currency": "TWD",
"pfn": "WECHATOFF",
"trans_type": 1,
"result_type": 4,
"result_content_type": "WECHATOFF",
"result_content": "{}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 0,
"invoice_print_device": 0,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
}
經銷商微信線下交易參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『微信線下交易』欄位參考 JSON格式,AES256加密資料 |
『直接交易-微信線下交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | 必填 |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | 必填 |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
data_json | string(500) | 微信線下資訊輸入(JSON格式) | 『街口線下資料』值參考 |
『直接交易-微信線下交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『微信線下交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
街口線上交易
因上游無提供測試資料,皆無法進行測試
<?php
/**
* 經銷商串接-直接交易-街口支付線上
*/
final class AgentJkoon
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "A1234567891002";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "JKOON";
$rawData['success_returl'] = "http://www.google.com.tw";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentJkoon = new AgentJkoon();
$AgentJkoon->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-Pi錢包線下交易
/// </summary>
public class AgentJKOon {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentJKOon simulator = new AgentJKOon();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1";
rawData.pfn = "PIOFF";
rawData.data_json = "{\"piCode\":\"PI24456862cukoY9JD\"}";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-Pi錢包線下交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentJKOon {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentJKOon simulator = new AgentJKOon();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "PIOFF");
rawData.put("data_json", "{\"piCode\":\"PI24456862cukoY9JD\"}");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-Pi錢包線下交易
*/
function AgentJKOon() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentJKOon.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: 10,
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "PIOFF",
data_json: "{\"piCode\":\"PI24456862cukoY9JD\"}",
};
};
/**
* 取得服務位置
*/
AgentJKOon.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentJKOon.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentJKOon.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentJKOon.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentJKOon.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentJKOon = new AgentJKOon();
AgentJKOon.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-Pi錢包線下交易
"""
class AgentJKOon:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': 10,
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "PIOFF",
'data_json': "{\"piCode\":\"PI24456862cukoY9JD\"}",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentJKOon = AgentJKOon()
AgentJKOon.run()
回傳 JSON 結構如下:
{
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_seller_name": "",
"invoice_buyer_ban": "",
"invoice_buyer_name": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 2,
"invoice_print_device": 1,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_tax_rate": "",
"invoice_remark": "",
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_tax_title": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
"code": "280",
"msg": "執行成功。",
"uid": 156449,
"key": "ed35ea0459c28b0f91573e7731c377ca",
"finishtime": "",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"is_agent_charge": 0,
"transaction_mode": "1",
"supplier_name": "街口電子支付",
"supplier_code": "W4",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "JKOON",
"actual_pay_mode": "",
"trans_type": 1,
"result_type": 4,
"result_content_type": "JKOON",
"result_content": "{\"Web\":\"https:\\\/\\\/uat-onlinepay.jkopay.app\\\/web\\\/paymentRouter?j=OL%231%3AENT%23bENQNkFWRkxYL2tmeWZoOUlUL2VBZz09%3AS%2303eb9890-4c78-11e9-8d1a-0050568403ed%3AA%2310%3ACUR%23TWD%3ASRC%23REDIRECT_MWEB
%3AUNRDM%230%3AFX%230%3ATA%2310%3ATCUR%23TWD%3AFXR%231.00%3AUR%231%3AD%23D&s=21e567dcb56036dbda741182255c31de9325dddd5b37eb9e805ff7b4b4b6775f\",\"OrderTotalCost\":\"10\",\"ExpiredTime\":\"1700473798\",\"QRCodeUrl\":\"https:\\\/\\\/u
at-onlinepay.jkopay.app\\\/web\\\/qr?j=OL%231%3AENT%23bENQNkFWRkxYL2tmeWZoOUlUL2VBZz09%3AS%2303eb9890-4c78-11e9-8d1a-0050568403ed%3AA%2310%3ACUR%23TWD%3ASRC%23REDIRECT_MWEB%3AUNRDM%230%3AFX%230%3ATA%2310%3ATCUR%23TWD%3AFXR%231.00%3AUR%231%3AD%23D&s=21e567dcb56036dbda741182255c31de9325dddd5b37eb9e805ff7b4b4b6775f\"}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"sys_echo": ""
}
特約商店『街口線上交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『街口線上交易』欄位參考 JSON格式,AES256加密資料 |
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float(5) | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string(70) | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
success_returl | string(255) | 交易成功導頁網址(導頁式交易有效) | |
failure_returl | string(255) | 交易失敗導頁網址(導頁式交易有效) |
『街口線上交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
actual_pay_mode | string(20) | 實際支付方式 (當pfn為CASH-自行收款時,告知系統實際收款方式) |
『自行收款付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『街口線上交易』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
街口線下交易
消費者提供街口支付碼供設備進行掃碼做交易動作。
因上游無提供測試資料,皆無法進行測試
<?php
/**
* 經銷商串接-直接交易-街口支付線下
*/
final class AgentJkooff
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['user_email'] = "[email protected]";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "JKOOFF";
$rawData['data_json'] = json_encode(['jkoCode' => '22J111111111111111', 'posId' => '1', 'posTradeTime' => date("YmdHis"), 'remark' => '交易註記'], JSON_UNESCAPED_UNICODE);
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentJkooff = new AgentJkooff();
$AgentJkooff->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-街口支付線下
/// </summary>
public class AgentJkooff {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentJkooff simulator = new AgentJkooff();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "O20211203114630";
rawData.ip = "127.0.0.1";
rawData.pfn = "JKOOFF";
rawData.data_json = "{\"jkoCode\":\"22J111111111111111\",\"posId\":\"1\",\"posTradeTime\":\"20220422114630\",\"remark\":\"交易註記\"}";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-街口支付線下
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentJkooff {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentJkooff simulator = new AgentJkooff();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "O20211203114630");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "JKOOFF");
rawData.put("data_json", "{\"jkoCode\":\"22J111111111111111\",\"posId\":\"1\",\"posTradeTime\":\"20220422114630\",\"remark\":\"交易註記\"}");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-錢包被掃交易-街口支付線下
*/
function AgentJkooff() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentJkooff.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: "10",
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "JKOOFF",
data_json: "{\"jkoCode\":\"22J111111111111111\",\"posId\":\"1\",\"posTradeTime\":\"20220422114630\",\"remark\":\"交易註記\"}",
};
};
/**
* 取得服務位置
*/
AgentJkooff.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentJkooff.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentJkooff.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentJkooff.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentJkooff.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentJkooff = new AgentJkooff();
AgentJkooff.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-錢包被掃交易-街口支付線下
"""
class AgentJkooff:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': "10",
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "JKOOFF",
'data_json': "{\"jkoCode\":\"22J111111111111111\",\"posId\":\"1\",\"posTradeTime\":\"20220422114630\",\"remark\":\"交易註記\"}",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentJkooff = AgentJkooff()
AgentJkooff.run()
回傳 JSON 結構如下:
{
"code": "250",
"msg": "執行成功。",
"uid": 106658,
"key": "970f6eb5c70e3a7582e825d67cc6a289",
"finishtime": "20220419174739",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "台灣連線股份有限公司",
"supplier_code": "W2",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 10,
"actual_currency": "TWD",
"pfn": "JKOOFF",
"trans_type": 1,
"result_type": 4,
"result_content_type": "JKOOFF",
"result_content": "{}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 0,
"invoice_print_device": 0,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
}
經銷商街口線下交易參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『街口線下交易』欄位參考 JSON格式,AES256加密資料 |
『直接交易-街口線下交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | 必填 |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | 必填 |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
data_json | string(500) | 街口線下資訊輸入(JSON格式) | 『街口線下資料』值參考 |
『直接交易-街口線下交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『街口線下交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
Apple Pay線下交易
消費者提供Apple Pay支付碼供設備進行掃碼做交易動作。
需要去申請憑證,再將憑證給予我司
<?php
/**
* 經銷商串接-直接交易-Apple Pay
*/
final class AgentApplepay
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "APPLEPAY";
$rawData['data_json'] = '{"paymentData":{"version":"RSA_v1","data":"","signature":"","header":{"publicKeyHash":"","transactionId":"","wrappedKey":""}},"paymentMethod":{"displayName":"Visa 0492","network":"Visa","type":"debit"},"transactionIdentifier":""}';
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentApplepay = new AgentApplepay();
$AgentApplepay->run();
?>
回傳 JSON 結構如下:
{
"code": "250",
"msg": "執行成功。",
"uid": 106658,
"key": "970f6eb5c70e3a7582e825d67cc6a289",
"finishtime": "20220419174739",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "台灣連線股份有限公司",
"supplier_code": "W2",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 10,
"actual_currency": "TWD",
"pfn": "APPLEPAY",
"trans_type": 1,
"result_type": 4,
"result_content_type": "APPLEPAY",
"result_content": "{}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 0,
"invoice_print_device": 0,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
}
經銷商Apple Pay線下交易參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『ApplePay線下交易』欄位參考 JSON格式,AES256加密資料 |
『直接交易-Apple Pay線下交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | 必填 |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | 必填 |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
data_json | string(500) | Apple Pay線下資訊輸入(JSON格式) | 『Apple Pay線下資料』值參考 |
『直接交易-Apple Pay線下交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『Apple Pay線下交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
Google Pay線下交易
消費者提供Goole Pay支付碼供設備進行掃碼做交易動作。
需要準備
1.提供domain
2.項目選擇(當使用者瀏覽項目或服務時)
3.預購畫面(當用戶最終準備好購買時)
4.付款方式畫面(當用戶選擇 Google Pay 作為付款方式)
5.Google Pay API 付款畫面(當用戶看到他們儲存到 Google Pay 的付款資訊。提示:Android 不允許您拍攝此畫面的螢幕截圖,因此請使用其他裝置拍攝螢幕的照片)
6.購買後螢幕(當用戶成功購買)
ps.只能用於app開啟webview或網頁交易,無法使用應用程式做交易
<?php
/**
* 經銷商串接-直接交易-Google Pay
*/
final class AgentGooglepay
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "GOOGLEPAY";
$rawData['data_json'] = "{\"apiVersionMinor\": 0, \"apiVersion\": 2,\"paymentMethodData\": {\"description\": \"Visa??????1234\",\"tokenizationData\": {\"type\": \"PAYMENT_GATEWAY\",\"token\": \"{\\\"signature\\\":\\\"MEQCICA????\\\\u003d\\\\u003d\\\",\\\"protocolVersion\\\":\\\"ECv1\\\",\\\"signedMessage\\\":\\\"{\\\\\\\"encryptedMessage\\\\\\\":\\\\\\\"2oGYBPrbBJIAg????\\\\\\\\u003d\\\\\\\\u003d\\\\\\\",\\\\\\\"ephemeralPublicKey\\\\\\\":\\\\\\\"BOlRJqnD????\\\\\\\\u003d\\\\\\\",\\\\\\\"tag\\\\\\\":\\\\\\\"g0lZC4????\\\\\\\\u003d\\\\\\\"}\\\"}\"},\"type\": \"CARD\",\"info\": {\"cardNetwork\": \"VISA\",\"cardDetails\": \"1234\"}}}";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentGooglepay = new AgentGooglepay();
$AgentGooglepay->run();
?>
回傳 JSON 結構如下:
{
"code": "250",
"msg": "執行成功。",
"uid": 106658,
"key": "970f6eb5c70e3a7582e825d67cc6a289",
"finishtime": "20220419174739",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "台灣連線股份有限公司",
"supplier_code": "W2",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 10,
"actual_currency": "TWD",
"pfn": "GOOGLEPAY",
"trans_type": 1,
"result_type": 4,
"result_content_type": "GOOGLEPAY",
"result_content": "{}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 0,
"invoice_print_device": 0,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
}
經銷商Google Pay線下交易參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『GooglePay線下交易』欄位參考 JSON格式,AES256加密資料 |
『直接交易-Google Pay線下交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | 必填 |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | 必填 |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
data_json | string(500) | Google Pay線下資訊輸入(JSON格式) | 『Google Pay線下資料』值參考 |
{
"apiVersionMinor": 0,
"apiVersion": 2,
"paymentMethodData": {
"description": "Visa •••• 1234",
"tokenizationData": {
"type": "PAYMENT_GATEWAY",
"token": "{\"signature\":\"MEQCICA••••\\u003d\\u003d\",\"protocolVersion\":\"ECv1\",\"signedMessage\":\"{\\\"encryptedMessage\\\":\\\"2oGYBPrbBJIAg••••\\\\u003d\\\\u003d\\\",\\\"ephemeralPublicKey\\\":\\\"BOlRJqnD••••\\\\u003d\\\",\\\"tag\\\":\\\"g0lZC4••••\\\\u003d\\\"}\"}"
},
"type": "CARD",
"info": {
"cardNetwork": "VISA",
"cardDetails": "1234"
}
}
}
『直接交易-Google Pay線下交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『Google Pay線下交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
悠遊付線下交易請求
消費者提供悠遊付支付碼供設備進行掃碼做交易動作。
因上游無提供測試資料,皆無法進行測試
<?php
/**
* 經銷商串接-直接交易-悠遊付線下交易
*/
final class AgentEasywalletoff
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "A1234567891002";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "EASYWALLETOFF";
$rawData['data_json'] = json_encode(['ewCode' => '99401096207398302106'], JSON_UNESCAPED_UNICODE);
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentEasywalletoff = new AgentEasywalletoff();
$AgentEasywalletoff->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-悠遊付線下
/// </summary>
public class AgentEasywalletoff {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "A1234567891002";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentEasywalletoff simulator = new AgentEasywalletoff();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic JsonData = new ExpandoObject();
JsonData.ewCode = "99401096207398302106";
String DataJson = JsonConvert.SerializeObject(JsonData, Formatting.None);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = "10";
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1"; // 此為消費者IP,會做為驗證用
rawData.pfn = "EASYWALLETOFF";
rawData.data_json = DataJson;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-悠遊付線下
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentEasywalletoff {
/**
* 經銷商商務代號
*/
String agentUid = "A1234567891002";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentEasywalletoff simulator = new AgentEasywalletoff();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<String, String> dataJson = new HashMap<>();
dataJson.put("ewCode", "99401096207398302106");
String data_json = "{}";
try {
ObjectMapper objMapper = new ObjectMapper();
data_json = objMapper.writeValueAsString(dataJson);
} catch (Exception e) {
e.printStackTrace();
}
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", "10");
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1"); // 此為消費者IP,會做為驗證用
rawData.put("pfn", "EASYWALLETOFF");
rawData.put("data_json", data_json);
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-悠遊付線下
*/
function AgentEasywalletoff() {
// 經銷商商務代號
this.agentUid = "A1234567891002";
// 經銷商金鑰或認證碼
this.agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentEasywalletoff.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}],
cost: "10",
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "EASYWALLETOFF",
data_json: JSON.stringify({ewCode: '99401096207398302106'})
};
};
/**
* 取得服務位置
*/
AgentEasywalletoff.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentEasywalletoff.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentEasywalletoff.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentEasywalletoff.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentEasywalletoff.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentEasywalletoff = new AgentEasywalletoff();
AgentEasywalletoff.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-悠遊付線下交易
"""
class AgentEasywalletoff:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': 10,
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "EASYWALLETOFF",
'data_json': "{\"ewCode\":\"99401096207398302106\"}",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentEasywalletoff = AgentEasywalletoff()
AgentEasywalletoff.run()
回傳 JSON 結構如下:
{
"code": "250",
"msg": "執行成功。",
"uid": 98432,
"key": "7f8a2b459ae296a9d3fe8fffd0d7f8d2",
"finishtime": "20211203114635",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "悠遊付",
"supplier_code": "W5",
"order_id": "O20211203114630",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 10,
"actual_currency": "TWD",
"pfn": "PXPAYOFF",
"trans_type": 1,
"result_type": 4,
"result_content_type": "EASYWALLETOFF",
"result_content": "{\n \"Remark\": \"\",\n \"TradeNo\": \"GR58745\",\n \"OrderTotalCost\": \"100\",\n \"InvoiceVehicle\": \"/ABD.122\",\n \"CitizenDigitalCertificate\": \"\",\n \"LoveCode\": \"\",\n \"EventCode\": \"\",\n \"PaymentType\": \"\",\n \"DebitAmount\": \"100\"\n}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 0,
"invoice_print_device": 0,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": ""
}
特約商店悠遊付線下交易參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 特約商店商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『悠遊付線下交易』欄位參考 JSON格式,AES256加密資料 |
『直接交易-悠遊付線下交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | 『付款方式』值參考 |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
data_json | string(500) | 悠遊付線下資訊輸入(JSON格式) | 『悠遊付線下資料』值參考 |
『直接交易-悠遊付線下交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『悠遊付線下交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
支付寶線下交易請求
消費者提供支付寶支付碼供設備進行掃碼做交易動作。
因上游無提供測試資料,皆無法進行測試
<?php
/**
* 經銷商串接-直接交易-支付寶線下
*/
final class AgentAlipayoff
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "A1234567891002";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "ALIPAYOFF";
$rawData['data_json'] = json_encode(['alipayCode' => '134507721102798524'], JSON_UNESCAPED_UNICODE);
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentAlipayoff = new AgentAlipayoff();
$AgentAlipayoff->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-支付寶線下交易
/// </summary>
public class AgentAlipayoff {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentAlipayoff simulator = new AgentAlipayoff();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item1 = new ExpandoObject();
item1.id = "1";
item1.name = "商品名稱";
item1.cost = "10";
item1.amount = "1";
item1.total = "10";
items.Add(item1);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1";
rawData.pfn = "ALIPAYOFF";
rawData.data_json = "{\"alipayCode\":\"134507721102798524\"}";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-支付寶線下交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentAlipayoff {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentAlipayoff simulator = new AgentAlipayoff();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item1 = new HashMap<Object, Object>();
item1.put("id", "1");
item1.put("name", "商品名稱");
item1.put("cost", "10");
item1.put("amount", "1");
item1.put("total", "10");
items.add(item1);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "ALIPAYOFF");
rawData.put("data_json", "{\"alipayCode\":\"134507721102798524\"}");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-支付寶線下交易
*/
function AgentAlipayoff() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentAlipayoff.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: 10,
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "ALIPAYOFF",
data_json: "{\"alipayCode\":\"134507721102798524\"}",
};
};
/**
* 取得服務位置
*/
AgentAlipayoff.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentAlipayoff.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentAlipayoff.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentAlipayoff.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentAlipayoff.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentAlipayoff = new AgentAlipayoff();
AgentAlipayoff.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-支付寶線下交易
"""
class AgentAlipayoff:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': 10,
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "ALIPAYOFF",
'data_json': "{\"alipayCode\":\"134507721102798524\"}",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentAlipayoff = AgentAlipayoff()
AgentAlipayoff.run()
回傳 JSON 結構如下:
{
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 2,
"invoice_print_device": 1,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_tax_rate": "",
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
"code": "300",
"msg": "執行失敗,交易失敗,原因:。",
"uid": 147393,
"key": "b04eecddac77286ab9feafb1527032d6",
"finishtime": "",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "玉山銀行",
"supplier_code": "B4",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "ALIPAYOFF",
"trans_type": 1,
"result_type": 4,
"result_content_type": "ALIPAYOFF",
"result_content": "{}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"sys_echo": ""
}
經銷商『支付寶線下交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『支付寶線下交易』欄位參考 JSON格式,AES256加密資料 |
『支付寶線下交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | (ALIPAYOFF) |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float(5) | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string(70) | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
data_json | string(500) | 支付寶線下資訊輸入(JSON格式) | 『支付寶線下資料』值參考 |
『支付寶線下交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『支付寶線下交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float(5) | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string(70) | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
全盈支付線上交易
商家發動後會根據回應資料內容result_content中,依據使用裝置,開啟相對應的連結
因上游無提供測試資料,皆無法進行測試
<?php
/**
* 經銷商串接-全盈支付線上交易
*/
final class AgentPluspayon
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880011";
/**
* 串接交易位置
* @var string
*/
public $url = "http://pay.k20-mypay.tw/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [
[
'id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10'
]
];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "O20240618120110";
$rawData['ip'] = "127.0.0.1";
$rawData['pfn'] = "PLUSPAYON";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPluspayon = new AgentPluspayon();
$AgentPluspayon->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-全盈支付線上交易
/// </summary>
public class AgentPluspayon {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880011";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "http://pay.k20-mypay.tw/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPluspayon simulator = new AgentPluspayon();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item1 = new ExpandoObject();
item1.id = "1";
item1.name = "商品名稱";
item1.cost = "10";
item1.amount = "1";
item1.total = "10";
items.Add(item1);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "O20240618120110";
rawData.ip = "127.0.0.1";
rawData.pfn = "PLUSPAYON";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-全盈支付線上交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPluspayon {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880011";
/**
* 串接交易位置
*/
String url = "http://pay.k20-mypay.tw/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPluspayon simulator = new AgentPluspayon();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item1 = new HashMap<Object, Object>();
item1.put("id", "1");
item1.put("name", "商品名稱");
item1.put("cost", "10");
item1.put("amount", "1");
item1.put("total", "10");
items.add(item1);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "O20240618120110");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "PLUSPAYON");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-全盈支付線上交易
*/
function AgentPluspayon() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880011";
// 串接交易位置
this.url = "http://pay.k20-mypay.tw/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPluspayon.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: 10,
user_id: "phper",
order_id: "O20240618120110",
ip: "127.0.0.1",
pfn: "PLUSPAYON",
};
};
/**
* 取得服務位置
*/
AgentPluspayon.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentPluspayon.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPluspayon.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPluspayon.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPluspayon.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPluspayon = new AgentPluspayon();
AgentPluspayon.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-全盈支付線上交易
"""
class AgentPluspayon:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880011"
# 串接交易位置
url = "http://pay.k20-mypay.tw/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': 10,
'user_id': "phper",
'order_id': "O20240618120110",
'ip': "127.0.0.1",
'pfn': "PLUSPAYON",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPluspayon = AgentPluspayon()
AgentPluspayon.run()
回傳 JSON 結構如下:
{
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_seller_name": "",
"invoice_buyer_ban": "",
"invoice_buyer_name": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 2,
"invoice_print_device": 1,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_tax_rate": "",
"invoice_remark": "",
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_tax_title": "",
"invoice_natural_person": "",
"invoice_m_post_zone": "",
"invoice_m_address": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
"code": "280",
"msg": "執行成功。",
"uid": 194591,
"key": "68d2a09c31643660f29172d80dbaf9ef",
"finishtime": "",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"is_agent_charge": 0,
"transaction_mode": "1",
"supplier_name": "全盈支付",
"supplier_code": "W8",
"order_id": "O20240618120152",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "PLUSPAYON",
"actual_pay_mode": "",
"trans_type": 1,
"result_type": 4,
"result_content_type": "PLUSPAYON",
"result_content": "{\"Web\":\"https:\\/\\/qr-uat.pluspay.com.tw\\/ABBOQhmtUo\"}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"sys_echo": ""
}
經銷商『全盈支付線上交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『全盈支付線上交易』欄位參考 JSON格式,AES256加密資料 |
『全盈支付線上交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string | 特約商店代碼 | 必填 |
cost | string | 訂單總金額 | 必填 |
currency | string | 預設交易幣別(預設為TWD新台幣) | |
order_id | string | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 | |
pfn | string | 付費方法 (PLUSPAYON) | 必填 |
discount | string | 折價金額 (預設0) | |
shipping_fee | string | 運費 | |
user_id | string | 消費者帳號 | |
user_name | string | 消費者姓名 | |
user_real_name | string | 消費者真實姓名 | |
user_english_name | string | 消費者英文名稱 | |
user_zipcode | string | 消費者郵遞區號 | |
user_address | string | 消費者地址 | |
user_sn_type | string | 證號類型 | 『證號類型』值參考 |
user_sn | string | 付款人身分證/統一證號/護照號碼 | |
user_phone | string | 消費者家用電話 | |
user_cellphone_code | string | 消費者行動電話國碼 | |
user_cellphone | string | 消費者行動電話 | |
user_email | string | 消費者 E-Mail | |
user_birthday | string | 消費者生日 | |
ip | string | 消費者來源 IP | |
issue_invoice_state | integer | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_m_post_zone | string | EMail 紙本寄送郵遞區號 | 當invoice_cloud_type為4,此欄位才有效,非必須 |
invoice_m_address | string | EMail 紙本寄送住址 | 當invoice_cloud_type為4,此欄位才有效,非必須 |
invoice_love_code | string | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
interface | string | 消費者操作介面類型 pc/app | |
agent_sms_fee_type | integer | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string | 經銷商代收費 | |
is_agent_charge | integer | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
『全盈支付線上交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 交易狀態代碼 | |
msg | string | 回傳訊息 | |
uid | string | Payment Hub之交易流水號 | |
key | string | 交易驗証碼 | |
finishtime | string | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string | 銀行端口回傳碼 | |
acode | string | 授權碼 | |
card_type | integer | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string | 發卡行 | |
issuing_bank_uid | string | 發卡銀行代碼 | |
is_agent_charge | int | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string | 交易之金融服務商 | |
supplier_code | string | 交易之金融服務商代碼 | |
order_id | string | 貴特店系統的訂單編號 | |
user_id | string | 消費者帳號 | |
cost | string | 總交易金額 | |
currency | string | 原交易幣別 | |
actual_cost | string | 實際交易金額 | |
actual_currency | string | 實際交易幣別 | |
pfn | string | 付費方法 | 『回傳付款方式』值參考 |
actual_pay_mode | string | 實際支付方式 (當pfn為CASH-自行收款時,告知系統實際收款方式) |
『自行收款付款方式』值參考 |
trans_type | integer | 交易類型 | 『交易類型定義』值參考 |
result_type | string | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string | 回傳結果 | 『全盈支付線上交易回傳欄位』值參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 | |
invoice_state | integer | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string | 發票開立狀態訊息 | |
invoice_date | string | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string | 發票字軌 | |
invoice_number | string | 發票號碼 | |
invoice_rand_code | string | 電子發票隨機碼 | |
invoice_seller_ban | string | 賣方統一編號 | |
invoice_seller_name | string | 賣方名稱 | |
invoice_buyer_ban | string | 買方統一編號 | |
invoice_buyer_name | string | 買方名稱 | |
invoice_left_qrcode | string | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string | 電子發票右邊QrCode內容 | |
invoice_title_type | integer | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string | 電子發票列印標題格式 | |
invoice_print_type | integer | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string | 電子發票銷售總額 | |
invoice_sales_amount | string | 電子發票銷售額 | |
invoice_tax_amount | string | 電子發票稅額 | |
invoice_order_detail | string | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_tax_title | string | 當invoice_cloud_type為2時紀錄的買受人公司名稱 | |
invoice_natural_person | string | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_m_post_zone | string | 當invoice_cloud_type為4時紀錄中獎時紙本發票郵遞區號 | |
invoice_m_address | string | 當invoice_cloud_type為4時紀錄中獎時紙本發票收件住址 | |
invoice_love_code | string | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string | 當invoice_input_type為3時紀錄的發票地址 |
全盈支付線下交易請求
消費者提供全盈支付支付碼供設備進行掃碼做交易動作。
因上游無提供測試資料,皆無法進行測試
<?php
/**
* 經銷商串接-直接交易-全盈支付線下
*/
final class AgentPluspayoff
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "A1234567891002";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "PLUSPAYOFF";
$rawData['data_json'] = json_encode(['plusCode' => 'FP372E9AGSAI9OJNRW'], JSON_UNESCAPED_UNICODE);
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPluspayoff = new AgentPluspayoff();
$AgentPluspayoff->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-全盈支付線下交易
/// </summary>
public class AgentPluspayoff {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPluspayoff simulator = new AgentPluspayoff();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item1 = new ExpandoObject();
item1.id = "1";
item1.name = "商品名稱";
item1.cost = "10";
item1.amount = "1";
item1.total = "10";
items.Add(item1);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1";
rawData.pfn = "PLUSPAYOFF";
rawData.data_json = "{\"plusCode\":\"134507721102798524\"}";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-全盈支付線下交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPluspayoff {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPluspayoff simulator = new AgentPluspayoff();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item1 = new HashMap<Object, Object>();
item1.put("id", "1");
item1.put("name", "商品名稱");
item1.put("cost", "10");
item1.put("amount", "1");
item1.put("total", "10");
items.add(item1);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "PLUSPAYOFF");
rawData.put("data_json", "{\"plusCode\":\"134507721102798524\"}");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-全盈支付線下交易
*/
function AgentPluspayoff() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPluspayoff.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: 10,
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: "PLUSPAYOFF",
data_json: "{\"plusCode\":\"134507721102798524\"}",
};
};
/**
* 取得服務位置
*/
AgentPluspayoff.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentPluspayoff.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPluspayoff.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPluspayoff.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPluspayoff.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPluspayoff = new AgentPluspayoff();
AgentPluspayoff.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-全盈支付線下交易
"""
class AgentPluspayoff:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': 10,
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': "PLUSPAYOFF",
'data_json': "{\"plusCode\":\"134507721102798524\"}",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPluspayoff = AgentPluspayoff()
AgentPluspayoff.run()
回傳 JSON 結構如下:
{
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 2,
"invoice_print_device": 1,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_tax_rate": "",
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
"code": "300",
"msg": "執行失敗,交易失敗,原因:。",
"uid": 147393,
"key": "b04eecddac77286ab9feafb1527032d6",
"finishtime": "",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "玉山銀行",
"supplier_code": "B4",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "PLUSPAYOFF",
"trans_type": 1,
"result_type": 4,
"result_content_type": "PLUSPAYOFF",
"result_content": "{}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"sys_echo": ""
}
經銷商『全盈支付線下交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『全盈支付線下交易』欄位參考 JSON格式,AES256加密資料 |
『全盈支付線下交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | (PLUSPAYOFF) |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float(5) | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string(70) | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
data_json | string(500) | 全盈支付線下資訊輸入(JSON格式) | 『全盈支付線下資料』值參考 |
『全盈支付線下交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『全盈支付線下交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float(5) | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string(70) | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
錢包被掃交易
消費者提供支付碼供設備進行掃碼做交易動作。(支援自動辨識MYPAY電子錢包、Pi 拍錢包、LINE Pay、街口支付、WeChat Pay、支付宝、悠遊付、全支付、全盈支付)
<?php
/**
* 經銷商串接-錢包被掃交易
*/
final class AgentOffline
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [
[
'id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10'
]
];
$rawData['cost'] = "10";
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1";
$rawData['pfn'] = 98;
$rawData['data_json'] = "{\"qrCode\":\"MY13697573pbmQsYhY\"}";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentOffline = new AgentOffline();
$AgentOffline->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-錢包被掃交易
/// </summary>
public class AgentOffline {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentOffline simulator = new AgentOffline();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = "10";
rawData.user_id = "phper";
rawData.order_id = "1234567890";
rawData.ip = "127.0.0.1";
rawData.pfn = 98;
rawData.data_json = "{\"qrCode\":\"MY13697573pbmQsYhY\"}";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-錢包被掃交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentOffline {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentOffline simulator = new AgentOffline();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", "10");
rawData.put("user_id", "phper");
rawData.put("order_id", "1234567890");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", 98);
rawData.put("data_json", "{\"qrCode\":\"MY13697573pbmQsYhY\"}");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-錢包被掃交易
*/
function AgentOffline() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentOffline.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: "10",
user_id: "phper",
order_id: "1234567890",
ip: "127.0.0.1",
pfn: 98,
data_json: "{\"qrCode\":\"MY13697573pbmQsYhY\"}",
};
};
/**
* 取得服務位置
*/
AgentOffline.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentOffline.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentOffline.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentOffline.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentOffline.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentOffline = new AgentOffline();
AgentOffline.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-錢包被掃交易
"""
class AgentOffline:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': "10",
'user_id': "phper",
'order_id': "1234567890",
'ip': "127.0.0.1",
'pfn': 98,
'data_json': "{\"qrCode\":\"MY13697573pbmQsYhY\"}",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentOffline = AgentOffline()
AgentOffline.run()
回傳 JSON 結構如下:
{
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 2,
"invoice_print_device": 1,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_tax_rate": "",
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": "",
"code": "300",
"msg": "執行失敗,並未將物件參考設定為物件的執行個體。",
"uid": 147394,
"key": "8a956d21964aca9ed1a52dd08fb61173",
"finishtime": "",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "1",
"supplier_name": "華泰銀行",
"supplier_code": "BE",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"pfn": "TWPAYOFF",
"trans_type": 1,
"result_type": 4,
"result_content_type": "TWPAYOFF",
"result_content": "{}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"sys_echo": ""
}
經銷商『錢包被掃交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『錢包被掃交易』欄位參考 JSON格式,AES256加密資料 |
『錢包被掃交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法 | (OFFLINE) |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float(5) | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string(70) | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
data_json | string(500) | 錢包被掃交易資訊輸入(JSON格式) | 『錢包被掃交易資料』值參考 |
『錢包被掃交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『全支付線下交易回傳欄位』值參考 『支付寶線下交易回傳欄位』值參考 『悠遊付線下交易回傳欄位』值參考 『Pi錢包線下交易回傳欄位』值參考 『街口支付線下交易回傳欄位』值參考 『LINE Pay線下交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_tax_rate | float(5) | 電子發票稅率:預設0.05(零稅與免稅帶0) | |
invoice_remark | string(70) | 發票註記(依加值中心提供註記功能) | |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
自行收款交易
商店自行向消費者收款時,可發動此交易請求,將收款記錄在MYPAY。
<?php
/**
* 經銷商串接-直接交易-自行收款交易
*/
final class AgentCash
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['items'] = [['id' => '1',
'name' => '商品名稱',
'cost' => '10',
'amount' => '1',
'total' => '10']];
$rawData['cost'] = 10;
$rawData['user_id'] = "phper";
$rawData['order_id'] = "1234567890";
$rawData['ip'] = "127.0.0.1"; // 此為消費者IP,會做為驗證用
$rawData['pfn'] = "CASH";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/transaction'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentCash = new AgentCash();
$AgentCash->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易-自行收款交易
/// </summary>
public class AgentCash {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentCash simulator = new AgentCash();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "商品名稱";
item.cost = "10";
item.amount = "1";
item.total = "10";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.items = items;
rawData.cost = 10;
rawData.user_id = "phper";
rawData.order_id = "O20211203114630";
rawData.ip = "127.0.0.1";
rawData.pfn = "CASH";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/transaction";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易-自行收款交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentCash {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentCash simulator = new AgentCash();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "商品名稱");
item.put("cost", "10");
item.put("amount", "1");
item.put("total", "10");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("items", items);
rawData.put("cost", 10);
rawData.put("user_id", "phper");
rawData.put("order_id", "O20211203114630");
rawData.put("ip", "127.0.0.1");
rawData.put("pfn", "CASH");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/transaction");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易-自行收款交易
*/
function AgentCash() {
// 特約商店商務代號
this.agentUid = "518169081001";
// 特約商店金鑰或認證碼
this.agentKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentCash.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
items: [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
cost: 10,
user_id: "phper",
order_id: "O20211203114630",
ip: "127.0.0.1",
pfn: "CASH",
};
};
/**
* 取得服務位置
*/
AgentCash.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/transaction"
};
};
/**
* AES 256 加密
*/
AgentCash.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentCash.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentCash.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentCash.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentCash = new AgentCash();
AgentCash.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易-自行收款交易
"""
class AgentCash:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'items': [
{
'id': "1",
'name': "商品名稱",
'cost': "10",
'amount': "1",
'total': "10"
}
],
'cost': 10,
'user_id': "phper",
'order_id': "O20211203114630",
'ip': "127.0.0.1",
'pfn': "CASH",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/transaction'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentCash = AgentCash()
AgentCash.run()
回傳 JSON 結構如下:
{
"code": "250",
"msg": "執行成功。",
"uid": 106991,
"key": "50306bf7def7cd1d37788558ed253259",
"finishtime": "20220422143522",
"cardno": "",
"acode": "",
"card_type": "0",
"issuing_bank": "",
"issuing_bank_uid": "",
"transaction_mode": "2",
"supplier_name": "高鉅科技",
"supplier_code": "T0",
"order_id": "1234567890",
"user_id": "phper",
"cost": 10,
"currency": "TWD",
"actual_cost": 10,
"actual_currency": "TWD",
"pfn": "CASH",
"trans_type": 1,
"result_type": 4,
"result_content_type": "CASH",
"result_content": "{\n \"OrderTotalCost\": 10,\n \"TradeDate\": \"20220422143522\"\n}",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"invoice_state": 0,
"invoice_state_msg": "不處理",
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_print_type": 0,
"invoice_print_device": 0,
"invoice_amount": "",
"invoice_sales_amount": "",
"invoice_tax_amount": "",
"invoice_order_detail": "",
"invoice_ratetype": 1,
"invoice_input_type": 0,
"invoice_cloud_type": 0,
"invoice_mobile_code": "",
"invoice_tax_id": "",
"invoice_natural_person": "",
"invoice_love_code": "",
"invoice_b2b_title": "",
"invoice_b2b_id": "",
"invoice_b2b_post_zone": "",
"invoice_b2b_address": ""
}
經銷商自行收款交易參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/transaction"} JSON格式,AES256加密資料 |
encry_data | text | 『自行收款交易』欄位參考 JSON格式,AES256加密資料 |
『直接交易-自行收款交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店代碼 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
currency | string(10) | 預設交易幣別(預設為TWD新台幣) | |
order_id | string(50) | 訂單編號 | 必填 |
items | array | 訂單內物品數 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
pfn | string(20) | 付費方法(請帶字串CASH) | |
discount | string(19) | 折價金額 (預設0) | |
shipping_fee | string(19) | 運費 | |
user_id | string(50) | 消費者帳號 | 必填 |
user_name | string(20) | 消費者姓名 | |
user_real_name | string(20) | 消費者真實姓名 | |
user_english_name | string(50) | 消費者英文名稱 | |
user_zipcode | string(10) | 消費者郵遞區號 | |
user_address | string(255) | 消費者地址 | |
user_sn_type | string(1) | 證號類型 | 『證號類型』值參考 |
user_sn | string(19) | 付款人身分證/統一證號/護照號碼 | |
user_phone | string(20) | 消費者家用電話 | |
user_cellphone_code | string(6) | 消費者行動電話國碼 | |
user_cellphone | string(20) | 消費者行動電話 | |
user_email | string(80) | 消費者 E-Mail | |
user_birthday | string(10) | 消費者生日 | |
ip | string(50) | 消費者來源 IP | 必填 |
issue_invoice_state | integer(1) | 開立發票 | 『電子發票是否開立狀態』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 「雲端發票」類型 | 當invoice_input_type為1,此狀態才有效 『雲端發票類型』值參考 |
invoice_tax_id | string(8) | 統一編號 | 當invoice_input_type為1,此欄位才有效,非必要 |
invoice_mobile_code | string(20) | 手機條碼 | 當invoice_cloud_type為2,此欄位才有效 |
invoice_natural_person | string(20) | 自然人憑證條碼 | 當invoice_cloud_type為3,此欄位才有效 |
invoice_love_code | string(20) | 愛心碼 | 當invoice_input_type為2,此欄位才有效 |
invoice_b2b_title | string(50) | 發票抬頭 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_id | string(8) | 統一編號 | 當invoice_input_type為3時,此欄位才有效 |
invoice_b2b_post_zone | string(10) | 發票郵遞區號 | 當invoice_input_type為3時,此欄位才有效,非必須 |
invoice_b2b_address | string(200) | 發票地址 | 當invoice_input_type為3時,此欄位才有效 |
agent_sms_fee_type | integer(1) | 經銷商代收費是否含簡訊費 (0.不含 1.含) | 『含不含簡訊費』值參考 |
agent_charge_fee_type | integer(1) | 經銷商代收費是否含手續費 (0.不含 1.含) | 『含不含手續費類型』值參考 |
agent_charge_fee | string(9) | 經銷商代收費 | |
is_agent_charge | integer(1) | 是否為經銷商代收費模式 若 is_agent_charge 有指定,以指定優先 若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1 若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0 |
『是否為經銷商代收費模式』值參考 |
actual_pay_mode | string(20) | 實際支付方式 (當pfn為CASH-自行收款時,告知系統實際收款方式) |
『自行收款付款方式』值參考 |
『直接交易-自行收款交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string(10) | 交易狀態代碼 | |
msg | string(500) | 回傳訊息 | |
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | integer(1) | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
pfn | string(20) | 付費方法 | 『回傳付款方式』值參考 |
actual_pay_mode | string(20) | 實際支付方式 (當pfn為CASH-自行收款時,告知系統實際收款方式) |
『自行收款付款方式』值參考 |
trans_type | integer(1) | 交易類型 | 『交易類型定義』值參考 |
result_type | string(2) | 回傳結果資料類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string(20) | 回傳資料內容類型 | 『資料內容所屬支付名稱』值參考 |
result_content | string(1000) | 回傳結果 | 『自行收款交易回傳欄位』值參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_state_msg | string(500) | 發票開立狀態訊息 | |
invoice_date | string(14) | 發票開立日期(YYYYMMDDHHmmss) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string(50) | 電子發票列印標題格式 | |
invoice_print_type | integer(1) | 電子發票列印類型 | 『電子發票列印類型』值參考 |
invoice_print_device | integer(1) | 電子發票列印設備 | 『電子發票列印設備』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_cloud_type | integer(1) | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
invoice_mobile_code | string(20) | 當invoice_cloud_type為2時紀錄的手機條碼 | |
invoice_tax_id | string(8) | 當invoice_cloud_type為2時紀錄的統一編號 | |
invoice_natural_person | string(20) | 當invoice_cloud_type為3時紀錄的自然人憑證條碼 | |
invoice_love_code | string(20) | 當invoice_input_type為2時紀錄的愛心碼 | |
invoice_b2b_title | string(50) | 當invoice_input_type為3時紀錄的發票抬頭 | |
invoice_b2b_id | string(8) | 當invoice_input_type為3時紀錄的統一編號 | |
invoice_b2b_post_zone | string(10) | 當invoice_input_type為3時紀錄的郵遞區號 | |
invoice_b2b_address | string(200) | 當invoice_input_type為3時紀錄的發票地址 |
直接交易查詢
<?php
/**
* 經銷商串接-直接交易查詢
*/
final class AgentQueryDirect
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 特約商店金鑰或認證碼
* @var string
*/
public $storeKey = "5p8LnrEiuwUn8Zn5yH31s0mg3Jjq5elB";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['order_id'] = '53654';
$rawData['user_id'] = 'phper';
$rawData['cost'] = '10';
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/querydirect'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);<
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentQueryDirect = new AgentQueryDirect();
$AgentQueryDirect->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-直接交易查詢
/// </summary>
public class AgentQueryDirect {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentQueryDirect simulator = new AgentQueryDirect();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.order_id = "2020020210003";
rawData.user_id = "phper";
rawData.cost = "10";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/querydirect";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-直接交易查詢
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentQueryDirect {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 特約商店金鑰或認證碼
*/
String storeKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentQueryDirect simulator = new AgentQueryDirect();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("order_id", "2020020210003");
rawData.put("user_id", "phper");
rawData.put("cost", "10");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/querydirect");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-直接交易查詢
*/
function AgentQueryDirect() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 特約商店金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentQueryDirect.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
order_id: "2020020210003",
user_id: "phper",
cost: "10"
};
};
/**
* 取得服務位置
*/
AgentQueryDirect.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/querydirect"
};
};
/**
* AES 256 加密
*/
AgentQueryDirect.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentQueryDirect.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentQueryDirect.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentQueryDirect.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentQueryDirect = new AgentQueryDirect();
AgentQueryDirect.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-直接交易查詢
"""
class AgentQueryDirect:
# 經銷商商務代號
agentUid = "518169081001"
# 經銷商店金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS"
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'agent_uid': self.agentUid,
'order_id': "2020020210003",
'user_id': "phper",
'cost': "10"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/querydirect'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentQueryDirect = AgentQueryDirect()
AgentQueryDirect.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"rows": [{
"key": "9d2aefb66584290fe1f56f626ea71680",
"prc": "300",
"cardno": "543045******1219",
"acode": "",
"card_type": "1",
"issuing_bank": "國泰世華",
"issuing_bank_uid": "013",
"is_agent_charge": 0,
"transaction_mode": 1,
"supplier_name": "聯合信用卡處理中心",
"supplier_code": "B6",
"order_id": "1234567890",
"user_id": "phper",
"uid": 30232,
"cost": 10,
"currency": "TWD",
"actual_cost": 0,
"actual_currency": "TWD",
"love_cost": 0,
"retmsg": "交易失敗",
"pay_mode_uid": 1,
"pfn": "CREDITCARD",
"trans_type": 1,
"redeem": "",
"installment": "",
"finishtime": "",
"store_group_id": "",
"nois": "",
"payment_name": "",
"bank_id": "",
"expired_date": "",
"appropriation_date": "",
"result_type": 4,
"result_content_type": "CREDITCARD",
"result_content": "{}",
"invoice_state": 0,
"invoice_date": "",
"invoice_wordtrack": "",
"invoice_number": "",
"invoice_rand_code": "",
"invoice_seller_ban": "",
"invoice_buyer_ban": "",
"invoice_left_qrcode": "",
"invoice_middle_barcode": "",
"invoice_right_qrcode": "",
"invoice_title_type": 1,
"invoice_title": "",
"invoice_amount": "0",
"invoice_sales_amount": "0",
"invoice_tax_amount": "0",
"invoice_order_detail": "[]",
"invoice_ratetype": 1,
"invoice_input_type": null,
"invoice_allowance": [],
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}]
}
發動交易後,如果遲遲未接收回報,可透過此方法查詢訂單交易。
經銷商直接交易查詢參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/querydirect"} JSON格式,AES256加密資料 |
encry_data | text | 『直接交易查詢』欄位參考 JSON格式,AES256加密資料 |
『直接交易查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店編號 | 必填 |
order_id | string(50) | 訂單編號 | 必填 |
cost | string(19) | 訂單總金額 | 必填 |
user_id | string(50) | 消費者帳號 |
回傳資料
欄位 | 說明 | 型態 | 補充說明 |
---|---|---|---|
code | 執行結果 | string | 參考交易回傳碼 |
msg | 執行結果訊息 | string | |
rows | 查詢資料清單 | array | 交易成功可能含多筆退款或取消以及發票等相關資訊 每筆『交易查詢』欄位參考 |
特約商店可用支付工具查詢
可查詢目前特約商店所支援的支付工具有哪些,需注意當支付工具有設定不到一定的金額不能使用時,則cost必須要達到該金額以上,否則無法查詢到
<?php
/**
* 經銷商串接-查詢特約商店支援之支付方式
*/
final class AgentSupportPayMode
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "A1234567891002";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['cost'] = "1000";
$rawData['currency'] = "TWD";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/paymentsupportpaymode'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentSupportPayMode = new AgentSupportPayMode();
$AgentSupportPayMode->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-查詢特約商店支援之支付方式
/// </summary>
public class AgentSupportPayMode {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "A1234567891002";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentSupportPayMode simulator = new AgentSupportPayMode();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.cost = "1000";
rawData.currency = "TWD";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/paymentsupportpaymode";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-查詢特約商店支援之支付方式
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentSupportPayMode {
/**
* 經銷商商務代號
*/
String agentUid = "A1234567891002";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentSupportPayMode simulator = new AgentSupportPayMode();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("cost", "1000");
rawData.put("currency", "TWD");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/paymentsupportpaymode");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-查詢特約商店支援之支付方式
*/
function AgentSupportPayMode() {
// 經銷商商務代號
this.agentUid = "A1234567891002";
// 經銷商金鑰或認證碼
this.agentKey = "nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentSupportPayMode.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
cost: "1000",
currency: "TWD"
};
};
/**
* 取得服務位置
*/
AgentSupportPayMode.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/paymentsupportpaymode"
};
};
/**
* AES 256 加密
*/
AgentSupportPayMode.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentSupportPayMode.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentSupportPayMode.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentSupportPayMode.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentSupportPayMode = new AgentSupportPayMode();
AgentSupportPayMode.run();
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-查詢特約商店支援之支付方式
"""
class AgentSupportPayMode:
# 經銷商商務代號
agentUid = "A1234567891002";
# 經銷商金鑰或認證碼
agentKey = b"nq8KL8qNNCW12A3TBfAp4lU0y3PED8IQ";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'cost': "1000",
'currency': "TWD"
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/paymentsupportpaymode'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentSupportPayMode = AgentSupportPayMode()
AgentSupportPayMode.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": [
"CREDITCARD",
"CSTORECODE",
"WEBATM",
"E_COLLECTION",
"ABROAD",
"MATM",
"WECHAT",
"WECHATOFF",
"LINEPAYON",
"LINEPAYOFF",
"APPLEPAY",
"GOOGLEPAY",
"CARDLESS",
"PION",
"PIOFF",
"JKOON",
"JKOOFF",
"CASH",
"EASYWALLETON",
"EASYWALLETOFF",
"BARCODE"
]
}
特約商店『可用支付工具查詢』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/paymentsupportpaymode"} JSON格式,AES256加密資料 |
encry_data | text | 『可用支付工具查詢』欄位參考 JSON格式,AES256加密資料 |
『可用支付工具查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string(16) | 特約商店商務代號 | 必要 |
cost | string | 交易金額 | 必要,最小值須為1 |
cost | string | 預設交易幣別(預設為TWD新台幣) | 『幣別類型』值參考 |
『可用支付工具查詢』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 交易回傳碼(B200或B500或100) | |
msg | string(500) | 回傳訊息 | |
content | string | 支付方式清單(狀態B200才有) |
交易退款
<?php
/**
* 經銷商串接-交易退款
*/
final class AgentRefund
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['uid'] = "88833";
$rawData['key'] = "1c943777706d68f757afdb9034213001";
$rawData['cost'] = 100;
$rawData['invoice_state'] = 6;
$rawData['items'] = [
[
'id' => '1',
'name' => '倚天劍模型',
'cost' => 100,
'amount' => 1,
'total' => 100
]
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/refund'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentRefund = new AgentRefund();
$AgentRefund->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-交易退款
/// </summary>
public class AgentRefund {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentRefund simulator = new AgentRefund();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "1";
item.name = "倚天劍模型";
item.cost = 100;
item.amount = 1;
item.total = 100;
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.uid = "88833";
rawData.key = "1c943777706d68f757afdb9034213001";
rawData.cost = 100;
rawData.invoice_state = 6;
rawData.items = items;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/refund";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-交易退款
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentRefund {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentRefund simulator = new AgentRefund();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "1");
item.put("name", "倚天劍模型");
item.put("cost", 100);
item.put("amount", 1);
item.put("total", 100);
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("uid", "88833");
rawData.put("key", "1c943777706d68f757afdb9034213001");
rawData.put("cost", 100);
rawData.put("invoice_state", 6);
rawData.put("items", items);
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/refund");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-交易退款
*/
function AgentRefund() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentRefund.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
uid: "88833",
key: "1c943777706d68f757afdb9034213001",
cost: 100,
invoice_state: 6,
items: [
{
'id': "1",
'name': "倚天劍模型",
'cost': 100,
'amount': 1,
'total': 100
}
],
};
};
/**
* 取得服務位置
*/
AgentRefund.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/refund"
};
};
/**
* AES 256 加密
*/
AgentRefund.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentRefund.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentRefund.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentRefund.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentRefund = new AgentRefund();
AgentRefund.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-交易退款
"""
class AgentRefund:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'uid': "88833",
'key': "1c943777706d68f757afdb9034213001",
'cost': 100,
'invoice_state': 6,
'items': [
{
'id': "1",
'name': "倚天劍模型",
'cost': 100,
'amount': 1,
'total': 100
}
],
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/refund'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentRefund = AgentRefund()
AgentRefund.run()
回傳 JSON 結構如下:
{
"row_data": {
"uid": 88833,
"refund_uid": 88834,
"key": "1c943777706d68f757afdb9034213001",
"prc": "230",
"finishtime": "20210701104600",
"order_id": "20210701107C23AA66",
"user_id": "userid",
"cost": 100,
"currency": "TWD",
"actual_cost": 100,
"actual_currency": "TWD",
"retmsg": "退款完成",
"pfn": "CREDITCARD",
"payment_name": "",
"nois": "",
"group_id": "",
"refund_type": 1,
"expected_refund_date": "",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
},
"key": "1c943777706d68f757afdb9034213001",
"uid": "88833",
"code": "B200",
"msg": "執行成功"
}
若需要退款時,發動此API提出退款請求。支援即時退款且未超過退款期限內之支付方式皆可使用此方式發動退款。 支援即時退款的支付方式有信用卡、美國運通、LINEPay、Pi錢包、街口支付、微信支付、支付寶、悠遊付、現金、GooglePay、ApplePay。
經銷商『交易退款』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/refund"} JSON格式,AES256加密資料 |
encry_data | text | 『交易退款』欄位參考 JSON格式,AES256加密資料 |
『交易退款』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string | 特約商店代碼 | |
key | string | 交易驗証碼 | |
uid | string | 訂單編號(UID) | |
cost | string | 退款金額(可部分退款) | |
invoice_state | integer | 若有開立電子發票,指定電子發票使用作廢或折讓 注意:跨發票月份無法作廢 |
『電子發票退款時使用作廢或折讓』值參考 |
items | array | 退款項目 若使用電子發票,此欄位必填 退款項目之項目名稱必須和交易時之產品項目名稱相同 退款項目之總金額必須與退款金額一致 |
每筆『商品項目』欄位參考 |
『交易退款』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
key | string | 特約商店驗證碼 (store_token) | |
uid | string | 訂單編號(UID) | |
code | string | 處理狀態 B200 或 B500 | |
msg | string | 回傳訊息 | |
row_data | object | 退款資訊(即時退款才有此資訊) | 『退款完成回傳資訊』欄位參考 |
其他關聯欄位說明
關聯欄位
『商品項目』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
id | string(5) | 商品編號 | 必填 |
name | string(50) | 商品名稱 | 必填 |
cost | string(9) | 商品單價 | 必填 |
amount | string(5) | 商品數量 | 必填 |
total | string(9) | 商品小計 | 必填 |
image_url | string(255) | 商品圖片連結(僅LINEPay線上使用) |
『虛擬帳號回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
PinCode | string | 虛擬帳號 | |
LimitDate | string | 繳費有效期限,格式YYYYMMDDHHmmss | |
BankCode | string | 銀行代碼 |
『ibon』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
PinCode | string | 超商代碼(可用qrcode被掃) | |
LimitDate | string | 超商代碼繳費有效期限,格式YYYYMMDDHHmmss | |
BarCode1 | string | 三段條碼繳費條碼1(格式:Code-39 barcode) | |
BarCode2 | string | 三段條碼繳費條碼2(格式:Code-39 barcode) | |
BarCode3 | string | 三段條碼繳費條碼3(格式:Code-39 barcode) | |
BarcodeEndDate | string | 三段條碼繳費期限,格式YYYYMMDDHHmmss |
『FamiPort』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
PinCode | string | 繳費代碼(可憑此代碼至設備列印繳費單) | |
LimitDate | string | 繳費有效期限,格式YYYYMMDDHHmmss | |
BarCode1 | string | 三段條碼繳費條碼1(格式:Code-39 barcode) | |
BarCode2 | string | 三段條碼繳費條碼2(格式:Code-39 barcode) | |
BarCode3 | string | 三段條碼繳費條碼3(格式:Code-39 barcode) | |
BarcodeEndDate | string | 三段條碼繳費期限,格式YYYYMMDDHHmmss |
『Hi Life』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
PinCode | string | 代碼(不可用來繳費) | |
BarCode1 | string | 繳費條碼1(格式:Code-39 barcode) | |
BarCode2 | string | 繳費條碼2(格式:Code-39 barcode) | |
BarCode3 | string | 繳費條碼3(格式:Code-39 barcode) | |
LimitDate | string | 繳費有效期限,格式YYYYMMDDHHmmss |
『超商條碼繳費』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
BarCode1 | string | 繳費條碼1(格式:Code-39 barcode) | |
BarCode2 | string | 繳費條碼2(格式:Code-39 barcode) | |
BarCode3 | string | 繳費條碼3(格式:Code-39 barcode) | |
LimitDate | string | 繳費有效期限,格式YYYYMMDDHHmmss |
『交易查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string(50) | Payment Hub之交易流水號 | |
key | string(50) | 交易驗証碼 | |
prc | string | 交易回傳碼 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string(50) | 銀行端口回傳碼 | |
acode | string(10) | 授權碼 | |
card_type | string | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string(50) | 發卡行 | |
issuing_bank_uid | string(50) | 發卡銀行代碼 | |
is_agent_charge | int(1) | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer(1) | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string(50) | 交易之金融服務商 | |
supplier_code | string(50) | 交易之金融服務商代碼 | 『金流供應商代碼』值參考 |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
price | string | 請求交易點數/金額 | |
actual_price | string | 實際交易點數/金額 | |
recharge_code | string | 交易產品代碼 | |
love_cost | string | 愛心捐款金額 | |
retmsg | string(500) | 回傳訊息 | |
pfn | string(20) | 付費方法 | |
trans_type | string | 付款種類 | 『交易類型定義』值參考 |
redeem | string | 紅利資訊 JSON 格式 | 『紅利資訊』值參考 |
installment | string | 信用卡分期資訊 JSON 格式 | 『分期資訊』值參考 |
payment_name | string | 定期定額式/定期分期式扣款名稱 | |
nois | string | 定期定額式/定期分期式扣繳期數 | |
group_id | string | 1.定期定額式扣款編號 2.定期分期式扣款編號 |
|
bank_id | string | 銀行代碼 | 虛擬帳號資訊 |
expired_date | string | 有效日期(YYYYMMDDHHmmss) | 虛擬帳號、超商代碼、無卡分期資訊 |
appropriation_date | string | 預計撥款日期(YYYYMMDD) | |
result_type | integer | 虛擬帳號、超商代碼 資料格式類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string | 資料內容所屬支付名稱 | 『資料內容所屬支付名稱』值參考 |
result_content | string | 虛擬帳號、超商代碼 資料內容 | 『虛擬帳號回傳欄位』值參考 『ibon』值參考 『FamiPort』值參考 『Hi Life』值參考 |
refund_order | array | 退款訂單資訊(多筆格式) | 每筆『交易查詢-退款資訊』欄位參考 |
cancel_order | array | 取消訂單資訊(多筆格式) | 每筆『交易查詢-取消資訊』欄位參考 |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_date | string | 發票開立日期(YYYYMMDD) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | integer | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_allowance | array | 電子發票折讓資訊 | 每筆『電子發票折讓資訊』欄位參考 |
items | array | 訂單商品項目 | 每筆『商品項目』欄位參考 |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
『商品項目』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
id | string | 商品編號 | |
name | string | 商品名稱 | |
cost | string | 商品單價 | |
amount | string | 商品數量 | |
total | string | 商品小計 |
『紅利資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
type | string | 紅利類型 | 『紅利資訊類型』值參考 |
used | string | 紅利折抵點數 | |
amount | string | 自付金額 |
『分期資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
period_number | integer | 分期期數 | |
total | integer | 應付總金額 | |
first | integer | 第一期應付金額 | |
every | integer | 第二期起每期應付金額 |
『交易查詢-退款資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string(50) | Payment Hub之交易流水號 | |
prc | string | 交易回傳碼 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
retmsg | string(500) | 回傳訊息 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
appropriation_date | string | 預計撥款日期(YYYYMMDD) | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_date | string | 發票開立日期(YYYYMMDD) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string | 電子發票列印標題內容 | |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_allowance | array | 電子發票折讓資訊 | 每筆『電子發票折讓資訊』欄位參考 |
『交易查詢-取消資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string(50) | Payment Hub之交易流水號 | |
prc | string | 交易回傳碼 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
retmsg | string(500) | 回傳訊息 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) |
『電子發票折讓資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 發生之退款交易流水號(UID) | |
amount | integer | 電子發票折讓金額 | |
order_detail | string | 電子發票折讓明細(JSON格式) | 『商品細項』值參考 |
『退款完成回傳資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 原MYPAYLINK 之交易流水號 | |
refund_uid | string | 退款之交易流水號(若多次退款,每次皆會不同) | |
key | string | 交易驗証碼 | |
prc | string | 主要交易回傳碼(retcode) | |
finishtime | string | 退款處理完成時間(YYYYMMDDHHmmss) | |
order_id | string | 貴特店系統的訂單編號 | |
user_id | string | 消費者帳號 | |
cost | string | 申請之退款金額 | |
currency | string | 申請之退款幣別 | |
actual_cost | string | 實際退款金額 | |
actual_currency | string | 實際退款幣別 | |
retmsg | string | 回傳訊息 | |
pfn | string | 付費方法 | |
payment_name | string | 定期定額式/定期分期式扣款名稱 | |
nois | string | 定期定額式/定期分期式扣繳期數 | |
group_id | string | 1.定期定額式扣款編號 2.定期分期式扣款編號 |
|
refund_type | string | 退款類型(1.直接線上退款 2.手動退款(信用卡類) 3.手動退款(現金類) | |
expected_refund_date | string | 現金退款預計退款日(YYYYMMDD) | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『商品細項』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
Description | string(50) | 商品名稱 | |
Quantity | string(10) | 數量 | |
UnitPrice | string(19) | 單價 | |
Amount | string(19) | 總金額 |
『後付款送貨資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
shipment_type | integer | 配送方式 | 『後付款送貨資訊』值參考 |
company_name | string | 寄送地公司名稱 | |
department_name | string | 寄送地部門名稱 | |
name | string | 收貨姓名 | 必填 |
cvs | integer | 超商類型(超商店到店必填) | 『後付款超商取貨』值參考 |
cvs_store | string | 超商店號代碼(超商店到店必填) | |
cvs_store_name | string | 超商店號名稱(超商店到店必填) | |
zip_code | string | 收貨郵遞區號(純宅配必填) | |
ship_address | string | 收貨地址(超商店到店為超商店址) | 必填 |
tel | string | 收貨電話(超商店到店為超商電話) | 必填 |
『後付款交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
OrderTotalCost | string | 交易金額 | |
TradeNo | string | 後付款交易單號 | |
TradeDate | string | 交易發動時間,格式YYYYMMDDHHmmss |
『後付款請款交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
OrderTotalCost | string | 出貨交易金額 | |
TradeNo | string | 後付款交易單號 | |
TradeDate | string | 出貨交易發動時間,格式YYYYMMDDHHmmss |
『後付款出貨查詢-退款資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 退款訂單編號(UID) | |
code | string | 交易狀態碼 | |
msg | string | 交易狀態訊息 | |
cost | string(19) | 總交易金額 | |
currency | string(10) | 原交易幣別 | |
actual_cost | string(19) | 實際交易金額 | |
actual_currency | string(10) | 實際交易幣別 | |
finishtime | string(14) | 交易完成時間(YYYYMMDDHHmmss) | |
invoice_state | integer(2) | 發票開立狀態 | 『電子發票開立狀態類型』值參考 |
invoice_date | string | 發票開立日期(YYYYMMDD) | |
invoice_wordtrack | string(2) | 發票字軌 | |
invoice_number | string(8) | 發票號碼 | |
invoice_rand_code | string(4) | 電子發票隨機碼 | |
invoice_seller_ban | string(8) | 賣方統一編號 | |
invoice_buyer_ban | string(8) | 買方統一編號 | |
invoice_left_qrcode | string(500) | 電子發票左邊QrCode內容 | |
invoice_middle_barcode | string(50) | 電子發票中間Barcode內容(格式Code-39) | |
invoice_right_qrcode | string(1000) | 電子發票右邊QrCode內容 | |
invoice_title_type | integer(1) | 電子發票列印標題格式 | 『電子發票紙本列印標題類型』值參考 |
invoice_title | string | 電子發票列印標題內容 | |
invoice_amount | string(19) | 電子發票銷售總額 | |
invoice_sales_amount | string(19) | 電子發票銷售額 | |
invoice_tax_amount | string(19) | 電子發票稅額 | |
invoice_order_detail | string(1000) | 電子發票全部產品明細(JSON格式) | 『商品細項』值參考 |
invoice_ratetype | integer(1) | 電子發票稅率別 | 『電子發票稅率別』值參考 |
invoice_input_type | integer(1) | 電子發票開立類型 | 『電子發票開立類型』值參考 |
invoice_allowance | array | 電子發票折讓資訊 | 每筆『電子發票折讓資訊』欄位參考 |
『電票交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
OrderTotalCost | string | 交易金額 | |
TradeDate | string | 交易時間,格式YYYYMMDDHHmmss | |
Balance | string | 扣款後餘額 | |
BeforeBalance | string | 扣款前餘額 | |
AutoTopUpAmount | string | 自動加值金額 | |
CardId | string | 電子票證卡號 |
『電票交易退款完成資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 訂單編號(UID) | |
refund_uid | string | 退款之交易流水號(若多次退款,每次皆會不同) | |
key | string(50) | 交易驗証碼 | |
code | string | 交易回傳碼 | |
msg | string(500) | 回傳訊息 | |
finishtime | string | 退款處理完成時間(YYYYMMDDHHmmss) | |
order_id | string(50) | 貴特店系統的訂單編號 | |
user_id | string(50) | 消費者帳號 | |
cost | string | 申請之退款金額 | |
currency | string | 申請之退款幣別 | |
actual_cost | string | 實際退款金額 | |
actual_currency | string | 實際退款幣別 | |
pfn | string(20) | 付費方法 | |
echo_0 | string(255) | 自訂回傳參數 1 | |
echo_1 | string(255) | 自訂回傳參數 2 | |
echo_2 | string(255) | 自訂回傳參數 3 | |
echo_3 | string(255) | 自訂回傳參數 4 | |
echo_4 | string(255) | 自訂回傳參數 5 |
『全支付線下資料』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
pxCode | string | 全支付qrcode二維條碼資訊 | 必填 |
posId | string | POS 機號或設備機號 | 必填 |
posTradeTime | string | POS 端交易日期時間 | |
remark | string | 註記 |
『全支付線下交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
PosID | string | POS 機號或設備機號 | |
PosTradeTime | string | POS 端交易日期時間,格式:YYYYMMDDHHmmss | |
Remark | string | 交易註記說明文字 | |
TradeNo | string | 金流服務商訂單編號 | |
OrderTotalCost | string | 交易金額 | |
TradeDate | string | 金流服務商交易時間,格式YYYYMMDDHHmmss | |
DebitAmount | string | 付款方式扣款金額(折抵後金額) | |
InvoiceVehicle | string | 發票載具 (消費者綁定全支付時設定之發票載具) |
|
MerMemToken | string | 第三方合作廠商會員識別資訊 | |
Pan | string | 遮碼卡號 | |
IsControversy | string | 是否為爭議款 0.不是 1.是 |
『Line Pay線上交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
Web | string | line pay 網頁支付網址 | |
App | string | line pay app支付網址 | |
TradeNo | string | 金流服務商訂單編號 |
『LINE Pay線下資料』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
linepayCode | string | LinePayqrcode二維條碼資訊 | 必填 |
『Line Pay線下交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
TradeNo | string | 金流服務商訂單編號 | |
OrderTotalCost | string | 交易金額 | |
TradeDate | string | 金流服務商交易時間,格式YYYYMMDDHHmmss | |
InvoiceVehicle | string | 發票載具 (消費者綁定LINE Pay時設定之發票載具) |
|
RedeemAmount | string | 折扣金額 | |
RedeemType | string | 折扣種類『紅利資訊類型』 | |
OrderRealCost | string | 實際交易金額 | |
PaymentType | string | 付款方式 | |
CreditAmt | string | 持卡人自付金額(信用卡使用) | |
IsControversy | integer | 爭議款 |
『Pi線下資料』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
piCode | string | Pi App qrcode二維條碼資訊 | 必填 |
『Pi線上資料回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
Web | string | 導頁網址 | |
App | string | app連結 |
『Pi線下交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
TradeNo | string | 金流服務商訂單編號 | |
OrderTotalCost | string | 交易金額 | |
TradeDate | string | 金流服務商交易時間,格式YYYYMMDDHHmmss | |
InvoiceVehicle | string | 發票載具 (消費者綁定Pi時設定之發票載具) |
『微信線下資料』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
piCode | string | 微信支付 App qrcode二維條碼資訊 | 必填 |
『街口線上交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
Web | string | 導頁網址+App連結網址 | |
QRCodeUrl | string | QRCode圖片 |
『街口線下資料』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
jkoCode | string | 街口支付 App qrcode二維條碼資訊 | 必填 |
posId | string | POS 機號或設備機號 | 必填 |
posTradeTime | string | POS 端交易日期時間 | |
remark | string | 註記 |
『街口線下交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
PosID | string | POS 機號或設備機號 | |
PosTradeTime | string | POS 端交易日期時間,格式:YYYYMMDDHHmmss | |
Remark | string | 交易註記說明文字 | |
TradeNo | string | 金流服務商訂單編號 | |
OrderTotalCost | string | 交易金額 | |
TradeDate | string | 金流服務商交易時間,格式YYYYMMDDHHmmss | |
DebitAmount | string | 付款方式扣款金額(折抵後金額) | |
InvoiceVehicle | string | 發票載具 (消費者綁定Pi時設定之發票載具) |
|
MerMemToken | string | 第三方合作廠商會員識別資訊 | |
Pan | string | 遮碼卡號 | |
IsControversy | string | 是否為爭議款 0.不是 1.是 |
『Apple Pay線下資料』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
paymentData | json | 由ApplePay產生之資料 | 必填 |
paymentMethod | json | 由ApplePay產生之資料 | 必填 |
transactionIdentifier | string | 由ApplePay產生之資料 | 必填 |
*.從ApplePay取得Token就應包含上述欄位,不需要修改內容或自行重組,只需將物件轉為Json String置於data_json即可
*.送出前請注意貴司程式是否有UrlEncode/UrlDecode的行為,若導致paymentToken經過轉換,可能丟失原始Token內容,造成付款失敗。
*.規格參考網址https://developer.apple.com/library/archive/documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.html#//apple_ref/doc/uid/TP40014929-CH8
『Google Pay線下資料』欄位
請參閱Google官方文件(Google 官方文件 https://developers.google.com/pay/api/android/guides/tutorial#step_3_create_paymentdatarequest_object),請依程式範例與順序取得JSON資料。
下圖例中的步驟2,gateway值請帶入「mypay」,gatewayMerchantId請帶入貴司申請之「商務代號」。 下圖例中的步驟9,請依紅色文字框取得到JSON資料後,直接放入data_json此欄位即可。
JSON 結構如下:
{
"apiVersionMinor": 0,
"apiVersion": 2,
"paymentMethodData": {
"description": "Visa •••• 1234",
"tokenizationData": {
"type": "PAYMENT_GATEWAY",
"token": "{\"signature\":\"MEQCICA••••\\u003d\\u003d\",\"protocolVersion\":\"ECv1\",\"signedMessage\":\"{\\\"encryptedMessage\\\":\\\"2oGYBPrbBJIAg••••\\\\u003d\\\\u003d\\\",\\\"ephemeralPublicKey\\\":\\\"BOlRJqnD••••\\\\u003d\\\",\\\"tag\\\":\\\"g0lZC4••••\\\\u003d\\\"}\"}"
},
"type": "CARD",
"info": {
"cardNetwork": "VISA",
"cardDetails": "1234"
}
}
}
『悠遊付線下資料』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
ewCode | string | 悠遊付二維條碼資訊 | 必填 |
『悠遊付線下交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
Remark | string | 交易註記說明文字 | |
TradeNo | string | 金流服務商訂單編號 | |
OrderTotalCost | string | 交易金額 | |
InvoiceVehicle | string | 發票載具 (消費者綁定Pi時設定之發票載具) |
|
CitizenDigitalCertificate | string | 自然人憑證條碼 | |
LoveCode | string | 愛心碼 | |
EventCode | string | 活動代碼 | |
PaymentType | string | 付款方式 | |
DebitAmount | string | 付款方式扣款金額(折抵後金額) |
『自行收款交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
OrderTotalCost | string | 交易金額 | |
TradeDate | string | 金流服務商交易時間,格式YYYYMMDDHHmmss |
『錢包被掃交易資料』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
qrCode | string | qrcode 交易碼 | 必填 |
『支付寶線下交易回傳欄位』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
TradeNo | string | 金流服務商編號 | |
OrderTotalCost | string | 交易金額 | |
TradeDate | string | 金流服務商交易時間,格式YYYYMMDDHHmmss |
『支付寶線下資料』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
alipayCode | string | alipay qrcode | 必填 |
值的定義
『付款方式』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
CREDITCARD | string | 信用卡 | |
CSTORECODE | string | 超商代碼 | |
WEBATM | string | WEBATM | |
E_COLLECTION | string | 虛擬帳號 | |
UNIONPAY | string | 銀聯卡 | |
ABROAD | string | 海外信用卡 | |
ALIPAY | string | 支付寶 | |
string | 微信支付 | ||
LINEPAYON | string | LINE Pay線上付款 | |
LINEPAYOFF | string | LINE Pay線下付款 | |
WECHATOFF | string | 微信支付線下 | |
APPLEPAY | string | APPLE PAY | |
GOOGLEPAY | string | Google Pay | |
CARDLESS | string | 無卡分期 | |
PION | string | Pi 拍錢包線上 | |
PIOFF | string | Pi 拍錢包線下 | |
AMEX | string | 美國運通 | |
JKOON | string | 街口支付線上 | |
JKOOFF | string | 街口支付線下 | |
ALIPAYOFF | string | 支付寶線下 | |
EASYWALLETON | string | 悠遊付線上 | |
EASYWALLETOFF | string | 悠遊付線下 | |
PXPAYOFF | string | 全支付線下 | |
AFP | string | 後付款 | |
OFFLINE | string | 錢包被掃交易 | |
CREDITCARDALL | string | 線下信用卡交易 | |
ESVC | string | 電票交易 | |
EACH | string | eACH交易 | |
BARCODE | string | 超商繳費代碼 |
『回傳付款方式』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
CREDITCARD | string | 信用卡 | |
CSTORECODE | string | 超商代碼 | |
WEBATM | string | WEBATM | |
E_COLLECTION | string | 虛擬帳號 | |
UNIONPAY | string | 銀聯卡 | |
ABROAD | string | 海外信用卡 | |
ALIPAY | string | 支付寶 | |
string | 微信支付 | ||
LINEPAYON | string | LINE Pay線上付款 | |
LINEPAYOFF | string | LINE Pay線下付款 | |
WECHATOFF | string | 微信支付線下 | |
APPLEPAY | string | APPLE PAY | |
GOOGLEPAY | string | Google Pay | |
CARDLESS | string | 無卡分期 | |
PION | string | Pi 拍錢包線上 | |
PIOFF | string | Pi 拍錢包線下 | |
AMEX | string | 美國運通 | |
JKOON | string | 街口支付線上 | |
JKOOFF | string | 街口支付線下 | |
ALIPAYOFF | string | 支付寶線下 | |
EASYWALLETON | string | 悠遊付線上 | |
EASYWALLETOFF | string | 悠遊付線下 | |
PXPAYOFF | string | 全支付線下 | |
AFP | string | 後付款 | |
EACH | string | eACH交易 | |
BARCODE | string | 超商繳費代碼 | |
EASYCARD | string | 悠遊卡 | |
IPASS | string | 一卡通 | |
ICASH | string | iCash |
『電票類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
EASYCARD | string | 悠遊卡 | |
IPASS | string | 一卡通 | |
ICASH | string | iCash |
『證號類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 身份證字號(預設) | |
2 | integer | 統一證號 | |
3 | integer | 護照號碼 |
『幣別類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
TWD | integer | 新台幣(預設) | |
CNY | integer | 人民幣 |
『電子發票是否開立狀態』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 不開立電子發票 | |
1 | integer | 開立電子發票 | |
2 | integer | 依系統設定(預設) |
『電子發票稅率別』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 應稅(預設) | |
2 | integer | 零稅率 | |
3 | integer | 免稅 |
『電子發票開立類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 未使用電子發票開立 | |
1 | integer | 雲端發票 | |
2 | integer | 發票捐贈 | |
3 | integer | 實體發票 | 重要提示,若選擇此模式,商戶需要自行列印實體發票交付給消費者,系統不會寄送mail通知與中獎後也不會通知給消費者。電子發票列印格式,請參考國稅局頒布標準。 |
『雲端發票類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 未使用雲端發票類型 | |
2 | integer | 手機條碼 | |
3 | integer | 自然人憑證條碼 | |
4 | integer | 以E-Mail寄送 |
『含不含簡訊費』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 含手續費 | |
0 | integer | 不含手續費(預設) |
『含不含手續費類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 含手續費 | |
0 | integer | 不含手續費(預設) |
『交易服務類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 尚未進行閘道交易 | |
1 | integer | 代收代付 | |
2 | integer | 特店模式 |
『金流供應商代碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
A1 | string | 裕富數位資融 | |
A2 | string | 三環亞洲 | |
B0 | string | 新光銀行 | |
B1 | string | 永豐銀行 | |
B2 | string | 合作金庫 | |
B3 | string | 台北富邦 | |
B4 | string | 玉山銀行 | |
B5 | string | 台新銀行 | |
B6 | string | 聯合信用卡處理中心 | |
B7 | string | 台中商銀 | |
B8 | string | 中國信託商業銀行 | |
B9 | string | 上海商業儲蓄銀行 | |
BA | string | 第一銀行 | |
BB | string | 元大商業銀行 | |
BC | string | 凱基銀行 | |
BD | string | 國泰世華商業銀行 | |
BE | string | 華泰商業銀行 | |
BF | string | 兆豐銀行 | |
BG | string | 環滙亞太 | |
S0 | string | 全網行銷股份有限公司(FamiPort) | |
S1 | string | 安源資訊股份有限公司(ibon) | |
S2 | string | 萊爾富國際股份有限公司(Hi-Life) | |
T0 | string | 高鉅科技 | |
T1 | string | 藍新金流 | |
T2 | string | 統一客樂得(黑貓Pay) | |
W0 | string | 統振 | |
W1 | string | 遊戲橘子數位 | |
W2 | string | 台灣連線(LINEPay) | |
W3 | string | 博經 | |
W4 | string | 街口電子支付 | |
W5 | string | 悠遊卡 | |
W6 | string | 一卡通票證 | |
W7 | string | iCash | |
W8 | string | 全支付(PXPay plus) | |
W9 | string | 拍付國際資訊(Pi錢包) | |
E0 | string | MYTIX |
『交易類型定義』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 一般 (預設) | |
2 | integer | 分期 | |
3 | integer | 紅利 |
『紅利資訊類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 全額 | |
2 | integer | 部分 |
『閘道內容回傳格式類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 無法辨識 | |
1 | integer | 網址 | |
2 | integer | 超連結本文 | |
3 | integer | xml | |
4 | integer | json | |
5 | integer | csv | |
6 | integer | 串流 |
『電子發票開立狀態類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 不處理(預設) | |
1 | integer | 等候處理中, | |
2 | integer | 發票處理成功 | |
3 | integer | 發票處理失敗 | |
4 | integer | 作癈 | |
5 | integer | 發票號碼設定不正確 |
『電子發票紙本列印標題類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 文字 | |
2 | integer | 圖形(圖片網址) |
『後付款送貨資訊』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
2 | integer | 純宅配 | |
4 | integer | 超商店到店 |
『後付款超商取貨』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 7-11 | |
2 | integer | 全家 |
『貨運商家編號』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 無法辨識 | |
1 | integer | 黑貓宅急便 | |
2 | integer | 台灣宅配通 | |
3 | integer | 新竹貨運 | |
4 | integer | 大榮貨運 | |
5 | integer | 中華郵政 | |
6 | integer | 便利帶 | |
7 | integer | 大智通物流 | |
8 | integer | 日翊文化行銷 | |
9 | integer | EMS | |
10 | integer | 國際e郵包 | |
11 | integer | 大和國際宅急便 | |
12 | integer | 佐川國際宅急便 | |
13 | integer | Dmail/Pmail | |
14 | integer | ECMS日本 |
『資料內容所屬支付名稱』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
E_COLLECTION | string | 虛擬帳號 | |
IBON | string | iBON | |
FAMIPORT | string | FamiPort | |
LIFEET | string | LIFE-ET | |
WEBATM | string | WEBATM | |
CREDITCARD | string | 信用卡 | |
UNIONPAY | string | 銀聯卡 | |
SVC | string | 點數卡(GASH ,Imoney) | |
ABROAD | string | 海外信用卡 | |
ALIPAY | string | 支付寶 | |
string | 微信支付 | ||
LINEPAYON | string | LINE Pay線上付款 | |
LINEPAYOFF | string | LINE Pay線下付款 | |
WECHATOFF | string | 微信支付線下 | |
APPLEPAY | string | APPLE PAY | |
GOOGLEPAY | string | Google Pay | |
EACH | string | eACH交易 | |
CARDLESS | string | 無卡分期 | |
PION | string | Pi 拍錢包線上 | |
PIOFF | string | Pi 拍錢包線下 | |
AMEX | string | 美國運通 | |
JKOON | string | 街口支付線上 | |
JKOOFF | string | 街口支付線下 | |
ALIPAYOFF | string | 支付寶線下 | |
EASYWALLETON | string | 悠遊付線上 | |
EASYWALLETOFF | string | 悠遊付線下 | |
PXPAYOFF | string | 全支付線下 | |
AFP | string | 後付款 | |
BARCODE | string | 超商條碼繳費 |
『信用卡別類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 無法辨識或支付方式為非信用卡類 | |
1 | integer | VISA | |
2 | integer | MasterCard | |
3 | integer | JCB | |
4 | integer | AMEX |
『電子發票退款時使用作廢或折讓』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
4 | integer | 作廢或作廢重開 | 預設 |
6 | integer | 折讓 |
『是否為經銷商代收費模式』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 是經銷商代收費模式 | |
0 | integer | 不是經銷商代收費模式 |
『自行收款付款方式』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
CASH | string | 現金交易 | |
ZINGALAPAY | string | 銀角零卡 | |
LINEPAY | string | LINE Pay | |
JKO | string | 街口支付 | |
PI | string | Pi 拍錢包 | |
EASYWALLET | string | 悠遊付 | |
PXPAY | string | 全支付 | |
PLUSPAY | string | 全盈支付 | |
REMITTENCE | string | 轉帳匯款(無分類) | |
REMITTENCE_000 | string | 轉帳匯款(中央銀行) | |
REMITTENCE_004 | string | 轉帳匯款(臺灣銀行) | |
REMITTENCE_005 | string | 轉帳匯款(土地銀行) | |
REMITTENCE_006 | string | 轉帳匯款(合作金庫) | |
REMITTENCE_007 | string | 轉帳匯款(第一銀行) | |
REMITTENCE_008 | string | 轉帳匯款(華南銀行) | |
REMITTENCE_009 | string | 轉帳匯款(彰化銀行) | |
REMITTENCE_011 | string | 轉帳匯款(上海銀行) | |
REMITTENCE_012 | string | 轉帳匯款(台北富邦) | |
REMITTENCE_013 | string | 轉帳匯款(國泰世華) | |
REMITTENCE_016 | string | 轉帳匯款(高雄銀行) | |
REMITTENCE_017 | string | 轉帳匯款(兆豐銀行) | |
REMITTENCE_018 | string | 轉帳匯款(農業金庫) | |
REMITTENCE_020 | string | 轉帳匯款(日商瑞穗銀行) | |
REMITTENCE_021 | string | 轉帳匯款(花旗銀行) | |
REMITTENCE_022 | string | 轉帳匯款(美國銀行) | |
REMITTENCE_023 | string | 轉帳匯款(盤谷銀行) | |
REMITTENCE_025 | string | 轉帳匯款(首都銀行) | |
REMITTENCE_029 | string | 轉帳匯款(新加坡大華銀行) | |
REMITTENCE_030 | string | 轉帳匯款(美商道富銀行) | |
REMITTENCE_037 | string | 轉帳匯款(法商法國興業銀行台北分行) | |
REMITTENCE_039 | string | 轉帳匯款(澳盛銀行) | |
REMITTENCE_048 | string | 轉帳匯款(王道銀行) | |
REMITTENCE_050 | string | 轉帳匯款(臺灣企銀) | |
REMITTENCE_052 | string | 轉帳匯款(渣打銀行) | |
REMITTENCE_053 | string | 轉帳匯款(台中銀行) | |
REMITTENCE_054 | string | 轉帳匯款(京城銀行) | |
REMITTENCE_060 | string | 轉帳匯款(兆豐票券) | |
REMITTENCE_061 | string | 轉帳匯款(中華票券) | |
REMITTENCE_062 | string | 轉帳匯款(國際票券) | |
REMITTENCE_066 | string | 轉帳匯款(萬通票券) | |
REMITTENCE_072 | string | 轉帳匯款(德意志銀行) | |
REMITTENCE_075 | string | 轉帳匯款(東亞銀行) | |
REMITTENCE_076 | string | 轉帳匯款(摩根大通銀行) | |
REMITTENCE_081 | string | 轉帳匯款(滙豐銀行) | |
REMITTENCE_082 | string | 轉帳匯款(巴黎銀行) | |
REMITTENCE_085 | string | 轉帳匯款(新加坡華僑銀行) | |
REMITTENCE_086 | string | 轉帳匯款(東方匯理銀行) | |
REMITTENCE_092 | string | 轉帳匯款(瑞士銀行) | |
REMITTENCE_093 | string | 轉帳匯款(安智銀行) | |
REMITTENCE_098 | string | 轉帳匯款(三菱東京日聯銀行) | |
REMITTENCE_101 | string | 轉帳匯款(瑞興銀行) | |
REMITTENCE_102 | string | 轉帳匯款(華泰銀行) | |
REMITTENCE_103 | string | 轉帳匯款(新光銀行) | |
REMITTENCE_104 | string | 轉帳匯款(台北五信) | |
REMITTENCE_108 | string | 轉帳匯款(陽信銀行) | |
REMITTENCE_114 | string | 轉帳匯款(基隆一信) | |
REMITTENCE_115 | string | 轉帳匯款(基隆二信) | |
REMITTENCE_118 | string | 轉帳匯款(板信銀行) | |
REMITTENCE_119 | string | 轉帳匯款(淡水一信) | |
REMITTENCE_120 | string | 轉帳匯款(淡水信合社) | |
REMITTENCE_124 | string | 轉帳匯款(宜蘭信合社) | |
REMITTENCE_127 | string | 轉帳匯款(桃園信合社) | |
REMITTENCE_130 | string | 轉帳匯款(新竹一信) | |
REMITTENCE_132 | string | 轉帳匯款(新竹三信) | |
REMITTENCE_146 | string | 轉帳匯款(台中二信) | |
REMITTENCE_147 | string | 轉帳匯款(三信銀行) | |
REMITTENCE_158 | string | 轉帳匯款(彰化一信) | |
REMITTENCE_161 | string | 轉帳匯款(彰化五信) | |
REMITTENCE_162 | string | 轉帳匯款(彰化六信) | |
REMITTENCE_163 | string | 轉帳匯款(彰化十信) | |
REMITTENCE_165 | string | 轉帳匯款(鹿港信合社) | |
REMITTENCE_178 | string | 轉帳匯款(嘉義三信) | |
REMITTENCE_188 | string | 轉帳匯款(台南三信) | |
REMITTENCE_204 | string | 轉帳匯款(高雄三信) | |
REMITTENCE_215 | string | 轉帳匯款(花蓮一信) | |
REMITTENCE_216 | string | 轉帳匯款(花蓮二信) | |
REMITTENCE_222 | string | 轉帳匯款(澎湖一信) | |
REMITTENCE_223 | string | 轉帳匯款(澎湖二信) | |
REMITTENCE_224 | string | 轉帳匯款(金門信合社) | |
REMITTENCE_321 | string | 轉帳匯款(三井住友銀行) | |
REMITTENCE_326 | string | 轉帳匯款(西班牙商西班牙對外銀行臺北分行) | |
REMITTENCE_329 | string | 轉帳匯款(印尼人民銀行) | |
REMITTENCE_330 | string | 轉帳匯款(韓亞銀行) | |
REMITTENCE_372 | string | 轉帳匯款(大慶票券) | |
REMITTENCE_380 | string | 轉帳匯款(中國銀行) | |
REMITTENCE_381 | string | 轉帳匯款(交通銀行) | |
REMITTENCE_382 | string | 轉帳匯款(中國建設銀行) | |
REMITTENCE_501 | string | 轉帳匯款(宜蘭縣蘇澳區漁會) | |
REMITTENCE_502 | string | 轉帳匯款(宜蘭縣頭城區漁會) | |
REMITTENCE_503 | string | 轉帳匯款(基隆漁會) | |
REMITTENCE_504 | string | 轉帳匯款(瑞芳/萬里漁會) | |
REMITTENCE_505 | string | 轉帳匯款(頭城/蘇澳漁會) | |
REMITTENCE_506 | string | 轉帳匯款(桃園漁會) | |
REMITTENCE_507 | string | 轉帳匯款(新竹漁會) | |
REMITTENCE_508 | string | 轉帳匯款(通苑區漁會) | |
REMITTENCE_510 | string | 轉帳匯款(農金資中心) | |
REMITTENCE_511 | string | 轉帳匯款(彰化區漁會) | |
REMITTENCE_512 | string | 轉帳匯款(雲林區漁會) | |
REMITTENCE_513 | string | 轉帳匯款(新北市瑞芳區漁會) | |
REMITTENCE_514 | string | 轉帳匯款(萬里區漁會) | |
REMITTENCE_515 | string | 轉帳匯款(嘉義區漁會) | |
REMITTENCE_516 | string | 轉帳匯款(基隆區漁會) | |
REMITTENCE_517 | string | 轉帳匯款(南市區漁會) | |
REMITTENCE_518 | string | 轉帳匯款(南縣區漁會) | |
REMITTENCE_519 | string | 轉帳匯款(新化區農會) | |
REMITTENCE_520 | string | 轉帳匯款(小港區漁會;高雄區漁會) | |
REMITTENCE_521 | string | 轉帳匯款(彌陀/永安/興達港/林園區漁會) | |
REMITTENCE_523 | string | 轉帳匯款(東港/琉球/林邊區漁會) | |
REMITTENCE_524 | string | 轉帳匯款(新港區漁會) | |
REMITTENCE_525 | string | 轉帳匯款(澎湖區漁會) | |
REMITTENCE_526 | string | 轉帳匯款(南農中心) | |
REMITTENCE_538 | string | 轉帳匯款(宜蘭市農會) | |
REMITTENCE_541 | string | 轉帳匯款(白河區農會) | |
REMITTENCE_542 | string | 轉帳匯款(麻豆區農會) | |
REMITTENCE_547 | string | 轉帳匯款(後壁區農會) | |
REMITTENCE_549 | string | 轉帳匯款(下營區農會) | |
REMITTENCE_551 | string | 轉帳匯款(官田區農會) | |
REMITTENCE_552 | string | 轉帳匯款(大內區農會) | |
REMITTENCE_556 | string | 轉帳匯款(學甲區農會) | |
REMITTENCE_557 | string | 轉帳匯款(新市區農會) | |
REMITTENCE_558 | string | 轉帳匯款(安定區農會) | |
REMITTENCE_559 | string | 轉帳匯款(山上區農會) | |
REMITTENCE_561 | string | 轉帳匯款(左鎮區農會) | |
REMITTENCE_562 | string | 轉帳匯款(仁德區農會) | |
REMITTENCE_564 | string | 轉帳匯款(關廟區農會) | |
REMITTENCE_565 | string | 轉帳匯款(龍崎區農會) | |
REMITTENCE_567 | string | 轉帳匯款(南化區農會) | |
REMITTENCE_568 | string | 轉帳匯款(七股區農會) | |
REMITTENCE_570 | string | 轉帳匯款(南投市農會) | |
REMITTENCE_573 | string | 轉帳匯款(埔里鎮農會) | |
REMITTENCE_574 | string | 轉帳匯款(竹山鎮農會) | |
REMITTENCE_575 | string | 轉帳匯款(中寮鄉農會) | |
REMITTENCE_577 | string | 轉帳匯款(魚池鄉農會) | |
REMITTENCE_578 | string | 轉帳匯款(水里鄉農會) | |
REMITTENCE_579 | string | 轉帳匯款(國姓鄉農會) | |
REMITTENCE_580 | string | 轉帳匯款(鹿谷鄉農會) | |
REMITTENCE_581 | string | 轉帳匯款(信義鄉農會) | |
REMITTENCE_582 | string | 轉帳匯款(仁愛鄉農會) | |
REMITTENCE_583 | string | 轉帳匯款(東山區農會) | |
REMITTENCE_585 | string | 轉帳匯款(頭城鎮農會) | |
REMITTENCE_586 | string | 轉帳匯款(羅東鎮農會) | |
REMITTENCE_587 | string | 轉帳匯款(礁溪鄉農會) | |
REMITTENCE_588 | string | 轉帳匯款(壯圍鄉農會) | |
REMITTENCE_589 | string | 轉帳匯款(員山鄉農會) | |
REMITTENCE_596 | string | 轉帳匯款(五結鄉農會) | |
REMITTENCE_598 | string | 轉帳匯款(蘇澳地區農會) | |
REMITTENCE_599 | string | 轉帳匯款(三星地區農會) | |
REMITTENCE_600 | string | 轉帳匯款(農金資訊股份有限公司) | |
REMITTENCE_602 | string | 轉帳匯款(中華民國農會中壢辦事處信用部) | |
REMITTENCE_603 | string | 轉帳匯款(基隆地區農會) | |
REMITTENCE_605 | string | 轉帳匯款(高雄市農會) | |
REMITTENCE_606 | string | 轉帳匯款(新北市農會) | |
REMITTENCE_607 | string | 轉帳匯款(宜蘭地區農會) | |
REMITTENCE_608 | string | 轉帳匯款(桃園地區農會) | |
REMITTENCE_609 | string | 轉帳匯款(中華民國農會) | |
REMITTENCE_610 | string | 轉帳匯款(新竹地區農會) | |
REMITTENCE_611 | string | 轉帳匯款(後龍農會) | |
REMITTENCE_612 | string | 轉帳匯款(豐原市農會;神岡鄉農會) | |
REMITTENCE_613 | string | 轉帳匯款(名間/集集農會) | |
REMITTENCE_614 | string | 轉帳匯款(彰化地區農會) | |
REMITTENCE_615 | string | 轉帳匯款(基隆市農會) | |
REMITTENCE_616 | string | 轉帳匯款(雲林地區農會) | |
REMITTENCE_617 | string | 轉帳匯款(嘉義地區農會) | |
REMITTENCE_618 | string | 轉帳匯款(台南地區農會) | |
REMITTENCE_619 | string | 轉帳匯款(高雄地區農會) | |
REMITTENCE_620 | string | 轉帳匯款(屏東地區農會) | |
REMITTENCE_621 | string | 轉帳匯款(花蓮地區農會) | |
REMITTENCE_622 | string | 轉帳匯款(台東地區農會) | |
REMITTENCE_623 | string | 轉帳匯款(台北市農會) | |
REMITTENCE_624 | string | 轉帳匯款(澎湖農會) | |
REMITTENCE_625 | string | 轉帳匯款(台中市農會) | |
REMITTENCE_627 | string | 轉帳匯款(連江縣農會) | |
REMITTENCE_628 | string | 轉帳匯款(鹿港鎮農會) | |
REMITTENCE_629 | string | 轉帳匯款(和美鎮農會) | |
REMITTENCE_631 | string | 轉帳匯款(溪湖鎮農會) | |
REMITTENCE_632 | string | 轉帳匯款(田中鎮農會) | |
REMITTENCE_633 | string | 轉帳匯款(北斗鎮農會) | |
REMITTENCE_635 | string | 轉帳匯款(線西鄉農會) | |
REMITTENCE_636 | string | 轉帳匯款(伸港鄉農會) | |
REMITTENCE_638 | string | 轉帳匯款(花壇鄉農會) | |
REMITTENCE_639 | string | 轉帳匯款(大村鄉農會) | |
REMITTENCE_642 | string | 轉帳匯款(社頭鄉農會) | |
REMITTENCE_643 | string | 轉帳匯款(二水鄉農會) | |
REMITTENCE_646 | string | 轉帳匯款(大城鄉農會) | |
REMITTENCE_647 | string | 轉帳匯款(溪州鄉農會) | |
REMITTENCE_649 | string | 轉帳匯款(埔鹽鄉農會) | |
REMITTENCE_650 | string | 轉帳匯款(福興鄉農會) | |
REMITTENCE_651 | string | 轉帳匯款(彰化市農會) | |
REMITTENCE_683 | string | 轉帳匯款(北港鎮農會) | |
REMITTENCE_685 | string | 轉帳匯款(土庫鎮農會) | |
REMITTENCE_693 | string | 轉帳匯款(東勢鄉農會) | |
REMITTENCE_696 | string | 轉帳匯款(水林鄉農會) | |
REMITTENCE_697 | string | 轉帳匯款(元長鄉農會) | |
REMITTENCE_698 | string | 轉帳匯款(麥寮鄉農會) | |
REMITTENCE_699 | string | 轉帳匯款(林內鄉農會) | |
REMITTENCE_700 | string | 轉帳匯款(中華郵政) | |
REMITTENCE_749 | string | 轉帳匯款(內埔地區農會) | |
REMITTENCE_762 | string | 轉帳匯款(大溪區農會) | |
REMITTENCE_763 | string | 轉帳匯款(桃園區農會) | |
REMITTENCE_764 | string | 轉帳匯款(平鎮區農會) | |
REMITTENCE_765 | string | 轉帳匯款(楊梅區農會) | |
REMITTENCE_766 | string | 轉帳匯款(大園區農會) | |
REMITTENCE_767 | string | 轉帳匯款(蘆竹區農會) | |
REMITTENCE_768 | string | 轉帳匯款(龜山區農會) | |
REMITTENCE_769 | string | 轉帳匯款(八德區農會) | |
REMITTENCE_770 | string | 轉帳匯款(新屋區農會) | |
REMITTENCE_771 | string | 轉帳匯款(龍潭區農會) | |
REMITTENCE_772 | string | 轉帳匯款(復興區農會) | |
REMITTENCE_773 | string | 轉帳匯款(觀音區農會) | |
REMITTENCE_775 | string | 轉帳匯款(土城區農會) | |
REMITTENCE_776 | string | 轉帳匯款(三重區農會) | |
REMITTENCE_777 | string | 轉帳匯款(中和地區農會) | |
REMITTENCE_778 | string | 轉帳匯款(淡水區農會) | |
REMITTENCE_779 | string | 轉帳匯款(樹林區農會) | |
REMITTENCE_780 | string | 轉帳匯款(鶯歌區農會) | |
REMITTENCE_781 | string | 轉帳匯款(三峽區農會) | |
REMITTENCE_785 | string | 轉帳匯款(蘆洲區農會) | |
REMITTENCE_786 | string | 轉帳匯款(五股區農會) | |
REMITTENCE_787 | string | 轉帳匯款(林口區農會) | |
REMITTENCE_788 | string | 轉帳匯款(泰山區農會) | |
REMITTENCE_789 | string | 轉帳匯款(坪林區農會) | |
REMITTENCE_790 | string | 轉帳匯款(八里區農會) | |
REMITTENCE_791 | string | 轉帳匯款(金山地區農會) | |
REMITTENCE_792 | string | 轉帳匯款(瑞芳地區農會) | |
REMITTENCE_793 | string | 轉帳匯款(新店地區農會) | |
REMITTENCE_795 | string | 轉帳匯款(深坑區農會) | |
REMITTENCE_796 | string | 轉帳匯款(石碇區農會) | |
REMITTENCE_797 | string | 轉帳匯款(平溪區農會) | |
REMITTENCE_798 | string | 轉帳匯款(石門區農會) | |
REMITTENCE_799 | string | 轉帳匯款(三芝區農會) | |
REMITTENCE_803 | string | 轉帳匯款(聯邦銀行) | |
REMITTENCE_805 | string | 轉帳匯款(遠東銀行) | |
REMITTENCE_806 | string | 轉帳匯款(元大銀行) | |
REMITTENCE_807 | string | 轉帳匯款(永豐銀行) | |
REMITTENCE_808 | string | 轉帳匯款(玉山銀行) | |
REMITTENCE_809 | string | 轉帳匯款(凱基銀行) | |
REMITTENCE_810 | string | 轉帳匯款(星展銀行) | |
REMITTENCE_812 | string | 轉帳匯款(台新銀行) | |
REMITTENCE_814 | string | 轉帳匯款(大眾銀行) | |
REMITTENCE_815 | string | 轉帳匯款(日盛銀行) | |
REMITTENCE_816 | string | 轉帳匯款(安泰銀行) | |
REMITTENCE_822 | string | 轉帳匯款(中國信託) | |
REMITTENCE_823 | string | 轉帳匯款(將來銀行) | |
REMITTENCE_824 | string | 轉帳匯款(LINE Bank) | |
REMITTENCE_826 | string | 轉帳匯款(樂天銀行) | |
REMITTENCE_860 | string | 轉帳匯款(中埔鄉農會) | |
REMITTENCE_866 | string | 轉帳匯款(阿里山鄉農會) | |
REMITTENCE_868 | string | 轉帳匯款(東勢區農會) | |
REMITTENCE_869 | string | 轉帳匯款(清水區農會) | |
REMITTENCE_870 | string | 轉帳匯款(梧棲區農會) | |
REMITTENCE_871 | string | 轉帳匯款(大甲區農會) | |
REMITTENCE_872 | string | 轉帳匯款(沙鹿區農會) | |
REMITTENCE_874 | string | 轉帳匯款(霧峰區農會) | |
REMITTENCE_875 | string | 轉帳匯款(太平區農會) | |
REMITTENCE_876 | string | 轉帳匯款(烏日區農會) | |
REMITTENCE_877 | string | 轉帳匯款(后里區農會) | |
REMITTENCE_878 | string | 轉帳匯款(大雅區農會) | |
REMITTENCE_879 | string | 轉帳匯款(潭子區農會) | |
REMITTENCE_880 | string | 轉帳匯款(石岡區農會) | |
REMITTENCE_881 | string | 轉帳匯款(新社區農會) | |
REMITTENCE_882 | string | 轉帳匯款(大肚區農會) | |
REMITTENCE_883 | string | 轉帳匯款(外埔區農會) | |
REMITTENCE_884 | string | 轉帳匯款(大安區農會) | |
REMITTENCE_885 | string | 轉帳匯款(龍井區農會) | |
REMITTENCE_886 | string | 轉帳匯款(和平區農會) | |
REMITTENCE_891 | string | 轉帳匯款(花蓮市農會) | |
REMITTENCE_895 | string | 轉帳匯款(瑞穗鄉農會) | |
REMITTENCE_896 | string | 轉帳匯款(玉溪地區農會) | |
REMITTENCE_897 | string | 轉帳匯款(鳳榮地區農會) | |
REMITTENCE_898 | string | 轉帳匯款(光豐地區農會) | |
REMITTENCE_901 | string | 轉帳匯款(大里市農會) | |
REMITTENCE_902 | string | 轉帳匯款(苗栗市農會) | |
REMITTENCE_903 | string | 轉帳匯款(汐止農會) | |
REMITTENCE_904 | string | 轉帳匯款(新莊農會) | |
REMITTENCE_906 | string | 轉帳匯款(頭份市農會) | |
REMITTENCE_907 | string | 轉帳匯款(竹南鎮農會) | |
REMITTENCE_908 | string | 轉帳匯款(通霄鎮農會) | |
REMITTENCE_909 | string | 轉帳匯款(苑裡鎮農會) | |
REMITTENCE_910 | string | 轉帳匯款(聯資中心) | |
REMITTENCE_912 | string | 轉帳匯款(冬山農會) | |
REMITTENCE_913 | string | 轉帳匯款(後龍鎮農會) | |
REMITTENCE_914 | string | 轉帳匯款(卓蘭鎮農會) | |
REMITTENCE_915 | string | 轉帳匯款(西湖鄉農會) | |
REMITTENCE_916 | string | 轉帳匯款(草屯農會) | |
REMITTENCE_917 | string | 轉帳匯款(公館鄉農會) | |
REMITTENCE_918 | string | 轉帳匯款(銅鑼鄉農會) | |
REMITTENCE_919 | string | 轉帳匯款(三義鄉農會) | |
REMITTENCE_920 | string | 轉帳匯款(造橋鄉農會) | |
REMITTENCE_921 | string | 轉帳匯款(南庄鄉農會) | |
REMITTENCE_922 | string | 轉帳匯款(臺南農會) | |
REMITTENCE_923 | string | 轉帳匯款(獅潭鄉農會) | |
REMITTENCE_924 | string | 轉帳匯款(頭屋鄉農會) | |
REMITTENCE_925 | string | 轉帳匯款(三灣鄉農會) | |
REMITTENCE_926 | string | 轉帳匯款(大湖地區農會) | |
REMITTENCE_928 | string | 轉帳匯款(板橋農會) | |
REMITTENCE_929 | string | 轉帳匯款(關西鎮農會) | |
REMITTENCE_930 | string | 轉帳匯款(新埔鎮農會) | |
REMITTENCE_931 | string | 轉帳匯款(竹北市農會) | |
REMITTENCE_932 | string | 轉帳匯款(湖口鄉農會) | |
REMITTENCE_933 | string | 轉帳匯款(芎林鄉農會) | |
REMITTENCE_934 | string | 轉帳匯款(寶山鄉農會) | |
REMITTENCE_935 | string | 轉帳匯款(峨眉鄉農會) | |
REMITTENCE_936 | string | 轉帳匯款(北埔鄉農會) | |
REMITTENCE_937 | string | 轉帳匯款(竹東地區農會) | |
REMITTENCE_938 | string | 轉帳匯款(橫山地區農會) | |
REMITTENCE_939 | string | 轉帳匯款(新豐鄉農會) | |
REMITTENCE_940 | string | 轉帳匯款(新竹市農會信用部) | |
REMITTENCE_951 | string | 轉帳匯款(北農中心) | |
REMITTENCE_952 | string | 轉帳匯款(南部地區農漁會) | |
REMITTENCE_953 | string | 轉帳匯款(田尾鄉農會) | |
REMITTENCE_954 | string | 轉帳匯款(中部地區農漁會) | |
REMITTENCE_960 | string | 轉帳匯款(台灣樂天) | |
REMITTENCE_975 | string | 轉帳匯款(美國運通) | |
REMITTENCE_978 | string | 轉帳匯款(台灣永旺) | |
REMITTENCE_984 | string | 轉帳匯款(北投區農會) | |
REMITTENCE_985 | string | 轉帳匯款(士林區農會) | |
REMITTENCE_986 | string | 轉帳匯款(內湖區農會) | |
REMITTENCE_987 | string | 轉帳匯款(南港區農會) | |
REMITTENCE_988 | string | 轉帳匯款(木柵區農會) | |
REMITTENCE_989 | string | 轉帳匯款(景美區農會) | |
REMITTENCE_995 | string | 轉帳匯款(關貿網路) | |
REMITTENCE_996 | string | 轉帳匯款(財政部國庫署) | |
REMITTENCE_997 | string | 轉帳匯款(南資中心) | |
ALIPAY_YUANTABANK | string | 支付寶元大 | |
ALIPAY_MEGABANK | string | 支付寶兆豐 | |
ALIPAY_TCB | string | 支付寶合庫 | |
WECHAT_SKBANK | string | 微信支付新光 | |
MOMO | string | Momo收款 | |
SHOPEE | string | 蝦皮拍賣收款 | |
ETMALL | string | 東森收款 | |
PCSTORE | string | PChome商店街收款 | |
PCHOME24H | string | PChome24H收款 | |
RUTEN | string | 露天拍賣收款 | |
SHOPLINE | string | Shop line收款 | |
FOODPANDA | string | 熊貓收款 | |
UBEREATS | string | Uber eats收款 | |
CYBERBIZ | string | Cyberbiz收款 | |
YAHOOBID | string | YAHOO拍賣收款 | |
RAKUTEN | string | 樂天市場收款 | |
CAROUSELL | string | 旋轉拍賣收款 | |
FACEBOOKGROUPS | string | FB社團收款 | |
PINKOI | string | Pinkoi收款 | |
91APP | string | 91APP收款 | |
COD_MYPAY | string | MYPAY物流代收 | |
COD_HCT | string | 新竹物流代收 | |
COD_TCAT | string | 黑貓宅急便代收 | |
COD_MYSHIP711 | string | 7-ELEVEN賣貨便代收 | |
COD_FAMISTORE | string | 好賣+代收 | |
COD_HISHIPBUYER | string | 萊賣貨代收 | |
COD_KERRYTJ | string | 嘉里大榮代收 | |
CSTORECODE_IBON | string | 超商代碼(IBON) | |
CSTORECODE_FAMIPORT | string | 超商代碼(FamiPort) | |
CSTORECODE_LIFEET | string | 超商代碼(Life-ET) | |
CSTORECODE_OKGO | string | 超商代碼(OK GO) | |
ETICKET_EASYCARD | string | 悠遊卡 | |
ETICKET_IPASS | string | 一卡通 | |
ETICKET_ICASH | string | iCash | |
CRYPTO_BTC | string | 比特幣 | |
CRYPTO_ETH | string | 乙太幣 | |
TELECOM_CHT | string | 中華電信代收 | |
TELECOM_FET | string | 遠傳電信代收 | |
TELECOM_TWM | string | 台灣大哥大代收 | |
TELECOM_TSTAR | string | 台灣之星代收 | |
TELECOM_APT | string | 亞太電信代收 | |
ECPAY_CREDIT | string | 綠界收款(信用卡) | |
ECPAY_WEBATM | string | 綠界收款(網路ATM) | |
ECPAY_ATM | string | 綠界收款(自動櫃員機) | |
ECPAY_CVS | string | 綠界收款(超商代碼) | |
ECPAY_BARCODE | string | 綠界收款(超商條碼) | |
ECPAY_TWQR | string | 綠界收款(行動支付) | |
ECPAY_IN_STORE_PICKUP | string | 綠界收款(超取) | |
NEWEBPAY_CREDIT | string | 藍新收款(信用卡付款) | |
NEWEBPAY_VACC | string | 藍新收款(銀行 ATM 轉帳付款) | |
NEWEBPAY_WEBATM | string | 藍新收款(網路銀行轉帳付款) | |
NEWEBPAY_BARCODE | string | 藍新收款(超商條碼繳費) | |
NEWEBPAY_CVS | string | 藍新收款(超商代碼繳費) | |
NEWEBPAY_LINEPAY | string | 藍新收款(LINE Pay 付款) | |
NEWEBPAY_ESUNWALLET | string | 藍新收款(玉山 Wallet) | |
NEWEBPAY_TAIWANPAY | string | 藍新收款(台灣 Pay) | |
NEWEBPAY_CVSCOM | string | 藍新收款(超商取貨付款) | |
CREDITCARD_TCB | string | 信用卡(合庫銀行) | |
CREDITCARD_ESUNBANK | string | 信用卡(玉山銀行) | |
CREDITCARD_FIRSTBANK | string | 信用卡(第一銀行) | |
CREDITCARD_FUBONBANK | string | 信用卡(台北富邦銀行) | |
CREDITCARD_TSIB | string | 信用卡(台新銀行) | |
CREDITCARD_NCCC | string | 信用卡(聯信) | |
CREDITCARD_CTBC | string | 信用卡(中信銀行) | |
CREDITCARD_KGIBANK | string | 信用卡(凱基銀行) | |
CREDITCARD_YUANTABANK | string | 信用卡(元大銀行) | |
CREDITCARD_CUB | string | 信用卡(國泰世華銀行) | |
CREDITCARD_BANKSINOPAC | string | 信用卡(永豐銀行) | |
CREDITCARD_MEGABANK | string | 信用卡(兆豐銀行) | |
CREDITCARD_GLOBALPAYMENTS | string | 信用卡(環匯亞太) | |
AMEX_TSIB | string | 美國運通(台新銀行) | |
AMEX_CTBC | string | 美國運通(中信銀行) | |
AMEX_NCCC | string | 美國運通(聯信) | |
UNIONPAY_TCB | string | 銀聯卡(合庫銀行) | |
UNIONPAY_ESUNBANK | string | 銀聯卡(玉山銀行) | |
UNIONPAY_NCCC | string | 銀聯卡(聯信) | |
UNIONPAY_TSIB | string | 銀聯卡(台新銀行) | |
UNIONPAY_KGIBANK | string | 銀聯卡(凱基銀行) | |
UNIONPAY_YUANTABANK | string | 銀聯卡(元大銀行) | |
UNIONPAY_BANKSINOPAC | string | 銀聯卡(永豐銀行) | |
UNIONPAY_CUB | string | 銀聯卡(國泰世華銀行) | |
BARCODE_SKBANK | string | 超商繳費條碼(新光銀行) | |
BARCODE_ESUNBANK | string | 超商繳費條碼(玉山銀行) | |
BARCODE_CTBC | string | 超商繳費條碼(中信銀行) | |
TWPAY_BOT | string | 台灣Pay(台灣銀行) | |
TWPAY_LANDBANK | string | 台灣Pay(台灣土地銀行) | |
TWPAY_TCB | string | 台灣Pay(合庫銀行) | |
TWPAY_FIRSTBANK | string | 台灣Pay(第一銀行) | |
TWPAY_HNCB | string | 台灣Pay(華南銀行) | |
TWPAY_CHB | string | 台灣Pay(彰化銀行) | |
TWPAY_SCSB | string | 台灣Pay(上海商銀) | |
TWPAY_CUB | string | 台灣Pay(國泰世華銀行) | |
TWPAY_MEGABANK | string | 台灣Pay(兆豐銀行) | |
TWPAY_BOK | string | 台灣Pay(高雄銀行) | |
TWPAY_TBB | string | 台灣Pay(台灣企銀) | |
TWPAY_KTB | string | 台灣Pay(京城銀行) | |
TWPAY_HWATAIBANK | string | 台灣Pay(華泰銀行) | |
TWPAY_SUNNYBANK | string | 台灣Pay(陽信銀行) | |
TWPAY_KSCC | string | 台灣Pay(基隆二信) | |
TWPAY_TFCCBANK | string | 台灣Pay(淡水一信) | |
TWPAY_HCFCBANK | string | 台灣Pay(新竹一信) | |
TWPAY_TSCA | string | 台灣Pay(台中二信) | |
TWPAY_CH6C | string | 台灣Pay(彰化六信) | |
TWPAY_HL2C | string | 台灣Pay(花蓮二信) | |
TWPAY_ESUNBANK | string | 台灣Pay(玉山銀行) | |
TWPAY_TSIB | string | 台灣Pay(台新銀行) | |
TWPAY_AFISC | string | 台灣Pay(農金資) | |
TWPAY_YUANTABANK | string | 台灣Pay(元大銀行) | |
TWPAY_CTBC | string | 台灣Pay(中信銀行) | |
TWPAY_FAST | string | 台灣Pay(南農中心) | |
TWPAY_SCU | string | 台灣Pay(南資中心) | |
DS_SHINSHIN | string | 欣欣大眾 | |
DS_MINGYAO | string | 明曜百貨 | |
DS_DAYEH | string | 大葉高島屋 | |
DS_CHUNGYO | string | 中友百貨 | |
DS_KSSOGO | string | 廣三SOGO百貨 | |
DS_FOCUSQUARE | string | Focus時尚流行館 | |
DS_NICEPLAZA | string | 耐斯廣場 | |
DS_DREAMMALL | string | 夢時代購物中心 | |
DS_UNIUSTYLE | string | 統一時代百貨 | |
DS_PARKLANES | string | 金典綠園道商場 | |
DS_CITYPLAZA | string | 大都會廣場 | |
DS_LIHPAOMALL | string | 麗寶百貨廣場 | |
DS_EDORAPARK | string | 瀚星百貨 | |
DS_BEYONDPLAZA | string | 比漾廣場 | |
DS_HAYASHI | string | 林百貨 | |
DS_SHINESQUARE | string | 昕境廣場 | |
DS_LANDMARKLIFEPLAZA | string | 置地生活廣場 | |
DS_TONLIN | string | 統領廣場 | |
DS_HONHUI | string | 宏匯廣場 | |
DS_TSRD | string | 南紡購物中心 | |
DS_FEDS_XINYIA13 | string | 遠東百貨-遠百信義 A13 | |
DS_FEDS_BANQIAO | string | 遠東百貨-板橋中山店 | |
DS_FEDS_TAOYUAN | string | 遠東百貨-桃園店 | |
DS_FEDS_ZHUPEI | string | 遠東百貨-竹北店 | |
DS_FEDS_CHIAYI | string | 遠東百貨-嘉義店 | |
DS_FEDS_HUALIEN | string | 遠東百貨-花蓮店 | |
DS_FEDS_MEGACITY_BANQIAO | string | 遠東百貨-MegaCity板橋大遠百 | |
DS_FEDS_HSINCHU | string | 遠東百貨-新竹大遠百 | |
DS_FEDS_TOPCITY_TAICHUNG | string | 遠東百貨-Top City台中大遠百 | |
DS_FEDS_TAINAN_GONGYUAN | string | 遠東百貨-台南大遠百公園店 | |
DS_FEDS_TAINAN_CHENGKUNG | string | 遠東百貨-台南大遠百成功店 | |
DS_FEDS_KAOHSIUNG | string | 遠東百貨-高雄大遠百 | |
DS_SKM_XINYI | string | 新光三越-台北信義新天地 | |
DS_SKM_TAIPEI_STATION | string | 新光三越-台北站前店 | |
DS_SKM_TAIPEI_NANJING_W | string | 新光三越-台北南西店 | |
DS_SKM_TAIPEI_TIANMU | string | 新光三越-台北天母店 | |
DS_SKM_TAOYUAN_STATION | string | 新光三越-桃園站前店 | |
DS_SKM_TAICHUNG_PORT | string | 新光三越-台中中港店 | |
DS_SKM_CHIAYI_CHUIYANG | string | 新光三越-嘉義垂楊店 | |
DS_SKM_TAINAN_ZHONGSHAN | string | 新光三越-台南中山店 | |
DS_SKM_TAINAN_XIMEN | string | 新光三越-台南西門店 | |
DS_SKM_KAOHSIUNG_SANDUO | string | 新光三越-高雄三多店 | |
DS_SKM_KAOHSIUNG_ZUOYING | string | 新光三越-高雄左營店 | |
DS_SKM_PARK | string | 新光三越-SKM Park Outlets 高雄草衙 | |
DS_SOGO_TAIPEI_ZHONGXIAO | string | 遠東SOGO百貨-台北忠孝館 | |
DS_SOGO_TAIPEI_FUXING | string | 遠東SOGO百貨-台北復興館 | |
DS_SOGO_TAIPEI_DUNHUA | string | 遠東SOGO百貨-台北敦化館 | |
DS_SOGO_TIANMU | string | 遠東SOGO百貨-天母店 | |
DS_SOGO_ZHONGLI | string | 遠東SOGO百貨-中壢店 | |
DS_SOGO_HSINCHU | string | 遠東SOGO百貨-新竹店 | |
DS_SOGO_KAOHSIUNG | string | 遠東SOGO百貨-高雄店 | |
DS_PACIFIC_FENGYUAN | string | 太平洋百貨-豐原 | |
DS_PACIFIC_PINGTUNG | string | 太平洋百貨-屏東 | |
DS_PACIFIC_SUNNYPARK | string | 太平洋百貨-Sunny Park日光廣場 | |
DS_PACIFIC_PINGTUNG_GONGYONG | string | 太平洋百貨-屏東驛站商場 | |
DS_PACIFIC_PINGTUNG_GUANGFU | string | 太平洋百貨-屏東轉運站商場 | |
DS_PACIFIC_CHAOZHOU | string | 太平洋百貨-潮州驛站商場 | |
DS_HANSHIN_KAOHSIUNG | string | 漢神百貨 | |
DS_HANSHIN_ARENA | string | 漢神巨蛋購物廣場 | |
DS_BREEZE_CENTER | string | 微風廣場 | |
DS_BREEZE_TAIPEISTATION | string | 微風台北車站 | |
DS_BREEZE_NTUHOSPITAL | string | 微風台大醫院商場 | |
DS_BREEZE_NANJING | string | 微風南京 | |
DS_BREEZE_XINYI | string | 微風信義 | |
DS_BREEZE_SONGGAO | string | 微風松高 | |
DS_BREEZE_NANSHAN | string | 微風南山 | |
DS_BREEZE_TSGHOSPITAL | string | 微風三總商店街 | |
DS_BREEZE_ACADEMIASINICA | string | 微風中央研究院 | |
DS_GM_ZHONGHE | string | GlobalMall-新北中和 | |
DS_GM_BANQIAO | string | GlobalMall-環球板橋車站 | |
DS_GM_A8 | string | GlobalMall-環球桃園A8 | |
DS_GM_A19 | string | GlobalMall-環球桃園A19 | |
DS_GM_A9 | string | GlobalMall-環球林口A9 | |
DS_GM_NANGANG | string | GlobalMall-環球南港車站 | |
DS_GM_XINZUOYING | string | GlobalMall-環球新左營車站 | |
DS_GM_PINGTUNG | string | GlobalMall-環球屏東市 | |
DS_TRK_MALL | string | 大魯閣新時代購物中心 | |
DS_TRK_SQUARE | string | 大魯閣湳雅廣場 | |
DS_TALEE_WUFU | string | 大立大統五福店 | |
DS_TALEE_A | string | 大立百貨A館 | |
DS_TALEE_B | string | 大立百貨B館 | |
DS_MITSUI_OUTLET_TAICHUNGPORT | string | MITSUI OUTLET PARK 台中港 | |
DS_MITSUI_OUTLET_TAINAN | string | MITSUI OUTLET PARK 台南 | |
DS_MITSUI_OUTLET_LINKOU | string | MITSUI OUTLET PARK 林口 | |
DS_MITSUI_LALAPORT_TAICHUNG | string | Mitsui Shopping Park LaLaport 台中 |
附錄一:PFN(支付工具)參數表
資料傳遞可使用編號,也可以使用代碼 。 例如:pfn=27跟pfn=PION,一樣都是使用Pi 拍錢包線上付款支付工具。
編號 | 代碼 | 狀態 | 說明 |
---|---|---|---|
1 | CREDITCARD | 啟用 | 信用卡 |
3 | CSTORECODE | 啟用 | 超商代碼 |
4 | WEBATM | 啟用 | WEBATM |
6 | E_COLLECTION | 啟用 | 虛擬帳號 (ATM轉帳) |
7 | UNIONPAY | 啟用 | 銀聯卡 |
9 | ABROAD | 啟用 | 海外信用卡(非台灣發行信用卡) |
10 | ALIPAY | 啟用 | 支付寶 |
13 | 啟用 | 微信支付 | |
14 | DIRECTDEBIT | 啟用 | 定期扣款 |
15 | LINEPAYON | 啟用 | LINE線上付款(消費者主掃) |
16 | LINEPAYOFF | 啟用 | LINE線下付款(消費者被掃) |
19 | WECHATOFF | 啟用 | 微信支付線下 |
20 | APPLEPAY | 啟用 | Apple Pay |
21 | GOOGLEPAY | 啟用 | Google Pay |
22 | EACH | 啟用 | eACH |
23 | C_INSTALLMENT | 啟用 | 信用卡分期 |
24 | C_REDEEM | 啟用 | 信用卡紅利 |
25 | CARDLESS | 啟用 | 無卡分期(由資融公司提供分期服務) |
27 | PION | 啟用 | Pi 拍錢包線上付款(消費者主掃) |
28 | PIOFF | 啟用 | Pi 拍錢包線下付款(消費者被掃) |
29 | AMEX | 啟用 | 美國運通 |
31 | JKOON | 啟用 | 街口支付線上付款(消費者主掃) |
32 | JKOOF | 啟用 | 街口支付線下付款(消費者被掃) |
33 | ALIPAYOFF | 啟用 | 支付寶線下(消費者被掃) |
36 | AFP | 啟用 | 後付款 |
37 | CASH | 啟用 | 現金 |
38 | EASYWALLETON | 啟用 | 悠遊付線上付款(消費者主掃) |
39 | EASYWALLETOFF | 啟用 | 悠遊付線下付款(消費者被掃) |
40 | EASYCARD | 啟用 | 悠遊卡 |
41 | IPASS | 啟用 | 一卡通 |
42 | ICASH | 啟用 | iCash |
43 | BARCODE | 啟用 | 超商條碼繳費 |
46 | PXPAYOFF | 啟用 | 全支付線下(消費者被掃) |
附錄二:交易狀態代碼
以下回傳的狀態代碼均須處理,避免系統連線錯誤,MYPAY LINK回傳時,貴司系統無法判讀
狀態代碼 | 狀態說明 | 詳細說明 |
---|---|---|
100 | 資料錯誤 | MYPAYLINK收到資料,但是格式或資料錯誤 |
200 | 資料正確 | MYPAYLINK收到正確資料,會接續下一步交易 |
220 | 取消成功 | 如申請取消,取消訂單狀態為取消成功 |
230 | 退款成功 | 如申請退款,申請退款成功時狀態。 |
245 | 授權成功 | 若使用信用卡類自行請款模式,則交易後為授權成功。之後進行請款動作,才會轉為付款成功(250) |
247 | 請款進行中 | 若使用信用卡類自行請款模式,閘道為玉山或NCCC(聯信、凱基、元大)等批次處理,發動請款時轉為此狀態,等候金融服務商通知請款成功,才會轉為付款成功(250) |
250 | 付款成功 | 此次交易,消費者付款成功 |
260 | 交易成功 尚未付款完成 |
超商代碼繳費-請等候消費者繳費入帳完成付款或消費者放棄交易,MYPAY LINK會再傳送一次結果: 250:代表消費者付款成功,此為最終結果 380:代表消費者沒有在時限內去繳費,逾期未去繳費,視同交易失敗,此為最終結果 |
265 | 訂單綁定 | 表示訂單編號生效,進入貸款頁面,但尚未註冊 最後會在回傳狀態 A0002:消費者放棄該筆交易,該筆交易視同交易失敗,為最終結果 275:無卡分期-請等候審查通過 |
270 | 交易成功 尚未付款完成 |
虛擬帳號-請等候消費者繳費入帳 完成付款或消費者放棄交易,MYPAY LINK會再傳送一次結果: 250:代表消費者付款成功,此為最終結果 380:代表消費者沒有在時限內去繳費,逾期未去繳費,視同交易失敗,此為最終結果 |
280 | 交易成功 尚未付款完成 |
儲值/WEBATM-線上待付款,等待狀態,等到使用者線上完成交易後MYPAY LINK會再傳送一次結果 250:代表消費者付款成功,此為最終結果 300:代表消費者付款失敗 |
282 | 訂單成立待後付款審核確認 尚未付款完成 |
後付款,等待狀態,等後付款審核通過通知 284:代表後付款審核通過 300:代表審核不通過 |
284 | 訂單成立後付款待請款 尚未付款完成 |
後付款,等待狀態,等特約商店出貨後,需發動請款告知後付款已出貨請款 250:代表後付款請款成功,此為最終結果 300:代表後付款請款失敗 |
290 | 交易成功 但資訊不符 |
交易成功,但資訊不符(包含金額不符,如多繳或少繳...等),該類型交易請特別注意 |
300 | 交易失敗 | 金流服務商回傳交易失敗或該筆交易超過風險控管限制規則 |
380 | 逾期交易 | 超商代碼或虛擬帳號交易,超過系統設定繳費期限 若經MYPAY LINK查詢驗證後,有機會在變更狀態 290:交易成功,但資訊不符 原因有可能是服務商的參數規則漏洞或是系統時間差異造成 |
400 | 系統錯誤訊息 | 若MYPAY LINK或上游服務商系統異常時 |
600 | 結帳完成 | 視為付款完成,此狀態為上游服務商確認訂單後的狀態,表示該筆訂單會撥款 透過MYPAY主動查詢或每日對帳機制 操作訂單功能內發動查詢功能 |
A0001 | 交易待確認 | MYPAY LINK與金流服務商發生連線異常,待查詢後確認結果,會主動再次回傳交易結果 250:代表消費者確實付款完成 600:結帳完成 300:金流服務商回傳交易失敗或超過風險控管限制規則交易 |
A0002 | 放棄交易 | 畫面導向MYPAY LINK後,消費者即放棄該筆交易,該筆交易視同交易失敗,為最終結果 |
B200 | 執行成功 | 處理成功執行 |
B500 | 執行失敗 | 處理時,資料異常不予以處理 |
附錄三:設定調整
- 交易回傳設定,通知網址的部分,僅限80跟443 port
- 交易金鑰重新發送與變更
附錄四:資料加密方式說明
- 所有的API送出HTTPs請求之欄位中,service 和 encry_data 欄位皆進行 AES256+BASE64 加密處理。
- AES加密,格式為CBC,長度為256bits,金鑰長度32,IV長度16,傳遞內文為加密後組合IV並經過Base64轉換後傳出。
- IV資料建議隨機產生。
PHP加密示意:
AesEncrypt -> base64_ecode($IV . $JSON)
C#加密示意:
AesEncrypt -> (bytes)IV+(bytes)Json -> toBase64
Java加密示意:
AesEncrypt -> (bytes)IV+(bytes)Json -> toBase64
Node.js加密示意:
AesEncrypt -> concat([IV,JSON], [IV_SIZE,JSON_SIZE]) -> toString('base64')
Python加密示意:
AesEncrypt -> (bytes)IV+(bytes)Json -> base64.b64encode
附錄五:API模擬串接服務
提供模擬使用HTTP Protocol,透過POST方式傳遞資料到MYPAY, 並且得到回傳結果。
- 虛擬帳號交易
- 超商代碼交易
- WebATM交易
- 後付款交易
- 後付款請款
- 後付款更正出貨
- 後付款查詢出貨
- 電票交易
- 電票查詢卡號
- 電票查詢餘額
- 電票退款
- eACH 交易
- 超商條碼繳費
- 全支付線下交易
- LINE Pay線下交易
- Pi線下交易
- 微信線下交易
- 街口線下交易
- Apple pay線下交易
- Google pay線下交易
- 悠遊付線下交易
- 支付寶線下交易
- 訂單查詢
- 查詢特約商店可用支付方式
附錄六:測試區測試用信用卡卡號
下面卡號僅限在測試區測試使用
聯合信用卡中心閘道(其中MasterCard/JCB可測分期與紅利)
Visa | MasterCard | JCB | |
---|---|---|---|
卡號 | 4938170130000003 | 5430450100001219 | 3560500100001218 |
有效日期 | 1228 | 1218 | 1218 |
安全碼 | 985 | 214 | 023 |
3D交易密碼 | nccc1234 |
永豐銀行信用卡
Visa | MasterCard | JCB | |
---|---|---|---|
卡號 | 4058650600065507 | 5433760200078009 | 3566703300032801 |
有效日期 | 1022 | 1022 | 0922 |
安全碼 | 395 | 597 | 033 |
中國信託信用卡 (使用電子錢包功能適用)
Visa | |
---|---|
一般交易 | 4003618704777729 |
有效日期 | 任意 |
安全碼 | 任意 |
3D交易密碼 | 1234567 |
高鉅模擬信用卡(成功卡)
Visa | MasterCard | JCB | |
---|---|---|---|
一般交易 | 4761120010000492 | 5204247750001471 | 3566703300032801 |
有效日期 | 1122 | 1122 | 0922 |
安全碼 | 533 | 111 | 033 |
高鉅模擬信用卡(失敗卡)
MasterCard | |
---|---|
一般交易 | 5204247750001471 |
有效日期 | 1122 |
安全碼 | 111 |
高鉅模擬信用卡(3D)
說明 | 卡號 |
---|---|
3D交易 | 4003618704777729 |
有效日期 | 任意 |
安全碼 | 任意 |
凱基 (醫療費/捐款費用) 信用卡
Visa | |
---|---|
一般交易 | 4907060600015101 |
有效日期 | 1226 |
安全碼 | 905 |
備註:(醫療費/捐款費用)信用卡所使用之訂單編號「order_id」(繳費單號)長度最長為16bytes。(此為上游限制)
附錄七:測試區測試用線下交易支付碼
下面支付碼僅限在測試區測試使用
1.街口支付線下
說明 | 支付碼 |
---|---|
二維條碼 | 22J111111111111111 |
2.全支付線下
說明 | 支付碼 |
---|---|
二維條碼 | P1M281A4C00B2JOO1N |
3.LINEPay線下
說明 | 支付碼產生連結 |
---|---|
二維條碼 | https://sandbox-web-pay.line.me/web/sandbox/payment/oneTimeKey?countryCode=TW&paymentMethod=card&point=20 |
上述支付方式為通用測試支付碼,其餘須依向服務商帳號申請之相關Sandbox模式進行測試。
附錄八:交易背景通知回報欄位
『交易完成回傳資訊』回報欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | Payment Hub之交易流水號 | |
key | string | 交易驗証碼 | |
prc | string | 主要交易回傳碼(retcode) | |
finishtime | string | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string | 銀行端口回傳碼 | |
acode | string | 授權碼 | |
card_type | string | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string | 發卡行 | |
issuing_bank_uid | string | 發卡銀行代碼 | |
is_agent_charge | int | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string | 交易之金融服務商 | |
supplier_code | string | 交易之金融服務商代碼 | 『金流供應商代碼』值參考 |
order_id | string | 貴特店系統的訂單編號 | |
user_id | string | 消費者帳號 | |
cost | string | 總交易金額 | |
currency | string | 原交易幣別 | |
actual_cost | string | 實際交易金額 | |
actual_currency | string | 實際交易幣別 | |
price | string | 請求交易點數/金額 | |
actual_price | string | 實際交易點數/金額 | |
recharge_code | string | 交易產品代碼 | |
love_cost | string | 愛心捐款金額 | |
retmsg | string | 回傳訊息 | |
pfn | string | 付費方法 | |
trans_type | integer | 交易類型 | 『交易類型定義』值參考 |
redeem | string | 紅利資訊 JSON 格式 | 『紅利資訊』值參考 |
installment | string | 信用卡分期資訊 JSON 格式 | 『分期資訊』值參考 |
payment_name | string | 定期定額式/定期分期式扣款名稱 | |
nois | string | 定期定額式/定期分期式扣繳期數 | |
group_id | string | 1.定期定額式扣款編號 2.定期分期式扣款編號 |
|
bank_id | string | 銀行代碼 虛擬帳號資訊 |
|
expired_date | string | 有效日期(YYYYMMDDHHmmss) 虛擬帳號、超商代碼、無卡分期資訊 |
|
result_type | integer | 虛擬帳號、超商代碼 資料格式類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string | 資料內容所屬支付名稱 | 『資料內容所屬支付名稱』值參考 |
result_content | string | 虛擬帳號、超商代碼 資料內容 | 『虛擬帳號回傳欄位』值參考 『ibon』值參考 『FamiPort』值參考 『Life-ET』值參考 『超商條碼繳費』值參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『非即時交易回傳資訊』回報欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | Payment Hub之交易流水號 | |
key | string | 交易驗証碼 | |
prc | string | 主要交易回傳碼(retcode) | |
cardno | string | 銀行端口回傳碼 | |
acode | string | 授權碼 | |
card_type | string | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string | 發卡行 | |
issuing_bank_uid | string | 發卡銀行代碼 | |
is_agent_charge | int | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string | 交易之金融服務商 | |
supplier_code | string | 交易之金融服務商代碼 | 『金流供應商代碼』值參考 |
finishtime | string | 交易完成時間(YYYYMMDDHHmmss) | |
order_id | string | 貴特店系統的訂單編號 | |
user_id | string | 消費者帳號 | |
cost | string | 總交易金額 | |
currency | string | 原交易幣別 | |
actual_cost | string | 實際交易金額 | |
actual_currency | string | 實際交易幣別 | |
price | string | 請求交易點數/金額 | |
actual_price | string | 實際交易點數/金額 | |
recharge_code | string | 交易產品代碼 | |
love_cost | string | 愛心捐款金額 | |
retmsg | string | 回傳訊息 | |
pfn | string | 付費方法 | |
trans_type | integer | 交易類型 | 『交易類型定義』值參考 |
redeem | string | 紅利資訊 JSON 格式 | 『紅利資訊』值參考 |
installment | string | 信用卡分期資訊 JSON 格式 | 『分期資訊』值參考 |
payment_name | string | 定期定額式/定期分期式扣款名稱 | |
nois | string | 定期定額式/定期分期式扣繳期數 | |
group_id | string | 1.定期定額式扣款編號 2.定期分期式扣款編號 |
|
bank_id | string | 銀行代碼 虛擬帳號資訊 |
|
expired_date | string | 有效日期(YYYYMMDDHHmmss) 虛擬帳號、超商代碼、無卡分期資訊 |
|
result_type | integer | 虛擬帳號、超商代碼 資料格式類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string | 資料內容所屬支付名稱 | 『資料內容所屬支付名稱』值參考 |
result_content | string | 虛擬帳號、超商代碼 資料內容 | 『虛擬帳號回傳欄位』值參考 『ibon』值參考 『FamiPort』值參考 『Life-ET』值參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『訂單確認回傳資訊』回報欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | Payment Hub之交易流水號 | |
key | string | 交易驗証碼 | |
prc | string | 主要交易回傳碼(retcode) | |
finishtime | string | 交易完成時間(YYYYMMDDHHmmss) | |
cardno | string | 銀行端口回傳碼 | |
acode | string | 授權碼 | |
card_type | string | 信用卡卡別 | 『信用卡別類型』值參考 |
issuing_bank | string | 發卡行 | |
issuing_bank_uid | string | 發卡銀行代碼 | |
is_agent_charge | int | 是否為經銷商代收費模式 | 『是否為經銷商代收費模式』值參考 |
transaction_mode | integer | 交易服務類型 | 『交易服務類型』值參考 |
supplier_name | string | 交易之金融服務商 | |
supplier_code | string | 交易之金融服務商代碼 | 『金流供應商代碼』值參考 |
order_id | string | 貴特店系統的訂單編號 | |
user_id | string | 消費者帳號 | |
cost | string | 總交易金額 | |
currency | string | 原交易幣別 | |
actual_cost | string | 實際交易金額 | |
actual_currency | string | 實際交易幣別 | |
price | string | 請求交易點數/金額 | |
actual_price | string | 實際交易點數/金額 | |
recharge_code | string | 交易產品代碼 | |
love_cost | string | 愛心捐款金額 | |
retmsg | string | 回傳訊息 | |
pfn | string | 付費方法 | |
trans_type | integer | 交易類型 | 『交易類型定義』值參考 |
redeem | string | 紅利資訊 JSON 格式 | 『紅利資訊』值參考 |
installment | string | 信用卡分期資訊 JSON 格式 | 『分期資訊』值參考 |
payment_name | string | 定期定額式/定期分期式扣款名稱 | |
nois | string | 定期定額式/定期分期式扣繳期數 | |
group_id | string | 1.定期定額式扣款編號 2.定期分期式扣款編號 |
|
bank_id | string | 銀行代碼 虛擬帳號資訊 |
|
expired_date | string | 有效日期(YYYYMMDDHHmmss) 虛擬帳號、超商代碼、無卡分期資訊 |
|
result_type | integer | 虛擬帳號、超商代碼 資料格式類型 | 『閘道內容回傳格式類型』值參考 |
result_content_type | string | 資料內容所屬支付名稱 | 『資料內容所屬支付名稱』值參考 |
result_content | string | 虛擬帳號、超商代碼 資料內容 | 『虛擬帳號回傳欄位』值參考 『ibon』值參考 『FamiPort』值參考 『Life-ET』值參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |