payment.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. from typing import Any, List, Optional
  2. from datetime import datetime
  3. from fastapi import APIRouter, Body, Depends, HTTPException, Form, status, Response
  4. from fastapi.encoders import jsonable_encoder
  5. from pydantic.networks import EmailStr, HttpUrl
  6. from sqlalchemy.orm import Session
  7. import app.crud as crud
  8. import app.models as models
  9. import app.schemas as schemas
  10. from app.api import deps
  11. from app.core.config import settings
  12. from app.core.ecpay_payment_sdk import ECPayPaymentSdk
  13. from app.utils import send_new_account_email
  14. from pydantic import BaseModel
  15. import requests
  16. from random import choice
  17. import string
  18. import json
  19. router = APIRouter()
  20. @router.post('/ecpay-test-payment')
  21. def ecpay_payment(
  22. *,
  23. db: Session = Depends(deps.get_db),
  24. current_user: models.User = Depends(deps.get_current_active_user),
  25. payment_data: schemas.PaymentCreate,
  26. lang: str=''
  27. ):
  28. print(payment_data)
  29. MerchantTradeNo = 'test'+datetime.now().strftime("NO%Y%m%d%H%M%S")
  30. remark = {'MerchantTradeNo':MerchantTradeNo}
  31. remark_string = json.dumps(remark, ensure_ascii=False)
  32. payment = crud.payment.create_with_payment_data(db,
  33. obj_in=payment_data,
  34. owner_id=current_user.id,
  35. epayment='ecpay',
  36. remark=remark_string)
  37. items = payment_data.item
  38. items = items.split("#")
  39. print(payment.item)
  40. content = {}
  41. for item in items:
  42. pair = item.split()
  43. content[str(pair[0]).lower()] = pair[1]
  44. content_string = json.dumps(content, ensure_ascii=False).replace('"', "'")
  45. order_params = {
  46. 'MerchantTradeNo': MerchantTradeNo,
  47. 'StoreID': 'SaaS',
  48. 'MerchantTradeDate': datetime.now().strftime("%Y/%m/%d %H:%M:%S"),
  49. 'PaymentType': 'aio',
  50. 'TotalAmount': payment_data.amount,
  51. 'TradeDesc': 'SaaS訂單',
  52. 'ItemName': payment_data.item,
  53. 'ReturnURL': 'https://cloud.choozmo.com/api/v1/payment/ecpay-result-return',
  54. 'ChoosePayment': 'ALL',
  55. 'ClientBackURL': 'https://cloud.choozmo.com/test-payment',
  56. 'ItemURL': 'https://cloud.choozmo.com/test-payment',
  57. 'Remark': '',
  58. 'ChooseSubPayment': '',
  59. 'OrderResultURL': '',
  60. 'NeedExtraPaidInfo': 'Y',
  61. 'DeviceSource': '',
  62. 'IgnorePayment': 'ATM#CVS#BARCODE',
  63. 'PlatformID': '',
  64. 'InvoiceMark': 'N',
  65. 'CustomField1': f'{str(payment.id)}',
  66. 'CustomField2': f'{str(current_user.id)}',
  67. 'CustomField3': content_string,
  68. 'CustomField4': '',
  69. 'EncryptType': 1,
  70. 'Language': lang,
  71. }
  72. print(order_params)
  73. extend_params_1 = {
  74. 'ExpireDate': 7,
  75. 'PaymentInfoURL': 'https://www.ecpay.com.tw/payment_info_url.php',
  76. 'ClientRedirectURL': '',
  77. }
  78. extend_params_2 = {
  79. 'StoreExpireDate': 15,
  80. 'Desc_1': '',
  81. 'Desc_2': '',
  82. 'Desc_3': '',
  83. 'Desc_4': '',
  84. 'PaymentInfoURL': 'https://www.ecpay.com.tw/payment_info_url.php',
  85. 'ClientRedirectURL': '',
  86. }
  87. extend_params_3 = {
  88. 'BindingCard': 0,
  89. 'MerchantMemberID': '',
  90. }
  91. extend_params_4 = {
  92. 'Redeem': 'N',
  93. 'UnionPay': 0,
  94. }
  95. inv_params = {
  96. # 'RelateNumber': 'Tea0001', # 特店自訂編號
  97. # 'CustomerID': 'TEA_0000001', # 客戶編號
  98. # 'CustomerIdentifier': '53348111', # 統一編號
  99. # 'CustomerName': '客戶名稱',
  100. # 'CustomerAddr': '客戶地址',
  101. # 'CustomerPhone': '0912345678', # 客戶手機號碼
  102. # 'CustomerEmail': 'abc@ecpay.com.tw',
  103. # 'ClearanceMark': '2', # 通關方式
  104. # 'TaxType': '1', # 課稅類別
  105. # 'CarruerType': '', # 載具類別
  106. # 'CarruerNum': '', # 載具編號
  107. # 'Donation': '1', # 捐贈註記
  108. # 'LoveCode': '168001', # 捐贈碼
  109. # 'Print': '1',
  110. # 'InvoiceItemName': '測試商品1|測試商品2',
  111. # 'InvoiceItemCount': '2|3',
  112. # 'InvoiceItemWord': '個|包',
  113. # 'InvoiceItemPrice': '35|10',
  114. # 'InvoiceItemTaxType': '1|1',
  115. # 'InvoiceRemark': '測試商品1的說明|測試商品2的說明',
  116. # 'DelayDay': '0', # 延遲天數
  117. # 'InvType': '07', # 字軌類別
  118. }
  119. # 建立實體
  120. ecpay_payment_sdk = ECPayPaymentSdk(
  121. MerchantID='3002607',
  122. HashKey='pwFHCqoQZGmho4w6',
  123. HashIV='EkRm7iFT261dpevs'
  124. )
  125. # 合併延伸參數
  126. order_params.update(extend_params_1)
  127. order_params.update(extend_params_2)
  128. order_params.update(extend_params_3)
  129. order_params.update(extend_params_4)
  130. # 合併發票參數
  131. order_params.update(inv_params)
  132. try:
  133. # 產生綠界訂單所需參數
  134. final_order_params = ecpay_payment_sdk.create_order(order_params)
  135. # 產生 html 的 form 格式
  136. action_url = 'https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5' # 測試環境
  137. # action_url = 'https://payment.ecpay.com.tw/Cashier/AioCheckOut/V5' # 正式環境
  138. html = ecpay_payment_sdk.gen_html_post_form(action_url, final_order_params)
  139. return html
  140. except Exception as error:
  141. print('An exception happened: ' + str(error))
  142. @router.post('/ecpay-payment')
  143. def ecpay_payment(
  144. *,
  145. db: Session = Depends(deps.get_db),
  146. current_user: models.User = Depends(deps.get_current_active_user),
  147. payment_data: schemas.PaymentCreate,
  148. lang: str=''
  149. ):
  150. print(payment_data)
  151. numbers = string.digits
  152. randomNumber = ''.join(choice(numbers) for _ in range(4))
  153. MerchantTradeNo = datetime.now().strftime("%Y%m%d%H%M%SNO")+randomNumber
  154. remark = {'MerchantTradeNo':MerchantTradeNo}
  155. remark_string = json.dumps(remark, ensure_ascii=False)
  156. payment = crud.payment.create_with_payment_data(db,
  157. obj_in=payment_data,
  158. owner_id=current_user.id,
  159. epayment='ecpay',
  160. remark=remark_string)
  161. items = payment_data.item
  162. items = items.split("#")
  163. content = {}
  164. for item in items:
  165. pair = item.split()
  166. content[str(pair[0]).lower()] = pair[1]
  167. content_string = json.dumps(content, ensure_ascii=False)
  168. order_params = {
  169. 'MerchantTradeNo': MerchantTradeNo,
  170. 'StoreID': 'SaaS',
  171. 'MerchantTradeDate': datetime.now().strftime("%Y/%m/%d %H:%M:%S"),
  172. 'PaymentType': 'aio',
  173. 'TotalAmount': payment_data.amount,
  174. 'TradeDesc': 'SaaS訂單',
  175. 'ItemName': payment_data.item,
  176. 'ReturnURL': 'https://cloud.choozmo.com/api/v1/payment/ecpay-result-return',
  177. 'ChoosePayment': 'ALL',
  178. 'ClientBackURL': 'https://cloud.choozmo.com/main/dashboard',
  179. 'ItemURL': 'https://cloud.choozmo.com/main/dashboard',
  180. 'Remark': '',
  181. 'ChooseSubPayment': '',
  182. 'OrderResultURL': '',
  183. 'NeedExtraPaidInfo': 'Y',
  184. 'DeviceSource': '',
  185. 'IgnorePayment': 'ATM#CVS#BARCODE',
  186. 'PlatformID': '',
  187. 'InvoiceMark': 'N',
  188. 'CustomField1': str(payment.id),
  189. 'CustomField2': str(current_user.id),
  190. 'CustomField3': content_string,
  191. 'CustomField4': '',
  192. 'EncryptType': 1,
  193. 'Language': lang,
  194. }
  195. extend_params_1 = {
  196. 'ExpireDate': 7,
  197. 'PaymentInfoURL': 'https://www.ecpay.com.tw/payment_info_url.php',
  198. 'ClientRedirectURL': '',
  199. }
  200. extend_params_2 = {
  201. 'StoreExpireDate': 15,
  202. 'Desc_1': '',
  203. 'Desc_2': '',
  204. 'Desc_3': '',
  205. 'Desc_4': '',
  206. 'PaymentInfoURL': 'https://www.ecpay.com.tw/payment_info_url.php',
  207. 'ClientRedirectURL': '',
  208. }
  209. extend_params_3 = {
  210. 'BindingCard': 0,
  211. 'MerchantMemberID': '',
  212. }
  213. extend_params_4 = {
  214. 'Redeem': 'N',
  215. 'UnionPay': 0,
  216. }
  217. inv_params = {
  218. # 'RelateNumber': 'Tea0001', # 特店自訂編號
  219. # 'CustomerID': 'TEA_0000001', # 客戶編號
  220. # 'CustomerIdentifier': '53348111', # 統一編號
  221. # 'CustomerName': '客戶名稱',
  222. # 'CustomerAddr': '客戶地址',
  223. # 'CustomerPhone': '0912345678', # 客戶手機號碼
  224. # 'CustomerEmail': 'abc@ecpay.com.tw',
  225. # 'ClearanceMark': '2', # 通關方式
  226. # 'TaxType': '1', # 課稅類別
  227. # 'CarruerType': '', # 載具類別
  228. # 'CarruerNum': '', # 載具編號
  229. # 'Donation': '1', # 捐贈註記
  230. # 'LoveCode': '168001', # 捐贈碼
  231. # 'Print': '1',
  232. # 'InvoiceItemName': '測試商品1|測試商品2',
  233. # 'InvoiceItemCount': '2|3',
  234. # 'InvoiceItemWord': '個|包',
  235. # 'InvoiceItemPrice': '35|10',
  236. # 'InvoiceItemTaxType': '1|1',
  237. # 'InvoiceRemark': '測試商品1的說明|測試商品2的說明',
  238. # 'DelayDay': '0', # 延遲天數
  239. # 'InvType': '07', # 字軌類別
  240. }
  241. # 建立實體
  242. ecpay_payment_sdk = ECPayPaymentSdk(
  243. MerchantID='3226141',
  244. HashKey='OhcjDTeXK9PKW9vb',
  245. HashIV='AfOmUM06S0bt8KPE'
  246. )
  247. # 合併延伸參數
  248. order_params.update(extend_params_1)
  249. order_params.update(extend_params_2)
  250. order_params.update(extend_params_3)
  251. order_params.update(extend_params_4)
  252. # 合併發票參數
  253. order_params.update(inv_params)
  254. try:
  255. # 產生綠界訂單所需參數
  256. final_order_params = ecpay_payment_sdk.create_order(order_params)
  257. # 產生 html 的 form 格式
  258. # action_url = 'https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5' # 測試環境
  259. action_url = 'https://payment.ecpay.com.tw/Cashier/AioCheckOut/V5' # 正式環境
  260. html = ecpay_payment_sdk.gen_html_post_form(action_url, final_order_params)
  261. return html
  262. except Exception as error:
  263. print('An exception happened: ' + str(error))
  264. @router.get('/list-all', response_model=List[schemas.YTViews])
  265. def get_list(
  266. *,
  267. db: Session = Depends(deps.get_db),
  268. ):
  269. ytviews_list = crud.ytviews.get_multi(db)
  270. return ytviews_list
  271. @router.post("/ecpay-result-return")
  272. def ecpay_return(
  273. *,
  274. db: Session = Depends(deps.get_db),
  275. MerchantID: Optional[str]=Form(None),
  276. MerchantTradeNo: Optional[str]=Form(None),
  277. StoreID: Optional[str]=Form(None),
  278. RtnCode: Optional[int]=Form(None),
  279. RtnMsg: Optional[str]=Form(None),
  280. TradeNo: Optional[str]=Form(None),
  281. TradeAmt: Optional[int]=Form(None),
  282. PaymentDate: Optional[str]=Form(None),
  283. PaymentType: Optional[str]=Form(None),
  284. PaymentTypeChargeFee: Optional[int]=Form(None),
  285. TradeDate: Optional[str]=Form(None),
  286. SimulatePaid: Optional[int]=Form(None),
  287. CustomField1: Optional[str]=Form(None),
  288. CustomField2: Optional[str]=Form(None),
  289. CustomField3: Optional[str]=Form(None),
  290. CustomField4: Optional[str]=Form(None),
  291. CheckMacValue: Optional[str]=Form(None),
  292. ) -> Any:
  293. #送email
  294. print(f"\
  295. MerchantID: {MerchantID} \n\
  296. MerchantTradeNo: {MerchantTradeNo}\n\
  297. StoreID: {StoreID}\n\
  298. RtnCode: {RtnCode}\n\
  299. RtnMsg: {RtnMsg}\n\
  300. TradeNo: {TradeNo}\n\
  301. TradeAmt: {TradeAmt}\n\
  302. PaymentDate: {PaymentDate}\n\
  303. PaymentType: {PaymentType}\n\
  304. PaymentTypeChargeFee: {PaymentTypeChargeFee}\n\
  305. TradeDate: {TradeDate}\n\
  306. SimulatePaid: {SimulatePaid}\n\
  307. CustomField1: {CustomField1}\n\
  308. CustomField2: {CustomField2}\n\
  309. CustomField3: {CustomField3}\n\
  310. CustomField4: {CustomField4}\n\
  311. CheckMacValue: {CheckMacValue}\
  312. ")
  313. if RtnCode==1:
  314. payment_id = int(CustomField1)
  315. payment = crud.payment.get(db=db, id=payment_id)
  316. remark = json.loads(payment.remark)
  317. remark['TradeNo'] = TradeNo
  318. content_string = CustomField3.replace("'",'"')
  319. content:dict = json.loads(content_string)
  320. user = crud.user.get(db=db, id=int(CustomField2))
  321. if 'credit' in content.keys():
  322. add_credit = content['credit']
  323. crud.user.update(db, db_obj=user, obj_in={"available_time": user.available_time + int(add_credit)})
  324. payment = crud.payment.update(db, db_obj=payment, obj_in={"payment_state":"succeeded", "remark":json.dumps(remark, ensure_ascii=False)})
  325. else:
  326. payment = crud.payment.update(db, db_obj=payment, obj_in={"payment_state":"failed", "remark":json.dumps(remark, ensure_ascii=False)})
  327. print(payment.payment_state)
  328. return Response(content='1', status_code=status.HTTP_200_OK)