|
@@ -0,0 +1,855 @@
|
|
|
+# coding: utf-8
|
|
|
+import collections
|
|
|
+import hashlib
|
|
|
+import copy
|
|
|
+import requests
|
|
|
+import json
|
|
|
+import pprint
|
|
|
+from decimal import Decimal
|
|
|
+from urllib.parse import quote_plus, parse_qsl, parse_qs
|
|
|
+
|
|
|
+"""
|
|
|
+付款方式
|
|
|
+"""
|
|
|
+ChoosePayment = {
|
|
|
+ 'Credit': 'Credit', # 信用卡及 GooglePay
|
|
|
+ 'GooglePay': 'GooglePay', # GooglePay (若為PC版時不支援)
|
|
|
+ 'WebATM': 'WebATM', # 網路 ATM (若為手機版時不支援)
|
|
|
+ 'ATM': 'ATM', # 自動櫃員機
|
|
|
+ 'CVS': 'CVS', # 超商代碼
|
|
|
+ 'BARCODE': 'BARCODE', # 超商條碼 (若為手機版時不支援)
|
|
|
+ 'ApplePay': 'ApplePay', # ApplePay (僅支援Safari瀏覽器)
|
|
|
+ 'ALL': 'ALL', # 不指定付款方式,由綠界顯示付款方式選擇頁面。
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+付款方式子項目
|
|
|
+"""
|
|
|
+ChooseSubPayment = {
|
|
|
+ 'WebATM': {
|
|
|
+ 'TAISHIN': 'TAISHIN', # 台新銀行
|
|
|
+ 'ESUN': 'ESUN', # 玉山銀行
|
|
|
+ 'BOT': 'BOT', # 台灣銀行
|
|
|
+ 'FUBON': 'FUBON', # 台北富邦
|
|
|
+ 'CHINATRUST': 'CHINATRUST', # 中國信託
|
|
|
+ 'FIRST': 'FIRST', # 第一銀行
|
|
|
+ 'CATHAY': 'CATHAY', # 國泰世華
|
|
|
+ 'MEGA': 'MEGA', # 兆豐銀行
|
|
|
+ 'LAND': 'LAND', # 土地銀行
|
|
|
+ 'TACHONG': 'TACHONG', # 大眾銀行
|
|
|
+ 'SINOPAC': 'SINOPAC', # 永豐銀行
|
|
|
+ },
|
|
|
+ 'ATM': {
|
|
|
+ 'TAISHIN': 'TAISHIN', # 台新銀行
|
|
|
+ 'ESUN': 'ESUN', # 玉山銀行
|
|
|
+ 'BOT': 'BOT', # 台灣銀行
|
|
|
+ 'FUBON': 'FUBON', # 台北富邦
|
|
|
+ 'CHINATRUST': 'CHINATRUST', # 中國信託
|
|
|
+ 'FIRST': 'FIRST', # 第一銀行
|
|
|
+ 'LAND': 'LAND', # 土地銀行
|
|
|
+ 'CATHAY': 'CATHAY', # 國泰世華銀行
|
|
|
+ 'TACHONG': 'TACHONG', # 大眾銀行
|
|
|
+ },
|
|
|
+ 'CVS': {
|
|
|
+ 'CVS': 'CVS', # 超商代碼繳款
|
|
|
+ 'OK': 'OK', # OK 超商代碼繳款
|
|
|
+ 'FAMILY': 'FAMILY', # 全家超商代碼繳款
|
|
|
+ 'HILIFE': 'HILIFE', # 萊爾富超商代碼繳款
|
|
|
+ 'IBON': 'IBON', # 7-11 ibon 代碼繳款
|
|
|
+ },
|
|
|
+ 'BARCODE': 'BARCODE', # 超商條碼繳款
|
|
|
+ 'Credit': 'Credit', # 信用卡 (MasterCard/JCB/VISA)
|
|
|
+ 'GooglePay': 'GooglePay', # GooglePay
|
|
|
+ 'ApplePay': '', # ApplePay
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+回覆付款方式
|
|
|
+"""
|
|
|
+ReplyPaymentType = {
|
|
|
+ 'WebATM_TAISHIN': '台新銀行 WebATM',
|
|
|
+ 'WebATM_ESUN': '玉山銀行 WebATM',
|
|
|
+ 'WebATM_BOT': '台灣銀行 WebATM',
|
|
|
+ 'WebATM_FUBON': '台北富邦 WebATM',
|
|
|
+ 'WebATM_CHINATRUST': '中國信託 WebATM',
|
|
|
+ 'WebATM_FIRST': '第一銀行 WebATM',
|
|
|
+ 'WebATM_CATHAY': '國泰世華 WebATM',
|
|
|
+ 'WebATM_MEGA': '兆豐銀行 WebATM',
|
|
|
+ 'WebATM_LAND': '土地銀行 WebATM',
|
|
|
+ 'WebATM_TACHONG': '元大銀行 WebATM',
|
|
|
+ 'WebATM_SINOPAC': '永豐銀行 WebATM',
|
|
|
+ 'ATM_TAISHIN': '台新銀行 ATM',
|
|
|
+ 'ATM_ESUN': '玉山銀行 ATM',
|
|
|
+ 'ATM_BOT': '台灣銀行 ATM',
|
|
|
+ 'ATM_FUBON': '台北富邦 ATM',
|
|
|
+ 'ATM_CHINATRUST': '中國信託 ATM',
|
|
|
+ 'ATM_FIRST': '第一銀行 ATM',
|
|
|
+ 'ATM_LAND': '土地銀行 ATM',
|
|
|
+ 'ATM_CATHAY': '國泰世華銀行 ATM',
|
|
|
+ 'ATM_TACHONG': '元大銀行 ATM',
|
|
|
+ 'CVS_CVS': '超商代碼繳款',
|
|
|
+ 'CVS_OK': 'OK 超商代碼繳款',
|
|
|
+ 'CVS_FAMILY': '全家超商代碼繳款',
|
|
|
+ 'CVS_HILIFE': '萊爾富超商代碼繳款',
|
|
|
+ 'CVS_IBON': '7-11 ibon 代碼繳款',
|
|
|
+ 'BARCODE_BARCODE': '超商條碼繳款',
|
|
|
+ 'Credit_CreditCard': '信用卡',
|
|
|
+ 'GooglePay': 'GooglePay',
|
|
|
+ 'ApplePay': 'ApplePay',
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+額外付款資訊
|
|
|
+"""
|
|
|
+NeedExtraPaidInfo = {
|
|
|
+ 'Yes': 'Y', # 需要額外付款資訊
|
|
|
+ 'No': 'N', # 不需要額外付款資訊
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+裝置來源
|
|
|
+"""
|
|
|
+DeviceSource = "" # 請帶空值,由系統自動判定。
|
|
|
+
|
|
|
+"""
|
|
|
+信用卡關帳/退刷/取消/放棄
|
|
|
+"""
|
|
|
+Action = {
|
|
|
+ 'C': 'C', # 關帳
|
|
|
+ 'R': 'R', # 退刷
|
|
|
+ 'E': 'E', # 取消
|
|
|
+ 'N': 'N', # 放棄
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+定期定額的週期種類
|
|
|
+"""
|
|
|
+PeriodType = {
|
|
|
+ 'Y': 'Y', # 以年為週期
|
|
|
+ 'M': 'M', # 以月為週期
|
|
|
+ 'D': 'D', # 以天為週期
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+電子發票開立註記
|
|
|
+"""
|
|
|
+InvoiceMark = 'Y' # 需要開立電子發票
|
|
|
+
|
|
|
+"""
|
|
|
+電子發票載具類別
|
|
|
+"""
|
|
|
+CarruerType = {
|
|
|
+ 'None': '', # 無載具
|
|
|
+ 'Member': '1', # 特店載具
|
|
|
+ 'Citizen': '2', # 買受人自然人憑證
|
|
|
+ 'Cellphone': '3', # 買受人手機條碼
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+電子發票捐贈註記
|
|
|
+"""
|
|
|
+Donation = {
|
|
|
+ 'No': '2', # 若為不捐贈或統一編號 [CustomerIdentifier] 有值時, 不捐贈
|
|
|
+ 'Yes': '1', # 捐贈
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+電子發票列印註記
|
|
|
+"""
|
|
|
+Print = {
|
|
|
+ 'No': '0', # 若為不列印或捐贈註記 [Donation] 為 1 (捐贈) 時, 不列印
|
|
|
+ 'Yes': '1', # 若為列印或統一編號 [CustomerIdentifier] 有值時, 列印
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+通關方式, 當課稅類別 [TaxType] 為 2 (零稅率)時
|
|
|
+"""
|
|
|
+ClearanceMark = {
|
|
|
+ 'Yes': '1', # 經海關出口
|
|
|
+ 'No': '2', # 非經海關出口
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+課稅類別
|
|
|
+"""
|
|
|
+TaxType = {
|
|
|
+ 'Dutiable': '1', # 應稅
|
|
|
+ 'Zero': '2', # 零稅率
|
|
|
+ 'Free': '3', # 免稅
|
|
|
+ 'Mix': '9', # 應稅與免稅混合(限收銀機發票無法分辦時使用,且需通過申請核可)
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+字軌類別
|
|
|
+"""
|
|
|
+InvType = {
|
|
|
+ 'General': '07', # 一般稅額
|
|
|
+ 'Special': '08', # 特種稅額
|
|
|
+}
|
|
|
+
|
|
|
+"""
|
|
|
+銀聯卡交易選項
|
|
|
+"""
|
|
|
+UnionPay = {
|
|
|
+ 'Select': 0, # 消費者於交易頁面可選擇是否使用銀聯交易
|
|
|
+ 'Only': 1, # 只使用銀聯卡交易, 且綠界會將交易頁面直接導到銀聯網站
|
|
|
+ 'Hidden': 2, # 不可使用銀聯卡, 綠界會將交易頁面隱藏銀聯選項
|
|
|
+}
|
|
|
+
|
|
|
+class BasePayment(object):
|
|
|
+
|
|
|
+ def merge(self, x, y):
|
|
|
+ """
|
|
|
+ Given two dicts, merge them into a new dict as a shallow copy.
|
|
|
+ """
|
|
|
+ z = x.copy()
|
|
|
+ z.update(y)
|
|
|
+ return z
|
|
|
+
|
|
|
+ # 檢查必填參數
|
|
|
+ # 檢查 merge.dict 是否有填正確的值或範圍
|
|
|
+ def check_required_parameter(self, parameters, patterns):
|
|
|
+ for patten in patterns:
|
|
|
+ for k, v in patten.items():
|
|
|
+ if v.get('required') and (v.get('type') is str):
|
|
|
+ if parameters.get(k) is None:
|
|
|
+ raise Exception('parameter %s is required.' % k)
|
|
|
+ elif len(parameters.get(k)) == 0:
|
|
|
+ raise Exception('%s content is required.' % k)
|
|
|
+ elif len(parameters.get(k)) > v.get('max', Decimal('Infinity')):
|
|
|
+ raise Exception('%s max langth is %d.' %
|
|
|
+ (k, v.get('max', Decimal('Infinity'))))
|
|
|
+ elif v.get('required') and (v.get('type') is int):
|
|
|
+ if parameters.get(k) is None:
|
|
|
+ raise Exception('parameter %s is required.' % k)
|
|
|
+
|
|
|
+ # 先用 required.dict 設定預設值並產生新 new.required.dict
|
|
|
+ def create_default_dict(self, parameters):
|
|
|
+ default_dict = dict()
|
|
|
+ for k, v in parameters.items():
|
|
|
+ if v['type'] is str:
|
|
|
+ default_dict.setdefault(k, '')
|
|
|
+ elif v['type'] is int:
|
|
|
+ default_dict.setdefault(k, -1)
|
|
|
+ else:
|
|
|
+ raise Exception('unsupported type!')
|
|
|
+ for k, v in parameters.items():
|
|
|
+ if v.get('default'):
|
|
|
+ default_dict[k] = v.get('default')
|
|
|
+ return default_dict
|
|
|
+
|
|
|
+ # 將 merge.dict 內的無用參數消除
|
|
|
+ def filter_parameter(self, parameters, pattern):
|
|
|
+ for patten in pattern:
|
|
|
+ for k, v in patten.items():
|
|
|
+ if (v.get('required') is False) and (v.get('type') is str):
|
|
|
+ if parameters.get(k) is None:
|
|
|
+ continue
|
|
|
+ if len(parameters.get(k)) == 0:
|
|
|
+ del parameters[k]
|
|
|
+ elif (v.get('required') is False) and (v.get('type') is int):
|
|
|
+ if parameters.get(k) is None:
|
|
|
+ continue
|
|
|
+ if parameters.get(k) < 0:
|
|
|
+ del parameters[k]
|
|
|
+
|
|
|
+ def generate_check_value(self, params):
|
|
|
+ _params = copy.deepcopy(params)
|
|
|
+
|
|
|
+ if _params.get('CheckMacValue'):
|
|
|
+ _params.pop('CheckMacValue')
|
|
|
+
|
|
|
+ encrypt_type = int(_params.get('EncryptType', 1))
|
|
|
+
|
|
|
+ _params.update({'MerchantID': self.MerchantID})
|
|
|
+
|
|
|
+ ordered_params = collections.OrderedDict(
|
|
|
+ sorted(_params.items(), key=lambda k: k[0].lower()))
|
|
|
+
|
|
|
+ encoding_lst = []
|
|
|
+ encoding_lst.append('HashKey=%s&' % self.HashKey)
|
|
|
+ encoding_lst.append(''.join(
|
|
|
+ ['{}={}&'.format(key, value) for key, value in ordered_params.items()]))
|
|
|
+ encoding_lst.append('HashIV=%s' % self.HashIV)
|
|
|
+
|
|
|
+ safe_characters = '-_.!*()'
|
|
|
+
|
|
|
+ encoding_str = ''.join(encoding_lst)
|
|
|
+ encoding_str = quote_plus(
|
|
|
+ str(encoding_str), safe=safe_characters).lower()
|
|
|
+
|
|
|
+ check_mac_value = ''
|
|
|
+ if encrypt_type == 1:
|
|
|
+ check_mac_value = hashlib.sha256(
|
|
|
+ encoding_str.encode('utf-8')).hexdigest().upper()
|
|
|
+ elif encrypt_type == 0:
|
|
|
+ check_mac_value = hashlib.md5(
|
|
|
+ encoding_str.encode('utf-8')).hexdigest().upper()
|
|
|
+
|
|
|
+ return check_mac_value
|
|
|
+
|
|
|
+ def integrate_parameter(self, parameters, patterns):
|
|
|
+ # 更新 MerchantID
|
|
|
+ parameters['MerchantID'] = self.MerchantID
|
|
|
+ # 檢查必填參數
|
|
|
+ self.check_required_parameter(parameters, patterns)
|
|
|
+ # 將 merge.dict 內的無用參數消除
|
|
|
+ self.filter_parameter(parameters, patterns)
|
|
|
+ # 計算 CheckMacValue
|
|
|
+ parameters['CheckMacValue'] = self.generate_check_value(parameters)
|
|
|
+ return parameters
|
|
|
+
|
|
|
+ def send_post(self, url, params):
|
|
|
+ response = requests.post(url, data=params)
|
|
|
+ return response
|
|
|
+
|
|
|
+
|
|
|
+class ExtendFunction(BasePayment):
|
|
|
+
|
|
|
+ def gen_html_post_form(self, action, parameters):
|
|
|
+ html = '<form id="data_set" action="' + action + '" method="post">'
|
|
|
+ for k, v in parameters.items():
|
|
|
+ html += '<input type="hidden" name="' + \
|
|
|
+ str(k) + '" value="' + str(v) + '" />'
|
|
|
+
|
|
|
+ html += '<script type="text/javascript">document.getElementById("data_set").submit();</script>'
|
|
|
+ html += "</form>"
|
|
|
+ return html
|
|
|
+
|
|
|
+
|
|
|
+class CreateOrder(BasePayment):
|
|
|
+
|
|
|
+ # 訂單基本參數
|
|
|
+ __ORDER_REQUIRED_PARAMETERS = {
|
|
|
+ 'MerchantID': {'type': str, 'required': True, 'max': 10},
|
|
|
+ 'MerchantTradeNo': {'type': str, 'required': True, 'max': 20},
|
|
|
+ 'StoreID': {'type': str, 'required': False, 'max': 20},
|
|
|
+ 'MerchantTradeDate': {'type': str, 'required': True, 'max': 20},
|
|
|
+ 'PaymentType': {'default': 'aio', 'type': str, 'required': True, 'max': 20},
|
|
|
+ 'TotalAmount': {'type': int, 'required': True},
|
|
|
+ 'TradeDesc': {'type': str, 'required': True, 'max': 200},
|
|
|
+ 'ItemName': {'type': str, 'required': True, 'max': 200},
|
|
|
+ 'ReturnURL': {'type': str, 'required': True, 'max': 200},
|
|
|
+ 'ChoosePayment': {'type': str, 'required': True, 'max': 200},
|
|
|
+ 'ClientBackURL': {'type': str, 'required': False, 'max': 200},
|
|
|
+ 'ItemURL': {'type': str, 'required': False, 'max': 200},
|
|
|
+ 'Remark': {'type': str, 'required': False, 'max': 100},
|
|
|
+ 'ChooseSubPayment': {'type': str, 'required': False, 'max': 20},
|
|
|
+ 'OrderResultURL': {'type': str, 'required': False, 'max': 200},
|
|
|
+ 'NeedExtraPaidInfo': {'type': str, 'required': False, 'max': 1},
|
|
|
+ 'DeviceSource': {'type': str, 'required': False, 'max': 10},
|
|
|
+ 'IgnorePayment': {'type': str, 'required': False, 'max': 100},
|
|
|
+ 'PlatformID': {'type': str, 'required': False, 'max': 10},
|
|
|
+ 'InvoiceMark': {'type': str, 'required': False, 'max': 1},
|
|
|
+ 'CustomField1': {'type': str, 'required': False, 'max': 50},
|
|
|
+ 'CustomField2': {'type': str, 'required': False, 'max': 50},
|
|
|
+ 'CustomField3': {'type': str, 'required': False, 'max': 50},
|
|
|
+ 'CustomField4': {'type': str, 'required': False, 'max': 50},
|
|
|
+ 'EncryptType': {'default': 1, 'type': int, 'required': True},
|
|
|
+ }
|
|
|
+
|
|
|
+ # 使用 ALL 或 ATM 付款方式
|
|
|
+ __ATM_EXTEND_PARAMETERS = {
|
|
|
+ 'ExpireDate': {'type': int, 'required': False},
|
|
|
+ 'PaymentInfoURL': {'type': str, 'required': False, 'max': 200},
|
|
|
+ 'ClientRedirectURL': {'type': str, 'required': False, 'max': 200},
|
|
|
+ }
|
|
|
+
|
|
|
+ # 使用 ALL 或 CVS 或 BARCODE 付款方式
|
|
|
+ __CVS_BARCODE_EXTEND_PARAMETERS = {
|
|
|
+ 'StoreExpireDate': {'type': int, 'required': False, },
|
|
|
+ 'Desc_1': {'type': str, 'required': False, 'max': 20},
|
|
|
+ 'Desc_2': {'type': str, 'required': False, 'max': 20},
|
|
|
+ 'Desc_3': {'type': str, 'required': False, 'max': 20},
|
|
|
+ 'Desc_4': {'type': str, 'required': False, 'max': 20},
|
|
|
+ 'PaymentInfoURL': {'type': str, 'required': False, 'max': 200},
|
|
|
+ 'ClientRedirectURL': {'type': str, 'required': False, 'max': 200},
|
|
|
+ }
|
|
|
+
|
|
|
+ # 使用 ALL 或 Credit 付款方式
|
|
|
+ __CREDIT_EXTEND_PARAMETERS_1 = {
|
|
|
+ "BindingCard": {'type': int, 'required': False, },
|
|
|
+ "MerchantMemberID": {'type': str, 'required': False, 'max': 30},
|
|
|
+ }
|
|
|
+
|
|
|
+ # 使用 Credit 付款方式
|
|
|
+ __CREDIT_EXTEND_PARAMETERS_2 = {
|
|
|
+ "Language": {'type': str, 'required': False, 'max': 3},
|
|
|
+ }
|
|
|
+
|
|
|
+ # 使用 ALL 或 Credit 付款方式: 一次付清(三擇一)
|
|
|
+ __CREDIT_EXTEND_PARAMETERS_3 = {
|
|
|
+ "Redeem": {'type': str, 'required': False, 'max': 1},
|
|
|
+ "UnionPay": {'type': int, 'required': False, },
|
|
|
+ }
|
|
|
+
|
|
|
+ # 使用 ALL 或 Credit 付款方式: 分期付款、圓夢分期付款(三擇一)
|
|
|
+ __CREDIT_EXTEND_PARAMETERS_4 = {
|
|
|
+ "CreditInstallment": {'type': str, 'required': True, 'max': 20},
|
|
|
+ }
|
|
|
+
|
|
|
+ # 使用 ALL 或 Credit 付款方式: 定期定額(三擇一)
|
|
|
+ __CREDIT_EXTEND_PARAMETERS_5 = {
|
|
|
+ "PeriodAmount": {'type': int, 'required': True, },
|
|
|
+ "PeriodType": {'type': str, 'required': True, 'max': 1},
|
|
|
+ "Frequency": {'type': int, 'required': True, },
|
|
|
+ "ExecTimes": {'type': int, 'required': True, },
|
|
|
+ "PeriodReturnURL": {'type': str, 'required': False, 'max': 200},
|
|
|
+ }
|
|
|
+
|
|
|
+ # 電子發票延伸參數
|
|
|
+ __INVOICE_EXTEND_PARAMETERS = {
|
|
|
+ "RelateNumber": {'type': str, 'required': True, 'max': 30},
|
|
|
+ "CustomerID": {'type': str, 'required': False, 'max': 20},
|
|
|
+ "CustomerIdentifier": {'type': str, 'required': False, 'max': 8},
|
|
|
+ "CustomerName": {'type': str, 'required': False, 'max': 30},
|
|
|
+ "CustomerAddr": {'type': str, 'required': False, 'max': 200},
|
|
|
+ "CustomerPhone": {'type': str, 'required': False, 'max': 20},
|
|
|
+ "CustomerEmail": {'type': str, 'required': False, 'max': 200},
|
|
|
+ "ClearanceMark": {'type': str, 'required': False, 'max': 1},
|
|
|
+ "TaxType": {'type': str, 'required': True, 'max': 1},
|
|
|
+ "CarruerType": {'type': str, 'required': False, 'max': 1},
|
|
|
+ "CarruerNum": {'type': str, 'required': False, 'max': 64},
|
|
|
+ "Donation": {'type': str, 'required': True, 'max': 1},
|
|
|
+ "LoveCode": {'type': str, 'required': False, 'max': 7},
|
|
|
+ "Print": {'type': str, 'required': True, 'max': 1},
|
|
|
+ "InvoiceItemName": {'type': str, 'required': True, 'max': 100},
|
|
|
+ "InvoiceItemCount": {'type': str, 'required': True, },
|
|
|
+ "InvoiceItemWord": {'type': str, 'required': True, },
|
|
|
+ "InvoiceItemPrice": {'type': str, 'required': True, },
|
|
|
+ "InvoiceItemTaxType": {'type': str, 'required': False, },
|
|
|
+ "InvoiceRemark": {'type': str, 'required': False, },
|
|
|
+ "DelayDay": {'type': int, 'required': True, },
|
|
|
+ "InvType": {'type': str, 'required': True, 'max': 2},
|
|
|
+ }
|
|
|
+
|
|
|
+ def create_order(self, client_parameters):
|
|
|
+ self.__check_pattern = []
|
|
|
+ # 先用 required.dict 設定預設值並產生新 new.required.dict
|
|
|
+ default_parameters = dict()
|
|
|
+ default_parameters = self.create_default_dict(
|
|
|
+ self.__ORDER_REQUIRED_PARAMETERS)
|
|
|
+ self.__check_pattern.append(self.__ORDER_REQUIRED_PARAMETERS)
|
|
|
+
|
|
|
+ # 看看 client.dict 付款方式
|
|
|
+ # 有的話 merge.dict 合併 payment.method.dict
|
|
|
+ # 使用 ALL 或 ATM 付款方式
|
|
|
+ choose_payment = client_parameters.get('ChoosePayment')
|
|
|
+ if choose_payment == ChoosePayment['ALL'] or \
|
|
|
+ choose_payment == ChoosePayment['ATM']:
|
|
|
+ payment_extend_parameters = self.create_default_dict(
|
|
|
+ self.__ATM_EXTEND_PARAMETERS)
|
|
|
+ self.__check_pattern.append(self.__ATM_EXTEND_PARAMETERS)
|
|
|
+ # 合併
|
|
|
+ default_parameters = super().merge(
|
|
|
+ default_parameters, payment_extend_parameters)
|
|
|
+
|
|
|
+ # 使用 ALL 或 CVS 或 BARCODE 付款方式
|
|
|
+ if choose_payment == ChoosePayment['ALL'] or \
|
|
|
+ choose_payment == ChoosePayment['CVS'] or \
|
|
|
+ choose_payment == ChoosePayment['BARCODE']:
|
|
|
+ payment_extend_parameters = self.create_default_dict(
|
|
|
+ self.__CVS_BARCODE_EXTEND_PARAMETERS)
|
|
|
+ self.__check_pattern.append(self.__CVS_BARCODE_EXTEND_PARAMETERS)
|
|
|
+ # 合併
|
|
|
+ default_parameters = super().merge(
|
|
|
+ default_parameters, payment_extend_parameters)
|
|
|
+
|
|
|
+ # 使用 ALL 或 Credit 付款方式
|
|
|
+ if choose_payment == ChoosePayment['ALL'] or \
|
|
|
+ choose_payment == ChoosePayment['Credit']:
|
|
|
+ payment_extend_parameters = self.create_default_dict(
|
|
|
+ self.__CREDIT_EXTEND_PARAMETERS_1)
|
|
|
+ self.__check_pattern.append(self.__CREDIT_EXTEND_PARAMETERS_1)
|
|
|
+ # 合併
|
|
|
+ default_parameters = super().merge(
|
|
|
+ default_parameters, payment_extend_parameters)
|
|
|
+
|
|
|
+ # 使用 Credit 付款方式
|
|
|
+ if choose_payment == ChoosePayment['Credit']:
|
|
|
+ payment_extend_parameters = self.create_default_dict(
|
|
|
+ self.__CREDIT_EXTEND_PARAMETERS_2)
|
|
|
+ self.__check_pattern.append(self.__CREDIT_EXTEND_PARAMETERS_2)
|
|
|
+ # 合併
|
|
|
+ default_parameters = super().merge(
|
|
|
+ default_parameters, payment_extend_parameters)
|
|
|
+
|
|
|
+ # 付款子方式 WebATM 大眾銀行跟永豐銀行已經無法使用
|
|
|
+ if client_parameters.get('ChooseSubPayment') == ChooseSubPayment['WebATM']['TACHONG'] or \
|
|
|
+ client_parameters.get('ChooseSubPayment') == ChooseSubPayment['WebATM']['SINOPAC']:
|
|
|
+ raise Exception(
|
|
|
+ 'ChooseSubPayment is not supported with TACHONG or SINOPAC.')
|
|
|
+
|
|
|
+ if choose_payment == ChoosePayment['ALL'] or \
|
|
|
+ choose_payment == ChoosePayment['Credit']:
|
|
|
+ credit_extend_parameters = dict()
|
|
|
+ # 使用 ALL 或 Credit 付款方式: 一次付清(三擇一)
|
|
|
+ if client_parameters.get('Redeem') or \
|
|
|
+ client_parameters.get('UnionPay'):
|
|
|
+ credit_extend_parameters = self.create_default_dict(
|
|
|
+ self.__CREDIT_EXTEND_PARAMETERS_3)
|
|
|
+ self.__check_pattern.append(self.__CREDIT_EXTEND_PARAMETERS_3)
|
|
|
+
|
|
|
+ # 使用 ALL 或 Credit 付款方式: 分期付款、圓夢分期付款(三擇一)
|
|
|
+ elif client_parameters.get('CreditInstallment'):
|
|
|
+ credit_extend_parameters = self.create_default_dict(
|
|
|
+ self.__CREDIT_EXTEND_PARAMETERS_4)
|
|
|
+ self.__check_pattern.append(self.__CREDIT_EXTEND_PARAMETERS_4)
|
|
|
+
|
|
|
+ # 使用 ALL 或 Credit 付款方式: 定期定額(三擇一)
|
|
|
+ elif client_parameters.get('PeriodAmount') or \
|
|
|
+ client_parameters.get('PeriodType') or \
|
|
|
+ client_parameters.get('Frequency') or \
|
|
|
+ client_parameters.get('ExecTimes') or \
|
|
|
+ client_parameters.get('PeriodReturnURL'):
|
|
|
+ credit_extend_parameters = self.create_default_dict(
|
|
|
+ self.__CREDIT_EXTEND_PARAMETERS_5)
|
|
|
+ self.__check_pattern.append(self.__CREDIT_EXTEND_PARAMETERS_5)
|
|
|
+ # 合併
|
|
|
+ if credit_extend_parameters:
|
|
|
+ default_parameters = super().merge(
|
|
|
+ default_parameters, credit_extend_parameters)
|
|
|
+
|
|
|
+ # 看看 client.dict 有無 invoice='Y'
|
|
|
+ # 有的話 new.required.dict 合併 invoice.dict
|
|
|
+ if client_parameters.get('InvoiceMark') == 'Y':
|
|
|
+ invoice_parameters = self.create_default_dict(
|
|
|
+ self.__INVOICE_EXTEND_PARAMETERS)
|
|
|
+ self.__check_pattern.append(self.__INVOICE_EXTEND_PARAMETERS)
|
|
|
+ # 合併
|
|
|
+ default_parameters = super().merge(
|
|
|
+ default_parameters, invoice_parameters)
|
|
|
+
|
|
|
+ # 該參數有值時,請帶固定長度為數字 8 碼
|
|
|
+ customer_identifier = client_parameters.get('CustomerIdentifier')
|
|
|
+ if customer_identifier and (len(customer_identifier) != 8):
|
|
|
+ raise Exception(
|
|
|
+ 'CustomerIdentifier have to fill fixed length of 8 digits.')
|
|
|
+ # 若統一編號 CustomerIdentifier 有值時,填入載具參數應出現錯誤訊息(不可以有載具)
|
|
|
+ if customer_identifier and client_parameters.get('CarruerType'):
|
|
|
+ raise Exception(
|
|
|
+ 'CarruerType do not fill any value, when CustomerIdentifier have value.')
|
|
|
+ # 統一編號 CustomerIdentifier 有值時,一定要列印,否則會出現錯誤訊息
|
|
|
+ if customer_identifier and (client_parameters.get('Print') == '0'):
|
|
|
+ raise Exception(
|
|
|
+ 'Print have to fill "1", when CustomerIdentifier have value.')
|
|
|
+ # 統一編號 CustomerIdentifier 有值時,Donation 要為 '0',否則會出現錯誤訊息
|
|
|
+ if customer_identifier and (client_parameters.get('Donation') == '1'):
|
|
|
+ raise Exception(
|
|
|
+ 'Donation have to fill "0", when CustomerIdentifier have value.')
|
|
|
+
|
|
|
+ # 當列印註記 Print 為 1 (列印)時,則 CustomerName 與 CustomerAddr 參數必須有值
|
|
|
+ print_param = client_parameters.get('Print')
|
|
|
+ if (print_param == '1') and (not client_parameters.get('CustomerName')):
|
|
|
+ raise Exception('CustomerName have to fill value.')
|
|
|
+ if (print_param == '1') and (not client_parameters.get('CustomerAddr')):
|
|
|
+ raise Exception('CustomerAddr have to fill value.')
|
|
|
+ if (print_param == '1') and client_parameters.get('CarruerType'):
|
|
|
+ raise Exception(
|
|
|
+ 'CarruerType do not fill any value, when Print is "1".')
|
|
|
+
|
|
|
+ # 當客戶電子信箱 CustomerEmail 為空字串時,則 CustomerPhone 參數必須有值
|
|
|
+ customer_email = client_parameters.get('CustomerEmail')
|
|
|
+ if (not customer_email) and (not client_parameters.get('CustomerPhone')):
|
|
|
+ raise Exception('CustomerPhone have to fill value.')
|
|
|
+
|
|
|
+ # 當客戶手機號碼 CustomerPhone 為空字串時,則 CustomerEmail 參數必須有值
|
|
|
+ customer_email = client_parameters.get('CustomerPhone')
|
|
|
+ if (not customer_email) and (not client_parameters.get('CustomerEmail')):
|
|
|
+ raise Exception('CustomerEmail have to fill value.')
|
|
|
+
|
|
|
+ # 當 Donation 為 '1' 時,Print 要為 '0',否則會出現錯誤訊息
|
|
|
+ donation_param = client_parameters.get('Donation')
|
|
|
+ if (donation_param == '1') and (print_param == '1'):
|
|
|
+ raise Exception(
|
|
|
+ 'Print have to fill "0", when Donation is "1".')
|
|
|
+ # 若捐贈註記 Donation = '1' (捐贈)時,LoveCode 須有值
|
|
|
+ love_code = client_parameters.get('LoveCode')
|
|
|
+ if (donation_param == '1') and (not love_code):
|
|
|
+ raise Exception(
|
|
|
+ 'LoveCode have to fill value, when Donation is "1".')
|
|
|
+ if love_code:
|
|
|
+ if len(love_code) < 3 or len(love_code) > 7:
|
|
|
+ raise Exception(
|
|
|
+ 'LoveCode have to fill fixed length of 3~7 digits.')
|
|
|
+
|
|
|
+ urlencode_parameters = ['CustomerName', 'CustomerAddr', 'CustomerEmail',
|
|
|
+ 'InvoiceItemName', 'InvoiceItemWord', 'InvoiceRemark']
|
|
|
+
|
|
|
+ for urlencode_parameter in urlencode_parameters:
|
|
|
+ for k, v in client_parameters.items():
|
|
|
+ if urlencode_parameter == k:
|
|
|
+ client_parameters.update(
|
|
|
+ {k: quote_plus(str(v)).lower()})
|
|
|
+
|
|
|
+ # 用 new.required.dict 與 client.dict 合併為 merge.dict
|
|
|
+ self.final_merge_parameters = super().merge(
|
|
|
+ default_parameters, client_parameters)
|
|
|
+
|
|
|
+ # 檢查參數, 並產生 CheckMacValue
|
|
|
+ self.final_merge_parameters = self.integrate_parameter(
|
|
|
+ self.final_merge_parameters,
|
|
|
+ self.__check_pattern)
|
|
|
+
|
|
|
+ # 回傳給 client
|
|
|
+ return self.final_merge_parameters
|
|
|
+
|
|
|
+
|
|
|
+class OrderSearch(BasePayment):
|
|
|
+
|
|
|
+ # 訂單基本參數
|
|
|
+ __ORDER_SEARCH_PARAMETERS = {
|
|
|
+ 'MerchantID': {'type': str, 'required': True, 'max': 10},
|
|
|
+ 'MerchantTradeNo': {'type': str, 'required': True, 'max': 20},
|
|
|
+ 'TimeStamp': {'type': int, 'required': True, },
|
|
|
+ 'PlatformID': {'type': str, 'required': False, 'max': 10},
|
|
|
+ }
|
|
|
+
|
|
|
+ __url = 'https://payment.ecpay.com.tw/Cashier/QueryTradeInfo/V5'
|
|
|
+
|
|
|
+ def order_search(self, action_url=__url, client_parameters={}):
|
|
|
+ self.__check_pattern = []
|
|
|
+ if action_url is None:
|
|
|
+ action_url = self.__url
|
|
|
+ # 先用 required.dict 設定預設值並產生新 new.required.dict
|
|
|
+ default_parameters = dict()
|
|
|
+ default_parameters = self.create_default_dict(
|
|
|
+ self.__ORDER_SEARCH_PARAMETERS)
|
|
|
+ self.__check_pattern.append(self.__ORDER_SEARCH_PARAMETERS)
|
|
|
+
|
|
|
+ # 用 new.required.dict 與 client.dict 合併為 merge.dict
|
|
|
+ self.final_merge_parameters = super().merge(
|
|
|
+ default_parameters, client_parameters)
|
|
|
+
|
|
|
+ # 檢查參數, 並產生 CheckMacValue
|
|
|
+ self.final_merge_parameters = self.integrate_parameter(
|
|
|
+ self.final_merge_parameters,
|
|
|
+ self.__check_pattern)
|
|
|
+
|
|
|
+ # 回傳給 client
|
|
|
+ response = super().send_post(
|
|
|
+ action_url, self.final_merge_parameters)
|
|
|
+ query = dict(parse_qsl(response.text, keep_blank_values=True))
|
|
|
+ if query.get('CheckMacValue') == self.generate_check_value(query):
|
|
|
+ query.pop('CheckMacValue')
|
|
|
+ return query
|
|
|
+ else:
|
|
|
+ raise Exception("CheckMacValue is error!")
|
|
|
+
|
|
|
+
|
|
|
+class OrderSearchPeriodic(BasePayment):
|
|
|
+
|
|
|
+ # 訂單基本參數
|
|
|
+ __ORDER_SEARCH_PERIODIC_PARAMETERS = {
|
|
|
+ 'MerchantID': {'type': str, 'required': True, 'max': 10},
|
|
|
+ 'MerchantTradeNo': {'type': str, 'required': True, 'max': 20},
|
|
|
+ 'TimeStamp': {'type': int, 'required': True, },
|
|
|
+ }
|
|
|
+
|
|
|
+ __url = 'https://payment.ecpay.com.tw/Cashier/QueryCreditCardPeriodInfo'
|
|
|
+
|
|
|
+ def order_search_period(self, action_url=__url, client_parameters={}):
|
|
|
+ self.__check_pattern = []
|
|
|
+ if action_url is None:
|
|
|
+ action_url = self.__url
|
|
|
+ # 先用 required.dict 設定預設值並產生新 new.required.dict
|
|
|
+ default_parameters = dict()
|
|
|
+ default_parameters = self.create_default_dict(
|
|
|
+ self.__ORDER_SEARCH_PERIODIC_PARAMETERS)
|
|
|
+ self.__check_pattern.append(self.__ORDER_SEARCH_PERIODIC_PARAMETERS)
|
|
|
+
|
|
|
+ # 用 new.required.dict 與 client.dict 合併為 merge.dict
|
|
|
+ self.final_merge_parameters = super().merge(
|
|
|
+ default_parameters, client_parameters)
|
|
|
+
|
|
|
+ # 檢查參數, 並產生 CheckMacValue
|
|
|
+ self.final_merge_parameters = self.integrate_parameter(
|
|
|
+ self.final_merge_parameters,
|
|
|
+ self.__check_pattern)
|
|
|
+
|
|
|
+ # 回傳給 client
|
|
|
+ response = super().send_post(
|
|
|
+ action_url, self.final_merge_parameters)
|
|
|
+ query = json.loads(response.text)
|
|
|
+ return query
|
|
|
+
|
|
|
+
|
|
|
+class CreditDoAction(BasePayment):
|
|
|
+
|
|
|
+ # 訂單基本參數
|
|
|
+ __CREDIT_DO_ACTION_PARAMETERS = {
|
|
|
+ 'MerchantID': {'type': str, 'required': True, 'max': 10},
|
|
|
+ 'MerchantTradeNo': {'type': str, 'required': True, 'max': 20},
|
|
|
+ 'TradeNo': {'type': str, 'required': True, 'max': 20},
|
|
|
+ 'Action': {'type': str, 'required': True, 'max': 1},
|
|
|
+ 'TotalAmount': {'type': int, 'required': True, },
|
|
|
+ 'PlatformID': {'type': str, 'required': False, 'max': 10},
|
|
|
+ }
|
|
|
+
|
|
|
+ __url = 'https://payment.ecpay.com.tw/CreditDetail/DoAction'
|
|
|
+
|
|
|
+ def credit_do_action(self, action_url=__url, client_parameters={}):
|
|
|
+ self.__check_pattern = []
|
|
|
+ if action_url is None:
|
|
|
+ action_url = self.__url
|
|
|
+ # 先用 required.dict 設定預設值並產生新 new.required.dict
|
|
|
+ default_parameters = dict()
|
|
|
+ default_parameters = self.create_default_dict(
|
|
|
+ self.__CREDIT_DO_ACTION_PARAMETERS)
|
|
|
+ self.__check_pattern.append(self.__CREDIT_DO_ACTION_PARAMETERS)
|
|
|
+
|
|
|
+ # 用 new.required.dict 與 client.dict 合併為 merge.dict
|
|
|
+ self.final_merge_parameters = super().merge(
|
|
|
+ default_parameters, client_parameters)
|
|
|
+
|
|
|
+ # 檢查參數, 並產生 CheckMacValue
|
|
|
+ self.final_merge_parameters = self.integrate_parameter(
|
|
|
+ self.final_merge_parameters,
|
|
|
+ self.__check_pattern)
|
|
|
+
|
|
|
+ # 回傳給 client
|
|
|
+ response = super().send_post(
|
|
|
+ action_url, self.final_merge_parameters)
|
|
|
+ query = dict(parse_qsl(response.text, keep_blank_values=True))
|
|
|
+
|
|
|
+ return query
|
|
|
+
|
|
|
+
|
|
|
+class DownloadMerchantBalance(BasePayment):
|
|
|
+
|
|
|
+ # 基本參數
|
|
|
+ __DOWNLOAD_MERCHANT_BALANCE_PARAMETERS = {
|
|
|
+ 'MerchantID': {'type': str, 'required': True, 'max': 10},
|
|
|
+ 'DateType': {'type': str, 'required': True, 'max': 1},
|
|
|
+ 'BeginDate': {'type': str, 'required': True, 'max': 10},
|
|
|
+ 'EndDate': {'type': str, 'required': True, 'max': 10},
|
|
|
+ 'PaymentType': {'type': str, 'required': False, 'max': 2},
|
|
|
+ 'PlatformStatus': {'type': str, 'required': False, 'max': 1},
|
|
|
+ 'PaymentStatus': {'type': str, 'required': False, 'max': 1},
|
|
|
+ 'AllocateStatus': {'type': str, 'required': False, 'max': 1},
|
|
|
+ 'MediaFormated': {'type': str, 'required': True, 'max': 1},
|
|
|
+ }
|
|
|
+
|
|
|
+ __url = 'https://vendor.ecpay.com.tw/PaymentMedia/TradeNoAio'
|
|
|
+
|
|
|
+ def download_merchant_balance(self, action_url=__url, client_parameters={}):
|
|
|
+ self.__check_pattern = []
|
|
|
+ if action_url is None:
|
|
|
+ action_url = self.__url
|
|
|
+ # 先用 required.dict 設定預設值並產生新 new.required.dict
|
|
|
+ default_parameters = dict()
|
|
|
+ default_parameters = self.create_default_dict(
|
|
|
+ self.__DOWNLOAD_MERCHANT_BALANCE_PARAMETERS)
|
|
|
+ self.__check_pattern.append(
|
|
|
+ self.__DOWNLOAD_MERCHANT_BALANCE_PARAMETERS)
|
|
|
+
|
|
|
+ # 用 new.required.dict 與 client.dict 合併為 merge.dict
|
|
|
+ self.final_merge_parameters = super().merge(
|
|
|
+ default_parameters, client_parameters)
|
|
|
+
|
|
|
+ # 檢查參數, 並產生 CheckMacValue
|
|
|
+ self.final_merge_parameters = self.integrate_parameter(
|
|
|
+ self.final_merge_parameters,
|
|
|
+ self.__check_pattern)
|
|
|
+
|
|
|
+ # 回傳給 client
|
|
|
+ response = super().send_post(
|
|
|
+ action_url, self.final_merge_parameters)
|
|
|
+ response.encoding = 'big5'
|
|
|
+ return response.text
|
|
|
+
|
|
|
+
|
|
|
+class SearchSingleTransaction(BasePayment):
|
|
|
+
|
|
|
+ # 基本參數
|
|
|
+ __SEARCH_SINGLE_TRANSACTION_PARAMETERS = {
|
|
|
+ 'MerchantID': {'type': str, 'required': True, 'max': 10},
|
|
|
+ 'CreditRefundId': {'type': int, 'required': True, },
|
|
|
+ 'CreditAmount': {'type': int, 'required': True, },
|
|
|
+ 'CreditCheckCode': {'type': int, 'required': True, },
|
|
|
+ }
|
|
|
+
|
|
|
+ __url = 'https://payment.ecPay.com.tw/CreditDetail/QueryTrade/V2'
|
|
|
+
|
|
|
+ def search_single_transaction(self, action_url=__url, client_parameters={}):
|
|
|
+ self.__check_pattern = []
|
|
|
+ if action_url is None:
|
|
|
+ action_url = self.__url
|
|
|
+ # 先用 required.dict 設定預設值並產生新 new.required.dict
|
|
|
+ default_parameters = dict()
|
|
|
+ default_parameters = self.create_default_dict(
|
|
|
+ self.__SEARCH_SINGLE_TRANSACTION_PARAMETERS)
|
|
|
+ self.__check_pattern.append(
|
|
|
+ self.__SEARCH_SINGLE_TRANSACTION_PARAMETERS)
|
|
|
+
|
|
|
+ # 用 new.required.dict 與 client.dict 合併為 merge.dict
|
|
|
+ self.final_merge_parameters = super().merge(
|
|
|
+ default_parameters, client_parameters)
|
|
|
+
|
|
|
+ # 檢查參數, 並產生 CheckMacValue
|
|
|
+ self.final_merge_parameters = self.integrate_parameter(
|
|
|
+ self.final_merge_parameters,
|
|
|
+ self.__check_pattern)
|
|
|
+
|
|
|
+ # 回傳給 client
|
|
|
+ response = super().send_post(
|
|
|
+ action_url, self.final_merge_parameters)
|
|
|
+ query = json.loads(response.text)
|
|
|
+
|
|
|
+ return query
|
|
|
+
|
|
|
+
|
|
|
+class DownloadDisbursementBalance(BasePayment):
|
|
|
+
|
|
|
+ # 基本參數
|
|
|
+ __DOWNLOAD_DISBURSEMENT_BALANCE_PARAMETERS = {
|
|
|
+ 'MerchantID': {'type': str, 'required': True, 'max': 10},
|
|
|
+ 'PayDateType': {'type': str, 'required': True, 'max': 10},
|
|
|
+ 'StartDate': {'type': str, 'required': True, 'max': 10},
|
|
|
+ 'EndDate': {'type': str, 'required': True, 'max': 10},
|
|
|
+ }
|
|
|
+
|
|
|
+ __url = 'https://payment.ecPay.com.tw/CreditDetail/FundingReconDetail'
|
|
|
+
|
|
|
+ def download_disbursement_balance(self, action_url=__url, client_parameters={}):
|
|
|
+ self.__check_pattern = []
|
|
|
+ if action_url is None:
|
|
|
+ action_url = self.__url
|
|
|
+ # 先用 required.dict 設定預設值並產生新 new.required.dict
|
|
|
+ default_parameters = dict()
|
|
|
+ default_parameters = self.create_default_dict(
|
|
|
+ self.__DOWNLOAD_DISBURSEMENT_BALANCE_PARAMETERS)
|
|
|
+ self.__check_pattern.append(
|
|
|
+ self.__DOWNLOAD_DISBURSEMENT_BALANCE_PARAMETERS)
|
|
|
+
|
|
|
+ # 用 new.required.dict 與 client.dict 合併為 merge.dict
|
|
|
+ self.final_merge_parameters = super().merge(
|
|
|
+ default_parameters, client_parameters)
|
|
|
+
|
|
|
+ # 檢查參數, 並產生 CheckMacValue
|
|
|
+ self.final_merge_parameters = self.integrate_parameter(
|
|
|
+ self.final_merge_parameters,
|
|
|
+ self.__check_pattern)
|
|
|
+
|
|
|
+ # 回傳給 client
|
|
|
+ response = super().send_post(
|
|
|
+ action_url, self.final_merge_parameters)
|
|
|
+ response.encoding = 'big5'
|
|
|
+ return response.text
|
|
|
+
|
|
|
+
|
|
|
+"""
|
|
|
+主程式
|
|
|
+"""
|
|
|
+a = [CreateOrder, OrderSearch,
|
|
|
+ OrderSearchPeriodic, CreditDoAction,
|
|
|
+ DownloadMerchantBalance, SearchSingleTransaction,
|
|
|
+ DownloadDisbursementBalance, ExtendFunction]
|
|
|
+
|
|
|
+
|
|
|
+class ECPayPaymentSdk(*a):
|
|
|
+
|
|
|
+ def __init__(self, MerchantID='', HashKey='', HashIV=''):
|
|
|
+ self.MerchantID = MerchantID
|
|
|
+ self.HashKey = HashKey
|
|
|
+ self.HashIV = HashIV
|