修改歷程
版本 | 異動日期 | 修訂內容 | 位置 |
---|---|---|---|
1.0 | 2021.01.01 | 新版文件 | |
1.0.1 | 2023.04.07 | 新增開發前請先閱讀 | 20230407_01 |
1.0.2 | 2023.07.18 | 新增退券回傳通知資料 | 20230718_01 |
1.0.3 | 2024.04.18 | 新增票券售出、作廢、狀態查詢等功能 | 20240418_01 |
1.0.4 | 2024.05.30 | 新增票券發票資訊回報等功能 | 20240530_01 |
開發前請先閱讀
金鑰的注意事項
Q:金鑰的有效期限
A:MyPay的金鑰有效期限只有一年,如果要延長,請自行至金鑰管理系統延長
Q:金鑰可以在什麼時候延長
A:到期日7天前,都可以延長(不包含第7天),一但超過,系統自動產生新金鑰後,即不可再延長
Q:金鑰即將到期前7天時,系統新發的金鑰是否會於信件中夾帶
A:會
Q:金鑰在到期前何時會發信通知
A:定期發送金鑰到期通知的頻率為:60天/30天/20天,若 貴司皆無動作,則系統會於到期前七天產製新金鑰並發送email到 貴司技術窗口信箱,此時舊的金鑰,因還未過期還可以使用,一旦過期,貴司仍使用舊金鑰則會無法交易
交易結果的告知
Q:交易完成的導頁會有交易結果的參數嗎
A:不論是參數中的success_returl 或 failure_returl或是後臺設定的交易成功、失敗導頁網址,均不會給予交易結果參數
Q:何時會給予交易結果
A:MyPay將在接收上游結果後,會由附錄三這邊的設定,背景主動發動通知商家
Q:當我接到MyPay通知時該做什麼
A:請直接回應8888,如沒有回應,MyPay會通知5次,若5次內均得不到8888,系統會寄發信件給予商家的技術人員以及附錄三而外設定的人員
票券交易設計概要
安全性設計
所有的要求發動都僅能從特約商店的網頁伺服器發出請求,將傳輸的資料以AES加密,再透過HTTPS加密傳輸。交易資料不由消費者端送出,可確保資料不被消費者竄改。所有付費資訊經過MYPAY Link匝道進行轉送處理,特約商店不需要處理消費者的付費流程以及安全控管。
MYTIX 目前提供之服務與格式
MYTIX 票券交易應用情境如下:
(1)購買票券交易:提供消費者購買票券頁面。
(2)購買票券交易查詢:查詢購買票券交易資訊。
(3)票券核銷線下交易:透過掃碼消費者提供之Qrcode,由Pos發動票券核銷交易。
(4)票券核銷線下交易查詢:查詢票券核銷線下交易的交易結果。
(5)票券核銷交易取消:30分鐘內,所核銷之票券,可取消票券核銷。
(6)票券核銷交易取消查詢:查詢票券核銷交易取消紀錄。
(7)票券售出:提供實體票券售出回報。
(8)票券售出交易查詢:查詢票券售出交易資訊。
(9)票券售出交易取消:30分鐘內,所售出之票券,可取消票券售出。
(10)票券售出交易取消查詢:查詢票券售出交易取消紀錄。
(11)票券作廢:提供實體票券作廢回報。
(12)票券作廢交易查詢:查詢票券作廢交易資訊。
(13)票券狀態查詢:查詢票券目前狀態。
(14)票券發票資訊回報:若有開立/作廢/折讓發票,可以回報關聯售出交易訂單或核銷交易訂單。
(15)票券發票資訊回報查詢:查詢票券發票資訊回報。
(16)票券核銷線下交易Qrcode掃碼頁面:取得消費者使用票券消費頁面,當消費者選擇後,顯示Qrcode提供給商家掃碼。
(17)票券消費者退券頁面(消費者主動):取得消費者票券退券頁面,可讓消費者自行退劵,當天選擇退劵的票劵,統一於隔日11點後統一退款。
(18)票券轉贈(消費者主動):取得消費者轉贈頁面,轉贈給會員與非會員。被贈與者可提出Qrcode提供給商家掃碼。
(19)票券匣:提供消費者在票券匣內一次使用Qrcode掃碼、退券、轉贈。
(20)建立或修改發行商票券:由API發動建立或修改發行商票券之設定內容。
(21)查詢發行商票券:依指定條件查詢發行商票券之設定內容。
我們提供介接方式是透過https連線,只接受POST方式傳送交易資料。
介接網址
特約商店模式
位置 | API介接網址 |
---|---|
測試區 | https://ka.usecase.cc/api/agent |
正式區 | https://ka.mypay.tw/api/agent |
Client模式(限定功能)
位置 | API介接網址 |
---|---|
測試區 | https://ka.usecase.cc/api/open |
正式區 | https://ka.mypay.tw/api/open |
資料加密方式
AES 256編碼 + base64編碼(附錄四資料加密方式)
加密金鑰
金鑰會透過mail發送,也可從管理後台取得
文字編碼
一律使用UTF-8相容編碼
購買票券交易
<?php
/**
* 經銷商串接-購買票券交易
*/
final class AgentVoucher
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['sales_store_uid'] = "289151880142";
$rawData['user_data'] = [
'user_id' => 'phper',
'user_name' => '金城武',
'user_real_name' => '金城武',
'ip' => '127.0.0.1'
];
$rawData['order_id'] = "VS20221208105148";
$rawData['pfn'] = "0";
$rawData['cost'] = 100;
$rawData['currency'] = "TWD";
$rawData['items'] = [
[
'issuance_uid' => '289151881006',
'service_id' => 'A01',
'id' => 'MANOR001',
'platform_fee' => 1,
'platform_uid' => '289151881007',
'sharing' =>
[
'headquarters' => '0.15',
'sales' => '0.1',
'reimbursement' => '0.75'
],
'service_rule' =>
[
'price' => 50,
'cost' => 50,
'amount' => 2,
'total_price' => 100,
'total_cost' => 100,
'trust_start_date' => '20221208',
'trust_end_date' => '20231207',
'validity_end_date' => '99991231',
'is_custom_serial' => 1,
'serial_numbers' => '["HA11670467908","HA21670467908"]',
'service_type' => 1
]
],
[
'issuance_uid' => '289151881006',
'service_id' => 'A01',
'id' => 'MANOR004',
'platform_fee' => 1,
'platform_uid' => '289151881007',
'sharing' =>
[
'headquarters' => '0.15',
'sales' => '0.1',
'reimbursement' => '0.75'
],
'service_rule' =>
[
'price' => 50,
'cost' => 0,
'amount' => 2,
'total_price' => 100,
'total_cost' => 0,
'trust_start_date' => '20221208',
'trust_end_date' => '20231207',
'validity_end_date' => '99991231',
'is_custom_serial' => 1,
'serial_numbers' => '["HB11670467908","HB21670467908"]',
'service_type' => 1
]
]
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherservicepurchase'
);
}
/**
* 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;
}
}
$AgentVoucher = new AgentVoucher();
$AgentVoucher->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 AgentVoucher {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucher simulator = new AgentVoucher();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic userData = new ExpandoObject();
userData.user_id = "phper";
userData.user_name = "金城武";
userData.user_real_name = "金城武";
userData.ip = "127.0.0.1";
ArrayList items = new ArrayList();
dynamic item1 = new ExpandoObject();
item1.issuance_uid = "289151881006";
item1.service_id = "A01";
item1.id = "MANOR001";
item1.platform_fee = 1;
item1.platform_uid = "289151881007";
dynamic sharing1 = new ExpandoObject();
sharing1.headquarters = "0.15";
sharing1.sales = "0.1";
sharing1.reimbursement = "0.75";
item1.sharing = sharing1;
dynamic serviceRule1 = new ExpandoObject();
serviceRule1.price = 50;
serviceRule1.cost = 50;
serviceRule1.amount = 2;
serviceRule1.total_price = 100;
serviceRule1.total_cost = 100;
serviceRule1.trust_start_date = "20221208";
serviceRule1.trust_end_date = "20231207";
serviceRule1.validity_end_date = "99991231";
serviceRule1.is_custom_serial = 1;
serviceRule1.serial_numbers = "[\"HA11670467908\",\"HA21670467908\"]";
serviceRule1.service_type = 1;
item1.service_rule = serviceRule1;
items.Add(item1);
dynamic item2 = new ExpandoObject();
item2.issuance_uid = "289151881006";
item2.service_id = "A01";
item2.id = "MANOR004";
item2.platform_fee = 1;
item2.platform_uid = "289151881007";
dynamic sharing2 = new ExpandoObject();
sharing2.headquarters = "0.15";
sharing2.sales = "0.1";
sharing2.reimbursement = "0.75";
item2.sharing = sharing2;
dynamic serviceRule2 = new ExpandoObject();
serviceRule2.price = 50;
serviceRule2.cost = 0;
serviceRule2.amount = 2;
serviceRule2.total_price = 100;
serviceRule2.total_cost = 0;
serviceRule2.trust_start_date = "20221208";
serviceRule2.trust_end_date = "20231207";
serviceRule2.validity_end_date = "99991231";
serviceRule2.is_custom_serial = 1;
serviceRule2.serial_numbers = "[\"HB11670467908\",\"HB21670467908\"]";
serviceRule2.service_type = 1;
item2.service_rule = serviceRule2;
items.Add(item2);
dynamic rawData = new ExpandoObject();
rawData.sales_store_uid = "289151880142";
rawData.user_data = userData;
rawData.order_id = "VS20221208105148";
rawData.pfn = "0";
rawData.cost = 100;
rawData.currency = "TWD";
rawData.items = items;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherservicepurchase";
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 AgentVoucher {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucher simulator = new AgentVoucher();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> userData = new HashMap<Object, Object>();
userData.put("user_id", "phper");
userData.put("user_name", "金城武");
userData.put("user_real_name", "金城武");
userData.put("ip", "127.0.0.1");
ArrayList items = new ArrayList();
Map<Object, Object> item1 = new HashMap<Object, Object>();
item1.put("issuance_uid", "289151881006");
item1.put("service_id", "A01");
item1.put("id", "MANOR001");
item1.put("platform_fee", 1);
item1.put("platform_uid", "289151881007");
Map<Object, Object> sharing1 = new HashMap<Object, Object>();
sharing1.put("headquarters", "0.15");
sharing1.put("sales", "0.1");
sharing1.put("reimbursement", "0.75");
item1.put("sharing", sharing1);
Map<Object, Object> serviceRule1 = new HashMap<Object, Object>();
serviceRule1.put("price", 50);
serviceRule1.put("cost", 50);
serviceRule1.put("amount", 2);
serviceRule1.put("total_price", 100);
serviceRule1.put("total_cost", 100);
serviceRule1.put("trust_start_date", "20221208");
serviceRule1.put("trust_end_date", "20231207");
serviceRule1.put("validity_end_date", "99991231");
serviceRule1.put("is_custom_serial", 1);
serviceRule1.put("serial_numbers", "[\"HA11670467908\",\"HA21670467908\"]");
serviceRule1.put("service_type", 1);
item1.put("service_rule", serviceRule1);
items.add(item1);
Map<Object, Object> item2 = new HashMap<Object, Object>();
item2.put("issuance_uid", "289151881006");
item2.put("service_id", "A01");
item2.put("id", "MANOR004");
item2.put("platform_fee", 1);
item2.put("platform_uid", "289151881007");
Map<Object, Object> sharing2 = new HashMap<Object, Object>();
sharing2.put("headquarters", "0.15");
sharing2.put("sales", "0.1");
sharing2.put("reimbursement", "0.75");
item2.put("sharing", sharing2);
Map<Object, Object> serviceRule2 = new HashMap<Object, Object>();
serviceRule2.put("price", 50);
serviceRule2.put("cost", 0);
serviceRule2.put("amount", 2);
serviceRule2.put("total_price", 100);
serviceRule2.put("total_cost", 0);
serviceRule2.put("trust_start_date", "20221208");
serviceRule2.put("trust_end_date", "20231207");
serviceRule2.put("validity_end_date", "99991231");
serviceRule2.put("is_custom_serial", 1);
serviceRule2.put("serial_numbers", "[\"HB11670467908\",\"HB21670467908\"]");
serviceRule2.put("service_type", 1);
item2.put("service_rule", serviceRule2);
items.add(item2);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("sales_store_uid", "289151880142");
rawData.put("user_data", userData);
rawData.put("order_id", "VS20221208105148");
rawData.put("pfn", "0");
rawData.put("cost", 100);
rawData.put("currency", "TWD");
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/voucherservicepurchase");
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 AgentVoucher() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucher.prototype.getRawData = function () {
return {
sales_store_uid: "289151880142",
user_data: {
'user_id': "phper",
'user_name': "金城武",
'user_real_name': "金城武",
'ip': "127.0.0.1"
},
order_id: "VS20221208105148",
pfn: "0",
cost: 100,
currency: "TWD",
items: [
{
'issuance_uid': "289151881006",
'service_id': "A01",
'id': "MANOR001",
'platform_fee': 1,
'platform_uid': "289151881007",
'sharing':
{
'headquarters': "0.15",
'sales': "0.1",
'reimbursement': "0.75"
},
'service_rule':
{
'price': 50,
'cost': 50,
'amount': 2,
'total_price': 100,
'total_cost': 100,
'trust_start_date': "20221208",
'trust_end_date': "20231207",
'validity_end_date': "99991231",
'is_custom_serial': 1,
'serial_numbers': "[\"HA11670467908\",\"HA21670467908\"]",
'service_type': 1
}
},
{
'issuance_uid': "289151881006",
'service_id': "A01",
'id': "MANOR004",
'platform_fee': 1,
'platform_uid': "289151881007",
'sharing':
{
'headquarters': "0.15",
'sales': "0.1",
'reimbursement': "0.75"
},
'service_rule':
{
'price': 50,
'cost': 0,
'amount': 2,
'total_price': 100,
'total_cost': 0,
'trust_start_date': "20221208",
'trust_end_date': "20231207",
'validity_end_date': "99991231",
'is_custom_serial': 1,
'serial_numbers': "[\"HB11670467908\",\"HB21670467908\"]",
'service_type': 1
}
}
],
};
};
/**
* 取得服務位置
*/
AgentVoucher.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherservicepurchase"
};
};
/**
* AES 256 加密
*/
AgentVoucher.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 到主機
*/
AgentVoucher.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucher.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucher.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucher = new AgentVoucher();
AgentVoucher.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 AgentVoucher:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'sales_store_uid': "289151880142",
'user_data': {
'user_id': "phper",
'user_name': "金城武",
'user_real_name': "金城武",
'ip': "127.0.0.1"
},
'order_id': "VS20221208105148",
'pfn': "0",
'cost': 100,
'currency': "TWD",
'items': [
{
'issuance_uid': "289151881006",
'service_id': "A01",
'id': "MANOR001",
'platform_fee': 1,
'platform_uid': "289151881007",
'sharing':
{
'headquarters': "0.15",
'sales': "0.1",
'reimbursement': "0.75"
},
'service_rule':
{
'price': 50,
'cost': 50,
'amount': 2,
'total_price': 100,
'total_cost': 100,
'trust_start_date': "20221208",
'trust_end_date': "20231207",
'validity_end_date': "99991231",
'is_custom_serial': 1,
'serial_numbers': "[\"HA11670467908\",\"HA21670467908\"]",
'service_type': 1
}
},
{
'issuance_uid': "289151881006",
'service_id': "A01",
'id': "MANOR004",
'platform_fee': 1,
'platform_uid': "289151881007",
'sharing':
{
'headquarters': "0.15",
'sales': "0.1",
'reimbursement': "0.75"
},
'service_rule':
{
'price': 50,
'cost': 0,
'amount': 2,
'total_price': 100,
'total_cost': 0,
'trust_start_date': "20221208",
'trust_end_date': "20231207",
'validity_end_date': "99991231",
'is_custom_serial': 1,
'serial_numbers': "[\"HB11670467908\",\"HB21670467908\"]",
'service_type': 1
}
}
],
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherservicepurchase'
}
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)
AgentVoucher = AgentVoucher()
AgentVoucher.run()
回傳 JSON 結構如下:
{
"code": "200",
"msg": "資料正確",
"uid": "100052",
"key": "0b1c6abdfea31cac31bda6a414dafd4f",
"url": "https:\/\/ka.usecase.cc\/voucher\/100052.html"
}
提供消費者購買票券頁面
在使用範例程式碼測試時,請注意以下參數要替換
order_id
trust_start_date,必須大等於今天
trust_end_date,必須大於今天且大於trust_start_date
serial_numbers
user_id,如要測試不同消費者時,必須更換,如不更換將視同一個
經銷商『購買票券交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/voucherservicepurchase"} JSON格式,AES256加密資料 |
encry_data | text | 『購買票券交易』欄位參考 JSON格式,AES256加密資料 |
『購買票券交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
sales_store_uid | string | 銷售點特約商店代碼 | 必填 |
order_id | string | 購買票券交易票券交易編號(唯一) | 必填 |
pfn | string | 指定購買票券時,指定支付方式(不指定請帶0) | 必填 |
user_data | object | 消費者資訊 | 必填 『消費者資訊』欄位參考 |
is_pre_issue | integer | 是否為預發行 | 『是否為預發行』值參考 |
cost | string | 總金額(此訂單應付的總金額) | 必填 |
currency | string | 預設交易幣別(預設為TWD新台幣) | |
items | array | 物品資訊 | 必填 每筆『票券項目』欄位參考 |
theme | string | 指定佈景主題名稱 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 | |
success_returl | string | 購買交易成功導頁網址 | |
failure_returl | string | 購買交易失敗導頁網址 |
『購買票券交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
uid | string | 購買票券交易UID | |
key | string | 交易驗証碼 | |
url | string | 交易網址(網址一分鐘內失效,只能使用一次) |
『購買票券交易回傳資訊』回報欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 購買票券交易UID | |
key | string | 交易驗証碼 | |
code | string | 目前狀態碼 | 『購買票券交易狀態碼』值參考 |
msg | string | 回傳訊息 | |
finishtime | string | 交易完成時間(YYYYMMDDHHmmss) | |
order_id | string | 購買票券交易票券交易編號 | |
user_id | string | 消費者帳號 | |
cost | string | 原交易金額 | |
currency | string | 原交易幣別 | |
actual_cost | string | 實際交易金額 | |
actual_currency | string | 實際交易幣別 | |
pfn | string | 付費方法 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券電子發票資訊』回報欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 購買票券交易訂單UID | |
key | string | 交易驗証碼 | |
order_id | string | 購買票券交易票券交易編號 | |
cost | float | 交易金額 | |
currency | string | 交易幣別 | |
actual_cost | float | 實際交易金額 | |
actual_currency | string | 實際交易幣別 | |
state | integer | 發票開立狀態 0.不處理 1等候處理中,2發票處理成功 3.發票處理失敗 5.系統服務異常 |
『票券電子發票開立狀態類型』值參考 |
date | string | 發票開立日期(YYYYMMDD) | |
wordtrack | string | 發票字軌 | |
number | string | 發票號碼 | |
rand_code | string | 隨機碼 | |
seller_ban | string | 賣方統編 | |
buyer_ban | string | 買方統編 | |
left_qrcode | string | 左邊QrCode(電子發票查詢碼) | |
middle_barcode | string | 中間Barcode (Code-39格式) | |
right_qrcode | string | 右邊QrCode(電子發票產品資訊-精簡版) | |
amount | string | 電子發票開立總額 | |
sales_amount | float | 電子發票銷售額 | |
tax_amount | float | 電子發票稅額 | |
order_detail | string | 電子發票開立之產品詳細資訊(JSON格式) | 『商品細項』值參考 |
ratetype | integer | 電子發票稅率別 | 『電子發票稅率別』值參考 |
input_type | integer | 電子發票開立類型 | 『電子發票開立類型』值參考 |
cloud_type | integer | 電子發票開立類型-雲端發票類型 | 『雲端發票類型』值參考 |
mobile_code | string | 當cloud_type為2時紀錄的手機條碼 | |
tax_id | string | 當cloud_type為2時紀錄的統一編號 | |
natural_person | string | 當cloud_type為3時紀錄的自然人憑證條碼 | |
m_post_zone | string | 當cloud_type為4時紀錄中獎時紙本發票郵遞區號 | |
m_address | string | 當cloud_type為4時紀錄中獎時紙本發票收件住址 | |
love_code | string | 當input_type為2時紀錄的愛心碼 | |
b2b_title | string | 當input_type為3時紀錄的發票抬頭 | |
b2b_id | string | 當input_type為3時紀錄的統一編號 | |
b2b_post_zone | string | 當input_type為3時紀錄的郵遞區號 | |
b2b_address | string | 當input_type為3時紀錄的發票地址 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
購買票券交易查詢
<?php
/**
* 經銷商串接-購買票券交易查詢
*/
final class AgentVoucherQuery
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VS20221011112610";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherservicequery'
);
}
/**
* 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;
}
}
$AgentVoucherQuery = new AgentVoucherQuery();
$AgentVoucherQuery->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 AgentVoucherQuery {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherQuery simulator = new AgentVoucherQuery();
//僅限走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.order_id = "VS20221011112610";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherservicequery";
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 AgentVoucherQuery {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherQuery simulator = new AgentVoucherQuery();
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("order_id", "VS20221011112610");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/voucherservicequery");
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 AgentVoucherQuery() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherQuery.prototype.getRawData = function () {
return {
order_id: "VS20221011112610",
};
};
/**
* 取得服務位置
*/
AgentVoucherQuery.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherservicequery"
};
};
/**
* AES 256 加密
*/
AgentVoucherQuery.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 到主機
*/
AgentVoucherQuery.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherQuery.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherQuery.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherQuery = new AgentVoucherQuery();
AgentVoucherQuery.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 AgentVoucherQuery:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VS20221011112610",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherservicequery'
}
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)
AgentVoucherQuery = AgentVoucherQuery()
AgentVoucherQuery.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"uid": 100051,
"key": "3fd356d92fc78a05189248536e8c89c5",
"code": "250",
"msg": "付款完成",
"finishtime": "20220422135946",
"order_id": "VS20220422135855",
"user_id": "phper",
"cost": 100,
"currency": "TWD",
"actual_cost": 100,
"actual_currency": "TWD",
"pfn": "CREDITCARD",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
}
消費者購買數位票券時,透過信用卡等多種支付方式作線上直接購買票券。
經銷商『購買票券交易查詢』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/voucherservicequery"} JSON格式,AES256加密資料 |
encry_data | text | 『購買票券交易查詢』欄位參考 JSON格式,AES256加密資料 |
『購買票券交易查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 購買票券交易票券交易編號 | 必填 |
『購買票券交易查詢』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 購買交易狀態碼 | |
msg | string | 回傳訊息 | |
content | object | 『購買票券交易查詢回傳』欄位參考 |
票券核銷線下交易
<?php
/**
* 經銷商串接-票券核銷線下交易
*/
final class AgentVoucherOffline
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['reimbursement_store_uid'] = "289151880142";
$rawData['order_id'] = "VO20221208105157";
$rawData['pay_token'] = "MYTIX12345678ABCDEFGH";
$rawData['pos_trade_time'] = "20221208105157";
$rawData['pos_id'] = "HC00001A2B";
$rawData['clerk_no'] = "A01";
$rawData['echo_0'] = "noodles-98";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucheroffline'
);
}
/**
* 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;
}
}
$AgentVoucherOffline = new AgentVoucherOffline();
$AgentVoucherOffline->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 AgentVoucherOffline {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherOffline simulator = new AgentVoucherOffline();
//僅限走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.reimbursement_store_uid = "289151880142";
rawData.order_id = "VO20221208105157";
rawData.pay_token = "MYTIX12345678ABCDEFGH";
rawData.pos_trade_time = "20221208105157";
rawData.pos_id = "HC00001A2B";
rawData.clerk_no = "A01";
rawData.echo_0 = "noodles-98";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucheroffline";
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 AgentVoucherQuery {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherQuery simulator = new AgentVoucherQuery();
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("order_id", "VS20221011112610");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/voucherservicequery");
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 AgentVoucherOffline() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherOffline.prototype.getRawData = function () {
return {
reimbursement_store_uid: "289151880142",
order_id: "VO20221208105157",
pay_token: "MYTIX12345678ABCDEFGH",
pos_trade_time: "20221208105157",
pos_id: "HC00001A2B",
clerk_no: "A01",
echo_0: "noodles-98",
};
};
/**
* 取得服務位置
*/
AgentVoucherOffline.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucheroffline"
};
};
/**
* AES 256 加密
*/
AgentVoucherOffline.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 到主機
*/
AgentVoucherOffline.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherOffline.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherOffline.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherOffline = new AgentVoucherOffline();
AgentVoucherOffline.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 AgentVoucherOffline:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'reimbursement_store_uid': "289151880142",
'order_id': "VO20221208105157",
'pay_token': "MYTIX12345678ABCDEFGH",
'pos_trade_time': "20221208105157",
'pos_id': "HC00001A2B",
'clerk_no': "A01",
'echo_0': "noodles-98",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucheroffline'
}
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)
AgentVoucherOffline = AgentVoucherOffline()
AgentVoucherOffline.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"uid": "100022",
"key": "9c2e173dda5318ee2c32d88e95b401ed",
"order_id": "VO20220422170139",
"code": "250",
"msg": "核銷成功。",
"finishtime": "20220422170147",
"pay_token": "MYTIX1E5A41322AFBD5C0",
"pos_trade_time": "20220422170139",
"pos_id": "HC00001A2B",
"clerk_no": "A01",
"items": [
{
"issuance_uid": "289151881006",
"id": "MANOR004",
"material_code": "",
"name": "莊園拿鐵咖啡(贈)",
"products": [
{
"amount": 1,
"cost": 0,
"price": 50,
"total_cost": 0,
"total_price": 50
}
],
"vouchers": [
{
"serial_no": "AZO-GLHKTCV6-D44O6L4K-7ZMLRHL59",
"cost": 0,
"price": 50
}
]
}
],
"echo_0": "noodles-98",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
}
數位票券:消費者挑選商品產生Qrcode,POS透過掃碼取得核銷交易碼,發動票券核銷線下交易。 實體票券:消費者提供實體票券,POS透過掃碼取得票券號碼,發動票券核銷線下交易。(票券狀態需為4.售出)
經銷商『票券核銷線下交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/voucheroffline"} JSON格式,AES256加密資料 |
encry_data | text | 『票券核銷線下交易』欄位參考 JSON格式,AES256加密資料 |
『票券核銷線下交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
reimbursement_from_type | int | 核銷點類型 | 『票券核銷點類型』值參考 |
reimbursement_store_uid | string | 核銷特約商店商務代號 | reimbursement_from_type =1為必填 |
reimbursement_dealer_no | string | 自訂核銷點編號 | reimbursement_from_type=2為必填 |
issuance_uid | string | 委託發行商商務代號 | 使用實體券時必填 |
pay_token | string | 核銷交易碼 格式1:MYTIX12345678ABCDEFGH共21碼(通常為數位券) 格式2:"[\"WU00000001\",\"WU00000001\"]" (JSON 格式 通常為實體券或實體數位混合,混合時,若有數位券只使用限定一組(一個消費者被掃)) |
必填 |
order_id | string | 票券核銷線下交易票券處理編號(唯一) | 必填 |
pos_trade_time | string | POS 端交易日期時間(格式為YYYYMMDDHHmmss) | |
pos_id | string | POS 機號或設備機號 | |
clerk_no | string | 收銀員代碼 | |
success_returl | string | 核銷成功導頁網址 | |
failure_returl | string | 核銷失敗導頁網址 | |
reimbursement_order_id | string | 核銷店家訂單單號 | |
issue_invoice_state | int | 票券核銷發票開立類型 | 『票券核銷發票開立類型』值參考 |
invoice | object | 當發票開立類型為1自行開立時,需帶入相關資訊 | 『票券核銷交易發票資訊』欄位參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券核銷線下交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 『票券核銷線下交易資訊回傳』欄位參考 |
票券核銷線下交易查詢
<?php
/**
* 經銷商串接-票券核銷線下交易查詢
*/
final class AgentVoucherOfflineQuery
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VO20221004115857";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherofflinequery'
);
}
/**
* 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;
}
}
$AgentVoucherOfflineQuery = new AgentVoucherOfflineQuery();
$AgentVoucherOfflineQuery->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 AgentVoucherOfflineQuery {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherOfflineQuery simulator = new AgentVoucherOfflineQuery();
//僅限走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.order_id = "VO20221004115857";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherofflinequery";
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 AgentVoucherOfflineQuery {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherOfflineQuery simulator = new AgentVoucherOfflineQuery();
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("order_id", "VO20221004115857");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/voucherofflinequery");
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 AgentVoucherOfflineQuery() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherOfflineQuery.prototype.getRawData = function () {
return {
order_id: "VO20221004115857",
};
};
/**
* 取得服務位置
*/
AgentVoucherOfflineQuery.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherofflinequery"
};
};
/**
* AES 256 加密
*/
AgentVoucherOfflineQuery.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 到主機
*/
AgentVoucherOfflineQuery.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherOfflineQuery.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherOfflineQuery.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherOfflineQuery = new AgentVoucherOfflineQuery();
AgentVoucherOfflineQuery.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 AgentVoucherOfflineQuery:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VO20221004115857",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherofflinequery'
}
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)
AgentVoucherOfflineQuery = AgentVoucherOfflineQuery()
AgentVoucherOfflineQuery.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"uid": "100022",
"key": "9c2e173dda5318ee2c32d88e95b401ed",
"order_id": "VO20220422170139",
"code": "250",
"msg": "核銷成功。",
"finishtime": "20220422170147",
"pay_token": "MYTIX1E5A41322AFBD5C0",
"pos_trade_time": "20220422170139",
"pos_id": "HC00001A2B",
"clerk_no": "A01",
"items": [
{
"issuance_uid": "289151881006",
"id": "MANOR004",
"name": "莊園拿鐵咖啡(贈)",
"products": [
{
"amount": 1,
"cost": 0,
"price": 50,
"total_cost": 0,
"total_price": 50
}
],
"vouchers": [
{
"serial_no": "AZO-GLHKTCV6-D44O6L4K-7ZMLRHL59",
"cost": 0,
"price": 50
}
]
}
],
"echo_0": "noodles-98",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
}
查詢票券核銷線下交易的交易結果。
經銷商『票券核銷線下交易查詢』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/voucherofflinequery"} JSON格式,AES256加密資料 |
encry_data | text | 『票券核銷線下交易查詢』欄位參考 JSON格式,AES256加密資料 |
『票券核銷線下交易查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券核銷線下交易票券處理編號 | 必填 |
『票券核銷線下交易查詢』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 查詢內容 | 『票券核銷線下交易資訊回傳』欄位參考 |
票券核銷交易取消
<?php
/**
* 經銷商串接-票券核銷交易取消
*/
final class AgentVoucherReverse
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VR20221208105201";
$rawData['items'] = [
[
'issuance_uid' => '289151881006',
'id' => 'H01',
'serial_no' => 'A00052'
],
[
'issuance_uid' => '289151881006',
'id' => 'H01',
'serial_no' => 'A00053'
]
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherreverse'
);
}
/**
* 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;
}
}
$AgentVoucherReverse = new AgentVoucherReverse();
$AgentVoucherReverse->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 AgentVoucherReverse {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherReverse simulator = new AgentVoucherReverse();
//僅限走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.issuance_uid = "289151881006";
item1.id = "H01";
item1.serial_no = "A00052";
items.Add(item1);
dynamic item2 = new ExpandoObject();
item2.issuance_uid = "289151881006";
item2.id = "H01";
item2.serial_no = "A00053";
items.Add(item2);
dynamic rawData = new ExpandoObject();
rawData.order_id = "VR20221208105201";
rawData.items = items;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherreverse";
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 AgentVoucherReverse {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherReverse simulator = new AgentVoucherReverse();
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("issuance_uid", "289151881006");
item1.put("id", "H01");
item1.put("serial_no", "A00052");
items.add(item1);
Map<Object, Object> item2 = new HashMap<Object, Object>();
item2.put("issuance_uid", "289151881006");
item2.put("id", "H01");
item2.put("serial_no", "A00053");
items.add(item2);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("order_id", "VR20221208105201");
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/voucherreverse");
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 AgentVoucherReverse() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherReverse.prototype.getRawData = function () {
return {
order_id: "VR20221208105201",
items: [
{
'issuance_uid': "289151881006",
'id': "H01",
'serial_no': "A00052"
},
{
'issuance_uid': "289151881006",
'id': "H01",
'serial_no': "A00053"
}
],
};
};
/**
* 取得服務位置
*/
AgentVoucherReverse.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherreverse"
};
};
/**
* AES 256 加密
*/
AgentVoucherReverse.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 到主機
*/
AgentVoucherReverse.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherReverse.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherReverse.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherReverse = new AgentVoucherReverse();
AgentVoucherReverse.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 AgentVoucherReverse:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VR20221208105201",
'items': [
{
'issuance_uid': "289151881006",
'id': "H01",
'serial_no': "A00052"
},
{
'issuance_uid': "289151881006",
'id': "H01",
'serial_no': "A00053"
}
],
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherreverse'
}
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)
AgentVoucherReverse = AgentVoucherReverse()
AgentVoucherReverse.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功。",
"content": {
"uid": "100017",
"key": "569f18f82f7d82e473860124ea532888",
"order_id": "VR20220422151024",
"reverse_date": "20220429142230",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"items": [
{
"issuance_uid": "289151881006",
"id": "MANOR004",
"serial_no": "AZO-GLHKTCV6-D44O6L4K-EMIMRPLYZ",
"code": "250",
"msg": "取消核銷成功"
}
]
}
}
30分鐘內,所核銷之票券,可取消票券核銷。
經銷商『票券核銷交易取消』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/voucherreverse"} JSON格式,AES256加密資料 |
encry_data | text | 『票券核銷交易取消』欄位參考 JSON格式,AES256加密資料 |
『票券核銷交易取消』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券核銷取消票券處理編號(唯一) | 必填 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 | |
items | array | 取消票券核銷資料 | 必填 每筆『票券取消項目』欄位參考 |
『票券核銷交易取消』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 查詢內容 | 『票券核銷交易取消查詢』欄位參考 |
票券核銷交易取消查詢
<?php
/**
* 經銷商串接-票券核銷交易取消查詢
*/
final class AgentVoucherReverseQuery
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VR20221031093012";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherreversequery'
);
}
/**
* 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;
}
}
$AgentVoucherReverseQuery = new AgentVoucherReverseQuery();
$AgentVoucherReverseQuery->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 AgentVoucherReverseQuery {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherReverseQuery simulator = new AgentVoucherReverseQuery();
//僅限走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.order_id = "VR20221031093012";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherreversequery";
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 AgentVoucherReverseQuery {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherReverseQuery simulator = new AgentVoucherReverseQuery();
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("order_id", "VR20221031093012");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/voucherreversequery");
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 AgentVoucherReverseQuery() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherReverseQuery.prototype.getRawData = function () {
return {
order_id: "VR20221031093012",
};
};
/**
* 取得服務位置
*/
AgentVoucherReverseQuery.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherreversequery"
};
};
/**
* AES 256 加密
*/
AgentVoucherReverseQuery.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 到主機
*/
AgentVoucherReverseQuery.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherReverseQuery.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherReverseQuery.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherReverseQuery = new AgentVoucherReverseQuery();
AgentVoucherReverseQuery.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 AgentVoucherReverseQuery:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VR20221031093012",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherreversequery'
}
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)
AgentVoucherReverseQuery = AgentVoucherReverseQuery()
AgentVoucherReverseQuery.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"uid": "100017",
"key": "569f18f82f7d82e473860124ea532888",
"order_id": "VR20220422151024",
"reverse_date": "20220429142230",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"items": [
{
"issuance_uid": "289151881006",
"id": "MANOR004",
"serial_no": "AZO-GLHKTCV6-D44O6L4K-EMIMRPLYZ",
"code": "250",
"msg": "取消核銷成功"
}
]
}
}
查詢票券核銷交易取消紀錄。
經銷商『票券核銷線下交易查詢』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/voucherreversequery"} JSON格式,AES256加密資料 |
encry_data | text | 『票券核銷線下交易查詢』欄位參考 JSON格式,AES256加密資料 |
『票券核銷交易取消查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券核銷取消票券處理編號 | 必填 |
『票券核銷交易取消查詢』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 查詢內容 | 『票券核銷交易取消查詢』欄位參考 |
票券售出
<?php
/**
* 經銷商串接-票券售出
*/
final class AgentVoucherSold
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881006";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
/**
* 串接交易位置
* @var string
*/
public $url = "http://ka.k20-mypay.tw/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VS20240508140309";
$rawData['sales_from_type'] = 2;
$rawData['sales_dealer_no'] = "A0001";
$rawData['sales_order_id'] = "T20240508140309";
$rawData['trust_start_date'] = "20240508";
$rawData['trust_end_date'] = "20260507";
$rawData['issue_invoice_state'] = 1;
$rawData['invoice'] = [
'number' => 'AB12345678',
'date' => '20240508140309'
];
$rawData['items'] = [
[
'issuance_uid' => '289151881006',
'no' => '2051088012',
'cost' => 50,
'trust_start_date' => '20240508',
'trust_end_date' => '20260507',
'trust_guarantee_date' => '20250507'
],
[
'issuance_uid' => '289151881006',
'no' => '2051088020',
'cost' => 50,
'trust_start_date' => '20240508',
'trust_end_date' => '20260507',
'trust_guarantee_date' => '20250507'
]
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/vouchersold'
);
}
/**
* 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;
}
}
$AgentVoucherSold = new AgentVoucherSold();
$AgentVoucherSold->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 AgentVoucherSold {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881006";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "http://ka.k20-mypay.tw/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherSold simulator = new AgentVoucherSold();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic invoice = new ExpandoObject();
invoice.number = "AB12345678";
invoice.date = "20240508140309";
ArrayList items = new ArrayList();
dynamic item1 = new ExpandoObject();
item1.issuance_uid = "289151881006";
item1.no = "2051088012";
item1.cost = 50;
item1.trust_start_date = "20240508";
item1.trust_end_date = "20260507";
item1.trust_guarantee_date = "20250507";
items.Add(item1);
dynamic item2 = new ExpandoObject();
item2.issuance_uid = "289151881006";
item2.no = "2051088020";
item2.cost = 50;
item2.trust_start_date = "20240508";
item2.trust_end_date = "20260507";
item2.trust_guarantee_date = "20250507";
items.Add(item2);
dynamic rawData = new ExpandoObject();
rawData.order_id = "VS20240508140309";
rawData.sales_from_type = 2;
rawData.sales_dealer_no = "A0001";
rawData.sales_order_id = "T20240508140309";
rawData.trust_start_date = "20240508";
rawData.trust_end_date = "20260507";
rawData.issue_invoice_state = 1;
rawData.invoice = invoice;
rawData.items = items;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/vouchersold";
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 AgentVoucherSold {
/**
* 經銷商商務代號
*/
String agentUid = "289151881006";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
/**
* 串接交易位置
*/
String url = "http://ka.k20-mypay.tw/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherSold simulator = new AgentVoucherSold();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> invoice = new HashMap<Object, Object>();
invoice.put("number", "AB12345678");
invoice.put("date", "20240508140309");
ArrayList items = new ArrayList();
Map<Object, Object> item1 = new HashMap<Object, Object>();
item1.put("issuance_uid", "289151881006");
item1.put("no", "2051088012");
item1.put("cost", 50);
item1.put("trust_start_date", "20240508");
item1.put("trust_end_date", "20260507");
item1.put("trust_guarantee_date", "20250507");
items.add(item1);
Map<Object, Object> item2 = new HashMap<Object, Object>();
item2.put("issuance_uid", "289151881006");
item2.put("no", "2051088020");
item2.put("cost", 50);
item2.put("trust_start_date", "20240508");
item2.put("trust_end_date", "20260507");
item2.put("trust_guarantee_date", "20250507");
items.add(item2);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("order_id", "VS20240508140309");
rawData.put("sales_from_type", 2);
rawData.put("sales_dealer_no", "A0001");
rawData.put("sales_order_id", "T20240508140309");
rawData.put("trust_start_date", "20240508");
rawData.put("trust_end_date", "20260507");
rawData.put("issue_invoice_state", 1);
rawData.put("invoice", invoice);
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/vouchersold");
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 AgentVoucherSold() {
// 經銷商商務代號
this.agentUid = "289151881006";
// 經銷商金鑰或認證碼
this.agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
// 串接交易位置
this.url = "http://ka.k20-mypay.tw/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherSold.prototype.getRawData = function () {
return {
order_id: "VS20240508140309",
sales_from_type: 2,
sales_dealer_no: "A0001",
sales_order_id: "T20240508140309",
trust_start_date: "20240508",
trust_end_date: "20260507",
issue_invoice_state: 1,
invoice: {
'number': "AB12345678",
'date': "20240508140309"
},
items: [
{
'issuance_uid': "289151881006",
'no': "2051088012",
'cost': 50,
'trust_start_date': "20240508",
'trust_end_date': "20260507",
'trust_guarantee_date': "20250507"
},
{
'issuance_uid': "289151881006",
'no': "2051088020",
'cost': 50,
'trust_start_date': "20240508",
'trust_end_date': "20260507",
'trust_guarantee_date': "20250507"
}
],
};
};
/**
* 取得服務位置
*/
AgentVoucherSold.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/vouchersold"
};
};
/**
* AES 256 加密
*/
AgentVoucherSold.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 到主機
*/
AgentVoucherSold.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherSold.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherSold.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherSold = new AgentVoucherSold();
AgentVoucherSold.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 AgentVoucherSold:
# 經銷商商務代號
agentUid = "289151881006";
# 經銷商金鑰或認證碼
agentKey = b"UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
# 串接交易位置
url = "http://ka.k20-mypay.tw/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VS20240508140309",
'sales_from_type': 2,
'sales_dealer_no': "A0001",
'sales_order_id': "T20240508140309",
'trust_start_date': "20240508",
'trust_end_date': "20260507",
'issue_invoice_state': 1,
'invoice': {
'number': "AB12345678",
'date': "20240508140309"
},
'items': [
{
'issuance_uid': "289151881006",
'no': "2051088012",
'cost': 50,
'trust_start_date': "20240508",
'trust_end_date': "20260507",
'trust_guarantee_date': "20250507"
},
{
'issuance_uid': "289151881006",
'no': "2051088020",
'cost': 50,
'trust_start_date': "20240508",
'trust_end_date': "20260507",
'trust_guarantee_date': "20250507"
}
],
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/vouchersold'
}
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)
AgentVoucherSold = AgentVoucherSold()
AgentVoucherSold.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"uid": "100076",
"key": "948c3aa0e08665a06836926a0d635954",
"order_id": "VS20240419144323",
"sales_date": "20240419144346",
"items": [
{
"issuance_uid": "289151881006",
"unit_type": 1,
"no": "2051088152",
"ticket": {
"custom_serial_no": "2051088152",
"serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-1NQUYYBQC",
"cost": 50,
"price": 50,
"trust_start_date": "20240419",
"trust_end_date": "20260418",
"trust_guarantee_date": "20250418"
},
"book": []
}
],
"sales_order_id": "T20240419144323",
"issue_invoice_state": 1,
"invoice": {
"number": "AB12345678",
"date": "20240419144323"
},
"sales_from_type": 2,
"sales_store_uid": "",
"sales_dealer_no": "A0001",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
}
經銷商『票券售出』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/vouchersold"} JSON格式,AES256加密資料 |
encry_data | text | 『票券售出』欄位參考 JSON格式,AES256加密資料 |
『票券售出』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券售出票券處理編號(唯一) | 必填 |
sales_from_type | int | 銷售點類型 | 必填 『票券銷售點類型』值參考 |
sales_store_uid | string | 銷售特約商店商務代號 | sales_from_type=1為必填 |
sales_dealer_no | string | 自訂銷售點編號 | sales_from_type=2為必填 |
api_mode | int | 票券掃碼方式 | 『票券售出票券掃碼方式』值參考 |
items | array | 票券銷售資料 | 必填 每筆『票券售出項目』欄位參考 |
sales_order_id | string | 銷售店家訂單單號 | |
issue_invoice_state | int | 票券售出發票開立類型 | 『票券售出發票開立類型』值參考 |
invoice | object | 當發票開立類型為1自行開立時,需帶入相關資訊 | 『票券售出交易發票資訊』欄位參考 |
buyer_name | string | 買家名稱 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券售出』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 票券售出交易內容 | 『票券售出交易內容』欄位參考 |
票券售出交易查詢
<?php
/**
* 經銷商串接-票券售出交易查詢
*/
final class AgentVoucherSoldQuery
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VS20221031093012";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/vouchersoldquery'
);
}
/**
* 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;
}
}
$AgentVoucherSoldQuery = new AgentVoucherSoldQuery();
$AgentVoucherSoldQuery->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 AgentVoucherSoldQuery {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherSoldQuery simulator = new AgentVoucherSoldQuery();
//僅限走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.order_id = "VS20221031093012";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/vouchersoldquery";
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 AgentVoucherSoldQuery {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherSoldQuery simulator = new AgentVoucherSoldQuery();
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("order_id", "VS20221031093012");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/vouchersoldquery");
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 AgentVoucherSoldQuery() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherSoldQuery.prototype.getRawData = function () {
return {
order_id: "VS20221031093012",
};
};
/**
* 取得服務位置
*/
AgentVoucherSoldQuery.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/vouchersoldquery"
};
};
/**
* AES 256 加密
*/
AgentVoucherSoldQuery.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 到主機
*/
AgentVoucherSoldQuery.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherSoldQuery.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherSoldQuery.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherSoldQuery = new AgentVoucherSoldQuery();
AgentVoucherSoldQuery.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 AgentVoucherSoldQuery:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VS20221031093012",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/vouchersoldquery'
}
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)
AgentVoucherSoldQuery = AgentVoucherSoldQuery()
AgentVoucherSoldQuery.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"code": "B200",
"msg": "執行成功",
"uid": "100076",
"key": "948c3aa0e08665a06836926a0d635954",
"order_id": "VS20240419144323",
"sales_date": "20240419144346",
"items": [
{
"issuance_uid": "289151881006",
"unit_type": 1,
"no": "2051088152",
"ticket": {
"custom_serial_no": "2051088152",
"serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-1NQUYYBQC"
},
"book": []
}
],
"sales_order_id": "T20240419144323",
"issue_invoice_state": 1,
"invoice": {
"number": "AB12345678",
"date": "20240419144323"
},
"trust_start_date": "20240419",
"trust_end_date": "20260418",
"sales_from_type": 2,
"sales_store_uid": "",
"sales_dealer_no": "A0001",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
}
提供票券售出交易之訂單查詢。
經銷商『票券售出交易查詢』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/vouchersoldquery"} JSON格式,AES256加密資料 |
encry_data | text | 『票券售出交易查詢』欄位參考 JSON格式,AES256加密資料 |
『票券售出交易查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券售出票券處理編號 | 必填 |
『票券售出交易查詢』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 查詢內容 | 『票券售出交易內容』欄位參考 |
票券售出交易取消
<?php
/**
* 經銷商串接-票券售出交易取消
*/
final class AgentVoucherSoldReverse
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VSR20240418165205";
$rawData['items'] = [
[
'issuance_uid' => '289151881006',
'no' => '2051088039'
],
[
'issuance_uid' => '289151881006',
'no' => '2051088047'
]
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/vouchersoldreverse'
);
}
/**
* 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;
}
}
$AgentVoucherSoldReverse = new AgentVoucherSoldReverse();
$AgentVoucherSoldReverse->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 AgentVoucherSoldReverse {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherSoldReverse simulator = new AgentVoucherSoldReverse();
//僅限走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.issuance_uid = "289151881006";
item1.no = "2051088039";
items.Add(item1);
dynamic item2 = new ExpandoObject();
item2.issuance_uid = "289151881006";
item2.no = "2051088047";
items.Add(item2);
dynamic rawData = new ExpandoObject();
rawData.order_id = "VSR20240418165205";
rawData.items = items;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/vouchersoldreverse";
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 AgentVoucherSoldReverse {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherSoldReverse simulator = new AgentVoucherSoldReverse();
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("issuance_uid", "289151881006");
item1.put("no", "2051088039");
items.add(item1);
Map<Object, Object> item2 = new HashMap<Object, Object>();
item2.put("issuance_uid", "289151881006");
item2.put("no", "2051088047");
items.add(item2);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("order_id", "VSR20240418165205");
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/vouchersoldreverse");
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 AgentVoucherSoldReverse() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherSoldReverse.prototype.getRawData = function () {
return {
order_id: "VSR20240418165205",
items: [
{
'issuance_uid': "289151881006",
'no': "2051088039"
},
{
'issuance_uid': "289151881006",
'no': "2051088047"
}
],
};
};
/**
* 取得服務位置
*/
AgentVoucherSoldReverse.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/vouchersoldreverse"
};
};
/**
* AES 256 加密
*/
AgentVoucherSoldReverse.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 到主機
*/
AgentVoucherSoldReverse.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherSoldReverse.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherSoldReverse.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherSoldReverse = new AgentVoucherSoldReverse();
AgentVoucherSoldReverse.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 AgentVoucherSoldReverse:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VSR20240418165205",
'items': [
{
'issuance_uid': "289151881006",
'no': "2051088039"
},
{
'issuance_uid': "289151881006",
'no': "2051088047"
}
],
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/vouchersoldreverse'
}
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)
AgentVoucherSoldReverse = AgentVoucherSoldReverse()
AgentVoucherSoldReverse.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"uid": "100026",
"key": "fc195aea975ad710bc01b9b5b8234c42",
"order_id": "VSR20240419145148",
"reverse_date": "20240419145203",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"items": [
{
"issuance_uid": "289151881006",
"unit_type": 1,
"no": "2051088152",
"ticket": {
"custom_serial_no": "2051088152",
"serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-1NQUYYBQC",
"book_no": "",
"sales_date": "20240419144346",
"status": 4
},
"book": [],
"code": "250",
"msg": "取消售出成功"
}
]
}
}
30分鐘內,所售出之票券,可取消票券售出(所取消之票券必須為同一筆售出訂單之票券)。
經銷商『票券售出交易取消』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/vouchersoldreverse"} JSON格式,AES256加密資料 |
encry_data | text | 『票券售出交易取消』欄位參考 JSON格式,AES256加密資料 |
『票券售出交易取消』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券售出取消票券處理編號(唯一) | 必填 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 | |
api_mode | int | 票券掃碼方式 | 『票券售出票券掃碼方式』值參考 |
items | array | 取消票券售出資料 | 必填 每筆『票券售出取消項目』欄位參考 |
『票券售出交易取消』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 查詢內容 | 『票券售出交易取消查詢』欄位參考 |
票券售出交易取消查詢
<?php
/**
* 經銷商串接-票券售出交易取消查詢
*/
final class AgentVoucherSoldReverseQuery
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VSR20221031093012";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/vouchersoldreversequery'
);
}
/**
* 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;
}
}
$AgentVoucherSoldReverseQuery = new AgentVoucherSoldReverseQuery();
$AgentVoucherSoldReverseQuery->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 AgentVoucherSoldReverseQuery {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherSoldReverseQuery simulator = new AgentVoucherSoldReverseQuery();
//僅限走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.order_id = "VSR20221031093012";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/vouchersoldreversequery";
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 AgentVoucherSoldReverseQuery {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherSoldReverseQuery simulator = new AgentVoucherSoldReverseQuery();
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("order_id", "VSR20221031093012");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/vouchersoldreversequery");
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 AgentVoucherSoldReverseQuery() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherSoldReverseQuery.prototype.getRawData = function () {
return {
order_id: "VSR20221031093012",
};
};
/**
* 取得服務位置
*/
AgentVoucherSoldReverseQuery.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/vouchersoldreversequery"
};
};
/**
* AES 256 加密
*/
AgentVoucherSoldReverseQuery.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 到主機
*/
AgentVoucherSoldReverseQuery.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherSoldReverseQuery.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherSoldReverseQuery.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherSoldReverseQuery = new AgentVoucherSoldReverseQuery();
AgentVoucherSoldReverseQuery.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 AgentVoucherSoldReverseQuery:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VSR20221031093012",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/vouchersoldreversequery'
}
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)
AgentVoucherSoldReverseQuery = AgentVoucherSoldReverseQuery()
AgentVoucherSoldReverseQuery.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"uid": "100026",
"key": "fc195aea975ad710bc01b9b5b8234c42",
"order_id": "VSR20240419145148",
"reverse_date": "20240419145203",
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": "",
"items": [
{
"issuance_uid": "289151881006",
"unit_type": 1,
"no": "2051088152",
"ticket": {
"custom_serial_no": "2051088152",
"serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-1NQUYYBQC",
"book_no": "",
"sales_date": "20240419144346",
"status": 4
},
"book": [],
"code": "250",
"msg": "取消售出成功"
}
]
}
}
提供票券售出交易取消之訂單查詢。
經銷商『票券售出交易取消查詢』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/vouchersoldreversequery"} JSON格式,AES256加密資料 |
encry_data | text | 『票券售出交易取消查詢』欄位參考 JSON格式,AES256加密資料 |
『票券售出交易取消查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券售出取消票券處理編號 | 必填 |
『票券售出交易取消查詢』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 查詢內容 | 『票券售出交易取消查詢』欄位參考 |
票券作廢
<?php
/**
* 經銷商串接-票券作廢
*/
final class AgentVoucherInvalid
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VI20240418165206";
$rawData['invalid_from_type'] = 2;
$rawData['invalid_dealer_no'] = "A0001";
$rawData['items'] = [
[
'issuance_uid' => '289151881006',
'no' => '2051088055'
],
[
'issuance_uid' => '289151881006',
'no' => '2051088063'
]
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherinvalid'
);
}
/**
* 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;
}
}
$AgentVoucherInvalid = new AgentVoucherInvalid();
$AgentVoucherInvalid->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 AgentVoucherInvalid {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherInvalid simulator = new AgentVoucherInvalid();
//僅限走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.issuance_uid = "289151881006";
item1.no = "2051088055";
items.Add(item1);
dynamic item2 = new ExpandoObject();
item2.issuance_uid = "289151881006";
item2.no = "2051088063";
items.Add(item2);
dynamic rawData = new ExpandoObject();
rawData.order_id = "VI20240418165206";
rawData.invalid_from_type = 2;
rawData.invalid_dealer_no = "A0001";
rawData.items = items;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherinvalid";
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 AgentVoucherInvalid {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherInvalid simulator = new AgentVoucherInvalid();
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("issuance_uid", "289151881006");
item1.put("no", "2051088055");
items.add(item1);
Map<Object, Object> item2 = new HashMap<Object, Object>();
item2.put("issuance_uid", "289151881006");
item2.put("no", "2051088063");
items.add(item2);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("order_id", "VI20240418165206");
rawData.put("invalid_from_type", 2);
rawData.put("invalid_dealer_no", "A0001");
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/voucherinvalid");
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 AgentVoucherInvalid() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherInvalid.prototype.getRawData = function () {
return {
order_id: "VI20240418165206",
invalid_from_type: 2,
invalid_dealer_no: "A0001",
items: [
{
'issuance_uid': "289151881006",
'no': "2051088055"
},
{
'issuance_uid': "289151881006",
'no': "2051088063"
}
],
};
};
/**
* 取得服務位置
*/
AgentVoucherInvalid.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherinvalid"
};
};
/**
* AES 256 加密
*/
AgentVoucherInvalid.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 到主機
*/
AgentVoucherInvalid.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherInvalid.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherInvalid.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherInvalid = new AgentVoucherInvalid();
AgentVoucherInvalid.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 AgentVoucherInvalid:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VI20240418165206",
'invalid_from_type': 2,
'invalid_dealer_no': "A0001",
'items': [
{
'issuance_uid': "289151881006",
'no': "2051088055"
},
{
'issuance_uid': "289151881006",
'no': "2051088063"
}
],
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherinvalid'
}
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)
AgentVoucherInvalid = AgentVoucherInvalid()
AgentVoucherInvalid.run()
回傳 JSON 結構如下:
提供票券回報作廢註記。(票券狀態1.建立 4.售出才可回報作廢)
經銷商『票券作廢』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/voucherinvalid"} JSON格式,AES256加密資料 |
encry_data | text | 『票券作廢』欄位參考 JSON格式,AES256加密資料 |
『票券作廢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券作廢票券處理編號(唯一) | 必填 |
invalid_from_type | int | 作廢點類型 | 必填 『票券作廢點類型』值參考 |
invalid_store_uid | string | 作廢特約商店商務代號 | invalid_from_type=1為必填 |
invalid_dealer_no | string | 自訂作廢點編號 | invalid_from_type=2為必填 |
items | array | 票券作廢資料 | 必填 每筆『票券作廢項目』欄位參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券作廢』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 票券作廢交易內容 | 『票券作廢交易內容』欄位參考 |
票券作廢交易查詢
<?php
/**
* 經銷商串接-票券作廢交易查詢
*/
final class AgentVoucherInvalidQuery
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VI20221031093012";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherinvalidquery'
);
}
/**
* 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;
}
}
$AgentVoucherInvalidQuery = new AgentVoucherInvalidQuery();
$AgentVoucherInvalidQuery->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 AgentVoucherInvalidQuery {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherInvalidQuery simulator = new AgentVoucherInvalidQuery();
//僅限走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.order_id = "VI20221031093012";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherinvalidquery";
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 AgentVoucherInvalidQuery {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherInvalidQuery simulator = new AgentVoucherInvalidQuery();
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("order_id", "VI20221031093012");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/voucherinvalidquery");
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 AgentVoucherInvalidQuery() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherInvalidQuery.prototype.getRawData = function () {
return {
order_id: "VI20221031093012",
};
};
/**
* 取得服務位置
*/
AgentVoucherInvalidQuery.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherinvalidquery"
};
};
/**
* AES 256 加密
*/
AgentVoucherInvalidQuery.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 到主機
*/
AgentVoucherInvalidQuery.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherInvalidQuery.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherInvalidQuery.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherInvalidQuery = new AgentVoucherInvalidQuery();
AgentVoucherInvalidQuery.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 AgentVoucherInvalidQuery:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VI20221031093012",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherinvalidquery'
}
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)
AgentVoucherInvalidQuery = AgentVoucherInvalidQuery()
AgentVoucherInvalidQuery.run()
回傳 JSON 結構如下:
提供票券作廢交易之訂單查詢。
經銷商『票券作廢交易查詢』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/voucherinvalidquery"} JSON格式,AES256加密資料 |
encry_data | text | 『票券作廢交易查詢』欄位參考 JSON格式,AES256加密資料 |
『票券作廢交易查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券作廢票券處理編號 | 必填 |
『票券作廢交易查詢』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 查詢內容 | 『票券作廢交易內容』欄位參考 |
票券狀態查詢
<?php
/**
* 經銷商串接-票券狀態查詢
*/
final class AgentVoucherStatusQuery
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['items'] = [
[
'issuance_uid' => '289151881006',
'no' => '2051088071'
],
[
'issuance_uid' => '289151881006',
'no' => '2051088080'
]
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherstatusquery'
);
}
/**
* 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;
}
}
$AgentVoucherStatusQuery = new AgentVoucherStatusQuery();
$AgentVoucherStatusQuery->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 AgentVoucherStatusQuery {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherStatusQuery simulator = new AgentVoucherStatusQuery();
//僅限走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.issuance_uid = "289151881006";
item1.no = "2051088071";
items.Add(item1);
dynamic item2 = new ExpandoObject();
item2.issuance_uid = "289151881006";
item2.no = "2051088080";
items.Add(item2);
dynamic rawData = new ExpandoObject();
rawData.items = items;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherstatusquery";
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 AgentVoucherStatusQuery {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherStatusQuery simulator = new AgentVoucherStatusQuery();
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("issuance_uid", "289151881006");
item1.put("no", "2051088071");
items.add(item1);
Map<Object, Object> item2 = new HashMap<Object, Object>();
item2.put("issuance_uid", "289151881006");
item2.put("no", "2051088080");
items.add(item2);
Map<Object, Object> rawData = new HashMap<Object, Object>();
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/voucherstatusquery");
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 AgentVoucherStatusQuery() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherStatusQuery.prototype.getRawData = function () {
return {
items: [
{
'issuance_uid': "289151881006",
'no': "2051088071"
},
{
'issuance_uid': "289151881006",
'no': "2051088080"
}
],
};
};
/**
* 取得服務位置
*/
AgentVoucherStatusQuery.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherstatusquery"
};
};
/**
* AES 256 加密
*/
AgentVoucherStatusQuery.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 到主機
*/
AgentVoucherStatusQuery.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherStatusQuery.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherStatusQuery.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherStatusQuery = new AgentVoucherStatusQuery();
AgentVoucherStatusQuery.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 AgentVoucherStatusQuery:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'items': [
{
'issuance_uid': "289151881006",
'no': "2051088071"
},
{
'issuance_uid': "289151881006",
'no': "2051088080"
}
],
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherstatusquery'
}
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)
AgentVoucherStatusQuery = AgentVoucherStatusQuery()
AgentVoucherStatusQuery.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": [{
"issuance_uid": "289151881006",
"unit_type": 1,
"no": "2051088071",
"ticket": {
"status": 31,
"custom_serial_no": "2051088071",
"serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-AG5IQAIUM",
"book_no": "",
"sales_from_type": 2,
"sales_store_uid": "",
"sales_dealer_no": "A0001",
"reimbursement_from_type": 2,
"reimbursement_store_uid": "",
"reimbursement_dealer_no": "A0002",
"invalid_from_type": 1,
"invalid_store_uid": "",
"invalid_dealer_no": "",
"cost": 200,
"price": 200,
"trust_start_date": "20240425",
"trust_end_date": "20260424",
"trust_guarantee_date": "20240424",
"is_paid": 0
},
"book": []
},
{
"issuance_uid": "289151881006",
"unit_type": 1,
"no": "2051088080",
"ticket": {
"status": 31,
"custom_serial_no": "2051088080",
"serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-157ZN69FN",
"book_no": "",
"sales_from_type": 2,
"sales_store_uid": "",
"sales_dealer_no": "A0001",
"reimbursement_from_type": 2,
"reimbursement_store_uid": "",
"reimbursement_dealer_no": "A0002",
"invalid_from_type": 1,
"invalid_store_uid": "",
"invalid_dealer_no": "",
"cost": 200,
"price": 200,
"trust_start_date": "20240425",
"trust_end_date": "20260424",
"trust_guarantee_date": "20240424",
"is_paid": 0
},
"book": []
}
]
}
提供查詢票券目前最新之票券狀態。
經銷商『票券狀態查詢』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/voucherstatusquery"} JSON格式,AES256加密資料 |
encry_data | text | 『票券狀態查詢』欄位參考 JSON格式,AES256加密資料 |
『票券狀態查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
items | array | 票券狀態查詢項目 | 必填 每筆『票券狀態查詢項目』欄位參考 |
『票券狀態查詢』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | array | 內容 | 每筆『票券狀態資訊回傳』欄位參考 |
票券發票資訊回報
<?php
/**
* 經銷商串接-票券發票資訊回報
*/
final class AgentVoucherSalesInvoice
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881006";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
/**
* 串接交易位置
* @var string
*/
public $url = "http://ka.k20-mypay.tw/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VSI20240530115634";
$rawData['invoice_mode'] = 2;
$rawData['issue_invoice_state'] = 1;
$rawData['order_uid'] = "100131";
$rawData['order_key'] = "f2ccc230288f7e7049ef514862b70dfd";
$rawData['items'] = [
[
'type' => 2,
'content' =>
[
'number' => 'AB12345678',
'date' => '20240530115634',
'cost' => 100,
'detail' =>
[
[
'description' => '50元禮券',
'quantity' => 2,
'unit_price' => 50,
'amount' => 100
]
]
]
],
[
'type' => 4,
'content' =>
[
'number' => 'AB12345678',
'date' => '20240530115634',
'cost' => 100,
'detail' =>
[
[
'description' => '50元禮券',
'quantity' => 2,
'unit_price' => 50,
'amount' => 100
]
]
]
]
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/vouchersalesinvoice'
);
}
/**
* 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;
}
}
$AgentVoucherSalesInvoice = new AgentVoucherSalesInvoice();
$AgentVoucherSalesInvoice->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 AgentVoucherSalesInvoice {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881006";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "http://ka.k20-mypay.tw/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherSalesInvoice simulator = new AgentVoucherSalesInvoice();
//僅限走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.type = 2;
dynamic content1 = new ExpandoObject();
content1.number = "AB12345678";
content1.date = "20240530115634";
content1.cost = 100;
ArrayList detail = new ArrayList();
dynamic detail1 = new ExpandoObject();
detail1.description = "50元禮券";
detail1.quantity = 2;
detail1.unit_price = 50;
detail1.amount = 100;
detail.Add(detail1);
content1.detail = detail;
item1.content = content1;
items.Add(item1);
dynamic item2 = new ExpandoObject();
item2.type = 4;
dynamic content2 = new ExpandoObject();
content2.number = "AB12345678";
content2.date = "20240530115634";
content2.cost = 100;
ArrayList detail = new ArrayList();
dynamic detail1 = new ExpandoObject();
detail1.description = "50元禮券";
detail1.quantity = 2;
detail1.unit_price = 50;
detail1.amount = 100;
detail.Add(detail1);
content2.detail = detail;
item2.content = content2;
items.Add(item2);
dynamic rawData = new ExpandoObject();
rawData.order_id = "VSI20240530115634";
rawData.invoice_mode = 2;
rawData.issue_invoice_state = 1;
rawData.order_uid = "100131";
rawData.order_key = "f2ccc230288f7e7049ef514862b70dfd";
rawData.items = items;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/vouchersalesinvoice";
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 AgentVoucherSalesInvoice {
/**
* 經銷商商務代號
*/
String agentUid = "289151881006";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
/**
* 串接交易位置
*/
String url = "http://ka.k20-mypay.tw/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherSalesInvoice simulator = new AgentVoucherSalesInvoice();
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("type", 2);
Map<Object, Object> content1 = new HashMap<Object, Object>();
content1.put("number", "AB12345678");
content1.put("date", "20240530115634");
content1.put("cost", 100);
ArrayList detail = new ArrayList();
Map<Object, Object> detail1 = new HashMap<Object, Object>();
detail1.put("description", "50元禮券");
detail1.put("quantity", 2);
detail1.put("unit_price", 50);
detail1.put("amount", 100);
detail.add(detail1);
content1.put("detail", detail);
item1.put("content", content1);
items.add(item1);
Map<Object, Object> item2 = new HashMap<Object, Object>();
item2.put("type", 4);
Map<Object, Object> content2 = new HashMap<Object, Object>();
content2.put("number", "AB12345678");
content2.put("date", "20240530115634");
content2.put("cost", 100);
ArrayList detail = new ArrayList();
Map<Object, Object> detail1 = new HashMap<Object, Object>();
detail1.put("description", "50元禮券");
detail1.put("quantity", 2);
detail1.put("unit_price", 50);
detail1.put("amount", 100);
detail.add(detail1);
content2.put("detail", detail);
item2.put("content", content2);
items.add(item2);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("order_id", "VSI20240530115634");
rawData.put("invoice_mode", 2);
rawData.put("issue_invoice_state", 1);
rawData.put("order_uid", "100131");
rawData.put("order_key", "f2ccc230288f7e7049ef514862b70dfd");
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/vouchersalesinvoice");
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 AgentVoucherSalesInvoice() {
// 經銷商商務代號
this.agentUid = "289151881006";
// 經銷商金鑰或認證碼
this.agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
// 串接交易位置
this.url = "http://ka.k20-mypay.tw/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherSalesInvoice.prototype.getRawData = function () {
return {
order_id: "VSI20240530115634",
invoice_mode: 2,
issue_invoice_state: 1,
order_uid: "100131",
order_key: "f2ccc230288f7e7049ef514862b70dfd",
items: [
{
'type': 2,
'content':
{
'number': "AB12345678",
'date': "20240530115634",
'cost': 100,
'detail':
[
{
'description': "50元禮券",
'quantity': 2,
'unit_price': 50,
'amount': 100
}
]
}
},
{
'type': 4,
'content':
{
'number': "AB12345678",
'date': "20240530115634",
'cost': 100,
'detail':
[
{
'description': "50元禮券",
'quantity': 2,
'unit_price': 50,
'amount': 100
}
]
}
}
],
};
};
/**
* 取得服務位置
*/
AgentVoucherSalesInvoice.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/vouchersalesinvoice"
};
};
/**
* AES 256 加密
*/
AgentVoucherSalesInvoice.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 到主機
*/
AgentVoucherSalesInvoice.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherSalesInvoice.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherSalesInvoice.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherSalesInvoice = new AgentVoucherSalesInvoice();
AgentVoucherSalesInvoice.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 AgentVoucherSalesInvoice:
# 經銷商商務代號
agentUid = "289151881006";
# 經銷商金鑰或認證碼
agentKey = b"UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
# 串接交易位置
url = "http://ka.k20-mypay.tw/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VSI20240530115634",
'invoice_mode': 2,
'issue_invoice_state': 1,
'order_uid': "100131",
'order_key': "f2ccc230288f7e7049ef514862b70dfd",
'items': [
{
'type': 2,
'content':
{
'number': "AB12345678",
'date': "20240530115634",
'cost': 100,
'detail':
[
{
'description': "50元禮券",
'quantity': 2,
'unit_price': 50,
'amount': 100
}
]
}
},
{
'type': 4,
'content':
{
'number': "AB12345678",
'date': "20240530115634",
'cost': 100,
'detail':
[
{
'description': "50元禮券",
'quantity': 2,
'unit_price': 50,
'amount': 100
}
]
}
}
],
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/vouchersalesinvoice'
}
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)
AgentVoucherSalesInvoice = AgentVoucherSalesInvoice()
AgentVoucherSalesInvoice.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"uid": "100007",
"key": "e71e5d33ea91f8b0825b3df4d4da6fac",
"order_id": "VSI20240530141335",
"invoice_mode": 2,
"issue_invoice_state": 1,
"order_uid": "100131",
"order_key": "f2ccc230288f7e7049ef514862b70dfd",
"items": [
{
"type": 2,
"content": {
"number": "AB12345678",
"date": "20240530141335",
"cost": 100,
"detail": [
{
"description": "50元禮券",
"quantity": 2,
"unit_price": 50,
"amount": 100
}
]
}
},
{
"type": 4,
"content": {
"number": "AB12345678",
"date": "20240530141335",
"cost": 100,
"detail": [
{
"description": "50元禮券",
"quantity": 2,
"unit_price": 50,
"amount": 100
}
]
}
}
],
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
}
經銷商『票券發票資訊回報』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/vouchersalesinvoice"} JSON格式,AES256加密資料 |
encry_data | text | 『票券發票資訊回報』欄位參考 JSON格式,AES256加密資料 |
『票券發票資訊回報』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券發票資訊回報處理編號(唯一) | 必填 |
invoice_mode | int | 發票何時開立 | 必填 『發票何時開立』值參考 |
issue_invoice_state | int | 發票誰開立 | 必填 『票券發票資訊回報』值參考 |
order_uid | string | 售出交易訂單UID或核銷交易訂單UID | 必填 |
order_key | string | 售出交易驗証碼或核銷交易驗證碼 | 必填 |
items | array | 發票資訊回報 開立時間/作廢時間/折讓時間需注意合理順序 |
必填 每筆『票券發票開立資訊指令』欄位參考 每筆『票券發票作廢資訊指令』欄位參考 每筆『票券發票折讓資訊指令』欄位參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券發票資訊回報』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 內容 | 『票券狀態資訊回傳』欄位參考 |
票券發票資訊回報查詢
<?php
/**
* 經銷商串接-票券發票資訊回報查詢
*/
final class AgentVoucherSalesInvoiceQuery
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881006";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
/**
* 串接交易位置
* @var string
*/
public $url = "http://ka.k20-mypay.tw/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VSIVSI20240528163410";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/vouchersalesinvoicequery'
);
}
/**
* 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;
}
}
$AgentVoucherSalesInvoiceQuery = new AgentVoucherSalesInvoiceQuery();
$AgentVoucherSalesInvoiceQuery->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 AgentVoucherSalesInvoiceQuery {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881006";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "http://ka.k20-mypay.tw/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherSalesInvoiceQuery simulator = new AgentVoucherSalesInvoiceQuery();
//僅限走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.order_id = "VSIVSI20240528163410";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/vouchersalesinvoicequery";
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 AgentVoucherSalesInvoiceQuery {
/**
* 經銷商商務代號
*/
String agentUid = "289151881006";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
/**
* 串接交易位置
*/
String url = "http://ka.k20-mypay.tw/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherSalesInvoiceQuery simulator = new AgentVoucherSalesInvoiceQuery();
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("order_id", "VSIVSI20240528163410");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/vouchersalesinvoicequery");
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 AgentVoucherSalesInvoiceQuery() {
// 經銷商商務代號
this.agentUid = "289151881006";
// 經銷商金鑰或認證碼
this.agentKey = "UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
// 串接交易位置
this.url = "http://ka.k20-mypay.tw/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherSalesInvoiceQuery.prototype.getRawData = function () {
return {
order_id: "VSIVSI20240528163410",
};
};
/**
* 取得服務位置
*/
AgentVoucherSalesInvoiceQuery.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/vouchersalesinvoicequery"
};
};
/**
* AES 256 加密
*/
AgentVoucherSalesInvoiceQuery.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 到主機
*/
AgentVoucherSalesInvoiceQuery.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherSalesInvoiceQuery.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherSalesInvoiceQuery.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherSalesInvoiceQuery = new AgentVoucherSalesInvoiceQuery();
AgentVoucherSalesInvoiceQuery.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 AgentVoucherSalesInvoiceQuery:
# 經銷商商務代號
agentUid = "289151881006";
# 經銷商金鑰或認證碼
agentKey = b"UZvvZq9FTidubsHIJj1fbdHbAJCpK8yw";
# 串接交易位置
url = "http://ka.k20-mypay.tw/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VSIVSI20240528163410",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/vouchersalesinvoicequery'
}
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)
AgentVoucherSalesInvoiceQuery = AgentVoucherSalesInvoiceQuery()
AgentVoucherSalesInvoiceQuery.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"code": "B200",
"msg": "執行成功",
"uid": "100006",
"key": "b59fe48ac742d006695739679b21ecd2",
"order_id": "VSI20240530111642",
"invoice_mode": 2,
"issue_invoice_state": 0,
"order_uid": "100134",
"order_key": "e410fbcc0585c2fdcce93c60586f9533",
"items": [
{
"type": 3,
"content": {
"number": "AB12345678",
"date": "20240530111641"
}
}
],
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
}
經銷商『票券發票資訊回報查詢』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name":"api","cmd":"api\/vouchersalesinvoicequery"} JSON格式,AES256加密資料 |
encry_data | text | 『票券發票資訊回報查詢』欄位參考 JSON格式,AES256加密資料 |
『票券發票資訊回報查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券發票資訊回報處理編號 | 必填 |
『票券發票資訊回報查詢』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | 內容 | 『票券狀態資訊回傳』值參考 |
票券核銷線下交易Qrcode掃碼頁面
<?php
/**
* 經銷商串接-票券核銷線下交易Qrcode掃碼頁面
*/
final class AgentVoucherOfflineQrcodePage
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['user_id'] = "phper";
$rawData['qrcode_type'] = "2";
$rawData['page_type'] = "1";
$rawData['issuance_uid'] = [
"289151881006"
];
$rawData['homepage_url'] = "https://www.mypay.com.tw/";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherofflineqrcodepage'
);
}
/**
* 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;
}
}
$AgentVoucherOfflineQrcodePage = new AgentVoucherOfflineQrcodePage();
$AgentVoucherOfflineQrcodePage->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>
/// 經銷商串接-票券核銷線下交易Qrcode掃碼頁面
/// </summary>
public class AgentVoucherOfflineQrcodePage {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherOfflineQrcodePage simulator = new AgentVoucherOfflineQrcodePage();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList issuanceUid = new ArrayList();
issuanceUid.Add("289151881006");
dynamic rawData = new ExpandoObject();
rawData.user_id = "phper";
rawData.qrcode_type = "2";
rawData.page_type = "1";
rawData.issuance_uid = issuanceUid;
rawData.homepage_url = "https://www.mypay.com.tw/";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherofflineqrcodepage";
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;
/**
* 經銷商串接-票券核銷線下交易Qrcode掃碼頁面
* 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 AgentVoucherOfflineQrcodePage {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherOfflineQrcodePage simulator = new AgentVoucherOfflineQrcodePage();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList issuanceUid = new ArrayList();
issuanceUid.add(new String("289151881006"));
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("user_id", "phper");
rawData.put("qrcode_type", "2");
rawData.put("page_type", "1");
rawData.put("issuance_uid", issuanceUid);
rawData.put("homepage_url", "https://www.mypay.com.tw/");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/voucherofflineqrcodepage");
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');
/**
* 經銷商串接-票券核銷線下交易Qrcode掃碼頁面
*/
function AgentVoucherOfflineQrcodePage() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherOfflineQrcodePage.prototype.getRawData = function () {
return {
user_id: "phper",
qrcode_type: "2",
page_type: "1",
issuance_uid: [
"289151881006"
],
homepage_url: "https://www.mypay.com.tw/",
};
};
/**
* 取得服務位置
*/
AgentVoucherOfflineQrcodePage.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherofflineqrcodepage"
};
};
/**
* AES 256 加密
*/
AgentVoucherOfflineQrcodePage.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 到主機
*/
AgentVoucherOfflineQrcodePage.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherOfflineQrcodePage.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherOfflineQrcodePage.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherOfflineQrcodePage = new AgentVoucherOfflineQrcodePage();
AgentVoucherOfflineQrcodePage.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
"""經銷商串接-票券核銷線下交易Qrcode掃碼頁面
"""
class AgentVoucherOfflineQrcodePage:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'user_id': "phper",
'qrcode_type': "2",
'page_type': "1",
'issuance_uid': [
"289151881006"
],
'homepage_url': "https://www.mypay.com.tw/",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherofflineqrcodepage'
}
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)
AgentVoucherOfflineQrcodePage = AgentVoucherOfflineQrcodePage()
AgentVoucherOfflineQrcodePage.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"url": "https:\/\/ka.usecase.cc\/voucher\/qrcode\/54acf767.html"
}
取得消費者使用票券消費頁面,當消費者選擇後,顯示Qrcode提供給商家掃碼。
經銷商『票券核銷線下交易Qrcode掃碼頁面』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/voucherofflineqrcodepage"} JSON格式,AES256加密資料 |
encry_data | text | 『票券核銷線下交易Qrcode掃碼頁面』欄位參考 JSON格式,AES256加密資料 |
『票券核銷線下交易Qrcode掃碼頁面』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
user_id | string | 消費者帳號 | 必填 |
qrcode_type | string | Qrcode內容模式 | 『Qrcode內容模式』值參考 |
page_type | string | 票券顯示模式 | 『票券顯示模式』值參考 |
issuance_uid | array | 以委託發行商顯示票券之委託發行商商務代號 1.資訊商發動,可以帶不同的委託發行商 2.委託發行商發動,只能自己本身委託發行商 |
|
reimbursement_store_uid | string | 以可核銷之特約商店顯示票券之核銷特約商店商務代號 | |
theme | string | 指定佈景主題名稱 | |
homepage_url | string | 返回首頁連結 |
『票券核銷線下交易Qrcode掃碼頁面』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
url | string | 消費網址 |
票券消費者退券頁面(消費者主動)
/**
* 經銷商串接-票券退券(消費者主動)
*/
final class AgentVoucherUserRefund
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_uid'] = "VU20221208105205";
$rawData['user_id'] = "phper";
$rawData['page_type'] = "1";
$rawData['issuance_uid'] = [
"289151881006"
];
$rawData['homepage_url'] = "https://www.mypay.com.tw/";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucheruserrefundpage'
);
}
/**
* 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;
}
}
$AgentVoucherUserRefund = new AgentVoucherUserRefund();
$AgentVoucherUserRefund->run();
?>
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 AgentVoucherUserRefund {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherUserRefund simulator = new AgentVoucherUserRefund();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList issuanceUid = new ArrayList();
issuanceUid.add(new String("289151881006"));
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("order_uid", "VU20221208105205");
rawData.put("user_id", "phper");
rawData.put("page_type", "1");
rawData.put("issuance_uid", issuanceUid);
rawData.put("homepage_url", "https://www.mypay.com.tw/");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/voucheruserrefundpage");
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;
}
}
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 AgentVoucherUserRefund {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherUserRefund simulator = new AgentVoucherUserRefund();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList issuanceUid = new ArrayList();
issuanceUid.Add("289151881006");
dynamic rawData = new ExpandoObject();
rawData.order_uid = "VU20221208105205";
rawData.user_id = "phper";
rawData.page_type = "1";
rawData.issuance_uid = issuanceUid;
rawData.homepage_url = "https://www.mypay.com.tw/";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucheruserrefundpage";
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; }
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-票券退券(消費者主動)
*/
function AgentVoucherUserRefund() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherUserRefund.prototype.getRawData = function () {
return {
order_uid: "VU20221208105205",
user_id: "phper",
page_type: "1",
issuance_uid: [
"289151881006"
],
homepage_url: "https://www.mypay.com.tw/",
};
};
/**
* 取得服務位置
*/
AgentVoucherUserRefund.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucheruserrefundpage"
};
};
/**
* AES 256 加密
*/
AgentVoucherUserRefund.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 到主機
*/
AgentVoucherUserRefund.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherUserRefund.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherUserRefund.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherUserRefund = new AgentVoucherUserRefund();
AgentVoucherUserRefund.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 AgentVoucherUserRefund:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_uid': "VU20221208105205",
'user_id': "phper",
'page_type': "1",
'issuance_uid': [
"289151881006"
],
'homepage_url': "https://www.mypay.com.tw/",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucheruserrefundpage'
}
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)
AgentVoucherUserRefund = AgentVoucherUserRefund()
AgentVoucherUserRefund.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"url": "https:\/\/ka.usecase.cc\/voucher\/refund\/54acf767.html"
}
店家發動API,取得退劵網址,消費者登入後,自行選取需要退劵的品項,待退劵完畢後,若有導轉網址,5秒鐘後會自行導轉
注意事項:實際退款時間為隔日11點後陸續退款
經銷商『票券消費者退劵頁面』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/voucheruserrefundpage"} JSON格式,AES256加密資料 |
encry_data | text | 『票券消費者退券頁面』欄位參考 JSON格式,AES256加密資料 |
『票券消費者退劵頁面』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_uid | string | 票券退券交易票券處理編號(唯一) | |
user_id | string | 消費者帳號 | 必填 |
page_type | string | 票券顯示模式 | 『票券顯示模式』值參考 |
issuance_uid | array | 以委託發行商顯示票券之委託發行商商務代號 1.資訊商發動,可以帶不同的委託發行商 2.委託發行商發動,只能自己本身委託發行商 |
|
theme | string | 指定佈景主題名稱 | |
homepage_url | string | 返回首頁連結 | |
success_returl | string | 成功退劵畫面 | |
failure_returl | string | 退劵失敗畫面 |
『票券退券交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『退券執行狀態碼』值參考 |
msg | string | 回傳訊息 | |
content | object | 退劵回傳系項資訊 | 『退劵回傳細項資訊』值參考 |
『消費者票券退券執行結果』回傳欄位
參數名稱 | 型態 | 說明 | 備註 |
---|---|---|---|
order_id | string | 退券訂單編號 | 如果消費是從票券匣退券,則由系統自動配號 |
uid | string | 票券退券交易UID | |
key | string | 驗証碼 | |
code | string | 退券狀態碼 | |
msg | string | 狀態碼訊息 | |
refund_date | string | 退券完成時間(YYYYMMDDHHIISS) | |
items | array | 退券產品 | 『退券產品資料』值參考 |
『退券產品資料』回傳欄位
參數名稱 | 型態 | 說明 | 備註 |
---|---|---|---|
sales_store_uid | string | 銷售點特約商店代碼 | |
headquarters_agent_uid | string | 總部商務代號 | |
issuance_uid | string | 委託發行商商務代號 | |
id | string | 票券產品編號 | |
serial_no | string | 票券序號 | |
price | string | 定價 | |
cost | string | 單價 | |
name | string | 產品名稱 | |
material_code | string | 委託發行商的商品料號 |
票券轉贈(消費者主動)
<?php
/**
* 經銷商串接-票券轉贈(消費者主動)
*/
final class AgentVoucherGift
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VG20221208105207";
$rawData['user_id'] = "phper";
$rawData['page_type'] = "1";
$rawData['issuance_uid'] = [
"289151881006"
];
$rawData['homepage_url'] = "https://www.mypay.com.tw/";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/vouchergift'
);
}
/**
* 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;
}
}
$AgentVoucherGift = new AgentVoucherGift();
$AgentVoucherGift->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 AgentVoucherGift {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherGift simulator = new AgentVoucherGift();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList issuanceUid = new ArrayList();
issuanceUid.Add("289151881006");
dynamic rawData = new ExpandoObject();
rawData.order_id = "VG20221208105207";
rawData.user_id = "phper";
rawData.page_type = "1";
rawData.issuance_uid = issuanceUid;
rawData.homepage_url = "https://www.mypay.com.tw/";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/vouchergift";
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 AgentVoucherGift {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherGift simulator = new AgentVoucherGift();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList issuanceUid = new ArrayList();
issuanceUid.add(new String("289151881006"));
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("order_id", "VG20221208105207");
rawData.put("user_id", "phper");
rawData.put("page_type", "1");
rawData.put("issuance_uid", issuanceUid);
rawData.put("homepage_url", "https://www.mypay.com.tw/");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/vouchergift");
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 AgentVoucherGift() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherGift.prototype.getRawData = function () {
return {
order_id: "VG20221208105207",
user_id: "phper",
page_type: "1",
issuance_uid: [
"289151881006"
],
homepage_url: "https://www.mypay.com.tw/",
};
};
/**
* 取得服務位置
*/
AgentVoucherGift.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/vouchergift"
};
};
/**
* AES 256 加密
*/
AgentVoucherGift.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 到主機
*/
AgentVoucherGift.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherGift.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherGift.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherGift = new AgentVoucherGift();
AgentVoucherGift.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 AgentVoucherGift:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VG20221208105207",
'user_id': "phper",
'page_type': "1",
'issuance_uid': [
"289151881006"
],
'homepage_url': "https://www.mypay.com.tw/",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/vouchergift'
}
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)
AgentVoucherGift = AgentVoucherGift()
AgentVoucherGift.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"url": "https:\/\/mytix.usecase.cc\/voucher\/gift\/6bfe4cac.html",
"uid": "100100",
"key": "4626ebbd99541c0b139bc5bd478d2861"
}
}
發動API後,消費者取得連結,並連結到票券轉贈頁面。透過指定的手機號碼,轉贈給予會員與非會員。當轉贈完成,依照簡訊設定,由MYTIX發送,或由委託發行商自行發送(MYTIX會發送『票券轉贈簡訊通知』)。 會員則依票券核銷線下交易Qrcode掃碼頁面功能進行核銷,非會員則在簡訊通知後,透過指定連結並解輸入手機號碼號,進行Qrcode掃碼頁面功能。
『票券轉贈(消費者主動)』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券轉贈交易票券處理編號(唯一) | 必填 |
user_id | string | 消費者帳號 | 必填 |
page_type | string | 票券顯示模式 | 必填 『票券顯示模式』值參考 |
issuance_uid | array | 以委託發行商顯示票券之委託發行商商務代號 1.資訊商發動,可以帶不同的委託發行商 2.委託發行商發動,只能自己本身委託發行商 |
必填 |
success_returl | string | 成功轉贈畫面 | |
failure_returl | string | 轉贈失敗畫面 | |
homepage_url | string | 返回首頁連結 | |
theme | string | 指定佈景主題名稱 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券轉贈(消費者主動)』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 票券轉贈回傳細項資訊 | 『票券轉贈回傳細項資訊』欄位參考 |
『票券轉贈簡訊通知』回報欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
sms_type | integer | 簡訊通知類型 1.票券轉贈簡訊通知 |
|
content | object | 簡訊通知內容 | 『票券轉贈簡訊通知』欄位參考 |
票券匣
1.發動API後,取得票券匣連結,消費者可在此操作票券匣。票券匣整合了Qrcode掃碼、退券、轉贈功能以及使用紀錄。
2.如要查看退劵執行回傳通知內容請查詢『消費者票券退券執行結果』
<?php
/**
* 經銷商串接-票券匣
*/
final class AgentVoucherBoxes
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['order_id'] = "VB20221208105209";
$rawData['user_id'] = "phper";
$rawData['page_type'] = "1";
$rawData['issuance_uid'] = [
"289151881006"
];
$rawData['homepage_url'] = "https://www.mypay.com.tw/";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherboxes'
);
}
/**
* 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;
}
}
$AgentVoucherBoxes = new AgentVoucherBoxes();
$AgentVoucherBoxes->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 AgentVoucherBoxes {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherBoxes simulator = new AgentVoucherBoxes();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList issuanceUid = new ArrayList();
issuanceUid.Add("289151881006");
dynamic rawData = new ExpandoObject();
rawData.order_id = "VB20221208105209";
rawData.user_id = "phper";
rawData.page_type = "1";
rawData.issuance_uid = issuanceUid;
rawData.homepage_url = "https://www.mypay.com.tw/";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherboxes";
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 AgentVoucherBoxes {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherBoxes simulator = new AgentVoucherBoxes();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList issuanceUid = new ArrayList();
issuanceUid.add(new String("289151881006"));
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("order_id", "VB20221208105209");
rawData.put("user_id", "phper");
rawData.put("page_type", "1");
rawData.put("issuance_uid", issuanceUid);
rawData.put("homepage_url", "https://www.mypay.com.tw/");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/voucherboxes");
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 AgentVoucherBoxes() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherBoxes.prototype.getRawData = function () {
return {
order_id: "VB20221208105209",
user_id: "phper",
page_type: "1",
issuance_uid: [
"289151881006"
],
homepage_url: "https://www.mypay.com.tw/",
};
};
/**
* 取得服務位置
*/
AgentVoucherBoxes.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherboxes"
};
};
/**
* AES 256 加密
*/
AgentVoucherBoxes.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 到主機
*/
AgentVoucherBoxes.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherBoxes.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherBoxes.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherBoxes = new AgentVoucherBoxes();
AgentVoucherBoxes.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 AgentVoucherBoxes:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'order_id': "VB20221208105209",
'user_id': "phper",
'page_type': "1",
'issuance_uid': [
"289151881006"
],
'homepage_url': "https://www.mypay.com.tw/",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherboxes'
}
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)
AgentVoucherBoxes = AgentVoucherBoxes()
AgentVoucherBoxes.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"url": "https:\/\/mytix.usecase.cc\/voucher\/boxes\/0279496f.html",
"uid": "100060",
"key": "35b4dd522d1280dcb1d63718dcbeed0f"
}
}
『票券匣』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
order_id | string | 票券匣處理編號(唯一) | 必填 |
user_id | string | 消費者帳號 | 必填 |
page_type | string | 票券顯示模式 | 必填 『票券顯示模式』值參考 |
issuance_uid | array | 以委託發行商顯示票券之委託發行商商務代號 1.資訊商發動,可以帶不同的委託發行商 2.委託發行商發動,只能自己本身委託發行商 |
必填 |
homepage_url | string | 返回首頁連結 | |
theme | string | 佈景主題名稱 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券匣』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 票券轉贈回傳細項資訊 | 『票券匣回傳細項資訊』欄位參考 |
『票券匣轉贈簡訊通知』回報欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
sms_type | integer | 簡訊通知類型 2.票券匣轉贈簡訊通知 |
|
content | object | 簡訊通知內容 | 『票券匣轉贈簡訊通知』欄位參考 |
建立或修改發行商票券
<?php
/**
* 經銷商串接-建立或修改發行商票券
*/
final class AgentVoucherDataCreator
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['issuance_uid'] = "289151881006";
$rawData['items'] = [
[
'product_id' => 'MANOR008',
'area_type' => 2,
'is_paid' => 1,
'detail' =>
[
'is_on' => 1,
'is_gift' => 1,
'material_code' => 'MC08',
'product_name' => '金沙咖啡',
'product_description' => '600(L)可調整冰塊甜度',
'declaration' => '<b>咖啡使用規則</b>'
]
]
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherdatacreator'
);
}
/**
* 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;
}
}
$AgentVoucherDataCreator = new AgentVoucherDataCreator();
$AgentVoucherDataCreator->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 AgentVoucherDataCreator {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherDataCreator simulator = new AgentVoucherDataCreator();
//僅限走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.product_id = "MANOR008";
item.area_type = 2;
item.is_paid = 1;
dynamic detail = new ExpandoObject();
detail.is_on = 1;
detail.is_gift = 1;
detail.material_code = "MC08";
detail.product_name = "金沙咖啡";
detail.product_description = "600(L)可調整冰塊甜度";
detail.declaration = "<b>咖啡使用規則</b>";
item.detail = detail;
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.issuance_uid = "289151881006";
rawData.items = items;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherdatacreator";
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 AgentVoucherDataCreator {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherDataCreator simulator = new AgentVoucherDataCreator();
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("product_id", "MANOR008");
item.put("area_type", 2);
item.put("is_paid", 1);
Map<Object, Object> detail = new HashMap<Object, Object>();
detail.put("is_on", 1);
detail.put("is_gift", 1);
detail.put("material_code", "MC08");
detail.put("product_name", "金沙咖啡");
detail.put("product_description", "600(L)可調整冰塊甜度");
detail.put("declaration", "<b>咖啡使用規則</b>");
item.put("detail", detail);
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("issuance_uid", "289151881006");
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/voucherdatacreator");
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 AgentVoucherDataCreator() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherDataCreator.prototype.getRawData = function () {
return {
issuance_uid: "289151881006",
items: [
{
'product_id': "MANOR008",
'area_type': 2,
'is_paid': 1,
'detail':
{
'is_on': 1,
'is_gift': 1,
'material_code': "MC08",
'product_name': "金沙咖啡",
'product_description': "600(L)可調整冰塊甜度",
'declaration': "<b>咖啡使用規則</b>"
}
}
],
};
};
/**
* 取得服務位置
*/
AgentVoucherDataCreator.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherdatacreator"
};
};
/**
* AES 256 加密
*/
AgentVoucherDataCreator.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 到主機
*/
AgentVoucherDataCreator.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherDataCreator.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherDataCreator.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherDataCreator = new AgentVoucherDataCreator();
AgentVoucherDataCreator.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 AgentVoucherDataCreator:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'issuance_uid': "289151881006",
'items': [
{
'product_id': "MANOR008",
'area_type': 2,
'is_paid': 1,
'detail':
{
'is_on': 1,
'is_gift': 1,
'material_code': "MC08",
'product_name': "金沙咖啡",
'product_description': "600(L)可調整冰塊甜度",
'declaration': "<b>咖啡使用規則</b>"
}
}
],
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherdatacreator'
}
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)
AgentVoucherDataCreator = AgentVoucherDataCreator()
AgentVoucherDataCreator.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": [
{
"code": "251",
"msg": "更新成功",
"product_id": "MANOR008"
}
]
}
透過API,建立發行商票券之設定內容或修改發行商票券設定之內容。
經銷商『建立或修改發行商票券』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/voucherdatacreator"} JSON格式,AES256加密資料 |
encry_data | text | 『建立或修改發行商票券』欄位參考 JSON格式,AES256加密資料 |
『建立或修改發行商票券』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商商務代號 | 必填 |
items | array | 票券資訊 | 必填 每筆『發行商票券資訊』欄位參考 |
『建立或修改發行商票券』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | array | 建立或修改結果回傳 | 每筆『發行商票券資訊』欄位參考 |
查詢發行商票券
<?php
/**
* 經銷商串接-查詢發行商票券
*/
final class AgentVoucherDataInquirer
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
* @var string
*/
public $url = "https://ka.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['issuance_uid'] = "289151881006";
$rawData['type'] = 1;
$rawData['product_ids'] = [
"MANOR008"
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/voucherdatainquirer'
);
}
/**
* 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;
}
}
$AgentVoucherDataInquirer = new AgentVoucherDataInquirer();
$AgentVoucherDataInquirer->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 AgentVoucherDataInquirer {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "289151881007";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://ka.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentVoucherDataInquirer simulator = new AgentVoucherDataInquirer();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList productIds = new ArrayList();
productIds.Add("MANOR008");
dynamic rawData = new ExpandoObject();
rawData.issuance_uid = "289151881006";
rawData.type = 1;
rawData.product_ids = productIds;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/voucherdatainquirer";
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 AgentVoucherDataInquirer {
/**
* 經銷商商務代號
*/
String agentUid = "289151881007";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
/**
* 串接交易位置
*/
String url = "https://ka.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentVoucherDataInquirer simulator = new AgentVoucherDataInquirer();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList productIds = new ArrayList();
productIds.add(new String("MANOR008"));
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("issuance_uid", "289151881006");
rawData.put("type", 1);
rawData.put("product_ids", productIds);
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/voucherdatainquirer");
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 AgentVoucherDataInquirer() {
// 經銷商商務代號
this.agentUid = "289151881007";
// 經銷商金鑰或認證碼
this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
// 串接交易位置
this.url = "https://ka.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentVoucherDataInquirer.prototype.getRawData = function () {
return {
issuance_uid: "289151881006",
type: 1,
product_ids: [
"MANOR008"
],
};
};
/**
* 取得服務位置
*/
AgentVoucherDataInquirer.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/voucherdatainquirer"
};
};
/**
* AES 256 加密
*/
AgentVoucherDataInquirer.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 到主機
*/
AgentVoucherDataInquirer.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();
});
};
/**
* 取得送出欄位資料
*/
AgentVoucherDataInquirer.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentVoucherDataInquirer.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentVoucherDataInquirer = new AgentVoucherDataInquirer();
AgentVoucherDataInquirer.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 AgentVoucherDataInquirer:
# 經銷商商務代號
agentUid = "289151881007";
# 經銷商金鑰或認證碼
agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
# 串接交易位置
url = "https://ka.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'issuance_uid': "289151881006",
'type': 1,
'product_ids': [
"MANOR008"
],
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/voucherdatainquirer'
}
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)
AgentVoucherDataInquirer = AgentVoucherDataInquirer()
AgentVoucherDataInquirer.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": [
{
"area_type": 2,
"product_id": "MANOR008",
"is_paid": 1,
"detail": {
"is_on": 1,
"material_code": "MC08",
"product_name": "金沙咖啡",
"declaration": "<b>咖啡使用規則<\/b>"
}
}
]
}
透過API,取得指定之委託發行商票券設定之內容。
經銷商『查詢發行商票券』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/voucherdatainquirer"} JSON格式,AES256加密資料 |
encry_data | text | 『查詢發行商票券』欄位參考 JSON格式,AES256加密資料 |
『查詢發行商票券』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商商務代號 | 必填 |
type | int | 查詢類型 | 必填 『查詢發行商票券』值參考 |
product_ids | array | 查詢之票券產品編號 如果未指定,則回傳全部票券 |
『查詢發行商票券』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | array | 查詢到的票券產品編號 | 每筆『發行商票券資訊』欄位參考 |
其他關聯欄位說明
關聯欄位
『消費者資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
user_id | string | 消費者帳號 | 必填 |
user_name | string | 消費者姓名 | |
user_real_name | string | 消費者真實姓名 | |
user_english_name | string | 消費者英文名稱 | |
user_address_post_zone | string | 消費者地址郵遞區號 | |
user_address | string | 消費者帳單地址 | |
user_sn_type | string | 1:身分證,2:統一證號,3:護照號碼 付款人為本國人為1,外國人2 or 3 | |
user_sn | string | 付款人身分證/統一證號/護照號碼 | |
user_phone | string | 消費者家用電話 | |
user_cellphone_code | string | 消費者行動電話國碼 | |
user_cellphone | string | 消費者行動電話 | |
user_email | string | 消費者 E-Mail | |
user_birthday | string | 消費者生日 | |
ip | string | 消費者來源 IP | 必填 |
『票券項目』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商商務代號 | |
service_id | string | 委託發行商票券服務編號(依MYTIX設定之編號),取得位置系統設定->票劵儲直系統->委託發行商票券服務檢視 | 必填 |
id | string | 高鉅後台產生或發行商角色提供, 發行商請從系統設定->票劵儲直系統->委託發行商票券名稱取得 票券產品編號(最長限32 Bytes) 限英數字([a-zA-Z0-9]) 1.票券服務-一般票券 限用通用券、區域券、單店券 |
必填 |
platform_fee | float | 平台服務費(每張票券) | |
platform_uid | string | 平台服務費收取商務代號 | |
sharing | object | 每張票券分潤比例 委託發行商 + 總部 + 銷售點 + 核銷點 需等於 1 |
必填 『票券分潤』欄位參考 |
service_rule | object | 票券服務規則(依票券服務類型帶入處理規則) | 必填 『票券服務-一般票券』欄位參考 『票券服務-月費』欄位參考 『票券服務-課程』欄位參考 『票券服務-貨運』欄位參考 |
『票券分潤』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance | float | 委託發行商分潤 | 必填 |
headquarters | float | 總部分潤 | 必填 |
sales | float | 銷售點分潤 | 必填 |
reimbursement | float | 核銷點分潤 | 必填 |
『票券服務-一般票券』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
price | float | 此批發行票券的每張票券面額 | 必填 |
cost | float | 此批發行票券的每張票券內含價值 (如為無償票券,則金額請帶0) |
必填 |
amount | integer | 購買票券數量 | 必填 |
total_price | float | 此批票券的面額總和 (定價) |
必填 |
total_cost | float | 此批票券內含價值總和 (售價) (如為無償票券,則金額請帶0) |
必填 |
trust_start_date | string | 票券履約保證起始日 | 必填 |
trust_end_date | string | 票券履約保證結束日(履約保證時間必須超過一年) | 必填 |
validity_end_date | string | 票券優惠結束日(格式YYYYmmdd) 如為無償,超過此日不可核銷 如為有償,可核銷,但應該要告知消費者優惠券結束日 |
必填 |
is_custom_serial | integer | 是否使用客製票券序號 0. 沒有 1.有 |
必填 |
serial_numbers | string | 客製票券序號JSON資料 注意: 1.客製票券序號不能重複,且限英數字([a-zA-Z0-9]) 2.長度最長32bytes 3.若購賣票券交易狀態為交易失敗、未進行交易等確定不可再進行交易,客製券號可進行回收再利用 4.如無回收未用客製票券序號機制,則請忽略3的實作,不重複即可 |
|
service_type | integer | 記名類型 | 必填 『票券服務(一般票券)記名類型』值參考 |
『票券服務-月費』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
service_type | integer | 記名類型 | 必填 『票券服務(月費)記名類型』值參考 |
area_type | integer | 適用區域類型 | 必填 『票券服務(月費)適用區域類型』值參考 |
『票券服務-課程』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
service_type | integer | 記名類型 | 必填 『票券服務(課程)記名類型』值參考 |
area_type | integer | 適用區域類型 | 必填 『票券服務(課程)適用區域類型』值參考 |
『票券服務-貨運』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
service_type | integer | 記名類型 | 必填 『票券服務(貨運)記名類型』值參考 |
area_type | integer | 適用區域類型 | 必填 『票券服務(貨運)適用區域類型』值參考 |
『購買票券交易查詢回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 購買票券交易UID | |
key | string | 交易驗証碼 | |
code | string | 目前狀態碼 | 『購買票券交易狀態碼』值參考 |
msg | string | 回傳訊息 | |
finishtime | string | 交易完成時間(YYYYMMDDHHmmss) | |
order_id | string | 購買票券交易票券交易編號 | |
user_id | string | 消費者帳號 | |
cost | string | 原交易金額 | |
currency | string | 原交易幣別 | |
actual_cost | string | 實際交易金額 | |
actual_currency | string | 實際交易幣別 | |
pfn | string | 付費方法 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券核銷線下交易資訊回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 票券核銷線下交易UID | |
key | string | 交易驗証碼 | |
order_id | string | 票券核銷線下交易票券處理編號 | |
code | string | 票券核銷線下交易狀態碼 | 『票券交易狀態碼』值參考 |
msg | string | 核銷交易訊息 | |
finishtime | string | MYTIX交易完成時間(格式為YYYYMMDDHHmmss) | |
pay_token | string | 核銷交易碼(例:MYTIX12345678ABCDEFGH共21碼) | |
pos_trade_time | string | POS 端交易日期時間(格式為YYYYMMDDHHmmss) | |
pos_id | string | POS 機號或設備機號 | |
clerk_no | string | 收銀員代碼 | |
items | array | 消費票券項目 | 每筆『票券核銷線下交易產品資訊』欄位參考 |
reimbursement_from_type | int | 核銷點類型 | 『票券核銷點類型』值參考 |
reimbursement_store_uid | string | 核銷特約商店商務代號 | |
reimbursement_dealer_no | string | 自訂核銷點編號 | |
issuance_uid | string | 委託發行商商務代號 | |
reimbursement_order_id | string | 核銷店家訂單單號 | |
issue_invoice_state | int | 票券核銷發票開立類型 | 『票券核銷發票開立類型』值參考 |
invoice | object | 當發票開立類型為1自行開立時,需帶入相關cost | float |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券核銷線下交易產品資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商商務代號 | |
id | string | 票券產品編號 | |
material_code | string | 商品料號 | |
name | string | 票券名稱 | |
products | array | 產品金額資訊 | 每筆『票券核銷線下交易產品金額資訊』欄位參考 |
vouchers | array | 單張票券資訊 | 每筆『單張票券資訊』欄位參考 |
『票券核銷線下交易產品金額資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
amount | integer | 數量 | |
cost | float | 支付金額 | |
price | float | 票面價值 | |
total_cost | float | 購買單價小計 | |
total_price | float | 購買定價小計 |
『單張票券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
serial_no | string | 系統票券序號 | |
custom_serial_no | string | 自訂票券序號 | |
book_no | string | 票券本號 | |
sales_from_type | int | 銷售點類型 | 必填 『票券銷售點類型』值參考 |
sales_store_uid | string | 銷售特約商店商務代號 | sales_from_type=1為必填 |
sales_dealer_no | string | 自訂銷售點編號 | sales_from_type=2為必填 |
cost | float | 支付金額 | |
price | float | 票面價值 | |
memo | string | 券的備註 | |
invoice_mode | string | 發票何時開立 |
『票券核銷交易發票資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
number | string | 發票號碼 | |
date | string | 發票開立日期(格式:YYYYMMDDHHmmss) | |
cost | int | 發票開立金額 | |
detail | array | 發票明細資訊 | 每筆『票券核銷發票明細資訊』欄位參考 |
『票券核銷發票明細資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
description | string | 商品名稱 | |
quantity | int | 商品數量 | |
unit_price | float | 商品單價 | |
amount | float | 商品總價 |
『票券取消項目』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商商務代號 | |
id | string | 票券產品編號(最長限32 Bytes) | 必填 |
serial_no | string | 票券號碼 | 必填 |
『票券核銷交易取消查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 取消票券核銷交易UID | |
key | string | 交易驗証碼 | |
order_id | string | 票券核銷取消票券處理編號 | |
reverse_date | string | 取消核銷完成日期時間(格式為YYYYMMDDHHmmss) | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 | |
items | array | 查詢內容 | 每筆『取消票券核銷資訊回傳』欄位參考 |
『取消票券核銷資訊回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商 | |
id | string | 票券產品編號(最長限32 Bytes) | |
serial_no | string | 票券號碼 | |
custom_serial_no | string | 自訂票券序號 | |
cost | float | 購買單價 | |
price | float | 購買定價 | |
memo | string | 券的備註 | |
invoice_mode | int | 發票何時開立 | |
code | string | 狀態碼 | 『票券核銷交易取消狀態碼』值參考 |
msg | string | 狀態訊息 |
『退劵回傳細項資訊』值內容
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
url | string | 網址 | |
uid | string | 票券退券交易UID | |
key | string | 驗証碼 |
『發行商票券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
product_id | string | 票券產品編號(最長限32 Bytes)(唯一) 限英數字([a-zA-Z0-9]) 若此編號已經建立過,則只更新detail欄位內資訊 |
必填 |
area_type | integer | 適用區域類型(此欄位新增後無法異動) | 必填 『適用區域類型』值參考 |
is_paid | integer | 票券價值類型(此欄位新增後無法異動) | 必填 『票券價值類型』值參考 |
detail | object | 票券細部資訊 | 必填 『單店券資訊』欄位參考 『通用券資訊』欄位參考 『區域券資訊』欄位參考 |
『單店券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
is_on | integer | 上下架狀態 | 必填 『票券上下架狀態』值參考 |
is_gift | integer | 是否可轉贈 | 『票券是否可轉贈』值參考 |
material_code | string | 委託發行商的商品料號 | |
product_name | string | 票券名稱 | 必填 |
product_description | string | 票券產品敘述 | |
declaration | string | 宣告內容,只允許下列html tag,h6,ul,li,b | 必填 |
store_uid | string | 可核銷特約商店商務代號 | 必填 |
『通用券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
is_on | integer | 上下架狀態 | 必填 『票券上下架狀態』值參考 |
is_gift | integer | 是否可轉贈 | 『票券是否可轉贈』值參考 |
material_code | string | 委託發行商的商品料號 | |
product_name | string | 票券名稱 | 必填 |
product_description | string | 票券產品敘述 | |
declaration | string | 宣告內容,只允許下列html tag,h6,ul,li,b | 必填 |
『區域券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
is_on | integer | 上下架狀態 | 必填 『票券上下架狀態』值參考 |
is_gift | integer | 是否可轉贈 | 『票券是否可轉贈』值參考 |
material_code | string | 委託發行商的商品料號 | |
product_name | string | 票券名稱 | 必填 |
product_description | string | 票券產品敘述 | |
declaration | string | 宣告內容,只允許下列html tag,h6,ul,li,b | 必填 |
used_name | string | 群體名稱 | 必填 |
store_uids | array | 可核銷特約商店商務代號 | 必填 |
『發行商票券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 處理狀態碼 | 『發行商票券處理狀態碼』值參考 |
msg | string | 狀態說明 | |
product_id | string | 票券產品編號 |
『發行商票券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
area_type | integer | 適用區域類型 | 『適用區域類型』值參考 |
product_id | string | 票券產品編號 | |
is_paid | integer | 票券價值類型 | 『票券價值類型』值參考 |
detail | object | 『單店券資訊』欄位參考 『通用券資訊』欄位參考 『區域券資訊』欄位參考 |
『單店券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
is_on | integer | 上下架狀態 | 『票券上下架狀態』值參考 |
is_gift | integer | 是否可轉贈 | 『票券是否可轉贈』值參考 |
material_code | string | 委託發行商的商品料號 | |
product_name | string | 票券名稱 | |
product_description | string | 票券產品敘述 | |
declaration | string | 宣告內容 | |
store_uid | string | 可核銷特約商店商務代號 |
『通用券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
is_on | integer | 上下架狀態 | 『票券上下架狀態』值參考 |
is_gift | integer | 是否可轉贈 | 『票券是否可轉贈』值參考 |
material_code | string | 委託發行商的商品料號 | |
product_name | string | 票券名稱 | |
product_description | string | 票券產品敘述 | |
declaration | string | 宣告內容 |
『區域券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
is_on | integer | 上下架狀態 | 『票券上下架狀態』值參考 |
is_gift | integer | 是否可轉贈 | 『票券是否可轉贈』值參考 |
material_code | string | 委託發行商的商品料號 | |
product_name | string | 票券名稱 | |
product_description | string | 票券產品敘述 | |
declaration | string | 宣告內容 | |
used_name | string | 群體名稱 | |
store_uids | array | 可核銷特約商店商務代號 |
『商品細項』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
Description | string | 商品名稱 | 必填 |
Quantity | string | 數量 | 必填 |
UnitPrice | string | 單價 | 必填 |
Amount | string | 總金額 | 必填 |
『電子發票折讓資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 發生之退款交易UID | |
date | string | 發票折讓日期(YYYYMMDD) | |
amount | float | 電子發票折讓金額 | |
order_detail | string | 電子發票折讓明細(JSON格式) | 『商品細項』值參考 |
『票券轉贈回傳細項資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
url | string | 網址 | |
uid | string | 票券轉贈交易UID | |
key | string | 驗証碼 |
『票券轉贈簡訊通知』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 票券轉贈交易UID | |
key | string | 交易驗証碼 | |
order_id | string | 票券轉贈交易票券處理編號 | |
cellphone_code | string | 被轉贈者手機國碼 | |
cellphone | string | 被轉贈者手機號碼 | |
is_member | integer | 被轉贈票券是否為記名 | 『被轉贈票券是否為記名』值參考 |
gift_url | string | 不記名票券領取與使用網址 | |
items | array | 轉贈票券項目 | 每筆『票券轉贈交易產品資訊』欄位參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券轉贈交易產品資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
id | string | 票券產品編號 | |
name | string | 票券名稱 | |
material_code | string | 委託發行商的商品料號 | |
products | array | 產品金額資訊 | 每筆『票券轉贈交易產品金額資訊』欄位參考 |
『票券轉贈交易產品金額資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
amount | integer | 數量 | |
cost | float | 支付金額 | |
price | float | 票面價值 | |
total_cost | float | 支付金額小計 | |
total_price | float | 票面價值小計 |
『票券轉贈回傳細項資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
url | string | 網址 | |
uid | string | 票券轉贈交易UID | |
key | string | 驗証碼 |
『票券匣轉贈簡訊通知』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 票券匣交易UID | |
key | string | 交易驗証碼 | |
order_id | string | 票券匣處理編號 | |
sys_order_id | string | 票券匣轉贈交易票券處理編號 | |
cellphone_code | string | 被轉贈者手機國碼 | |
cellphone | string | 被轉贈者手機號碼 | |
is_member | integer | 被轉贈票券是否為記名 | 『被轉贈票券是否為記名』值參考 |
gift_url | string | 不記名票券領取與使用網址 | |
items | array | 轉贈票券項目 | 每筆『票券轉贈交易產品資訊』欄位參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券售出項目』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商商務代號 | 必填 |
no | string | 自訂票券號碼或本號 | 必填 |
cost | int | 售出時一張券或一本券的單價(若非整數,金額會強制轉換整數) 註:單位為券時,每張券的單價 單位為本時,會以本的單價,算自動算出「本」內的每張券的單價 |
|
trust_start_date | string | 票券履約保證起始日(格式:YYYYMMDD) | 必填 |
trust_end_date | string | 票券履約保證結束日(履約保證時間必須超過一年)(格式:YYYYMMDD) | 必填 |
trust_guarantee_date | string | 與消費者定型化契約結束日(格式:YYYYMMDD) | 必填 |
『票券售出交易發票資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
number | string | 發票號碼 | |
date | string | 發票開立日期(格式:YYYYMMDDHHmmss) |
『票券售出交易內容』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 票券銷售交易訂單UID | |
key | string | 交易驗証碼 | |
order_id | string | 票券銷售票券處理編號 | |
sales_date | string | 售出處理完成日期時間(格式為YYYYMMDDHHmmss) | |
items | array | 內容 | 每筆『票券售出資訊回傳』欄位參考 |
sales_order_id | string | 銷售店家訂單單號 | |
issue_invoice_state | int | 票券售出發票開立類型 | 『票券售出發票開立類型』值參考 |
invoice | object | 當發票開立類型為1自行開立時,需帶入相關資訊 | 『票券售出交易發票資訊』欄位參考 |
sales_from_type | int | 銷售點類型 | 『票券銷售點類型』值參考 |
sales_store_uid | string | 銷售特約商店商務代號 | |
sales_dealer_no | string | 自訂銷售點編號 | |
buyer_name | string | 買家名稱 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券售出資訊回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商 | |
unit_type | int | 單位類型 | 『票券實體券單位』值參考 |
no | string | 自訂票券號碼或本號碼 | |
memo | string | 本或券的備註 | |
invoice_mode | string | 本或券之發票何時開立 | |
ticket | object | 若單位為券時,票券資訊 | 『單位為券,票券資訊』欄位參考 |
book | array | 若單位為本時,票券資訊清單 | 每筆『單位為本,票券資訊』欄位參考 |
『單位為券,票券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
custom_serial_no | string | 自訂票券號碼 | |
serial_no | string | 系統票券號碼 | |
cost | float | 支付金額 | |
price | float | 票面價值 | |
trust_start_date | string | 票券履約保證起始日(格式:YYYYMMDD) | |
trust_end_date | string | 票券履約保證結束日(履約保證時間必須超過一年)(格式:YYYYMMDD) | |
trust_guarantee_date | string | 與消費者定型化契約結束日(格式:YYYYMMDD) |
『單位為本,票券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
custom_serial_no | string | 自訂票券號碼 | |
serial_no | string | 系統票券號碼 | |
cost | float | 支付金額 | |
price | float | 票面價值 | |
trust_start_date | string | 票券履約保證起始日(格式:YYYYMMDD) | |
trust_end_date | string | 票券履約保證結束日(履約保證時間必須超過一年)(格式:YYYYMMDD) | |
trust_guarantee_date | string | 與消費者定型化契約結束日(格式:YYYYMMDD) |
『票券售出取消項目』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商商務代號 | 必填 |
no | string | 自訂票券號碼或本號 | 必填 |
『票券售出交易取消查詢』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 取消票券售出交易訂單UID | |
key | string | 交易驗証碼 | |
order_id | string | 票券售出取消票券處理編號 | |
reverse_date | string | 取消售出完成日期時間(格式為YYYYMMDDHHmmss) | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 | |
items | array | 查詢內容 | 每筆『取消票券售出資訊回傳』欄位參考 |
『取消票券售出資訊回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商 | |
unit_type | int | 單位類型 | 『票券單位』值參考 |
no | string | 自訂票券號碼或本號碼 | |
memo | string | 本或券的備註 | |
invoice_mode | string | 本或券之發票何時開立 | |
ticket | object | 若單位為券時,票券資訊 | 『單位為券,票券資訊』欄位參考 |
book | array | 若單位為本時,票券資訊清單 | 每筆『單位為本,票券資訊』欄位參考 |
code | string | 狀態碼 | 『票券售出交易取消狀態碼』值參考 |
msg | string | 狀態訊息 |
『單位為券,票券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
custom_serial_no | string | 自訂票券號碼 | |
serial_no | string | 系統票券號碼 | |
book_no | string | 自訂票券本號 | |
sales_date | string | 售出處理完成日期時間(格式為YYYYMMDDHHmmss) | |
status | int | 取消售出前之票券狀態 | |
cost | float | 支付金額 | |
price | float | 票面價值 |
『單位為本,票券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
custom_serial_no | string | 自訂票券號碼 | |
serial_no | string | 系統票券號碼 | |
sales_date | string | 售出處理完成日期時間(格式為YYYYMMDDHHmmss) | |
status | int | 取消售出前之票券狀態 | |
cost | float | 支付金額 | |
price | float | 票面價值 |
『票券售出交易內容』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
uid | string | 票券銷售交易訂單UID | |
key | string | 交易驗証碼 | |
order_id | string | 票券銷售票券處理編號 | |
sales_date | string | 銷售處理完成日期時間(格式為YYYYMMDDHHmmss) | |
items | array | 內容 | 每筆『票券售出資訊回傳』欄位參考 |
sales_order_id | string | 銷售店家訂單單號 | |
issue_invoice_state | int | 票券售出發票開立類型 | 『票券售出發票開立類型』值參考 |
invoice | object | 當發票開立類型為1自行開立時,需帶入相關資訊 | 『票券售出交易發票資訊』欄位參考 |
trust_start_date | string | 票券履約保證起始日(格式:YYYYMMDD) | |
trust_end_date | string | 票券履約保證結束日(履約保證時間必須超過一年)(格式:YYYYMMDD) | |
sales_from_type | int | 銷售點類型 | 『票券銷售點類型』值參考 |
sales_store_uid | string | 銷售特約商店商務代號 | |
sales_dealer_no | string | 自訂銷售點編號 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券作廢項目』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商商務代號 | 必填 |
no | string | 自訂票券號碼或本號 | 必填 |
『票券作廢交易內容』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 票券作廢交易訂單UID | |
key | string | 交易驗証碼 | |
order_id | string | 票券作廢票券處理編號 | |
invalid_date | string | 作廢處理完成日期時間(格式為YYYYMMDDHHmmss) | |
items | array | 內容 | 每筆『票券作廢資訊回傳』欄位參考 |
book_used | array | 若單位為本時,作廢失敗且原因為票券有使用過之票券清單 (一本如果有一張被使用就不能作廢) |
每筆『單位為本時,有使用過之票券清單』欄位參考 |
invalid_from_type | int | 作廢點類型 | 『票券作廢點類型』值參考 |
invalid_store_uid | string | 作廢特約商店商務代號 | |
invalid_dealer_no | string | 自訂作廢點編號 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券作廢資訊回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商 | |
unit_type | int | 單位類型 | 『票券實體券單位』值參考 |
no | string | 自訂票券號碼或本號碼 | |
ticket | object | 若單位為券時,作廢成功票券資訊 | 『票券作廢資訊回傳』欄位參考 |
book | array | 若單位為本時,作廢成功票券資訊清單 | 每筆『單位為本,作廢成功票券資訊』欄位參考 |
『單位為本時,有使用過之票券清單』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
book_no | string | 本號 | |
items | array | 已使用券資訊 | 每筆『單位為本時,有使用過之票券清單』欄位參考 |
『票券作廢資訊回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
status | int | 作廢前之票券狀態 | |
custom_serial_no | string | 自訂票券號碼 | |
serial_no | string | 系統票券號碼 | |
sales_from_type | int | 銷售點類型 | 『票券銷售點類型』值參考 |
sales_store_uid | string | 銷售特約商店商務代號 | |
sales_dealer_no | string | 自訂銷售點編號 | |
cost | float | 支付金額 | |
price | float | 票面價值 |
『單位為本,作廢成功票券資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
status | int | 作廢前之票券狀態 | |
custom_serial_no | string | 自訂票券號碼 | |
serial_no | string | 系統票券號碼 | |
sales_from_type | int | 銷售點類型 | 『票券銷售點類型』值參考 |
sales_store_uid | string | 銷售特約商店商務代號 | |
sales_dealer_no | string | 自訂銷售點編號 | |
cost | float | 支付金額 | |
price | float | 票面價值 |
『單位為本時,有使用過之票券清單』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
custom_serial_no | string | 自訂票券號碼 | |
serial_no | string | 系統票券號碼 | |
sales_from_type | int | 銷售點類型 | 『票券銷售點類型』值參考 |
sales_store_uid | string | 銷售特約商店商務代號 | |
sales_dealer_no | string | 自訂銷售點編號 | |
reimbursement_from_type | int | 核銷點類型 | 『票券核銷點類型』值參考 |
reimbursement_store_uid | string | 核銷特約商店商務代號 | |
reimbursement_dealer_no | string | 自訂核銷點編號 | |
cost | float | 支付金額 | |
price | float | 票面價值 |
『票券作廢交易內容』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
uid | string | 票券作廢交易訂單UID | |
key | string | 交易驗証碼 | |
order_id | string | 票券作廢票券處理編號 | |
invalid_date | string | 作廢處理完成日期時間(格式為YYYYMMDDHHmmss) | |
items | array | 內容 | 每筆『票券作廢資訊回傳』欄位參考 |
book_used | array | 若單位為本時,作廢失敗且原因為票券有使用過之票券清單 (一本如果有一張被使用就不能作廢) |
每筆『單位為本時,有使用過之票券清單』欄位參考 |
invalid_from_type | int | 作廢點類型 | 『票券作廢點類型』值參考 |
invalid_store_uid | string | 作廢特約商店商務代號 | |
invalid_dealer_no | string | 自訂作廢點編號 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券狀態查詢項目』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商商務代號 | 必填 |
no | string | 自訂票券號碼或本號 | 必填 |
『票券狀態資訊回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
issuance_uid | string | 委託發行商 | |
unit_type | int | 單位類型 | 『票券實體券單位』值參考 |
no | string | 自訂票券號碼或本號碼 | |
memo | string | 本或券的備註 | |
invoice_mode | string | 本或券之發票何時開立 | |
ticket | object | 若單位為券時,票券資訊 | 『單位為券-票券資訊回傳』欄位參考 |
book | array | 若單位為本時,票券資訊清單 | 每筆『單位為本-每張票券資訊回傳』欄位參考 |
『單位為券-票券資訊回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
status | int | 票券狀態 | 『票券流程狀態碼』值參考 |
custom_serial_no | string | 自訂票券號碼 | |
serial_no | string | 系統票券號碼 | |
book_no | string | 自訂票券本號 | |
sales_from_type | int | 銷售點類型 | 『票券銷售點類型』值參考 |
sales_store_uid | string | 銷售特約商店商務代號 | |
sales_dealer_no | string | 自訂銷售點編號 | |
reimbursement_from_type | int | 核銷點類型 | 『票券核銷點類型』值參考 |
reimbursement_store_uid | string | 核銷特約商店商務代號 | |
reimbursement_dealer_no | string | 自訂核銷點編號 | |
invalid_from_type | int | 作廢點類型 | 『票券作廢點類型』值參考 |
invalid_store_uid | string | 作廢特約商店商務代號 | |
invalid_dealer_no | string | 自訂作廢點編號 | |
cost | float | 支付金額 | |
price | float | 票面價值 | |
trust_start_date | string | 票券履約保證起始日(格式:YYYYMMDD) | |
trust_end_date | string | 票券履約保證結束日(履約保證時間必須超過一年)(格式:YYYYMMDD) | |
trust_guarantee_date | string | 與消費者定型化契約結束日(格式:YYYYMMDD) | |
is_paid | int | 票券價值類型 | 『票券價值類型』值參考 |
『單位為本-每張票券資訊回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
status | int | 票券狀態 | 『票券流程狀態碼』值參考 |
custom_serial_no | string | 自訂票券號碼 | |
serial_no | string | 系統票券號碼 | |
sales_from_type | int | 銷售點類型 | 『票券銷售點類型』值參考 |
sales_store_uid | string | 銷售特約商店商務代號 | |
sales_dealer_no | string | 自訂銷售點編號 | |
reimbursement_from_type | int | 核銷點類型 | 『票券核銷點類型』值參考 |
reimbursement_store_uid | string | 核銷特約商店商務代號 | |
reimbursement_dealer_no | string | 自訂核銷點編號 | |
invalid_from_type | int | 作廢點類型 | 『票券作廢點類型』值參考 |
invalid_store_uid | string | 作廢特約商店商務代號 | |
invalid_dealer_no | string | 自訂作廢點編號 | |
cost | float | 支付金額 | |
price | float | 票面價值 | |
trust_start_date | string | 票券履約保證起始日(格式:YYYYMMDD) | |
trust_end_date | string | 票券履約保證結束日(履約保證時間必須超過一年)(格式:YYYYMMDD) | |
trust_guarantee_date | string | 與消費者定型化契約結束日(格式:YYYYMMDD) | |
is_paid | int | 票券價值類型 | 『票券價值類型』值參考 |
『票券發票開立資訊指令』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
type | int | 開立指令 | 『發票指令模式』值參考 |
content | object | 票券發票開立資訊 | 『票券發票開立資訊』欄位參考 |
『票券發票作廢資訊指令』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
type | int | 作廢指令 | 『發票指令模式』值參考 |
content | object | 票券發票作廢資訊 | 『票券發票作廢資訊』欄位參考 |
『票券發票折讓資訊指令』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
type | int | 折讓指令 | 『發票指令模式』值參考 |
content | object | 票券發票折讓資訊 | 『票券發票開立資訊』欄位參考 |
『票券狀態資訊回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 票券發票資訊回報交易訂單UID | |
key | string | 交易驗証碼 | |
order_id | string | 票券發票資訊回報處理編號(唯一) | |
invoice_mode | int | 發票何時開立 | 『發票何時開立』值參考 |
issue_invoice_state | int | 發票誰開立 | 『票券發票資訊回報』值參考 |
order_uid | string | 售出交易訂單UID或核銷交易訂單UID | |
order_key | string | 售出交易驗証碼或核銷交易驗證碼 | |
items | array | 發票資訊回報 開立時間/作廢時間/折讓時間需注意合理順序 |
每筆『票券發票開立資訊指令』欄位參考 每筆『票券發票作廢資訊指令』欄位參考 每筆『票券發票折讓資訊指令』欄位參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券狀態資訊回傳』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
uid | string | 票券發票資訊回報交易訂單UID | |
key | string | 交易驗証碼 | |
order_id | string | 票券發票資訊回報處理編號(唯一) | |
invoice_mode | int | 發票何時開立 | 『發票何時開立』值參考 |
issue_invoice_state | int | 發票誰開立 | 『票券發票資訊回報』值參考 |
order_uid | string | 售出交易訂單UID或核銷交易訂單UID | |
order_key | string | 售出交易驗証碼或核銷交易驗證碼 | |
items | array | 發票資訊回報 開立時間/作廢時間/折讓時間需注意合理順序 |
每筆『票券發票開立資訊指令』欄位參考 每筆『票券發票作廢資訊指令』欄位參考 每筆『票券發票折讓資訊指令』欄位參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『票券發票開立資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
number | string | 發票號碼 | |
date | string | 發票開立日期(格式:YYYYMMDDHHmmss) | |
cost | int | 發票開立金額 | |
detail | array | 發票明細資訊 | 每筆『票券售出發票明細資訊』欄位參考 |
『票券發票作廢資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
number | string | 發票號碼 | |
date | string | 發票作廢日期(格式:YYYYMMDDHHmmss) |
『票券發票開立資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
number | string | 發票號碼 | |
date | string | 發票折讓日期(格式:YYYYMMDDHHmmss) | |
cost | int | 折讓總金額 | |
detail | array | 折讓明細資訊 | 每筆『票券售出發票明細資訊』欄位參考 |
『票券售出發票明細資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
description | string | 商品名稱 | |
quantity | int | 商品數量 | |
unit_price | float | 商品單價 | |
amount | float | 商品總價 |
值的定義
『是否為預發行』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 即時發行(預設) |
『票券執行狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
100 | string | 資料不正確 | |
400 | string | 系統錯誤 | |
B200 | string | 執行成功 | |
B500 | string | 執行失敗 |
『購買票券交易狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
100 | string | 資料不正確 | |
200 | string | 資料正確 | |
210 | string | 交易處理中 | |
250 | string | 交易成功 | |
260 | string | 交易進行中(超商代碼繳費) | |
270 | string | 交易進行中(虛擬帳號) | |
280 | string | 交易進行中(WEBATM等導頁式交易) | |
290 | string | 交易成功,但金額不符 | |
300 | string | 交易失敗 | |
380 | string | 交易逾時 | |
400 | string | 系統錯誤 | |
500 | string | 中斷交易(閘道) | |
600 | string | 交易成功且結帳 (信用卡) | |
A0001 | string | 中斷交易(金流) | |
A0002 | string | 未完成交易 |
『票券服務(一般票券)記名類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 記名票券(預設) | |
2 | integer | 不記名票券 |
『票券服務(月費)記名類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 記名票券(預設) |
『適用區域類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 單店券(預設) | |
2 | integer | 通用券 | |
3 | integer | 區域券 |
『票券服務(月費)適用區域類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 單店券(預設) | |
2 | integer | 通用券 | |
3 | integer | 區域券 |
『票券服務(課程)記名類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 記名票券(預設) |
『票券服務(課程)適用區域類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 單店券(預設) | |
2 | integer | 通用券 | |
3 | integer | 區域券 |
『票券服務(貨運)記名類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
2 | integer | 不記名票券(預設) |
『票券服務(貨運)適用區域類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 單店券(預設) |
『票券交易狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
250 | string | 核銷成功 | |
300 | string | 核銷失敗 |
『票券核銷點類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | int | MYTIX特約商店(預設) | |
2 | int | 自訂核銷點編號 |
『票券核銷發票開立類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | int | 不開立(預設) | |
1 | int | 自行開立 |
『票券核銷交易取消狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
250 | string | 取消核銷成功 | |
300 | string | 取消核銷失敗 |
『Qrcode內容模式』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
2 | string | Token字串 | |
1 | string | JSON格式(預設) |
『票券顯示模式』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | string | 以委託發行商顯示票券 | |
2 | string | 以可核銷之特約商店顯示票券 |
『票券價值類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 有償 | |
0 | integer | 無償 |
『發行商票券處理狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
250 | string | 建立成功 | |
251 | string | 修改成功 | |
300 | string | 建立失敗 | |
301 | string | 修改失敗 |
『票券上下架狀態』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 上架(預設) | |
0 | integer | 下架 |
『票券是否可轉贈』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 可轉贈(預設) | |
0 | integer | 不可轉贈 |
『查詢發行商票券』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 指定票券產品編號(預設) | |
2 | integer | 只有上架票券 | |
3 | integer | 所有票券 |
『票券電子發票開立狀態類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 不處理或已無效(預設) | |
1 | integer | 等候處理中 | |
2 | integer | 發票開立成功 | |
3 | integer | 發票開立失敗(系統或特約商店發票相關設定不正確) | |
5 | integer | 發票開立失敗(系統發生錯誤) |
『電子發票稅率別』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 應稅(預設) | |
2 | integer | 零稅率 | |
3 | integer | 免稅 |
『電子發票開立類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 未使用電子發票開立 | |
1 | integer | 雲端發票 | |
2 | integer | 發票捐贈 | |
3 | integer | 實體發票 |
『雲端發票類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | integer | 未使用雲端發票類型 | |
2 | integer | 手機條碼 | |
3 | integer | 自然人憑證條碼 | |
4 | integer | 以E-Mail寄送 |
『票券顯示模式』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | string | 以委託發行商顯示票券 |
『被轉贈票券是否為記名』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 是 | |
0 | integer | 不是 |
『票券顯示模式』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | string | 以委託發行商顯示票券 |
『票券銷售點類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | int | MYTIX特約商店(預設) | |
2 | int | 自訂銷售點編號 |
『票券售出票券掃碼方式』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | int | 以本或券單一掃碼方式(預設) | |
2 | int | 掃碼首券表示整本券方式 |
『票券售出發票開立類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | int | 不開立(預設) | |
1 | int | 自行開立 |
『票券執行狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
100 | string | 資料不正確 | |
400 | string | 系統錯誤 | |
B200 | string | 執行成功 | |
B500 | string | 執行失敗 | |
B501 | string | 執行失敗,資料不正確 |
『票券實體券單位』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | int | 券 | |
2 | int | 本 |
『票券單位』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
0 | int | 無法辨識 | |
1 | int | 券 | |
2 | int | 本 |
『票券售出交易取消狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
250 | string | 取消售出成功 | |
300 | string | 取消售出失敗 |
『票券作廢點類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | int | MYTIX特約商店(預設) | |
2 | int | 自訂作廢點編號 |
『票券流程狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | int | 建立 | |
2 | int | 綁定 | |
3 | int | 轉贈 | |
4 | int | 售出 | |
5 | int | 作廢 | |
31 | int | 票券核銷 | |
32 | int | 票券移轉 | |
33 | int | 票券退券 | |
34 | int | 退款進行中 | |
35 | int | 轉贈進行中 |
『發票何時開立』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
2 | int | 票券售出時開立 | |
3 | int | 票券核銷時開立 |
『票券發票資訊回報』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | int | 自行開立 |
『發票指令模式』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
2 | int | 開立 | |
3 | int | 作廢 | |
4 | int | 折讓 |
附錄一:PFN(支付工具)參數表
資料傳遞可使用編號,也可以使用代碼 。 例如:pfn=4跟pfn=WEBATM,一樣都是使用WEBATM線上付款支付工具。
編號 | 代碼 | 狀態 | 說明 |
---|---|---|---|
1 | CREDITCARD | 啟用 | 信用卡 |
3 | CSTORECODE | 啟用 | 超商代碼 |
4 | WEBATM | 啟用 | WEBATM |
6 | E_COLLECTION | 啟用 | 虛擬帳號 (ATM轉帳) |
附錄三:設定調整
- 交易回傳設定
- 交易金鑰重新發送與變更
附錄四:資料加密方式說明
- 所有的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方式傳遞資料到MYTIX, 並且得到回傳結果。