NAV
php csharp java javascript python

修改歷程

版本 異動日期 修訂內容 位置
1.0 2023.04.20 初版
1.1 2023.05.23 增加系統回報 20230523_01
1.2 2023.05.26 增加訂單查詢 20230526_01
1.3 2023.07.10 1.修正文件錯誤,service內的cmd應該是全小寫,誤植到大寫
2.增加直接建立請款單api
誤植到大寫_01
誤植到大寫_02
直接建立請款單api
1.4 2023.08.07 增加請款單延期 20230807_01
1.5 2023.09.18 1.請款單增加自訂參數
2.請款單回應調整回應格式
3.查詢請款單請求參數調整,回應格式調整
4.直接建立請款單增加自訂參數
5.直接建立請款單回應調整回應格式
6.請款單延期調整請求參數
20230918_01
20230918_02
20230918_03
20230918_04
20230918_05
20230918_06

開發前請先閱讀

金鑰的注意事項

Q:金鑰的有效期限

A:MyPay的金鑰有效期限只有一年,如果要延長,請自行至金鑰管理系統延長

Q:金鑰可以在什麼時候延長

A:到期日7天前,都可以延長(不包含第7天),一但超過,系統自動產生新金鑰後,即不可再延長

Q:金鑰即將到期前7天時,系統新發的金鑰是否會於信件中夾帶

A:會

Q:金鑰在到期前何時會發信通知

A:定期發送金鑰到期通知的頻率為:60天/30天/20天,若 貴司皆無動作,則系統會於到期前七天產製新金鑰並發送email到 貴司技術窗口信箱,此時舊的金鑰,因還未過期還可以使用,一旦過期,貴司仍使用舊金鑰則會無法交易

請款單結果的告知

Q:何時會給予請款單結果

A:請款單將在接收請求建立、付款完成、過期等狀態後,會由附錄三這邊的設定,背景主動發動通知商家

Q:當我接到請款單通知時該做什麼

A:請直接回應8888,如沒有回應,MyPay會通知5次,若5次內均得不到8888,系統會寄發信件給予商家的技術人員以及附錄三而外設定的人員

Q:請款單背景通知相關欄位

A:請查看請款單背景通知

支付工具注意事項

Q:目前支援的支付工具為何

A:目前僅支援信用卡及虛擬帳號

Q:虛擬帳號是否有可能造成重複付款或金額不符

A:代收的部分,不會造成此問題,如果非代收則要看店家與銀行端的申請

請款系統設計概要

安全性設計

所有的請求發動都僅能從特約商店的網頁伺服器發出請求,將傳輸的資料以AES加密,再透過HTTPS加密傳輸。

資料驗證

交易參數中有一組由雜湊函式運算出的驗証碼,作為資料驗証用,以確保資料正確性。

系統架構

所有的請求與查詢只能透過伺服器發動,由特約商店的網頁伺服器利用伺服端服務程式發動請求,以避免請求資料被竄改或攔截。為確保安全,請款單系統僅能接受 https connection,注意僅接受TLS1.2以上協定。

請款系統目前提供之服務與格式

請款系統提供應用方式,應用情境如下:

(1)請求建立請款單網址:發動端無須自建請款畫面,由Mypay提供畫面,當發動後,會給予請款單頁面網址。

(2)請求查詢請款單網址:查詢請款單。

(3)請求直接建立請款單網址:無需進到Mypay提供的畫面設定請款資料,直接產生請款單。

(4)請求請款單請款時間延長:請款時間已過期,不想成立新單,可呼叫此功能,將原本的請款單,請款時間延長,需注意,如使用虛擬帳號,則舊的匯款帳號將會失效,會重新產生一組新的

(5)請款單背景通知:系統接收到請款單建立或請款單狀態變更時,會透過在系統後台的通知網址,進行通知

我們提供介接方式是透過https連線,只接受POST方式傳送請求資料。

介接網址

特約商店模式

位置 API介接網址
測試區 https://pay.usecase.cc/api/init
正式區 https://ka.mypay.tw/api/init

資料加密方式

AES 256編碼 + base64編碼(附錄四資料加密方式)

加密金鑰

金鑰會透過mail發送,也可從管理後台取得

文字編碼

一律使用UTF-8相容編碼

請求建立請款單

<?php

final class StoreCompanyInvoiceCreator
{
    /**
     * 特約商店商務代號
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     * @var string
     */
    public $storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/init";

    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }

    /**
     * 資料 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['store_uid'] = $this->storeUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->storeKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->storeKey);
        return $postData;
    }

    /**
     * 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;
    }

    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/companyInvoiceCreator'
        );
    }

    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['store_order_id'] = time();

        return $rawData;
    }
}

$StoreCompanyInvoiceCreator = new StoreCompanyInvoiceCreator();
$StoreCompanyInvoiceCreator->run();
?>
const crypto = require('crypto');
const httpRequest = require('https');

/**
 * 特約商店串接-請款單建立
 */
function StoreCompanyInvoiceCreate() {
  // 特約商店商務代號
  this.storeUid = "289151880002";
  // 特約商店金鑰或認證碼
  this.storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
  // 串接交易位置
  this.url = "https://pay.usecase.cc/api/init";
};
/**
 * 取得串接欄位資料
 */
StoreCompanyInvoiceCreate.prototype.getRawData = function () {
  return {
    store_uid: this.storeUid,
    store_order_id: 1685000506,

  };
};
/**
 * 取得服務位置
 */
StoreCompanyInvoiceCreate.prototype.getService = function () {
  return {
    service_name: "api",
    cmd: "api/companyInvoiceCreator"
  };
};
/**
 * AES 256 加密
 */
StoreCompanyInvoiceCreate.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 到主機
 */
StoreCompanyInvoiceCreate.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();
  });
};
/**
 * 取得送出欄位資料
 */
StoreCompanyInvoiceCreate.prototype.getPostData = function () {
  return {
    "store_uid": this.storeUid,
    "service": this.encrypt(this.getService(), this.storeKey),
    "encry_data": this.encrypt(this.getRawData(), this.storeKey)
  };
};
/**
 * 執行
 */
StoreCompanyInvoiceCreate.prototype.run = async function () {
  json = await this.post(this.getPostData())
  console.log(json);
};

StoreCompanyInvoiceCreate = new StoreCompanyInvoiceCreate();
StoreCompanyInvoiceCreate.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 StoreCompanyInvoiceCreate {
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     */
    String storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/init";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        StoreCompanyInvoiceCreate simulator = new StoreCompanyInvoiceCreate();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

    @SuppressWarnings(value = { "unchecked", "deprecation" })
    /**
     * 取得串接欄位資料
     * @return 串接原始資料
     */
    public Map getRawData() {

        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("store_uid", this.storeUid);
        rawData.put("store_order_id", 1685000506);

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/companyInvoiceCreator");
        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.storeKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.storeKey), "UTF-8");

            postData = "store_uid=" + this.storeUid + "&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 StoreCompanyInvoiceCreate {
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";
        /// <summary>
        /// 特約商店金鑰或認證碼
        /// </summary>
        public string storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/init";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            StoreCompanyInvoiceCreate simulator = new StoreCompanyInvoiceCreate();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

            System.Console.WriteLine(result);
        }
        /// <summary>
        /// 取得串接欄位資料
        /// </summary>
        private dynamic GetRawData() {

            dynamic rawData = new ExpandoObject();
            rawData.store_uid = this.storeUid;
            rawData.store_order_id =  1685000506;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/companyInvoiceCreator";
            return rawData;
        }
        /// <summary>
        /// 取得送出欄位資料
        /// </summary>
        private NameValueCollection GetPostData() {
            string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
            string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整

            //產生AES向量
            var IV = GetBytesIV();

            //進行加密
            var data_encode = Encrypt(data_json, this.storeKey, IV);
            var svr_encode = Encrypt(svr_json, this.storeKey, IV);

            //請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
            //若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
            string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
            string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);

            NameValueCollection postData = new NameValueCollection();
            postData["store_uid"] = this.storeUid;
            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; }
    }
}
# -*- 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 StoreCompanyInvoiceCreate:
    # 特約商店商務代號
    storeUid = "289151880002"
    # 特約商店金鑰或認證碼
    storeKey = b"KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/init"

    def getRawData(self):
        """取得串接欄位資料

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'store_order_id': 1685000506,
        }
        return rawData

    def getService(self):
        """取得服務位置

        Returns:
            {dict}: 服務位置資料
        """
        return {
            'service_name': 'api',
            'cmd': 'api/companyInvoiceCreator'
        }

    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 = {
            'store_uid': self.storeUid,
            'service': self.encrypt(self.getService(), self.storeKey),
            'encry_data': self.encrypt(self.getRawData(), self.storeKey)
        }
        return postData

    def run(self):
        """執行
        """
        json = self.post(self.getPostData())
        print(json)

StoreCompanyInvoiceCreate = StoreCompanyInvoiceCreate()
StoreCompanyInvoiceCreate.run()

回傳 JSON 結構如下:

{
  "code": "B200",
  "msg": "執行成功",
  "resultData": {
    "code": "A0000",
    "msg": "成功",
    "store_order_id": "1695018535",
    "order_uid": "f8f315d97d",
    "key": "4703cc1c17a2d501fe319c7f3728b779",
    "url": "https:\/\/pay.usecase.cc\/companyinvoice\/creator\/f8f315d97d.html",
    "echo_0": "",
    "echo_1": "",
    "echo_2": "",
    "echo_3": "",
    "echo_4": ""
  }
}

發動請求後,得到URL,倒轉到該URL頁面讓操作者確認或修改該請款單是否正確。

特約商店『建立請款單』參數說明

欄位 型態 說明
store_uid string(16) 特約商店商務代號
service text {"service_name": "api", "cmd": "api\/companyinvoicecreator"}
JSON格式,AES256加密資料
encry_data text 『建立請款單』欄位參考
JSON格式,AES256加密資料

『建立請款單』欄位

參數名稱 型態 說明 必須
store_uid string (16) 請款方商務代號 必填
buy_store_uid string (16) 購買方商務代號(不一定有) 非必填
store_order_id string 客戶自訂請款單號,不可重複 必填
tong_bian string(10) 賣方統編 非必填
company_name string(20) 賣方公司名稱 非必填
company_trl string(20) 賣方公司電話 非必填
sales_name string(20) 賣方負責業務姓名 非必填
sales_phone string(10) 賣方負責業務手機 非必填
sales_tel string(12) 賣方負責業務電話 非必填
sales_mail string(50) 賣方負責業務email 非必填
buy_company_tong_bian string(10) 買方統編 非必填
buy_company_name string(20) 買方公司名稱 非必填
buy_company_tel string(20) 買方公司電話 非必填
buy_name string(20) 買方業務姓名 非必填
buy_phone string(10) 買方業務手機 非必填
buy_tel string(10) 買方業務電話 非必填
buy_mail string(50) 買方業務mail 非必填
date_start string 請款起始日
格式:YYYY-MM-DD
非必填
date_end string 請款截止日
格式:YYYY-MM-DD
非必填
create_type integer(2) 發票先開後開,預設 0 非必填
『發票開立先後順序』設定值
product_tax_type integer(2) 商品價格是否含稅,預設 1 非必填
『資料含不含稅』設定值
tax_type integer(2) 營業稅,預設 1 非必填
『發票稅率別』設定值
tax string(5) 稅額 非必填
pay_mode array 付款方式 非必填
使用前請先確認與MyPay的簽約是否有該項支付工具
『付款方式』設定值
product_detail array 請款項目 非必填
『請款項目資料』欄位
discount_type integer(2) 折扣方式,預設0 非必填
『折扣類型』設定值
discount integer(7) 折扣方式,預設0 非必填
不可有小數,如果是減價0以上都可,如果是折扣0~100
memo string(255) 備註 非必填
echo_0 string(500) 自訂回傳參數 1 非必填
echo_1 string(500) 自訂回傳參數 2 非必填
echo_2 string(500) 自訂回傳參數 3 非必填
echo_3 string(500) 自訂回傳參數 4 非必填
echo_4 string(500) 自訂回傳參數 5 非必填

『請款單建立』回傳欄位

參數名稱 型態 說明 必須
code string 請求回傳碼 『執行狀態碼』值參考
msg string 代碼訊息
resultData object 執行結果 『請款單建立結果』欄位參考

『請款單建立結果』欄位

參數名稱 型態 說明 必須
code string 執行結果回傳代碼 『請款單建立回應代碼』值參考
msg string 執行結果錯誤訊息
store_order_id string 商店訂單編號
order_uid string 回傳請款單系統提供單號
key string 驗證碼
url string 請款單輸入介面網址
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『請款單建立回應代碼』值內容

型態 說明 備註
A0000 string 成功
A0001 string 客戶自訂請款單號重複
A0002 string 失敗
A0003 string 發票備註超過70個字

查詢請款單

發動請求後,取得請款單的目前資訊。

<?php

/**
 * 特約商店串接-查詢請款單
 */
final class StoreCompanyInvoiceInquire
{
    /**
     * 特約商店商務代號
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     * @var string
     */
    public $storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/init";

    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }

    /**
     * 資料 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['store_uid'] = $this->storeUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->storeKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->storeKey);
        return $postData;
    }

    /**
     * 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;
    }

    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/companyInvoiceInquiry'
        );
    }

    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['page_code'] = "1cf169f897";
        $rawData['store_order_id'] = "2023041800001";

        return $rawData;
    }
}

$StoreCompanyInvoiceInquire = new StoreCompanyInvoiceInquire();
$StoreCompanyInvoiceInquire->run();
?>
const crypto = require('crypto');
const httpRequest = require('https');

/**
 * 特約商店串接-查詢請款單
 */
function StoreCompanyInvoiceInquire() {
    // 特約商店商務代號
    this.storeUid = "289151880002";
    // 特約商店金鑰或認證碼
    this.storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    // 串接交易位置
    this.url = "https://pay.usecase.cc/api/init";
};
/**
 * 取得串接欄位資料
 */
StoreCompanyInvoiceInquire.prototype.getRawData = function () {
    return {
        store_uid: this.storeUid,
        page_code: "1cf169f897",
        store_order_id: "2023041800001",

    };
};
/**
 * 取得服務位置
 */
StoreCompanyInvoiceInquire.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/companyInvoiceInquiry"
    };
};
/**
 * AES 256 加密
 */
StoreCompanyInvoiceInquire.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 到主機
 */
StoreCompanyInvoiceInquire.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();
    });
};
/**
 * 取得送出欄位資料
 */
StoreCompanyInvoiceInquire.prototype.getPostData = function () {
    return {
        "store_uid": this.storeUid,
        "service": this.encrypt(this.getService(), this.storeKey),
        "encry_data": this.encrypt(this.getRawData(), this.storeKey)
    };
};
/**
 * 執行
 */
StoreCompanyInvoiceInquire.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

StoreCompanyInvoiceInquire = new StoreCompanyInvoiceInquire();
StoreCompanyInvoiceInquire.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 StoreCompanyInvoiceInquire {
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     */
    String storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/init";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        StoreCompanyInvoiceInquire simulator = new StoreCompanyInvoiceInquire();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

    @SuppressWarnings(value = { "unchecked", "deprecation" })
    /**
     * 取得串接欄位資料
     * @return 串接原始資料
     */
    public Map getRawData() {

        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("store_uid", this.storeUid);
        rawData.put("page_code", "1cf169f897");
        rawData.put("store_order_id", "2023041800001");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/companyInvoiceInquiry");
        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.storeKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.storeKey), "UTF-8");

            postData = "store_uid=" + this.storeUid + "&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 StoreCompanyInvoiceInquire {
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";
        /// <summary>
        /// 特約商店金鑰或認證碼
        /// </summary>
        public string storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/init";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            StoreCompanyInvoiceInquire simulator = new StoreCompanyInvoiceInquire();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

            System.Console.WriteLine(result);
        }
        /// <summary>
        /// 取得串接欄位資料
        /// </summary>
        private dynamic GetRawData() {

            dynamic rawData = new ExpandoObject();
            rawData.store_uid = this.storeUid;
            rawData.page_code =  "1cf169f897";
            rawData.store_order_id =  "2023041800001";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/companyInvoiceInquiry";
            return rawData;
        }
        /// <summary>
        /// 取得送出欄位資料
        /// </summary>
        private NameValueCollection GetPostData() {
            string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
            string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整

            //產生AES向量
            var IV = GetBytesIV();

            //進行加密
            var data_encode = Encrypt(data_json, this.storeKey, IV);
            var svr_encode = Encrypt(svr_json, this.storeKey, IV);

            //請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
            //若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
            string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
            string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);

            NameValueCollection postData = new NameValueCollection();
            postData["store_uid"] = this.storeUid;
            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; }
    }
}
# -*- 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 StoreCompanyInvoiceInquire:
    # 特約商店商務代號
    storeUid = "289151880002"
    # 特約商店金鑰或認證碼
    storeKey = b"KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/init"

    def getRawData(self):
        """取得串接欄位資料

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'page_code': "1cf169f897",
            'store_order_id': "2023041800001",
        }
        return rawData

    def getService(self):
        """取得服務位置

        Returns:
            {dict}: 服務位置資料
        """
        return {
            'service_name': 'api',
            'cmd': 'api/companyInvoiceInquiry'
        }

    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 = {
            'store_uid': self.storeUid,
            'service': self.encrypt(self.getService(), self.storeKey),
            'encry_data': self.encrypt(self.getRawData(), self.storeKey)
        }
        return postData

    def run(self):
        """執行
        """
        json = self.post(self.getPostData())
        print(json)

StoreCompanyInvoiceInquire = StoreCompanyInvoiceInquire()
StoreCompanyInvoiceInquire.run()

回傳 JSON 結構如下:

{
  "code": "B200",
  "msg": "執行成功",
  "resultData": {
    "code": "A0000",
    "msg": "成功",
    "page_code": "87950ffc60",
    "store_uid": "289151880026",
    "key": "c9715ac2bcb631e392252b0992f84dae",
    "buy_store_uid": "",
    "state": "3",
    "store_order_id": "1695008080",
    "tong_bian": "28915188",
    "company_name": "高鉅科技股份有限公司",
    "company_tel": "04-2322-0267",
    "sales_name": "李逍遙",
    "sales_tel": "04-2322-0267#11",
    "sales_phone": "0911111111",
    "sales_mail": "[email protected]",
    "buy_company_tong_bian": "04541302",
    "buy_company_name": "FG",
    "buy_company_tel": "01-11111111",
    "buy_name": "趙靈兒",
    "buy_phone": "0922222222",
    "buy_tel": "",
    "buy_mail": "[email protected]",
    "date_start": "2023-09-18",
    "date_end": "2023-10-18",
    "create_type": "1",
    "product_tax_type": "1",
    "tax_type": "1",
    "tax": "0.05",
    "pay_mode": [
      "CREDITCARD"
    ],
    "final_pay_mode": "CREDITCARD",
    "product_detail": [
      {
        "name": "螺絲",
        "price": "0.1",
        "selling_price": "0.1",
        "quantity": "12"
      },
      {
        "name": "螺絲2",
        "price": "1.1",
        "selling_price": "1.1",
        "quantity": "12"
      }
    ],
    "discount_type": "0",
    "discount": "0",
    "total_discount_amount": "0",
    "sales_amount": "13",
    "tax_amount": "1",
    "total_amount": "14",
    "memo": "0",
    "invoice_date": "2023-09-18 11:36:45",
    "invoice_number": "TG00000073",
    "invoice_detail": [
      {
        "Description": "螺絲",
        "Quantity": "12",
        "UnitPrice": "0.1",
        "Amount": 1.2000000000000002
      },
      {
        "Description": "螺絲2",
        "Quantity": "12",
        "UnitPrice": "1.1",
        "Amount": 13.200000000000001
      },
      {
        "description": "螺絲",
        "quantity": 12,
        "unit_price": 0,
        "amount": 1
      },
      {
        "description": "螺絲2",
        "quantity": 12,
        "unit_price": 1,
        "amount": 13
      }
    ],
    "cash_order": [
      {
        "cash_uid": "148498",
        "pay_date": "2023-09-18 11:37:13",
        "prc": "250"
      }
    ],
    "invoice_memo": "",
    "echo0": "",
    "echo1": "",
    "echo2": "",
    "echo3": "",
    "echo4": ""
  }
}

特約商店『查詢請款單』參數說明

欄位 型態 說明
store_uid string(16) 特約商店商務代號
service text {"service_name": "api", "cmd": "api\/companyinvoiceinquiry"}
JSON格式,AES256加密資料
encry_data text 『查詢請款單』欄位參考
JSON格式,AES256加密資料

『查詢請款單』欄位

參數名稱 型態 說明 必須
store_uid string (16) 請款方商務代號 必填
store_order_id string(30) 客戶自訂請款單號 page_code或store_order_id擇一必填
page_code string 請款系統代碼 page_code或store_order_id擇一必填

『查詢請款單』回傳欄位

參數名稱 型態 說明 備註
code string 『資料接收回傳代碼』對照表
msg string 資料接收回傳代碼
resultData object 『查詢結果』

『查詢請款單』回傳欄位

參數名稱 型態 說明 備註
code string 『查詢結果代碼』對照表
msg string 查詢結果訊息
page_code string 請款系統代碼
store_uid string 請款方商務代號
buy_store_uid string 購買方商務代號(不一定有)
state string 『訂單狀態』設定值
store_order_id string 客戶自訂請款單號
tong_bian string 賣方統編
company_name string 賣方公司名稱
company_tel string 賣方公司電話
sales_name string 賣方負責業務姓名
sales_tel string 賣方負責業務電話
sales_phone string 賣方負責業務手機
sales_mail string 賣方負責業務mail
buy_company_tong_bian string 買方公司統編
buy_company_name string 買方公司名稱
buy_company_tel string 買方公司電話
buy_name string 買方業務姓名
buy_phone string 買方業務手機
buy_tel string 買方業務電話
buy_mail string 購買人mail
date_start string 請款起始日
date_end string 請款截止日
create_type string 『發票開立先後順序』設定值
product_tax_type string 『資料含不含稅』設定值
tax_type string 『稅率類型』設定值
tax string 稅額
pay_mode array 『付款方式』設定值
final_pay_mode string 消費者決定使用的支付工具
product_detail array 『請款項目資料』欄位
discount_type string 『折扣類型』設定值
discount string 依據折扣方式代表不同的意義如果是打折不得大於100
total_discount_amount string 折扣總額
sales_amount string 銷售額合計
tax_amount string 營業稅額
total_amount string 請款總金額
memo string 備註
invoice_date string 發票日期
invoice_number string 發票號碼
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5
cash_order array 『金流回應相關值』設定值

『查詢結果對應代碼』值內容

型態 說明 備註
A0000 查詢成功
A0001 查無資料
A0002 請款系統代碼或客戶自訂請款單號,兩者需有一個有值

直接建立請款單

不會產生請款網址,經系統驗證資料無誤後,會直接寄送請款單給予購買者

<?php
/**
 * 特約商店串接-請款單直接建立建立
 */
final class StoreCompanyInvoiceDirectCreator
{
    /**
     * 特約商店商務代號
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     * @var string
     */
    public $storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/init";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['store_order_id'] = 1688967861;
        $rawData['mode'] = 2;
        $rawData['tong_bian'] = "28915188";
        $rawData['company_name'] = "高鉅科技股份有限公司";
        $rawData['company_tel'] = "04-2322-0267";
        $rawData['sales_name'] = "李逍遙";
        $rawData['sales_phone'] = "0911111111";
        $rawData['sales_tel'] = "04-2322-0267#11";
        $rawData['sales_mail'] = "[email protected]";
        $rawData['buy_name'] = "趙靈兒";
        $rawData['buy_phone'] = "0922222222";
        $rawData['buy_mail'] = "[email protected]";
        $rawData['date_start'] = "2023-07-10";
        $rawData['date_end'] = "2023-08-10";
        $rawData['create_type'] = 3;
        $rawData['product_tax_type'] = 1;
        $rawData['tax_type'] = 1;
        $rawData['tax'] = "0.05";
        $rawData['pay_mode'] = [
                                "CREDITCARD"
                               ];
        $rawData['product_detail'] = [
                                         [
                                          'name' => 'iphone 14 PRO',
                                          'price' => '30000',
                                          'selling_price' => '30000',
                                          'quantity' => '3'
                                         ]
                                     ];
        $rawData['discount_type'] = 0;
        $rawData['discount'] = 0;
        $rawData['memo'] = 0;
        $rawData['send_mail_type'] = 1;
        $rawData['mail_subject'] = "請款信件主題";
        $rawData['mail_content'] = "請款信件內容";
        $rawData['mail_users'] = [
                                  "[email protected]"
                                 ];

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/companyinvoicedirectcreator'
        );
    }
    /**
     * 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['store_uid'] = $this->storeUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->storeKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->storeKey);
        return $postData;
    }
    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }
}

$StoreCompanyInvoiceDirectCreator = new StoreCompanyInvoiceDirectCreator();
$StoreCompanyInvoiceDirectCreator->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 StoreCompanyInvoiceDirectCreator {
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";
        /// <summary>
        /// 特約商店金鑰或認證碼
        /// </summary>
        public string storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/init";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            StoreCompanyInvoiceDirectCreator simulator = new StoreCompanyInvoiceDirectCreator();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

            System.Console.WriteLine(result);
        }
        /// <summary>
        /// 取得串接欄位資料
        /// </summary>
        private dynamic GetRawData() {

            ArrayList payMode = new ArrayList();

            payMode.Add("CREDITCARD");


            ArrayList productDetail = new ArrayList();

            dynamic productDetail1 = new ExpandoObject();
            productDetail1.name = "iphone 14 PRO";
            productDetail1.price = "30000";
            productDetail1.selling_price = "30000";
            productDetail1.quantity = "3";
            productDetail.Add(productDetail1);


            ArrayList mailUsers = new ArrayList();

            mailUsers.Add("[email protected]");


            dynamic rawData = new ExpandoObject();
            rawData.store_uid = this.storeUid;
            rawData.store_order_id =  1688967861;
            rawData.mode =  2;
            rawData.tong_bian =  "28915188";
            rawData.company_name =  "高鉅科技股份有限公司";
            rawData.company_tel =  "04-2322-0267";
            rawData.sales_name =  "李逍遙";
            rawData.sales_phone =  "0911111111";
            rawData.sales_tel =  "04-2322-0267#11";
            rawData.sales_mail =  "[email protected]";
            rawData.buy_name =  "趙靈兒";
            rawData.buy_phone =  "0922222222";
            rawData.buy_mail =  "[email protected]";
            rawData.date_start =  "2023-07-10";
            rawData.date_end =  "2023-08-10";
            rawData.create_type =  3;
            rawData.product_tax_type =  1;
            rawData.tax_type =  1;
            rawData.tax =  "0.05";
            rawData.pay_mode = payMode;
            rawData.product_detail = productDetail;
            rawData.discount_type =  0;
            rawData.discount =  0;
            rawData.memo =  0;
            rawData.send_mail_type =  1;
            rawData.mail_subject =  "請款信件主題";
            rawData.mail_content =  "請款信件內容";
            rawData.mail_users = mailUsers;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/companyinvoicedirectcreator";
            return rawData;
        }
        /// <summary>
        /// 取得送出欄位資料
        /// </summary>
        private NameValueCollection GetPostData() {
            string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
            string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整

            //產生AES向量
            var IV = GetBytesIV();

            //進行加密
            var data_encode = Encrypt(data_json, this.storeKey, IV);
            var svr_encode = Encrypt(svr_json, this.storeKey, IV);

            //請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
            //若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
            string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
            string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);

            NameValueCollection postData = new NameValueCollection();
            postData["store_uid"] = this.storeUid;
            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 StoreCompanyInvoiceDirectCreator() {
    // 特約商店商務代號
    this.storeUid = "289151880002";
    // 特約商店金鑰或認證碼
    this.storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    // 串接交易位置
    this.url = "https://pay.usecase.cc/api/init";
};
/**
 * 取得串接欄位資料
 */
StoreCompanyInvoiceDirectCreator.prototype.getRawData = function () {
    return {
        store_uid: this.storeUid,
        store_order_id: 1688967861,
        mode: 2,
        tong_bian: "28915188",
        company_name: "高鉅科技股份有限公司",
        company_tel: "04-2322-0267",
        sales_name: "李逍遙",
        sales_phone: "0911111111",
        sales_tel: "04-2322-0267#11",
        sales_mail: "[email protected]",
        buy_name: "趙靈兒",
        buy_phone: "0922222222",
        buy_mail: "[email protected]",
        date_start: "2023-07-10",
        date_end: "2023-08-10",
        create_type: 3,
        product_tax_type: 1,
        tax_type: 1,
        tax: "0.05",
        pay_mode: [
                   "CREDITCARD"
                  ],
        product_detail: [
                            {
                             'name': "iphone 14 PRO",
                             'price': "30000",
                             'selling_price': "30000",
                             'quantity': "3"
                            }
                        ],
        discount_type: 0,
        discount: 0,
        memo: 0,
        send_mail_type: 1,
        mail_subject: "請款信件主題",
        mail_content: "請款信件內容",
        mail_users: [
                     "[email protected]"
                    ],

    };
};
/**
 * 取得服務位置
 */
StoreCompanyInvoiceDirectCreator.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/companyinvoicedirectcreator"
    };
};
/**
 * AES 256 加密
 */
StoreCompanyInvoiceDirectCreator.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 到主機
 */
StoreCompanyInvoiceDirectCreator.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();
    });
};
/**
 * 取得送出欄位資料
 */
StoreCompanyInvoiceDirectCreator.prototype.getPostData = function () {
    return {
        "store_uid": this.storeUid,
        "service": this.encrypt(this.getService(), this.storeKey),
        "encry_data": this.encrypt(this.getRawData(), this.storeKey)
    };
};
/**
 * 執行
 */
StoreCompanyInvoiceDirectCreator.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

StoreCompanyInvoiceDirectCreator = new StoreCompanyInvoiceDirectCreator();
StoreCompanyInvoiceDirectCreator.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 StoreCompanyInvoiceDirectCreator {
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     */
    String storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/init";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        StoreCompanyInvoiceDirectCreator simulator = new StoreCompanyInvoiceDirectCreator();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

    @SuppressWarnings(value = { "unchecked", "deprecation" })
    /**
     * 取得串接欄位資料
     * @return 串接原始資料
     */
    public Map getRawData() {

        ArrayList payMode = new ArrayList();

        payMode.add(new String("CREDITCARD"));


        ArrayList productDetail = new ArrayList();

        Map<Object, Object> productDetail1 = new HashMap<Object, Object>();
        productDetail1.put("name", "iphone 14 PRO");
        productDetail1.put("price", "30000");
        productDetail1.put("selling_price", "30000");
        productDetail1.put("quantity", "3");
        productDetail.add(productDetail1);


        ArrayList mailUsers = new ArrayList();

        mailUsers.add(new String("[email protected]"));


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("store_uid", this.storeUid);
        rawData.put("store_order_id", 1688967861);
        rawData.put("mode", 2);
        rawData.put("tong_bian", "28915188");
        rawData.put("company_name", "高鉅科技股份有限公司");
        rawData.put("company_tel", "04-2322-0267");
        rawData.put("sales_name", "李逍遙");
        rawData.put("sales_phone", "0911111111");
        rawData.put("sales_tel", "04-2322-0267#11");
        rawData.put("sales_mail", "[email protected]");
        rawData.put("buy_name", "趙靈兒");
        rawData.put("buy_phone", "0922222222");
        rawData.put("buy_mail", "[email protected]");
        rawData.put("date_start", "2023-07-10");
        rawData.put("date_end", "2023-08-10");
        rawData.put("create_type", 3);
        rawData.put("product_tax_type", 1);
        rawData.put("tax_type", 1);
        rawData.put("tax", "0.05");
        rawData.put("pay_mode", payMode);
        rawData.put("product_detail", productDetail);
        rawData.put("discount_type", 0);
        rawData.put("discount", 0);
        rawData.put("memo", 0);
        rawData.put("send_mail_type", 1);
        rawData.put("mail_subject", "請款信件主題");
        rawData.put("mail_content", "請款信件內容");
        rawData.put("mail_users", mailUsers);

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/companyinvoicedirectcreator");
        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.storeKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.storeKey), "UTF-8");

            postData = "store_uid=" + this.storeUid + "&service="
                    + svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        return postData;
    }
}

# -*- 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 StoreCompanyInvoiceDirectCreator:
    # 特約商店商務代號
    storeUid = "289151880002"
    # 特約商店金鑰或認證碼
    storeKey = b"KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/init"

    def getRawData(self):
        """取得串接欄位資料

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'store_order_id': 1688967861,
            'mode': 2,
            'tong_bian': "28915188",
            'company_name': "高鉅科技股份有限公司",
            'company_tel': "04-2322-0267",
            'sales_name': "李逍遙",
            'sales_phone': "0911111111",
            'sales_tel': "04-2322-0267#11",
            'sales_mail': "[email protected]",
            'buy_name': "趙靈兒",
            'buy_phone': "0922222222",
            'buy_mail': "[email protected]",
            'date_start': "2023-07-10",
            'date_end': "2023-08-10",
            'create_type': 3,
            'product_tax_type': 1,
            'tax_type': 1,
            'tax': "0.05",
            'pay_mode': [
                         "CREDITCARD"
                        ],
            'product_detail': [
                                  {
                                   'name': "iphone 14 PRO",
                                   'price': "30000",
                                   'selling_price': "30000",
                                   'quantity': "3"
                                  }
                              ],
            'discount_type': 0,
            'discount': 0,
            'memo': 0,
            'send_mail_type': 1,
            'mail_subject': "請款信件主題",
            'mail_content': "請款信件內容",
            'mail_users': [
                           "[email protected]"
                          ],
        }
        return rawData

    def getService(self):
        """取得服務位置

        Returns:
            {dict}: 服務位置資料
        """
        return {
            'service_name': 'api',
            'cmd': 'api/companyinvoicedirectcreator'
        }

    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 = {
            'store_uid': self.storeUid,
            'service': self.encrypt(self.getService(), self.storeKey),
            'encry_data': self.encrypt(self.getRawData(), self.storeKey)
        }
        return postData

    def run(self):
        """執行
        """
        json = self.post(self.getPostData())
        print(json)

StoreCompanyInvoiceDirectCreator = StoreCompanyInvoiceDirectCreator()
StoreCompanyInvoiceDirectCreator.run()

回傳 JSON 結構如下:

{
  "code":"B200",
  "msg":"執行成功",
  "resultData":{
    "code":"A0000",
    "msg":"成功",
    "store_order_id":"1695104732",
    "order_uid":"bead516bc3",
    "key":"995751385a82e4552b56b0c5f7106410",
    "url":"https://pay.usecase.cc/companyinvoice/pay/bead516bc3.html",
    "echo_0":"",
    "echo_1":"",
    "echo_2":"",
    "echo_3":"",
    "echo_4":""
  }
}

特約商店『直接建立請款單』參數說明

欄位 型態 說明
store_uid string(16) 特約商店商務代號
service text {"service_name": "api", "cmd": "api\/companyinvoicedirectcreator"}
JSON格式,AES256加密資料
encry_data text 『直接建立請款單』欄位參考
JSON格式,AES256加密資料

『直接建立請款單』欄位

參數名稱 型態 說明 必須
store_uid string 請款方商務代號 必填
buy_store_uid string 購買方商務代號(不一定有) 非必填
mode integer(1) 請款對象 必填
『請款對象』設定值
store_order_id string(30) 客戶自訂請款單號 必填
tong_bian string(8) 賣方統編 非必填,如未填,則以在mypay申請記錄的資料為主
company_name string(20) 賣方公司名稱 非必填,如未填,則以在mypay申請記錄的資料為主
company_tel string(20) 賣方公司電話 非必填,如未填,則以在mypay申請記錄的資料為主
sales_name string(20) 賣方負責業務姓名 非必填,如未填,則以在mypay申請記錄的資料為主
sales_phone string(10) 賣方負責業務手機 非必填,如未填,則以在mypay申請記錄的資料為主
sales_tel string(12) 賣方負責業務電話 非必填,如未填,則以在mypay申請記錄的資料為主
sales_mail string(50) 賣方負責業務email 非必填,如未填,則以在mypay申請記錄的資料為主
buy_company_tong_bian string(10) 買方統編 當請款對象為1時必填
buy_company_name string(20) 買方公司名稱 當請款對象為1時必填
buy_company_tel string(20) 買方公司電話 當請款對象為1時必填
buy_name string(20) 買方業務姓名 必填
buy_phone string(10) 買方業務手機 必填
buy_tel string(10) 買方業務電話 當請款對象為1時必填
buy_mail string(50) 買方業務mail 必填
date_start string 請款起始日
格式:YYYY-MM-DD
必填
date_end string 請款截止日
格式:YYYY-MM-DD
必填,截止日不得小於發送API當日
create_type integer(2) 收據類型開立模式 必填
『收據類型開立模式』,設定值
product_tax_type integer(2) 商品價格是否含稅,預設 1 收據類型開立模式為1或2時為必填
『資料含不含稅』設定值
tax_type integer(2) 營業稅 收據類型開立模式為1或2時為必填
『發票稅率別』設定值
tax string(5) 稅額 收據類型開立模式為1或2時且發票稅率別為必填
pay_mode array 付款方式 必填
使用前請先確認與MyPay的簽約是否有該項支付工具
『付款方式』設定值
product_detail array 請款項目 必填
『請款項目資料』欄位
discount_type integer(2) 折扣方式,預設0 非必填
『折扣類型』設定值
discount integer(7) 折扣方式,預設0 非必填
不可有小數,如果是減價0以上都可,如果是折扣0~100
memo string(255) 備註 非必填
echo_0 string(500) 自訂回傳參數 1 非必填
echo_1 string(500) 自訂回傳參數 2 非必填
echo_2 string(500) 自訂回傳參數 3 非必填
echo_3 string(500) 自訂回傳參數 4 非必填
echo_4 string(500) 自訂回傳參數 5 非必填
send_mail_type integer(1) 是否需要寄信,預設1 必填
『是否需要寄信』設定值
mail_subject string(255) 信件主旨 必填
mail_content string(255) 信件內容 必填
mail_users array(255) 收信者email 非必填,如未填會自動抓取買方mail

『直接建立請款單』回傳欄位

參數名稱 型態 說明 備註
code string 『資料接收回傳代碼』對照表
msg string 資料接收回傳代碼
resultData object 『直接建立請款單執行結果』

『直接建立請款單執行結果』欄位

參數名稱 型態 說明 必須
code string 執行結果回傳代碼 『直接建立請款單回傳代碼』值參考
msg string 執行結果錯誤訊息
store_order_id string 商店訂單編號
order_uid string 回傳請款單系統提供單號
key string 驗證碼
url string 請款單付款網址
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『直接建立請款單回傳代碼』值內容

型態 說明 備註
A0000 string 成功
A0001 string 稅額不正確
A0002 string 發票稅率別不正確
A0003 string 請款單不存在
A0004 string 可使用支付工具錯誤
A0005 string 請款日期大於結束日期
A0006 string 商品金額減去折扣,不等於總金額
A0007 string 系統錯誤,請稍後在試
A0008 string 信件主旨未填
A0009 string 信件內容未填
A0010 string 沒有收件者
A0011 string 查無商家資料
A0012 string 客戶自訂請款單號重複
A0013 string 發票備註超過70個字
A0014 string 發票開立失敗
A0015 string 發票號碼不足

請款單請款時間延長

請款時間已過期,不想成立新單,可呼叫此功能,將原本的請款單,請款時間延長,需注意,如使用虛擬帳號,則舊的匯款帳號將會失效,會重新產生一組新的

<?php

/**
 * 特約商店串接-請款單延長
 */
final class StoreCompanyInvoiceOrderExtension
{
    /**
     * 特約商店商務代號
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     * @var string
     */
    public $storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/init";

    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }

    /**
     * 資料 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['store_uid'] = $this->storeUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->storeKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->storeKey);
        return $postData;
    }

    /**
     * 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;
    }

    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/companyinvoiceorderextension'
        );
    }

    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['page_code'] = "e0dc6daa3c";
        $rawData['date_start'] = "2023-08-01";
        $rawData['date_end'] = "2023-10-01";

        return $rawData;
    }
}

$StoreCompanyInvoiceOrderExtension = new StoreCompanyInvoiceOrderExtension();
$StoreCompanyInvoiceOrderExtension->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 StoreCompanyInvoiceOrderExtension {
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";
        /// <summary>
        /// 特約商店金鑰或認證碼
        /// </summary>
        public string storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/init";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            StoreCompanyInvoiceOrderExtension simulator = new StoreCompanyInvoiceOrderExtension();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

            System.Console.WriteLine(result);
        }
        /// <summary>
        /// 取得串接欄位資料
        /// </summary>
        private dynamic GetRawData() {

            dynamic rawData = new ExpandoObject();
            rawData.store_uid = this.storeUid;
            rawData.page_code =  "e0dc6daa3c";
            rawData.date_start =  "2023-08-01";
            rawData.date_end =  "2023-10-01";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/companyinvoiceorderextension";
            return rawData;
        }
        /// <summary>
        /// 取得送出欄位資料
        /// </summary>
        private NameValueCollection GetPostData() {
            string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
            string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整

            //產生AES向量
            var IV = GetBytesIV();

            //進行加密
            var data_encode = Encrypt(data_json, this.storeKey, IV);
            var svr_encode = Encrypt(svr_json, this.storeKey, IV);

            //請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
            //若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
            string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
            string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);

            NameValueCollection postData = new NameValueCollection();
            postData["store_uid"] = this.storeUid;
            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 StoreCompanyInvoiceOrderExtension {
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     */
    String storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/init";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        StoreCompanyInvoiceOrderExtension simulator = new StoreCompanyInvoiceOrderExtension();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

    @SuppressWarnings(value = { "unchecked", "deprecation" })
    /**
     * 取得串接欄位資料
     * @return 串接原始資料
     */
    public Map getRawData() {

        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("store_uid", this.storeUid);
        rawData.put("page_code", "e0dc6daa3c");
        rawData.put("date_start", "2023-08-01");
        rawData.put("date_end", "2023-10-01");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/companyinvoiceorderextension");
        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.storeKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.storeKey), "UTF-8");

            postData = "store_uid=" + this.storeUid + "&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 StoreCompanyInvoiceOrderExtension() {
    // 特約商店商務代號
    this.storeUid = "289151880002";
    // 特約商店金鑰或認證碼
    this.storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    // 串接交易位置
    this.url = "https://pay.usecase.cc/api/init";
};
/**
 * 取得串接欄位資料
 */
StoreCompanyInvoiceOrderExtension.prototype.getRawData = function () {
    return {
        store_uid: this.storeUid,
        page_code: "e0dc6daa3c",
        date_start: "2023-08-01",
        date_end: "2023-10-01",

    };
};
/**
 * 取得服務位置
 */
StoreCompanyInvoiceOrderExtension.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/companyinvoiceorderextension"
    };
};
/**
 * AES 256 加密
 */
StoreCompanyInvoiceOrderExtension.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 到主機
 */
StoreCompanyInvoiceOrderExtension.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();
    });
};
/**
 * 取得送出欄位資料
 */
StoreCompanyInvoiceOrderExtension.prototype.getPostData = function () {
    return {
        "store_uid": this.storeUid,
        "service": this.encrypt(this.getService(), this.storeKey),
        "encry_data": this.encrypt(this.getRawData(), this.storeKey)
    };
};
/**
 * 執行
 */
StoreCompanyInvoiceOrderExtension.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

StoreCompanyInvoiceOrderExtension = new StoreCompanyInvoiceOrderExtension();
StoreCompanyInvoiceOrderExtension.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 StoreCompanyInvoiceOrderExtension:
    # 特約商店商務代號
    storeUid = "289151880002"
    # 特約商店金鑰或認證碼
    storeKey = b"KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/init"

    def getRawData(self):
        """取得串接欄位資料

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'page_code': "e0dc6daa3c",
            'date_start': "2023-08-01",
            'date_end': "2023-10-01",
        }
        return rawData

    def getService(self):
        """取得服務位置

        Returns:
            {dict}: 服務位置資料
        """
        return {
            'service_name': 'api',
            'cmd': 'api/companyinvoiceorderextension'
        }

    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 = {
            'store_uid': self.storeUid,
            'service': self.encrypt(self.getService(), self.storeKey),
            'encry_data': self.encrypt(self.getRawData(), self.storeKey)
        }
        return postData

    def run(self):
        """執行
        """
        json = self.post(self.getPostData())
        print(json)

StoreCompanyInvoiceOrderExtension = StoreCompanyInvoiceOrderExtension()
StoreCompanyInvoiceOrderExtension.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "1685072654"
}

特約商店『請款單延長』參數說明

欄位 型態 說明
store_uid string(16) 特約商店商務代號
service text {"service_name":"api","cmd":"api\/companyinvoiceorderextension"}
JSON格式,AES256加密資料
encry_data text 『請款單延長』欄位參考
JSON格式,AES256加密資料

『請款單延長』欄位

參數名稱 型態 說明 必須
store_uid string 請款方商務代號 必填
page_code string 請款系統請款單號 與store_order_id則一必填
store_order_id string 自訂請款單號 與page_code則一必填
date_start string 要延長的起始日,格式 YYYY-MM-DD 必填
date_end string 要延長的結束日,格式 YYYY-MM-DD 必填

『請款單延長』回傳欄位

參數名稱 型態 說明 必須
code string 資料接收回傳代碼 『資料接收回傳代碼』值參考
msg string 查詢結果訊息

請款單背景通知

不論是從後台、API等方式建立請款單,或著請款單過期、付款完成,均會透過在後台設定的通知網址,進行通知。

『回傳資訊』回報欄位

參數名稱 型態 說明 必須
page_code string 請款系統代碼
store_uid string 請款方商務代號
key string 驗證碼
buy_store_uid string 購買方商務代號(不一定有)
state string 『訂單狀態』設定值
store_order_id string 客戶自訂請款單號
tong_bian string 賣方統編
company_name string 賣方公司名稱
company_tel string 賣方公司電話
sales_name string 賣方負責業務姓名
sales_tel string 賣方負責業務電話
sales_phone string 賣方負責業務手機
sales_mail string 賣方負責業務mail
buy_company_tong_bian string 買方公司統編
buy_company_name string 買方公司名稱
buy_company_tel string 買方公司電話
buy_name string 買方業務姓名
buy_phone string 買方業務手機
buy_tel string 買方業務電話
buy_mail string 購買人mail
date_start string 請款起始日
date_end string 請款截止日
create_type string 『發票開立先後順序』設定值
product_tax_type string 『資料含不含稅』設定值
tax_type string 『稅率類型』設定值
tax string 稅額
pay_mode array 『付款方式』設定值
final_pay_mode string 消費者決定使用的支付工具
product_detail array 『請款項目資料』欄位
discount_type string 『折扣類型』設定值
discount string 依據折扣方式代表不同的意義如果是打折不得大於100
total_discount_amount string 折扣總額
sales_amount string 銷售額合計
tax_amount string 營業稅額
total_amount string 請款總金額
memo string 備註
invoice_date string 發票日期
invoice_number string 發票號碼
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5
cash_order array 『金流回應相關值』設定值
型態 說明 備註
A0000 string 成功
A0001 string 客戶自訂請款單號重複
A0002 string 失敗

各項參數對應值

『訂單狀態』欄位

型態 說明 備註
1 integer 建檔中
2 integer 請款中
3 integer 已付款
4 integer 過期

『收據類型開類模式』欄位

型態 說明 備註
0 integer 不預設 預設
1 integer 發票先開
2 integer 發票後開
3 integer 免用統一發票先開
4 integer 免用統一發票後開

『資料含不含稅』欄位

型態 說明 備註
0 integer 無稅務
1 integer 含稅
2 integer 不含稅

『發票稅率別』欄位

型態 說明 備註
0 integer 無稅
1 integer 應稅
2 integer 零稅率
3 integer 零稅率

『付款方式』欄位

型態 說明 備註
all string 全部可用支付方式(預設)
MobilePayAll string 指定下列線上行動支付方式
支付寶、Pi 拍錢包、LINEPay、微信、街口支付、悠遊付
CREDITCARD string 信用卡
CSTORECODE string 超商代碼
WEBATM string WEBATM
E_COLLECTION string 虛擬帳號
UNIONPAY string 銀聯卡
SVC string 點數卡(GASH ,Imoney)
ABROAD string 海外信用卡
ALIPAY string 支付寶
WECHAT string 微信支付
DIRECTDEBIT string 定期定額扣款
LINEPAYON string LINE Pay線上付款
LINEPAYOFF string LINE Pay線下付款
WECHATOFF string 微信支付線下
APPLEPAY string APPLE PAY
GOOGLEPAY string Google Pay
EACH string eACH交易
C_INSTALLMENT string 信用卡分期
C_REDEEM string 信用卡紅利
CARDLESS string 無卡分期
PION string Pi 拍錢包線上
PIOFF string Pi 拍錢包線下
AMEX string 美國運通
JKOON string 街口支付線上
JKOOFF string 街口支付線下
ALIPAYOFF string 支付寶線下
M_RECHARGE string 儲值交易
EASYWALLETON string 悠遊付線上
EASYWALLETOFF string 悠遊付線下
AFP string 後付款
BARCODE string 超商條碼繳費

『請款項目資料』欄位

參數名稱 型態 說明 必須
name string 請款名目 必填
price string 定價 非必填
selling_price string 售價 必填
quantity string 數量 必填

『折扣類型』欄位

型態 說明 備註
0 integer 無折扣 預設
1 integer 減價
2 integer 打折

『請款對象』欄位

型態 說明 備註
1 integer B2B(公司戶) 預設
2 integer B2C(消費者)

『是否需要寄信』欄位

型態 說明 備註
0 integer 不需要
1 integer 需要 預設

『金流回應相關值』值內容

參數名稱 型態 說明
cash_uid string 金流系統訂單單號
prc string 金流交易回傳碼
pay_date string 付款完成時間,格式YYYY-mm-dd H:i:s

『執行狀態碼』值內容

型態 說明 備註
100 string 資料不正確
400 string 系統錯誤
B200 string 執行成功
B500 string 執行失敗

附錄一:PFN(支付工具)參數表

資料傳遞可使用編號,也可以使用代碼 。 例如:pfn=27跟pfn=PION,一樣都是使用Pi 拍錢包線上付款支付工具。

編號 代碼 狀態 說明
1 CREDITCARD 啟用 信用卡
3 CSTORECODE 啟用 超商代碼
4 WEBATM 啟用 WEBATM
6 E_COLLECTION 啟用 虛擬帳號 (ATM轉帳)
9 ABROAD 啟用 海外信用卡(非台灣發行信用卡)
10 ALIPAY 啟用 支付寶
13 WECHAT 啟用 微信支付
14 DIRECTDEBIT 啟用 定期扣款(國內信用卡)
15 LINEPAYON 啟用 LINE線上付款(消費者主掃)
16 LINEPAYOFF 啟用 LINE線下付款(消費者被掃)
19 WECHATOFF 啟用 微信支付線下
20 APPLEPAY 啟用 Apple Pay
21 GOOGLEPAY 啟用 Google Pay
23 C_INSTALLMENT 啟用 信用卡分期
24 C_REDEEM 啟用 信用卡紅利
25 CARDLESS 啟用 無卡分期(由資融公司提供分期服務)
27 PION 啟用 Pi 拍錢包線上付款(消費者主掃)
28 PIOFF 啟用 Pi 拍錢包線下付款(消費者被掃)
29 AMEX 啟用 美國運通
31 JKOON 啟用 街口支付線上付款(消費者主掃)
32 JKOOF 啟用 街口支付線下付款(消費者被掃)
33 ALIPAYOFF 啟用 支付寶線下(消費者被掃)
34 M_RECHARGE 啟用 儲值
36 AFP 啟用 後付款
37 CASH 啟用 現金
38 EASYWALLETON 啟用 悠遊付線上付款(消費者主掃)
39 EASYWALLETOFF 啟用 悠遊付線下付款(消費者被掃)
40 EASYCARD 啟用 悠遊卡
41 IPASS 啟用 一卡通
42 ICASH 啟用 iCash
43 BARCODE 啟用 超商條碼繳費
51 DIRECTDEBIT_ABROAD 啟用 定期扣款(國外信用卡)

附錄二:交易狀態代碼

以下回傳的狀態代碼均須處理,避免系統連線錯誤,MYPAY LINK回傳時,貴司系統無法判讀

狀態代碼 狀態說明 詳細說明
100 資料錯誤 MYPAYLINK收到資料,但是格式或資料錯誤
200 資料正確 MYPAYLINK收到正確資料,會接續下一步
B200 執行成功 處理成功執行
B500 執行失敗 處理時,資料異常不予以處理

附錄三:設定調整

附錄四:資料加密方式說明

  1. 所有的API送出HTTPs請求之欄位中,service 和 encry_data 欄位皆進行 AES256+BASE64 加密處理。
  2. AES加密,格式為CBC,長度為256bits,金鑰長度32,IV長度16,傳遞內文為加密後組合IV並經過Base64轉換後傳出。
  3. IV資料建議隨機產生。

附錄五:API模擬串接服務

提供模擬使用HTTP Protocol,透過POST方式傳遞資料到MYPAY, 並且得到回傳結果。