Advertisement
Guest User

Untitled

a guest
Nov 8th, 2016
423
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 47.51 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. from .base import BankModule
  3. from .exceptions import *
  4. import requests
  5. import datetime
  6. import urllib
  7. import time
  8. import json
  9. import re
  10.  
  11.  
  12. class TMB(BankModule):
  13.  
  14. name = 'TMB'
  15.  
  16. default_version = 3.0
  17. default_days = 2
  18. build = 1004
  19. TMB_APP_VER = '1.0.12.30'
  20. auto_add_account = 'autoAddAccount'
  21. sub_add_account = 'subAddAccount'
  22. WEBSITE = 'https://www.tmbdirect.com' # For test
  23.  
  24. def __init__(self, logger=None):
  25. super(self.__class__, self).__init__(logger=logger)
  26.  
  27. self.session = requests.Session()
  28. self.session.verify = False # TODO: Dev only
  29. self.TIMEOUT = None # TODO: Dev only
  30. self._domain = 'https://www.tmbdirect.com'
  31. self._landing_path = '/tmb/kdw1.7.5'
  32.  
  33. self._home_url = 'https://www.tmbdirect.com/tmb/kdw1.7.5'
  34. self._url = 'https://www.tmbdirect.com/tmb/MWServlet'
  35.  
  36. self._campaign_url = 'https://www.tmbdirect.com/services/TMBMIBService0/GetCampaign'
  37. self._login_url = 'https://www.tmbdirect.com/services/TMBMIBService9/IBVerifyLoginEligibility'
  38. self._customer_account_inquiry_url = 'https://www.tmbdirect.com/services/TMBMIBService5/customerAccountInquiry'
  39. self._calendar_inquiry_url = 'https://www.tmbdirect.com/services/TMBMIBService0/CalendarInquiry'
  40. self._logout_url = 'https://www.tmbdirect.com/services/TMBMIBService0/logOutTMB'
  41.  
  42. self._service_form = {
  43. 'appID': 'TMB',
  44. 'appver': self.TMB_APP_VER,
  45. 'locale': 'th_TH',
  46. 'channel': 'wap',
  47. 'platform': 'thinclient',
  48. 'cacheid': '',
  49. 'rcid': 'spadesktopweb',
  50. }
  51. self._useragent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36'
  52. self.session.headers.update({'User-Agent': self._useragent})
  53. self.auto_add_account_filter = self.auto_add_account[:13]
  54. self.tknid = None
  55.  
  56. def get_all_transactions(self):
  57. logger = self.logger.add_tag('get_all_transactions')
  58. self.accounts = []
  59. data = dict()
  60. today = datetime.date.today()
  61. query_date = []
  62. if (today - datetime.timedelta(days=1)).month != today.month: # Between month
  63. date_from = today - datetime.timedelta(days=2)
  64. date_to = date_from + datetime.timedelta(days=1)
  65. query_date.append((date_from, date_to))
  66.  
  67. date_from = today
  68. date_to = today
  69. query_date.append((date_from, date_to))
  70. else:
  71. date_from = today - datetime.timedelta(days=1)
  72. date_to = today
  73. query_date.append((date_from, date_to))
  74. for date_from, date_to in query_date:
  75. today_str = date_to.strftime('%d.%m.%Y')
  76. yesterday_str = date_from.strftime('%d.%m.%Y')
  77. data.update(self._service_form)
  78. data.update({
  79. 'serviceID': 'CalendarInquiry',
  80. 'tknid': self.tknid,
  81. 'reloadFlag': '1',
  82. 'accountDetailsFromLink': '',
  83. 'bankCd': '11',
  84. 'startDate': yesterday_str,
  85. 'endDate': today_str,
  86. })
  87. r = self.web_post(self._calendar_inquiry_url, data=data, soup=False)
  88. logger.debug(msg='Get CalendarInquiry page.', attachment=r)
  89. result = json.loads(r)
  90. # today_date_str = result['todayDate']
  91. self.tknid = result['tknid']
  92. for key, val in result.items():
  93. if key.startswith('0000'):
  94. account_exists = [x for x in self.accounts if x['account_no'] == key]
  95. if account_exists:
  96. account = account_exists[0]
  97. else:
  98. account = dict(name='acc_name', statements=[], account_no=key)
  99. self.accounts.append(account)
  100. for statement in val:
  101. ref_id = statement['finTxnRefID']
  102. txt_date = statement['txnDate']
  103. txt_time = statement['txnTime']
  104. amount = self.parse_float_or_none(statement['finTxnAmount'])
  105. from_id = statement['fromAcctID']
  106. to_acct = None
  107. if 'toAcctNickname' in statement and statement['toAcctNickname']:
  108. to_acct = statement['toAcctNickname']
  109. description = statement['txnDescription']
  110.  
  111. channel = None
  112. translate_channels = (
  113. ('via Mobile', 'MOB'),
  114. ('via Internet', 'IB'),
  115. ('via TMB ATM', 'ATM'),
  116. ('via KBANK ATM', 'ATM'),
  117. ('via SCB ATM', 'ATM'),
  118. ('via BAAC ATM', 'ATM'),
  119. ('via BBL ATM', 'ATM'),
  120. ('via KTB ATM', 'ATM'),
  121. ('via KBANK', 'IB'),
  122. ('via SCB', 'IB'),
  123. ('via KTB', 'IB'),
  124. ('via BBL', 'IB'),
  125. ('via BAAC', 'IB'),
  126. )
  127. for keyword, value in translate_channels:
  128. if keyword in description:
  129. channel = value
  130. break
  131.  
  132. if not amount:
  133. revert_desc = description[::-1]
  134. try:
  135. revert_index = revert_desc.index('t\\')
  136. except ValueError:
  137. revert_index = None
  138. if revert_index:
  139. revert_desc = revert_desc[:revert_index]
  140. amount_desc = revert_desc[::-1]
  141. else:
  142. amount_desc = description
  143. # KARAT 2 150.00 ฿ must result 150.00
  144. re_match = re.search(r'(?P<amount>[0-9.]+) ฿', amount_desc)
  145. if re_match:
  146. amount = self.parse_float_or_none(re_match.group('amount'))
  147. else:
  148. amount = self.parse_float_or_none(''.join([x for x in amount_desc if x in '0123456789.']))
  149. if not amount:
  150. raise PluginError('Cannot parse Amount on TMB! (get "" even finTxnAmount and txnDescription)')
  151. if not to_acct:
  152. method = 'DP'
  153. deposit = amount
  154. withdraw = None
  155. ref_id = 'DP {} {} {}'.format(from_id, txt_date, txt_time)
  156. elif to_acct:
  157. method = 'WD'
  158. withdraw = amount
  159. deposit = None
  160. date_time_str = '{} {}'.format(txt_date, txt_time)
  161. date_object = datetime.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S')
  162. account['statements'].append(dict(date_str=date_time_str, create_on=date_object, desc=description, withdraw=withdraw, deposit=deposit, balance=None, channel=channel, method=method, log=ref_id))
  163. return self.accounts
  164.  
  165. def pre_login(self):
  166. logger = self.logger.add_tag('pre_login')
  167. self.accounts = []
  168.  
  169. # GET Website and parse kdw version
  170. r = self.http_get(self.WEBSITE)
  171. logger.debug(msg='GET Pre home page.', attachment=r.text)
  172. re_kdw = re.search(r'(?P<kdw>https://www\.tmbdirect\.com/tmb/kdw\d+\.\d+\.\d+)', r.text)
  173. if not re_kdw:
  174. raise PluginHandledError('Unhandle Login Page (Might be kdw version changed).')
  175. kdw_url = re_kdw.group('kdw')
  176.  
  177. # GET home page and parse TMB APP VERSION
  178. r = self.http_get(kdw_url)
  179. logger.debug(msg='GET home page.', attachment=r.text)
  180.  
  181. if '$KG["version"] = "1.0.' in r.text:
  182. re_result = re.search(r'\$KG\[\"version\"\] = \"(?P<version>[0-9.]+)\"', r.text)
  183. if self.TMB_APP_VER != re_result.group('version'):
  184. logger.warning(msg='TMB version has change from %s to %s (Please contact developer team.)' % (self.TMB_APP_VER, re_result.group('version')))
  185. self.TMB_APP_VER = re_result.group('version')
  186. logger.debug(msg='TMB version %s' % self.TMB_APP_VER)
  187. self._service_form['appver'] = self.TMB_APP_VER
  188.  
  189. '''
  190. Kony App Key, Secret
  191. '''
  192. kony_app_key = 'ae8cd4fb292a12727a4833c9fdb8ccb0'
  193. kony_app_secret = '9bca06a1518df6af31382131cd911009'
  194. config_url = 'https://www.tmbdirect.com/authService/100000004/appconfig'
  195. login_url = 'https://www.tmbdirect.com/authService/100000004/login'
  196. headers = {
  197. 'Content-Type': 'application/json',
  198. 'X-HTTP-Method-Override': 'GET',
  199. 'X-Kony-App-Key': kony_app_key,
  200. 'X-Kony-App-Secret': kony_app_secret,
  201. }
  202. r = self.http_post(config_url, data='ltrim=function%20()%7Breturn%20this.replace(%2F%5E%5Cs%2B%2F%2C%22%22)%7D&rtrim=function%20()%7Breturn%20this.replace(%2F%5Cs%2B%24%2F%2C%22%22)%7D', headers=headers)
  203. logger.debug(msg='GET kony config.', attachment=r.text)
  204. r_json = r.json()
  205. self.mfbaseid = r_json['baseId']
  206. self.appid = r_json['appId']
  207.  
  208. headers = {
  209. 'X-Kony-App-Key': kony_app_key,
  210. 'X-Kony-App-Secret': kony_app_secret,
  211. }
  212. r = self.http_post(login_url, data={}, headers=headers)
  213. r_json = r.json()
  214. kony_token = r_json['claims_token']['value']
  215. self.session.headers.update({
  216. 'X-Kony-Authorization': kony_token,
  217. })
  218. logger.debug(msg='GET kony authorization.', attachment=kony_token)
  219.  
  220. data = self._craft_data({
  221. 'events': '[]',
  222. 'timestamp': '',
  223. 'localeId': '',
  224. 'platform1': 'D',
  225. 'serviceID': 'getPhrases',
  226. 'app_name': 'TMBUI',
  227. 'widgetName': 'segCampaignImage',
  228. 'formName': 'frmIBPreLogin',
  229. 'appChannel': 'I',
  230. 'prelogin': 'Y',
  231. 'tknid': '',
  232. 'httpheaders': '{}',
  233. 'httpconfig': '{"timeout":180000}',
  234. })
  235. r = self.http_post(self.get_service_url('getPhrases'), data=data)
  236. logger.debug(msg='GET pre login prases.', attachment=r.text)
  237.  
  238. # GET tknid
  239. data = self._craft_data({
  240. 'events': '[]',
  241. 'serviceID': 'GetCampaign',
  242. 'app_name': 'TMBUI',
  243. 'widgetName': 'segCampaignImage',
  244. 'formName': 'frmIBPreLogin',
  245. 'appChannel': 'I',
  246. 'prelogin': 'Y',
  247. 'tknid': '',
  248. 'httpheaders': '{}',
  249. 'httpconfig': '{"timeout":180000}',
  250. })
  251. r = self.http_post(self.get_service_url('GetCampaign'), data=data) # , cookies=cookies)
  252. logger.debug(msg='GET pre login.', attachment=r.text)
  253. result = r.json()
  254. self.tknid = result['tknid']
  255.  
  256. def login(self, username, password):
  257. logger = self.logger.add_tag('login')
  258. self.pre_login()
  259.  
  260. logger.info('Loggin with user="%s" appver="%s"' % (username, self.TMB_APP_VER))
  261. data = dict(loginId=username, userid=username, password=password)
  262. data.update({
  263. 'events': '[]',
  264. 'appID': 'TMB',
  265. 'appver': self.TMB_APP_VER,
  266. 'serviceID': 'IBVerifyLoginEligibility',
  267. 'locale': 'th_TH',
  268. 'channel': 'wap',
  269. 'platform': 'thinclient',
  270. 'cacheid': '',
  271. 'tknid': self.tknid,
  272. 'rcid': 'spadesktopweb',
  273. })
  274.  
  275. r = self.http_post(self.get_service_url('IBVerifyLoginEligibility'), data=data)
  276. raw_result = r.text
  277. logger.debug(msg='POST Login page.', attachment=raw_result)
  278. if r.status_code >= 500: # 500 Internal Server Error
  279. raise PluginHandledError('Unhandle Login result (Might be version changed or captcha).')
  280.  
  281. result = r.json()
  282. if 'httpStatusCode' not in result:
  283. logger.error(msg='Unhandle Login result (Might be version changed or captcha).', attachment=result)
  284. errmsg = result['errmsg'] if 'errmsg' in result else ''
  285. if result.get('captchaCode') == '1':
  286. raise PluginHandledError('Login Failed, Captcha detected.')
  287. raise Exception(u'Unhandle Login result (Might be version changed or captcha). (errmsg=%s)' % errmsg)
  288. if result['httpStatusCode'] == 500:
  289. if 'loginattemptcountint' in result:
  290. raise LoginError('Incorrect password')
  291. else:
  292. raise LoginInused('Login currenly in used.')
  293. self.tknid = result['tknid']
  294.  
  295. data = self._craft_data({
  296. 'serviceID': 'customerAccountInquiry',
  297. 'activationCompleteFlag': 'true',
  298. 'upgradeSkip': '',
  299. 'cacheid': '',
  300. })
  301. r = self.http_post(self.get_service_url('customerAccountInquiry'), data)
  302. logger.info(msg='Login activated page', attachment=r.text)
  303.  
  304. return True
  305.  
  306. def transactions(self, account_no):
  307. if not self.accounts:
  308. self.get_all_transactions()
  309. account_no = account_no.replace('-', '')
  310. seen_account = [x['account_no'] for x in self.accounts]
  311. for account in self.accounts:
  312. acc_no = account['account_no']
  313. if str('0000' + account_no) == str(acc_no):
  314. return account['statements']
  315. return []
  316. # raise PluginError('Account %s not found, available %s ' % (account_no, seen_account))
  317.  
  318. def balances(self):
  319. logger = self.logger.add_tag('balances')
  320. '''
  321. เปิดหน้าโอน
  322. '''
  323. data = self._craft_data({
  324. 'serviceID': 'customerAccountInquiry',
  325. # 'transferFlag': 'true',
  326. })
  327. r = self.http_post(self._customer_account_inquiry_url, data)
  328. logger.info(msg='Transfer(balance) page', attachment=r.text)
  329. result = r.json()
  330. all_acc = result['custAcctRec']
  331. data = []
  332. for account_rec in all_acc:
  333. account_no = account_rec['accId'][4:] # Trim 4 ตัวแรกทิ้ง
  334. status = account_rec['acctStatus']
  335. status = status[0:7]
  336. ledger_balance = self.parse_float_or_none(account_rec['ledgerBal'])
  337. balance = self.parse_float_or_none(account_rec['availableBal'])
  338. if status == 'Active ':
  339. ledger_balance = ledger_balance
  340. balance = ledger_balance
  341. elif status == 'Dormant':
  342. ledger_balance = ledger_balance
  343. balance = 0 # Dormant only
  344. else:
  345. raise Exception('Unhandled status.')
  346. data_row = {
  347. 'account_no': account_no,
  348. 'balance': balance, # 0 ถ่าโดนอายัด
  349. 'ledger_balance': ledger_balance,
  350. }
  351. data.append(data_row)
  352. return data
  353.  
  354. def balance(self, account_no):
  355. from banktransfer.models import STATE_ADD_ENUM
  356. balances = self.balances()
  357. balances = [x for x in balances if x['account_no'] == account_no]
  358. if not balances:
  359. raise Exception('Account no %s not found.' % account_no)
  360. data = {
  361. '_balance': balances[0]['balance'],
  362. '_state_add': STATE_ADD_ENUM.WAIT_ADD,
  363. }
  364. return data
  365.  
  366. def get_service_url(self, service_name):
  367. service_ids = {
  368. 'IBVerifyLoginEligibility': 9,
  369. 'customerAccountInquiry': 5,
  370. 'depositAccountInquiry': 7,
  371. 'debitCardInq': 5,
  372. 'crmProfileInq': 5,
  373. 'depositAccountInquiryNonSec': 7,
  374. 'fundTransferInq': 5,
  375. 'generateOTPWithUser': 14,
  376. }
  377. return 'https://www.tmbdirect.com/services/TMBMIBService%s/%s' % (service_ids.get(service_name, 0), service_name)
  378.  
  379. def pre_add_account(self, account_no, account_name='', branch_name='', mobile_no='', email='', task=None, amount=None, from_account_no=None):
  380. from banktransfer.models import STATE_ADD_ENUM
  381. logger = self.logger.add_tag('pre_add_account')
  382.  
  383. '''
  384. เปิดหน้าโอน
  385. '''
  386. data = self._craft_data({
  387. 'serviceID': 'customerAccountInquiry',
  388. 'transferFlag': 'true',
  389. })
  390. r = self.http_post(self._customer_account_inquiry_url, data)
  391. logger.info(msg='pre_add_account page1', attachment=r.text)
  392. result = r.json()
  393. self._save_session(result)
  394.  
  395. found = False
  396. found_accounts = []
  397. use_product_id = None
  398. for account_rec in result['custAcctRec']:
  399. account_id = account_rec['accId'][4:] # Trim 4 ตัวแรกทิ้ง
  400. product_id = account_rec['productID']
  401. if from_account_no == account_id:
  402. use_product_id = product_id
  403. found_accounts.append((account_id, product_id))
  404. if not use_product_id: # Not found, use fake
  405. from_account_no, use_product_id = found_accounts[0]
  406.  
  407. '''
  408. เปิดผู้รับโอน
  409. '''
  410. data = self._craft_data({
  411. 'serviceID': 'receipentgetBankService',
  412. })
  413. url = 'https://www.tmbdirect.com/services/TMBMIBService0/receipentgetBankService'
  414. r = self.http_post(url, data)
  415. logger.info(msg='pre_add_account page2', attachment=r.text)
  416. result = r.json()
  417. self._save_session(result)
  418.  
  419. data = self._craft_data({
  420. 'serviceID': 'getRecipientsForTransfer',
  421. 'prodId': use_product_id,
  422. 'accId': from_account_no,
  423. })
  424. url = 'https://www.tmbdirect.com/services/TMBMIBService0/getRecipientsForTransfer'
  425. r = self.http_post(url, data)
  426. logger.info(msg='pre_add_account page3(data)', attachment=json.dumps(data))
  427. logger.info(msg='pre_add_account page3', attachment=r.text)
  428. result = r.json()
  429. self._save_session(result)
  430.  
  431. found = False
  432. personalized_id = None
  433. for recepient in result['RecepientsList']:
  434. if recepient['personalizedName'] == self.auto_add_account:
  435. found = True
  436. personalized_id = recepient['personalizedId']
  437.  
  438. if not found: # autoAddAccount Not found, create!
  439.  
  440. data = self._craft_data({
  441. 'crmId': '',
  442. 'rqUUId': '',
  443. 'channelName': 'IB-INQ',
  444. 'serviceID': 'crmProfileInq',
  445. })
  446. url = 'https://www.tmbdirect.com/services/TMBMIBService5/crmProfileInq'
  447. r = self.http_post(url, data)
  448. logger.info(msg='pre_add_account (create account) page3.5', attachment=r.text)
  449. result = r.json()
  450.  
  451. data = self._craft_data({
  452. 'crmId': '',
  453. 'rqUUId': '',
  454. 'channelName': 'IB-INQ',
  455. 'serviceID': 'crmProfileInq',
  456. })
  457. r = self.http_post(url, data)
  458. logger.info(msg='pre_add_account (create account) page4.5(2)', attachment=r.text)
  459. result = r.json()
  460.  
  461. data = self._craft_data({
  462. 'serviceID': 'receipentgetBankService',
  463. })
  464. url = 'https://www.tmbdirect.com/services/TMBMIBService0/receipentgetBankService'
  465. r = self.http_post(url, data)
  466. logger.info(msg='pre_add_account getBankService', attachment=r.text)
  467. result = r.json()
  468. self._save_session(result)
  469.  
  470. data = self._craft_data({
  471. 'serviceID': 'depositAccountInquiryNonSec',
  472. 'acctId': account_no,
  473. 'toAcctNo': account_no,
  474. 'isFromRecipient': 'yes',
  475. 'bankcode': '11', # TMB Only
  476. })
  477. url = 'https://www.tmbdirect.com/services/TMBMIBService7/depositAccountInquiryNonSec'
  478. r = self.http_post(url, data)
  479. logger.info(msg='pre_add_account depositAccountInquiryNonSec', attachment=r.text)
  480. result = r.json()
  481. self._save_session(result)
  482. if 'accountTitle' not in result and result['errMsg'] == "Account is already present for customer's recipient": #
  483. data = {}
  484. data['_state_add'] = STATE_ADD_ENUM.SUCCESS # Already exists
  485. return data
  486. customer_name = result['accountTitle']
  487.  
  488. time.sleep(1) # Input
  489. self._token_switching()
  490. time.sleep(1)
  491.  
  492. ''' Add User '''
  493. acc_detail_msg = 'TMB(x%s)' % account_no[-4:]
  494.  
  495. receipent_list = '%s,png,,,,Added,N' % self.auto_add_account
  496. personal_acc_list = u'000000000000000000000000000000,,11,%s,%s,Added,%s' % (account_no, self.sub_add_account, customer_name)
  497. data = self._craft_data({
  498. 'receipentList': receipent_list,
  499. 'personalizedAccList': personal_acc_list.encode('utf-8'),
  500. 'gblTransactionType': '3',
  501. 'flow': 'recipients',
  502. 'Channel': 'AddRecipient',
  503. 'AccDetailMsg': acc_detail_msg,
  504. 'userAccountName': self.auto_add_account_filter, # no t
  505. 'serviceID': 'saveAddAccountDetails',
  506. 'oldRcName': self.auto_add_account,
  507. 'oldRcEmail': '',
  508. 'oldRcmobile': '',
  509. 'oldFbId': '',
  510. })
  511. url = 'https://www.tmbdirect.com/services/TMBMIBService0/saveAddAccountDetails'
  512. r = self.http_post(url, data)
  513. logger.info(msg='pre_add_account (create account) page5(data)', attachment=json.dumps(data))
  514. logger.info(msg='pre_add_account (create account) page5', attachment=r.text)
  515. result = r.json()
  516. self._save_session(result)
  517.  
  518. time.sleep(1)
  519. self._token_switching({
  520. 'crmId': '000000000000000000000000000000',
  521. })
  522. time.sleep(1)
  523.  
  524. ''' Request OTP for Add User '''
  525. data = self._craft_data({
  526. 'retryCounterRequestOTP': '0',
  527. 'Channel': 'AddRecipient',
  528. 'AccDetailMsg': acc_detail_msg,
  529. 'userAccountName': self.auto_add_account_filter,
  530. 'serviceID': 'generateOTPWithUser',
  531. })
  532. r = self.http_post(self.get_service_url('generateOTPWithUser'), data)
  533. logger.info(msg='pre_add_account (create account) page6(data)', attachment=json.dumps(data))
  534. logger.info(msg='pre_add_account (create account) page6', attachment=r.text)
  535. result = r.json()
  536. self._save_session(result)
  537. if 'errCode' in result:
  538. raise Exception(result['errCode'])
  539. otp_ref = result['Collection1'][7]['ValueString']
  540.  
  541. data = {}
  542. data['_customer_name'] = customer_name
  543. data['_state_add'] = STATE_ADD_ENUM.WAIT_INPUT_OTP
  544. data['_otp_ref'] = otp_ref
  545. data['_account_no'] = account_no
  546. data['_tmbflow'] = 'ADDACCOUNT'
  547.  
  548. return data
  549. ''' Else, autoAddAccount already! '''
  550.  
  551. ''' Add AccountNo '''
  552. data = self._craft_data({
  553. 'serviceID': 'depositAccountInquiryNonSec',
  554. 'acctId': account_no,
  555. 'toAcctNo': account_no,
  556. 'isFromRecipient': 'yes',
  557. 'bankcode': '11', # TMB Only
  558. })
  559. r = self.http_post(self.get_service_url('depositAccountInquiryNonSec'), data)
  560. logger.info(msg='pre_add_account (create account no) page8', attachment=r.text)
  561. result = r.json()
  562. self._save_session(result)
  563.  
  564. if result['opstatus'] == 1:
  565. if "Account is already present for customer's recipient" in result['errMsg']:
  566. data = {}
  567. data['_state_add'] = STATE_ADD_ENUM.SUCCESS
  568. return data
  569. raise Exception('errMsg: %s' % result['errMsg'])
  570.  
  571. customer_name = result['accountTitle']
  572.  
  573. self._token_switching()
  574. acc_detail_msg = 'TMB(x%s)' % account_no[-4:]
  575.  
  576. personal_acc_list = u'000000000000000000000000000000,%s,11,%s,%s,Added,%s' % (personalized_id, account_no, self.sub_add_account, customer_name)
  577. data = self._craft_data({
  578. 'serviceID': 'saveAddAccountDetails',
  579. 'personalizedAccList': personal_acc_list.encode('utf-8'),
  580. 'gblTransactionType': '4',
  581. 'oldRcName': self.auto_add_account,
  582. 'oldRcmobile': '',
  583. 'oldFbld': '',
  584. 'flow': 'recipients',
  585. 'Channel': 'EditRecipient',
  586. 'AccDetailMsg': acc_detail_msg,
  587. 'userAccountName': self.auto_add_account_filter,
  588. })
  589. r = self.http_post(self.get_service_url('saveAddAccountDetails'), data)
  590. logger.info(msg='pre_add_account (create account no) page9', attachment=r.text)
  591. result = r.json()
  592. self._save_session(result)
  593.  
  594. self._token_switching({'crmId': '000000000000000000000000000000'})
  595.  
  596. data = self._craft_data({
  597. 'serviceID': 'generateOTPWithUser',
  598. 'retryCounterRequestOTP': 0,
  599. 'Channel': 'EditRecipient',
  600. 'AccDetailMsg': acc_detail_msg,
  601. 'userAccountName': self.auto_add_account_filter,
  602. 'cacheid': '',
  603. 'httpconfig': '[object Object]',
  604. 'konyreportingparams': '{"plat":"windows","aid":"TMB","aver":"1.0.12.26","aname":"dev1_1.0.12.26_build191","did":"1450192634398-54ad-9631-2f27","os":"48","stype":"b2c","dm":"","ua":"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.41 Safari/537.36","chnl":"desktop","atype":"spa","fid":"frmIBMyReceipentsAddBankAccnt","kuid":"","rsid":"1450192669428-e517-7e10-a9e6","metrics":[]}',
  605. '': '',
  606. })
  607. r = self.http_post(self.get_service_url('generateOTPWithUser'), data)
  608. logger.info(msg='pre_add_account (create account no) page8', attachment=r.text)
  609. result = r.json()
  610. self._save_session(result)
  611. otp_ref = result['Collection1'][7]['ValueString']
  612.  
  613. data = {}
  614. data['_customer_name'] = customer_name
  615. data['_state_add'] = STATE_ADD_ENUM.WAIT_INPUT_OTP
  616. data['_otp_ref'] = otp_ref
  617. data['_personalized_id'] = personalized_id
  618. data['_account_no'] = account_no
  619. data['_tmbflow'] = 'EDITACCOUNT'
  620. return data
  621.  
  622. def post_add_account(self, params):
  623. from banktransfer.models import STATE_ADD_ENUM
  624. logger = self.logger.add_tag('post_add_account')
  625.  
  626. if params['_tmbflow'] == 'ADDACCOUNT':
  627. personal_acc_list = u'000000000000000000000000000000,,11,%s,%s,Added,%s' % (params['_account_no'], self.sub_add_account, params['_customer_name'])
  628. data = self._craft_data({
  629. 'serviceID': 'ExecuteMyRecipientAddService',
  630. 'gblTokenSwitchFlag': 'false',
  631. 'password': params['otp'],
  632. 'retryCounterVerifyAccessPin': '0',
  633. 'retryCounterVerifyTransPwd': '0',
  634. 'retryCounterVerifyOTP': '0',
  635. 'receipentList': '%s,png,,,,Added,N' % self.auto_add_account,
  636. 'personalizedAccList': personal_acc_list.encode('utf-8'),
  637. 'gblTransactionType': '3',
  638. 'serviceFlow': 'recipientsComp',
  639. 'oldRcName': self.auto_add_account,
  640. 'oldRcEmail': '',
  641. 'oldRcmobile': '',
  642. 'oldFbId': '',
  643. 'productCode': '200',
  644. 'cacheid': '',
  645. })
  646. r = self.http_post(self.get_service_url('ExecuteMyRecipientAddService'), data)
  647.  
  648. # logger.info(msg='post_add_account page1(data)', attachment=json.dumps(data))
  649. logger.info(msg='post_add_account page1', attachment=r.text)
  650. result = r.json()
  651. self._save_session(result)
  652. personalized_id = result['personalizedIdList'][0]['personalizedId']
  653.  
  654. data = self._craft_data({
  655. 'serviceID': 'confirmPicUpload',
  656. 'tknid': self.tknid,
  657. 'crmId': '000000000000000000000000000000',
  658. 'personalizedId': personalized_id,
  659. })
  660. r = self.http_post(self.get_service_url('confirmPicUpload'), data)
  661. logger.info(msg='post_add_account page2(data)', attachment=json.dumps(data))
  662. logger.info(msg='post_add_account page2', attachment=r.text)
  663. result = r.json()
  664. self._save_session(result)
  665.  
  666. if result['opstatus'] == 8005: # "User ID or Password is incorrect. Please try again.
  667. if result['errCode'] == 'VrfyOTPErr00001':
  668. logger.debug('Invalid OTP, try again.')
  669. data = {
  670. '_state_add': STATE_ADD_ENUM.WAIT_INPUT_OTP,
  671. '_customer_name': params['_customer_name'],
  672. '_otp_ref': params['_otp_ref'],
  673. '_personalized_id': params['_personalized_id'],
  674. '_account_no': params['_account_no'],
  675. }
  676. if '_tmbflow' in params:
  677. data['_tmbflow'] = params['_tmbflow']
  678. return data
  679. elif result['errCode'] == 'VrfyOTPErr00002':
  680. logger.error('UserID is temporary locked please call 1558')
  681. raise PluginError('UserID is temporary locked please call 1558')
  682. else:
  683. raise Exception('Unhandled Error')
  684.  
  685. ''' go Add Account again '''
  686. data = {}
  687. data['_state_add'] = STATE_ADD_ENUM.SUCCESS # WAITING
  688. data['_otp_ref'] = ''
  689.  
  690. return data
  691. elif params['_tmbflow'] == 'EDITACCOUNT':
  692. personal_acc_list = '000000000000000000000000000000,%s,11,%s,%s,Added,%s' % (params['_personalized_id'], params['_account_no'], self.sub_add_account, params['_customer_name'])
  693. data = self._craft_data({
  694. 'serviceID': 'ExecuteMyRecipientAddService',
  695. 'gblTokenSwitchFlag': 'false',
  696. 'password': params['otp'],
  697. 'retryCounterVerifyAccessPin': '0',
  698. 'retryCounterVerifyTransPwd': '0',
  699. 'retryCounterVerifyOTP': '0',
  700. 'personalizedAccList': personal_acc_list.encode('utf-8'),
  701. 'gblTransactionType': '4',
  702. 'oldRcName': self.auto_add_account,
  703. 'oldRcmobile': '',
  704. 'oldRcEmail': '',
  705. 'oldFbld': '',
  706. 'serviceFlow': 'recipientsComp',
  707. 'productCode': '200',
  708. })
  709. r = self.http_post(self.get_service_url('ExecuteMyRecipientAddService'), data)
  710. logger.info(msg='post_add_account page1(data)', attachment=json.dumps(data))
  711. logger.info(msg='post_add_account page1', attachment=r.text)
  712. result = r.json()
  713. self._save_session(result)
  714.  
  715. if result['opstatus'] == 8005: # "User ID or Password is incorrect. Please try again.
  716. if result['errCode'] == 'VrfyOTPErr00001':
  717. logger.debug('Invalid OTP, try again.')
  718. data = {
  719. '_state_add': STATE_ADD_ENUM.WAIT_INPUT_OTP,
  720. '_tmbflow': params['_tmbflow'],
  721. '_customer_name': params['_customer_name'],
  722. '_otp_ref': params['_otp_ref'],
  723. '_personalized_id': params['_personalized_id'],
  724. '_account_no': params['_account_no'],
  725. }
  726. return data
  727. elif result['errCode'] == 'VrfyOTPErr00002':
  728. logger.error('UserID is temporary locked please call 1558')
  729. raise PluginError('UserID is temporary locked please call 1558')
  730. else:
  731. raise Exception('Unhandled Error')
  732.  
  733. data = {}
  734. data['_state_add'] = STATE_ADD_ENUM.SUCCESS # WAITING
  735. data['_otp_ref'] = ''
  736. return data
  737. else:
  738. raise Exception('Unexpect _tmbflow')
  739. pass
  740.  
  741. def del_account(self, account_no):
  742. from banktransfer.models import STATE_DEL_ENUM
  743. data = {
  744. '_state_del': STATE_DEL_ENUM.SUCCESS,
  745. }
  746. return data
  747.  
  748. def del_all_accounts(self, task=None):
  749. from banktransfer.models import STATE_DEL_ENUM
  750. from bankcore.bankcore import account_no_format_full
  751. logger = self.logger.add_tag('del_all_accounts')
  752.  
  753. data = self._craft_data({
  754. 'serviceID': 'receipentListingService',
  755. 'crmId': '',
  756. 'cacheid': '',
  757. })
  758. r = self.http_post(self.get_service_url('receipentListingService'), data)
  759. logger.info(msg='del_all_accounts page1', attachment=r.text)
  760. result = r.json()
  761. self._save_session(result)
  762.  
  763. found = False
  764. personalized_id = None
  765. for recepient in result['Results']:
  766. if recepient['personalizedName'] == self.auto_add_account:
  767. found = True
  768. personalized_id = recepient['personalizedId']
  769.  
  770. if found:
  771. data = self._craft_data({
  772. 'serviceID': 'receipentAllDetailsService',
  773. 'crmId': '000000000000000000000000000000',
  774. 'personalizedId': personalized_id, # TODO: must be 1504464354
  775. })
  776. r = self.http_post(self.get_service_url('receipentAllDetailsService'), data)
  777. logger.info(msg='del_all_accounts page2', attachment=r.text)
  778. result = r.json()
  779. self._save_session(result)
  780.  
  781. sub_accounts = result['Results'][1:]
  782. for sub_account in sub_accounts:
  783. personal_id = sub_account['personalizedId']
  784. sub_account_id = sub_account['personalizedAcctId']
  785. name = sub_account['PersonalizedAcctName']
  786. nickname = sub_account['PersonalizedAcctNickName']
  787. data = self._craft_data({
  788. 'serviceID': 'ExecuteMyRecipientAccountEditDeleteService',
  789. 'personalizedAcctId': sub_account_id,
  790. 'acctNickName': nickname,
  791. 'personalizedId': personal_id,
  792. 'bankCD': '11',
  793. 'acctStatus': 'Deleted',
  794. 'nickname': nickname.encode('utf-8'),
  795. 'bankname': 'ธนาคารทหารไทย จำกัด (มหาชน)',
  796. 'accnumber': account_no_format_full(sub_account_id),
  797. 'AccountName': name.encode('utf-8'),
  798. })
  799. r = self.http_post(self.get_service_url('ExecuteMyRecipientAccountEditDeleteService'), data)
  800. logger.info(msg='del_all_accounts page3', attachment=r.text)
  801. result = r.json()
  802. self._save_session(result)
  803. if 'httpStatusCode' in result and result['httpStatusCode'] != 200:
  804. raise Exception('Unhandled Exception.')
  805.  
  806. data = {
  807. '_state_del': STATE_DEL_ENUM.SUCCESS,
  808. }
  809. return data
  810.  
  811. def transfer(self, from_account_no, to_account_no, amount):
  812. from banktransfer.models import STATE_TRANSFER_ENUM
  813. logger = self.logger.add_tag('transfer')
  814.  
  815. '''
  816. เปิดหน้าโอน
  817. '''
  818. transfer_date = datetime.datetime.now().strftime('%Y-%m-%d')
  819. data = self._craft_data({
  820. 'serviceID': 'customerAccountInquiry',
  821. 'transferFlag': 'true',
  822. })
  823. r = self.http_post(self.get_service_url('customerAccountInquiry'), data)
  824. logger.info(msg='transfer page1(data)', attachment=json.dumps(data))
  825. logger.info(msg='transfer page1', attachment=r.text)
  826. result = r.json()
  827. self._save_session(result)
  828.  
  829. found = False
  830. found_accounts = []
  831. available_balance = None
  832. from_account_nickname = None
  833. for account_rec in result['custAcctRec']:
  834. account_id = account_rec['accId'][4:] # Trim 4 ตัวแรกทิ้ง
  835. found_accounts.append(account_id)
  836. if account_id == from_account_no:
  837. found = True
  838. available_balance = account_rec['availableBal']
  839. from_account_nickname = account_rec['acctNickName']
  840. break
  841. if not found:
  842. raise InvalidAccountNoFrom('Account not found. (found only %s)' % found_accounts)
  843.  
  844. self._token_switching()
  845.  
  846. data = self._craft_data({
  847. 'serviceID': 'crmProfileInq',
  848. 'transferFlag': 'true',
  849. 'transferAmt': amount,
  850. 'gblisTMB': 11,
  851. 'gblTMBBankCD': 11,
  852. 'gblPaynow': 'true',
  853. 'frmAccnt': from_account_no,
  854. 'recipientMobile': '',
  855. 'recipientEmailAddr': '',
  856. 'toNum': to_account_no,
  857. 'bankRef': 'TMB',
  858. 'fee': 0,
  859. 'FuturetransferDate': transfer_date,
  860. 'accountName': self.sub_add_account,
  861. 'accountNum': 'xxx-x-%s-x' % to_account_no[4:9],
  862. 'bankName': 'TMB',
  863. 'module': 'execute',
  864. })
  865. r = self.http_post(self.get_service_url('crmProfileInq'), data)
  866. logger.info(msg='transfer page2(data)', attachment=json.dumps(data))
  867. logger.info(msg='transfer page2', attachment=r.text)
  868. result = r.json()
  869. self._save_session(result)
  870.  
  871. data = self._craft_data({
  872. 'serviceID': 'depositAccountInquiryNonSec',
  873. 'acctId': to_account_no,
  874. })
  875. r = self.http_post(self.get_service_url('depositAccountInquiryNonSec'), data)
  876. logger.info(msg='transfer page3(data)', attachment=json.dumps(data))
  877. logger.info(msg='transfer page3', attachment=r.text)
  878. result = r.json()
  879. self._save_session(result)
  880. customer_name = result['accountTitle']
  881.  
  882. data = self._craft_data({
  883. 'serviceID': 'fundTransferInq',
  884. 'transferAmt': amount,
  885. 'transferDate': transfer_date,
  886. # 'depositeNo': 'undefined',
  887. 'fromAcctNo': from_account_no,
  888. 'toAcctNo': to_account_no,
  889. })
  890. r = self.http_post(self.get_service_url('fundTransferInq'), data)
  891. logger.info(msg='transfer page4(data)', attachment=json.dumps(data))
  892. logger.info(msg='transfer page4', attachment=r.text)
  893. result = r.json()
  894. self._save_session(result)
  895. fee = result['transferFee']
  896.  
  897. self._token_switching()
  898.  
  899. ''' Generate OTP '''
  900. data = self._craft_data({
  901. 'events': '[]',
  902. 'retryCounterRequestOTP': 0,
  903. 'Channel': 'ExecuteTransfer',
  904. 'serviceID': 'generateOTPWithUser',
  905. 'nameFromRecipientList': 'false',
  906. 'httpheaders': '{}',
  907. 'httpconfig': '{"timeout":180000}',
  908. })
  909. r = self.http_post(self.get_service_url('generateOTPWithUser'), data)
  910. logger.info(msg='transfer page5(data)', attachment=json.dumps(data))
  911. logger.info(msg='transfer page5', attachment=r.text)
  912. result = r.json()
  913. self._save_session(result)
  914. otp_ref = result['Collection1'][7]['ValueString']
  915. data = {
  916. '_state_transfer': STATE_TRANSFER_ENUM.WAIT_INPUT_OTP,
  917. '_otp_ref': otp_ref,
  918. 'fromAcctNo': from_account_no,
  919. 'toAcctNo': to_account_no,
  920. 'amount': amount,
  921. 'fee': fee,
  922. '_customer_name': customer_name,
  923. 'available_balance': available_balance,
  924. 'from_account_nickname': from_account_nickname,
  925. }
  926. return data
  927.  
  928. def otp_transfer(self, params, amount=None):
  929. from banktransfer.models import STATE_TRANSFER_ENUM
  930. logger = self.logger.add_tag('otp_transfer')
  931.  
  932. transfer_date = datetime.datetime.now().strftime('%Y-%m-%d')
  933. fee_txt = (u'%s ฿' % (params['fee'])).encode('utf-8')
  934. expected_balance = (float(params['available_balance']) - amount)
  935. data = self._craft_data({
  936. 'serviceID': 'executeTransfer',
  937. 'retryCounterVerifyAccessPin': 0,
  938. 'retryCounterVerifyTransPwd': 0,
  939. 'password': params['otp'],
  940. 'retryCounterVerifyOTP': 1,
  941. 'freq': 'once',
  942. 'fromAcctNo': params['fromAcctNo'],
  943. 'toAcctNo': params['toAcctNo'],
  944. 'dueDateForEmail': '',
  945. 'memo': '',
  946. 'transferAmt': amount, # params['amount'],
  947. 'gblBANKREF': 'ธนาคารทหารไทย จำกัด (มหาชน)',
  948. 'gblTrasSMS': 0,
  949. 'gblTransEmail': 0,
  950. 'gblTransSMART': 0,
  951. 'gblTrasORFT': 0,
  952. 'gblisTMB': 11, # TMB
  953. 'toAcctBank': 'ธนาคารทหารไทย จำกัด (มหาชน)',
  954. 'bankShortName': 'TMB',
  955. 'gblTokenSwitchFlag': 'false',
  956. 'gblPaynow': 'true',
  957. 'recipientEmailAddr': '',
  958. 'recipientMobileNbr': '',
  959. 'recipientMobile': '',
  960. 'receipientNote': '',
  961. 'RecipentName': self.auto_add_account,
  962. 'times': '',
  963. 'frmFiident': '0011000102300200', # TODO: What ??
  964. 'toFIIdent': '11',
  965. 'acctTitle': self.sub_add_account,
  966. 'transferDate': transfer_date,
  967. 'transferFee': fee_txt, # TODO: What ??
  968. 'finTxnMemo': '',
  969. 'fromAcctName': params['from_account_nickname'],
  970. 'fromAcctNickName': params['from_account_nickname'],
  971. 'toAcctName': params['_customer_name'],
  972. 'toAcctNickname': self.sub_add_account,
  973. 'gblBalAfterXfer': expected_balance, # (params['available_balance'] - amount), # TODO: Balance expected after transfer
  974. 'endDate': '',
  975. 'transferOrderDate': '', # '15/12/2015 00:36:42', # TODO:
  976. 'recurring': '',
  977. 'Recp_category': '1',
  978. })
  979. r = self.http_post(self.get_service_url('executeTransfer'), data)
  980. logger.info(msg='otp_transfer page1(data)', attachment=json.dumps(data))
  981. logger.info(msg='otp_transfer page1', attachment=r.text)
  982. result = r.json()
  983. self._save_session(result)
  984.  
  985. if result['opstatus'] == 8005: # "User ID or Password is incorrect. Please try again.
  986. if result['errCode'] == 'VrfyOTPErr00001':
  987. logger.debug('Invalid OTP, try again.')
  988. data = {
  989. '_state_add': STATE_TRANSFER_ENUM.WAIT_INPUT_OTP,
  990. # '_tmbflow': params.get('_tmbflow'),
  991. '_customer_name': params['_customer_name'],
  992. '_otp_ref': params['_otp_ref'],
  993. '_personalized_id': params['_personalized_id'],
  994. '_account_no': params['_account_no'],
  995. }
  996. return data
  997. elif result['errCode'] == 'VrfyOTPErr00002':
  998. logger.error('UserID is temporary locked please call 1558')
  999. raise PluginError('UserID is temporary locked please call 1558')
  1000. else:
  1001. raise Exception('Unhandled Error')
  1002.  
  1003. if result['StatusCode'] == 100: # Sorry for inconvenience. TMB cannot proceed your transaction. For more info, please call 1558.
  1004. raise PluginHandledError('Target Account is locked.')
  1005.  
  1006. if result['StatusCode'] != 0:
  1007. raise Exception('Unhandled Error')
  1008.  
  1009. fee = result['Transfer'][0]['fee']
  1010. data = {
  1011. '_fee': fee,
  1012. '_state_transfer': STATE_TRANSFER_ENUM.SUCCESS,
  1013. }
  1014. return data
  1015.  
  1016. def _token_switching(self, optional_params=None):
  1017. logger = self.logger.add_tag('_token_switching')
  1018. data = {
  1019. 'serviceID': 'tokenSwitching',
  1020. }
  1021. if optional_params:
  1022. data.update(optional_params)
  1023. data = self._craft_data(data)
  1024. r = self.web_post(self.get_service_url('tokenSwitching'), data, soup=False)
  1025. logger.info(msg='_token_switching page(data)', attachment=json.dumps(data))
  1026. logger.info(msg='_token_switching page', attachment=r)
  1027. result = json.loads(r)
  1028. self._save_session(result)
  1029. return result
  1030.  
  1031. def logout(self):
  1032. if hasattr(self, 'tknid'):
  1033. '''
  1034. channelId:01
  1035. timeOut:false
  1036. deviceId:campaignBannerIBCount
  1037. languageCd:TH
  1038. appID:TMB
  1039. appver:1.0.12.17
  1040. serviceID:logOutTMB
  1041. locale:th_TH
  1042. channel:wap
  1043. platform:thinclient
  1044. cacheid:
  1045. tknid:E82192EF544DB62D3368E4C87E4CC32DD631C8F305BE83ACBB7AAB56B53B293D
  1046. rcid:spadesktopweb
  1047. :
  1048. '''
  1049. data = dict()
  1050. data.update(self._service_form)
  1051. data.update({
  1052. 'channelId': '01',
  1053. 'timeOut': 'false',
  1054. 'deviceId': 'campaignBannerIBCount',
  1055. 'languageCd': 'TH',
  1056. 'serviceID': 'logOutTMB',
  1057. 'tknid': self.tknid,
  1058. })
  1059. self.http_post(self._logout_url, data=data)
  1060. # json.loads(r)
  1061. print('Logout success')
  1062.  
  1063. def _save_session(self, result):
  1064. if 'opstatus' in result:
  1065. if result['opstatus'] == 0:
  1066. if 'isValidSession' in result and result['isValidSession'] is False:
  1067. raise InvalidToken()
  1068. if result['opstatus'] == 8004:
  1069. raise Exception('errmsg: %s' % result['errmsg'])
  1070. self.tknid = result['tknid']
  1071.  
  1072. def _craft_data(self, new_data):
  1073. data = dict()
  1074. data.update(self._service_form)
  1075. data.update({
  1076. 'tknid': self.tknid,
  1077. })
  1078. data.update(new_data)
  1079. return data
  1080.  
  1081. def serialize(self):
  1082. import pickle
  1083. return pickle.dumps([self.session, self.tknid])
  1084.  
  1085. @classmethod
  1086. def deserialize(cls, data):
  1087. import pickle
  1088. session, tknid, session_headers = pickle.loads(data)
  1089. entity = cls()
  1090. setattr(entity, 'session', session)
  1091. setattr(entity, 'tknid', tknid)
  1092. entity.session.headers = session_headers
  1093. return entity
  1094.  
  1095. @classmethod
  1096. def deserialize(cls, data):
  1097. return cls.deserialize_key(data, ['session', 'tknid'])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement