Commit f1c3c3e1efaf7e58728b0c89f766e2dc7816b412

Authored by Adhidarma Hadiwinoto
1 parent 6f184db816
Exists in master

sn kirim xltunai

Showing 3 changed files with 24 additions and 9 deletions Inline Diff

1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 2
3 import logging 3 import logging
4 from logging.handlers import TimedRotatingFileHandler 4 from logging.handlers import TimedRotatingFileHandler
5 import ConfigParser 5 import ConfigParser
6 import json 6 import json
7 from os import getpid 7 from os import getpid
8 import re 8 import re
9 import signal 9 import signal
10 import sys 10 import sys
11 11
12 config = ConfigParser.RawConfigParser() 12 config = ConfigParser.RawConfigParser()
13 config.read('config.ini') 13 config.read('config.ini')
14 14
15 PORT = config.get('globals','PORT') 15 PORT = config.get('globals','PORT')
16 BAUDRATE = config.getint('globals', 'BAUDRATE') 16 BAUDRATE = config.getint('globals', 'BAUDRATE')
17 PIN = None # SIM card PIN (if any) 17 PIN = None # SIM card PIN (if any)
18 PIN_TRX = config.get('globals', 'PIN_TRX') 18 PIN_TRX = config.get('globals', 'PIN_TRX')
19 19
20 BASE_CHIPINFO = config.get('globals', 'BASE_CHIPINFO') 20 BASE_CHIPINFO = config.get('globals', 'BASE_CHIPINFO')
21 CHIPINFO = BASE_CHIPINFO 21 CHIPINFO = BASE_CHIPINFO
22 22
23 AAA_HOST = config.get('globals', 'AAA_HOST') 23 AAA_HOST = config.get('globals', 'AAA_HOST')
24 CITY = config.get('globals', 'CITY') 24 CITY = config.get('globals', 'CITY')
25 PRODUCTS = config.get('globals', 'PRODUCTS') 25 PRODUCTS = config.get('globals', 'PRODUCTS')
26 26
27 REDIS_HOST = config.get('globals', 'REDIS_HOST') 27 REDIS_HOST = config.get('globals', 'REDIS_HOST')
28 REDIS_PORT = config.getint('globals', 'REDIS_PORT') 28 REDIS_PORT = config.getint('globals', 'REDIS_PORT')
29 REDIS_TTL = config.getint('globals', 'REDIS_TTL') 29 REDIS_TTL = config.getint('globals', 'REDIS_TTL')
30 REDIS_DISABLE_PULL_TTL = config.getint('globals', 'REDIS_DISABLE_PULL_TTL') 30 REDIS_DISABLE_PULL_TTL = config.getint('globals', 'REDIS_DISABLE_PULL_TTL')
31 31
32 PULL_INTERVAL = config.getint('globals', 'PULL_INTERVAL') 32 PULL_INTERVAL = config.getint('globals', 'PULL_INTERVAL')
33 SLEEP_AFTER_TOPUP = config.getint('globals', 'SLEEP_AFTER_TOPUP') 33 SLEEP_AFTER_TOPUP = config.getint('globals', 'SLEEP_AFTER_TOPUP')
34 SLEEP_BETWEEN_BALANCE_N_TOPUP = config.getint('globals', 'SLEEP_BETWEEN_BALANCE_N_TOPUP') 34 SLEEP_BETWEEN_BALANCE_N_TOPUP = config.getint('globals', 'SLEEP_BETWEEN_BALANCE_N_TOPUP')
35 TOPUP_USSD_TIMEOUT = config.getint('globals', 'TOPUP_USSD_TIMEOUT') 35 TOPUP_USSD_TIMEOUT = config.getint('globals', 'TOPUP_USSD_TIMEOUT')
36 SLEEP_AFTER_USSD_ERROR = 180 36 SLEEP_AFTER_USSD_ERROR = 180
37 37
38 MIN_SIGNAL_STRENGTH = 0 38 MIN_SIGNAL_STRENGTH = 0
39 try: 39 try:
40 MIN_SIGNAL_STRENGTH = config.getint('globals', 'MIN_SIGNAL_STRENGTH') 40 MIN_SIGNAL_STRENGTH = config.getint('globals', 'MIN_SIGNAL_STRENGTH')
41 except: 41 except:
42 pass 42 pass
43 if not MIN_SIGNAL_STRENGTH: 43 if not MIN_SIGNAL_STRENGTH:
44 MIN_SIGNAL_STRENGTH = 13 44 MIN_SIGNAL_STRENGTH = 13
45 45
46 MIN_BALANCE = config.getint('globals', 'MIN_BALANCE') 46 MIN_BALANCE = config.getint('globals', 'MIN_BALANCE')
47 47
48 PULL_COUNT = 0 48 PULL_COUNT = 0
49 MSISDN = '' 49 MSISDN = ''
50 BALANCE = 0 50 BALANCE = 0
51 51
52 DISABLE_SEM=0 52 DISABLE_SEM=0
53 DISABLE_SEM_ON_TRX=60 53 DISABLE_SEM_ON_TRX=60
54 54
55 TERMINATING=False 55 TERMINATING=False
56 56
57 LAST_REQUEST_ID = None 57 LAST_REQUEST_ID = None
58 LAST_SN = None 58 LAST_SN = None
59 LAST_PRODUCT = '' 59 LAST_PRODUCT = ''
60 60
61 PULSA = 0 61 PULSA = 0
62 MASA_AKTIF = "" 62 MASA_AKTIF = ""
63 63
64 logger = None 64 logger = None
65 65
66 from gsmmodem.modem import GsmModem 66 from gsmmodem.modem import GsmModem
67 from gsmmodem.exceptions import TimeoutException 67 from gsmmodem.exceptions import TimeoutException
68 68
69 from time import sleep 69 from time import sleep
70 from time import strftime 70 from time import strftime
71 71
72 import redis 72 import redis
73 import requests 73 import requests
74 74
75 import sate24 75 import sate24
76 import xltunai 76 import xltunai
77 77
78 redis_client = redis.StrictRedis(host=REDIS_HOST, port=REDIS_PORT, db=0) 78 redis_client = redis.StrictRedis(host=REDIS_HOST, port=REDIS_PORT, db=0)
79 79
80 def signalHandler(signum, frame): 80 def signalHandler(signum, frame):
81 global TERMINATING 81 global TERMINATING
82 82
83 if signum == signal.SIGINT or signum == signal.SIGTERM: 83 if signum == signal.SIGINT or signum == signal.SIGTERM:
84 logger.info('Signal ({0}) received, waiting for next loop to terminate. Terminating...'.format(signum)) 84 logger.info('Signal ({0}) received, waiting for next loop to terminate. Terminating...'.format(signum))
85 TERMINATING = True 85 TERMINATING = True
86 86
87 def handleSms(sms): 87 def handleSms(sms):
88 global CHIPINFO 88 global CHIPINFO
89 global DISABLE_SEM 89 global DISABLE_SEM
90 global PRODUCTS 90 global PRODUCTS
91 global LAST_PRODUCT 91 global LAST_PRODUCT
92 global LAST_REQUEST_ID 92 global LAST_REQUEST_ID
93 global LAST_SN 93 global LAST_SN
94 94
95 logger.info(u'Incoming SMS from: {0}; Time: {1}; Message: {2}'.format(sms.number, sms.time, sms.text)) 95 logger.info(u'Incoming SMS from: {0}; Time: {1}; Message: {2}'.format(sms.number, sms.time, sms.text))
96 96
97 try: 97 try:
98 epic_key = 'epic.msgin.gw:' + BASE_CHIPINFO 98 epic_key = 'epic.msgin.gw:' + BASE_CHIPINFO
99 redis_client.publish(epic_key + '.message', u'{0}: {1} ({2})'.format(sms.number, sms.text, CHIPINFO)) 99 redis_client.publish(epic_key + '.message', u'{0}: {1} ({2})'.format(sms.number, sms.text, CHIPINFO))
100 except: 100 except:
101 logger.warning('Fail to publish epic message to redis') 101 logger.warning('Fail to publish epic message to redis')
102 102
103 if not xltunai.isValidSender(sms.number): 103 if not xltunai.isValidSender(sms.number):
104 logger.info('Ignoring incoming SMS from invalid sender') 104 logger.info('Ignoring incoming SMS from invalid sender')
105 return 105 return
106 106
107 if sms.text.find('Terimakasih, transaksi CASH IN ke akun') >= 0: 107 if sms.text.find('Terimakasih, transaksi CASH IN ke akun') >= 0:
108 logger.info('handleSms: CASH IN, aktivasi pull jika non aktif') 108 logger.info('handleSms: CASH IN, aktivasi pull jika non aktif')
109 109
110 LAST_SN = xltunai.getSNFromCashInMessage(sms.text) 110 LAST_SN = xltunai.getSNFromCashInMessage(sms.text)
111 logger.info('Override LAST_SN: {0}'.format(LAST_SN)) 111 logger.info('Override LAST_SN: {0}'.format(LAST_SN))
112 112
113 enablePull() 113 enablePull()
114 return 114 return
115 115
116 if sms.text.find('Maaf, transaksi gagal') >= 0: 116 if sms.text.find('Maaf, transaksi gagal') >= 0:
117 pushTopupStatus(LAST_REQUEST_ID, '40', sms.text) 117 pushTopupStatus(LAST_REQUEST_ID, '40', sms.text)
118 return 118 return
119 119
120 elif sms.text.find('PIN yang Anda masukkan salah. Silahkan ulangi kembali') >= 0: 120 if sms.text.find('PIN yang Anda masukkan salah. Silahkan ulangi kembali') >= 0:
121 pushTopupStatus(LAST_REQUEST_ID, '91', sms.text) 121 pushTopupStatus(LAST_REQUEST_ID, '91', sms.text)
122 return 122 return
123 123
124 elif sms.text.find('Maaf, saldo XL-Tunai anda tidak cukup') >= 0: 124 if sms.text.find('Maaf, saldo XL-Tunai anda tidak cukup') >= 0:
125 pushTopupStatus(LAST_REQUEST_ID, '40', sms.text) 125 pushTopupStatus(LAST_REQUEST_ID, '40', sms.text)
126 return 126 return
127 127
128 elif sms.text.find('Maaf, layanan ini hanya untuk nomor tujuan prabayar XL') >= 0: 128 if sms.text.find('Maaf, layanan ini hanya untuk nomor tujuan prabayar XL') >= 0:
129 pushTopupStatus(LAST_REQUEST_ID, '14', sms.text) 129 pushTopupStatus(LAST_REQUEST_ID, '14', sms.text)
130 return 130 return
131 131
132 elif sms.text.find('Mohon maaf, nomor yang Anda masukkan tidak valid') >= 0: 132 if sms.text.find('Mohon maaf, nomor yang Anda masukkan tidak valid') >= 0:
133 pushTopupStatus(LAST_REQUEST_ID, '14', sms.text) 133 pushTopupStatus(LAST_REQUEST_ID, '14', sms.text)
134 return 134 return
135 135
136 elif sms.text.find('Mohon maaf, transaksi Anda melebihi limit nominal bulanan') >= 0: 136 if sms.text.find('Mohon maaf, transaksi Anda melebihi limit nominal bulanan') >= 0:
137 pushTopupStatus(LAST_REQUEST_ID, '40', sms.text) 137 pushTopupStatus(LAST_REQUEST_ID, '40', sms.text)
138 138
139 logger.info('Monthly limit for "{0}" detected, removing from product list'.format(LAST_PRODUCT)) 139 logger.info('Monthly limit for "{0}" detected, removing from product list'.format(LAST_PRODUCT))
140 PRODUCTS = sate24.removeProduct(PRODUCTS, LAST_PRODUCT) 140 PRODUCTS = sate24.removeProduct(PRODUCTS, LAST_PRODUCT)
141 logger.warning('Monthly limit for "{0}" exceeded. New active products: "{1}"'.format(LAST_PRODUCT, PRODUCTS)) 141 logger.warning('Monthly limit for "{0}" exceeded. New active products: "{1}"'.format(LAST_PRODUCT, PRODUCTS))
142 return 142 return
143 143
144 elif sms.text.find('Maaf, transaksi Anda masih dalam proses') >= 0: 144 if sms.text.find('Maaf, transaksi Anda masih dalam proses') >= 0:
145 pushTopupStatus(LAST_REQUEST_ID, '68', sms.text) 145 pushTopupStatus(LAST_REQUEST_ID, '68', sms.text)
146 return 146 return
147 147
148 elif sms.text.find('Maaf, saat ini sistem sedang proses maintenance') >= 0: 148 if sms.text.find('Maaf, saat ini sistem sedang proses maintenance') >= 0:
149 pushTopupStatus(LAST_REQUEST_ID, '91', sms.text) 149 pushTopupStatus(LAST_REQUEST_ID, '91', sms.text)
150 return 150 return
151 151
152 elif sms.text.find('Anda terima uang XLTunai') >= 0: 152 if sms.text.find('Anda terima uang XLTunai') >= 0:
153 LAST_SN = xltunai.getSNFromReceiveTransferMessage(sms.text) 153 LAST_SN = xltunai.getSNFromReceiveTransferMessage(sms.text)
154 logger.info('Override LAST_SN: {0}'.format(LAST_SN)) 154 logger.info('Override LAST_SN: {0}'.format(LAST_SN))
155 return 155 return
156 156
157 if sms.text.find('Kirim uang ke ') == 0:
158 LAST_SN = xltunai.getSNFromSentTransferMessage(sms.text)
159 logger.info('Override LAST_SN: {0}'.format(LAST_SN))
160 return
161
157 destination = xltunai.getDestinationFromMessage(sms.text) 162 destination = xltunai.getDestinationFromMessage(sms.text)
158 if destination == '': 163 if destination == '':
159 logger.warning('handleSms: gagal parsing nomor tujuan') 164 logger.warning('handleSms: gagal parsing nomor tujuan')
160 return 165 return
161 166
162 nominal = xltunai.getNominalFromMessage(sms.text) 167 nominal = xltunai.getNominalFromMessage(sms.text)
163 if nominal == '': 168 if nominal == '':
164 logger.warning('handleSms: gagal parsing nominal') 169 logger.warning('handleSms: gagal parsing nominal')
165 return 170 return
166 171
167 sn = xltunai.getSNFromMessage(sms.text) 172 sn = xltunai.getSNFromMessage(sms.text)
168 if sn == '': 173 if sn == '':
169 logger.warning('handleSms: gagal parsing SN') 174 logger.warning('handleSms: gagal parsing SN')
170 175
171 176
172 DISABLE_SEM = 0 177 DISABLE_SEM = 0
173 178
174 response_code = xltunai.getResponseCodeByMessage(sms.text) 179 response_code = xltunai.getResponseCodeByMessage(sms.text)
175 180
176 request_id = getRequestIdByNominalDestination(nominal, destination) 181 request_id = getRequestIdByNominalDestination(nominal, destination)
177 if not request_id: 182 if not request_id:
178 logger.info('Unknown request id for nominal:{0} destination:{1}'.format(nominal, destination)) 183 logger.info('Unknown request id for nominal:{0} destination:{1}'.format(nominal, destination))
179 return 184 return
180 185
181 pushTopupStatus(request_id, response_code, sms.text) 186 pushTopupStatus(request_id, response_code, sms.text)
182 try: 187 try:
183 deleteMultipleStoredSms(2) 188 deleteMultipleStoredSms(2)
184 except: 189 except:
185 #logger.warning('Failed on delete SMS') 190 #logger.warning('Failed on delete SMS')
186 pass 191 pass
187 192
188 193
189 def getRequestIdByNominalDestination(nominal, destination): 194 def getRequestIdByNominalDestination(nominal, destination):
190 global CHIPINFO 195 global CHIPINFO
191 196
192 redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, destination) 197 redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, destination)
193 #return redis_client.spop(redis_key) 198 #return redis_client.spop(redis_key)
194 return redis_client.rpop(redis_key) 199 return redis_client.rpop(redis_key)
195 200
196 def pushTopupStatus(request_id, response_code, _message, dontparsesn = False): 201 def pushTopupStatus(request_id, response_code, _message, dontparsesn = False):
197 global BALANCE 202 global BALANCE
198 global CHIPINFO 203 global CHIPINFO
199 global LAST_SN 204 global LAST_SN
200 205
201 redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code' 206 redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code'
202 if response_code == '00': 207 if response_code == '00':
203 redis_client.set(redis_key, response_code) 208 redis_client.set(redis_key, response_code)
204 else: 209 else:
205 redis_response_code = redis_client.get(redis_key) 210 redis_response_code = redis_client.get(redis_key)
206 if redis_response_code == '00': 211 if redis_response_code == '00':
207 logger.info('Ignoring message from success trx ') 212 logger.info('Ignoring message from success trx ')
208 return 213 return
209 214
210 message = "{0} -- Prev balance: {1}".format(_message, BALANCE) 215 message = "{0} -- Prev balance: {1}".format(_message, BALANCE)
211 216
212 timestamp = strftime('%Y%m%d%H%M%S') 217 timestamp = strftime('%Y%m%d%H%M%S')
213 218
214 if response_code == '00' and not dontparsesn: 219 if response_code == '00' and not dontparsesn:
215 sn = xltunai.getSNFromMessage(message) 220 sn = xltunai.getSNFromMessage(message)
216 LAST_SN = sn 221 LAST_SN = sn
217 message = 'SN={0};{1}'.format(sn, message) 222 message = 'SN={0};{1}'.format(sn, message)
218 223
219 push_message = CHIPINFO + '$' + message 224 push_message = CHIPINFO + '$' + message
220 225
221 payload = { 226 payload = {
222 'trans_id': request_id, 227 'trans_id': request_id,
223 'trans_date': timestamp, 228 'trans_date': timestamp,
224 'resp_code': response_code, 229 'resp_code': response_code,
225 'ussd_msg': push_message 230 'ussd_msg': push_message
226 } 231 }
227 232
228 url = AAA_HOST + '/topup' 233 url = AAA_HOST + '/topup'
229 234
230 try: 235 try:
231 logger.info('Sending topup status to AAA') 236 logger.info('Sending topup status to AAA')
232 logger.info(payload) 237 logger.info(payload)
233 r = requests.get(url, params=payload) 238 r = requests.get(url, params=payload)
234 except: 239 except:
235 logger.warning('Error sending topup status to AAA') 240 logger.warning('Error sending topup status to AAA')
236 241
237 try: 242 try:
238 # publish echi topup report ke redis 243 # publish echi topup report ke redis
239 echi_key = 'echi.topup_report.gw:' + BASE_CHIPINFO 244 echi_key = 'echi.topup_report.gw:' + BASE_CHIPINFO
240 245
241 redis_client.publish(echi_key + '.json', json.dumps(payload)) 246 redis_client.publish(echi_key + '.json', json.dumps(payload))
242 247
243 echi_message = timestamp + ' - ' + response_code + ' - ' + message 248 echi_message = timestamp + ' - ' + response_code + ' - ' + message
244 redis_client.publish(echi_key + '.message', echi_message) 249 redis_client.publish(echi_key + '.message', echi_message)
245 except: 250 except:
246 logger.warning('Error publishing topup report to redis') 251 logger.warning('Error publishing topup report to redis')
247 252
248 def getIsDisableRedisKey(): 253 def getIsDisableRedisKey():
249 return CHIPINFO + '.pulldisable' 254 return CHIPINFO + '.pulldisable'
250 255
251 def isPullEnable(): 256 def isPullEnable():
252 redis_key = getIsDisableRedisKey() 257 redis_key = getIsDisableRedisKey()
253 result = 'FALSE' 258 result = 'FALSE'
254 259
255 try: 260 try:
256 result = redis_client.get(redis_key) 261 result = redis_client.get(redis_key)
257 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) 262 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL)
258 except: 263 except:
259 return False 264 return False
260 265
261 if not result: 266 if not result:
262 return True 267 return True
263 268
264 return result == 'FALSE' 269 return result == 'FALSE'
265 270
266 def enablePull(): 271 def enablePull():
267 logger.info('Enabling Pull on products {0}'.format(PRODUCTS)) 272 logger.info('Enabling Pull on products {0}'.format(PRODUCTS))
268 redis_key = getIsDisableRedisKey() 273 redis_key = getIsDisableRedisKey()
269 try: 274 try:
270 redis_client.set(redis_key, 'FALSE') 275 redis_client.set(redis_key, 'FALSE')
271 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) 276 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL)
272 except: 277 except:
273 return 278 return
274 279
275 def disablePull(): 280 def disablePull():
276 global DISABLE_SEM 281 global DISABLE_SEM
277 global DISABLE_SEM_ON_TRX 282 global DISABLE_SEM_ON_TRX
278 283
279 logger.info('Disabling Pull') 284 logger.info('Disabling Pull')
280 redis_key = getIsDisableRedisKey() 285 redis_key = getIsDisableRedisKey()
281 try: 286 try:
282 redis_client.set(redis_key, 'TRUE') 287 redis_client.set(redis_key, 'TRUE')
283 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) 288 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL)
284 except: 289 except:
285 return 290 return
286 291
287 def adviceLastSN(requestId, modem): 292 def adviceLastSN(requestId, modem):
288 global DISABLE_SEM 293 global DISABLE_SEM
289 global LAST_SN 294 global LAST_SN
290 global TOPUP_USSD_TIMEOUT 295 global TOPUP_USSD_TIMEOUT
291 296
292 if not LAST_SN: 297 if not LAST_SN:
293 message = 'Tidak ada trx sebelumnya untuk perbandingan SN. Silahkan bandingkan prev balance dengan trx berikutnya di chip yang sama' 298 message = 'Tidak ada trx sebelumnya untuk perbandingan SN. Silahkan bandingkan prev balance dengan trx berikutnya di chip yang sama'
294 pushTopupStatus(requestId, '68', message) 299 pushTopupStatus(requestId, '68', message)
295 DISABLE_SEM = 0 300 DISABLE_SEM = 0
296 return 301 return
297 302
298 ussd_command = xltunai.getHistoryUSSDCommand() 303 ussd_command = xltunai.getHistoryUSSDCommand()
299 304
300 logger.info(u'Executing advice {0}'.format(ussd_command)) 305 logger.info(u'Executing advice {0}'.format(ussd_command))
301 try: 306 try:
302 response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT) 307 response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT)
303 308
304 message = response.message.strip() 309 message = response.message.strip()
305 logger.info(u'USSD response: {0}'.format(message)) 310 logger.info(u'USSD response: {0}'.format(message))
306 311
307 lastSNFromHistory = xltunai.getLastSNFromHistoryMessage(message) 312 lastSNFromHistory = xltunai.getLastSNFromHistoryMessage(message)
308 313
309 if response.sessionActive: 314 if response.sessionActive:
310 response.cancel() 315 response.cancel()
311 316
312 if not lastSNFromHistory: 317 if not lastSNFromHistory:
313 if DISABLE_SEM: 318 if DISABLE_SEM:
314 logger.info('Failed to get last sn from history, retrying in 15 secs') 319 logger.info('Failed to get last sn from history, retrying in 15 secs')
315 sleep(15) 320 sleep(15)
316 adviceLastSN(requestid, modem) 321 adviceLastSN(requestid, modem)
317 322
318 elif lastSNFromHistory == 'NON RELOAD': 323 elif lastSNFromHistory == 'NON RELOAD':
319 topupMessage = "Topup gagal berdasarkan advice. Trx terakhir adalah P2P Transfer." 324 topupMessage = "Topup gagal berdasarkan advice. Trx terakhir adalah P2P Transfer."
320 pushTopupStatus(requestId, '40', topupMessage) 325 pushTopupStatus(requestId, '40', topupMessage)
321 DISABLE_SEM = 0 326 DISABLE_SEM = 0
322 327
323 elif lastSNFromHistory == LAST_SN: 328 elif lastSNFromHistory == LAST_SN:
324 topupMessage = "Topup gagal berdasarkan advice. {0} = {1}. {2}".format(lastSNFromHistory, LAST_SN, message) 329 topupMessage = "Topup gagal berdasarkan advice. {0} = {1}. {2}".format(lastSNFromHistory, LAST_SN, message)
325 pushTopupStatus(requestId, '40', topupMessage) 330 pushTopupStatus(requestId, '40', topupMessage)
326 DISABLE_SEM = 0 331 DISABLE_SEM = 0
327 332
328 333
329 else: 334 else:
330 topupMessage = "SN={0}; Topup berhasil berdasarkan advice. {1}".format(lastSNFromHistory, message) 335 topupMessage = "SN={0}; Topup berhasil berdasarkan advice. {1}".format(lastSNFromHistory, message)
331 LAST_SN = lastSNFromHistory 336 LAST_SN = lastSNFromHistory
332 pushTopupStatus(requestId, '00', topupMessage, True) 337 pushTopupStatus(requestId, '00', topupMessage, True)
333 DISABLE_SEM = 0 338 DISABLE_SEM = 0
334 339
335 except: 340 except:
336 message = "USSD Error: Something wrong when executing USSD advice. Signal strength: {0}".format(modem.signalStrength) 341 message = "USSD Error: Something wrong when executing USSD advice. Signal strength: {0}".format(modem.signalStrength)
337 logger.warning(message) 342 logger.warning(message)
338 pushTopupStatus(requestId, '68', message) 343 pushTopupStatus(requestId, '68', message)
339 344
340 sleep(60) 345 sleep(60)
341 adviceLastSN(requestId, modem) 346 adviceLastSN(requestId, modem)
342 #waitForResultSmsAfterUssdError(modem, task['requestId'], message) 347 #waitForResultSmsAfterUssdError(modem, task['requestId'], message)
343 return 348 return
344 349
345 350
346 351
347 def topupTask(task, modem): 352 def topupTask(task, modem):
348 global LAST_REQUEST_ID 353 global LAST_REQUEST_ID
349 global LAST_PRODUCT 354 global LAST_PRODUCT
350 355
351 if not task: 356 if not task:
352 return 357 return
353 358
354 if task['status'] != 'OK': 359 if task['status'] != 'OK':
355 return 360 return
356 361
357 LAST_REQUEST_ID = task['requestId'] 362 LAST_REQUEST_ID = task['requestId']
358 LAST_PRODUCT = task['product'].upper() 363 LAST_PRODUCT = task['product'].upper()
359 364
360 redis_key = sate24.keyByRequestId(CHIPINFO, task['requestId']) 365 redis_key = sate24.keyByRequestId(CHIPINFO, task['requestId'])
361 redis_client.set(redis_key, task) 366 redis_client.set(redis_key, task)
362 redis_client.expire(redis_key, REDIS_TTL) 367 redis_client.expire(redis_key, REDIS_TTL)
363 368
364 nominal = xltunai.getNominalFromProduct(task['product']) 369 nominal = xltunai.getNominalFromProduct(task['product'])
365 intl_destination = xltunai.toInternationalNumber(task['destination']) 370 intl_destination = xltunai.toInternationalNumber(task['destination'])
366 371
367 redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, intl_destination) 372 redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, intl_destination)
368 #redis_client.sadd(redis_key, task['requestId']) 373 #redis_client.sadd(redis_key, task['requestId'])
369 try: 374 try:
370 redis_client.rpush(redis_key, task['requestId']) 375 redis_client.rpush(redis_key, task['requestId'])
371 except: 376 except:
372 redis_client.delete(redis_key) 377 redis_client.delete(redis_key)
373 redis_client.rpush(redis_key, task['requestId']) 378 redis_client.rpush(redis_key, task['requestId'])
374 finally: 379 finally:
375 redis_client.expire(redis_key, REDIS_TTL) 380 redis_client.expire(redis_key, REDIS_TTL)
376 381
377 #pushTopupStatus(task['requestId'], '68', 'Siap mengirimkan trx ke operator') 382 #pushTopupStatus(task['requestId'], '68', 'Siap mengirimkan trx ke operator')
378 383
379 message = 'Executing USSD' 384 message = 'Executing USSD'
380 response_code = '68' 385 response_code = '68'
381 386
382 ussd_command = xltunai.getTopupUSSDCommand(task['destination'], task['product'], PIN_TRX) 387 ussd_command = xltunai.getTopupUSSDCommand(task['destination'], task['product'], PIN_TRX)
383 388
384 logger.info(u'Executing {0}'.format(ussd_command)) 389 logger.info(u'Executing {0}'.format(ussd_command))
385 try: 390 try:
386 response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT) 391 response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT)
387 392
388 message = response.message.strip() 393 message = response.message.strip()
389 logger.info(u'USSD response: {0}'.format(message)) 394 logger.info(u'USSD response: {0}'.format(message))
390 395
391 response_code = xltunai.getResponseCodeByUSSDResponse(message) 396 response_code = xltunai.getResponseCodeByUSSDResponse(message)
392 397
393 if response.sessionActive: 398 if response.sessionActive:
394 response.cancel() 399 response.cancel()
395 400
396 except TimeoutException: 401 except TimeoutException:
397 message = "USSD Error: Timeout when executing USSD topup. Signal strength: {0}".format(modem.signalStrength) 402 message = "USSD Error: Timeout when executing USSD topup. Signal strength: {0}".format(modem.signalStrength)
398 logger.warning(message) 403 logger.warning(message)
399 pushTopupStatus(task['requestId'], '68', message) 404 pushTopupStatus(task['requestId'], '68', message)
400 #waitForResultSmsAfterUssdError(modem, task['requestId'], message) 405 #waitForResultSmsAfterUssdError(modem, task['requestId'], message)
401 sleep(15) 406 sleep(15)
402 adviceLastSN(task['requestId'], modem) 407 adviceLastSN(task['requestId'], modem)
403 return 408 return
404 except: 409 except:
405 message = "USSD Error: Something wrong when executing USSD topup. Signal strength: {0}".format(modem.signalStrength) 410 message = "USSD Error: Something wrong when executing USSD topup. Signal strength: {0}".format(modem.signalStrength)
406 logger.warning(message) 411 logger.warning(message)
407 pushTopupStatus(task['requestId'], '68', message) 412 pushTopupStatus(task['requestId'], '68', message)
408 #waitForResultSmsAfterUssdError(modem, task['requestId'], message) 413 #waitForResultSmsAfterUssdError(modem, task['requestId'], message)
409 sleep(15) 414 sleep(15)
410 adviceLastSN(task['requestId'], modem) 415 adviceLastSN(task['requestId'], modem)
411 return 416 return
412 417
413 DISABLE_SEM = DISABLE_SEM_ON_TRX 418 DISABLE_SEM = DISABLE_SEM_ON_TRX
414 pushTopupStatus(task['requestId'], response_code, message) 419 pushTopupStatus(task['requestId'], response_code, message)
415 420
416 def waitForResultSmsAfterUssdError(modem, request_id, last_error_message = ''): 421 def waitForResultSmsAfterUssdError(modem, request_id, last_error_message = ''):
417 logger.info('Sleeping for {0} seconds after an USSD error'.format(SLEEP_AFTER_USSD_ERROR)) 422 logger.info('Sleeping for {0} seconds after an USSD error'.format(SLEEP_AFTER_USSD_ERROR))
418 sleep(SLEEP_AFTER_USSD_ERROR) 423 sleep(SLEEP_AFTER_USSD_ERROR)
419 424
420 redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code' 425 redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code'
421 response_code = redis_client.get(redis_key) 426 response_code = redis_client.get(redis_key)
422 427
423 if response_code == '68' or response_code == None: 428 if response_code == '68' or response_code == None:
424 429
425 prev_balance = BALANCE 430 prev_balance = BALANCE
426 current_balance = checkBalance(modem, do_not_update = True, return_result = True) 431 current_balance = checkBalance(modem, do_not_update = True, return_result = True)
427 432
428 if current_balance == 0: 433 if current_balance == 0:
429 return 434 return
430 435
431 if current_balance < prev_balance: 436 if current_balance < prev_balance:
432 delta = prev_balance - current_balance 437 delta = prev_balance - current_balance
433 pushTopupStatus( 438 pushTopupStatus(
434 request_id, 439 request_id,
435 '00', 440 '00',
436 'Transaksi dianggap sukses karena saldo berkurang {0}. Last error message: {1}'.format( 441 'Transaksi dianggap sukses karena saldo berkurang {0}. Last error message: {1}'.format(
437 delta, 442 delta,
438 last_error_message 443 last_error_message
439 ) 444 )
440 ) 445 )
441 else: 446 else:
442 pushTopupStatus( 447 pushTopupStatus(
443 request_id, 448 request_id,
444 '40', 449 '40',
445 'Transaksi dianggap gagal karena saldo tidak berkurang. Last error message: {0}'.format(last_error_message) 450 'Transaksi dianggap gagal karena saldo tidak berkurang. Last error message: {0}'.format(last_error_message)
446 ) 451 )
447 452
448 def _saveBalanceToRedis(balance_key, balance_value): 453 def _saveBalanceToRedis(balance_key, balance_value):
449 try: 454 try:
450 redis_client.set(balance_key, balance_value) 455 redis_client.set(balance_key, balance_value)
451 redis_client.expire(balance_key, 3600*24*60) 456 redis_client.expire(balance_key, 3600*24*60)
452 except: 457 except:
453 logger.warning('Failed to save balance to redis') 458 logger.warning('Failed to save balance to redis')
454 459
455 def saveBalanceToRedis(balance): 460 def saveBalanceToRedis(balance):
456 global BASE_CHIPINFO 461 global BASE_CHIPINFO
457 global CHIPINFO 462 global CHIPINFO
458 global MSISDN 463 global MSISDN
459 464
460 try: 465 try:
461 balance = int(balance) 466 balance = int(balance)
462 except ValueError: 467 except ValueError:
463 return 468 return
464 469
465 470
466 data = { 471 data = {
467 'balance.gw:' + BASE_CHIPINFO: balance, 472 'balance.gw:' + BASE_CHIPINFO: balance,
468 'balance.gw:' + CHIPINFO: balance, 473 'balance.gw:' + CHIPINFO: balance,
469 'balance.gw:' + MSISDN: balance 474 'balance.gw:' + MSISDN: balance
470 } 475 }
471 476
472 redis_pipe = redis_client.pipeline() 477 redis_pipe = redis_client.pipeline()
473 478
474 try: 479 try:
475 redis_pipe.mset(data) 480 redis_pipe.mset(data)
476 481
477 for k in data: 482 for k in data:
478 redis_pipe.expire(k, 3600 * 24 * 60) 483 redis_pipe.expire(k, 3600 * 24 * 60)
479 484
480 except: 485 except:
481 logger.warning('Failed to save balance to redis') 486 logger.warning('Failed to save balance to redis')
482 finally: 487 finally:
483 redis_pipe.execute() 488 redis_pipe.execute()
484 489
485 def saveSignalStrengthToRedis(value): 490 def saveSignalStrengthToRedis(value):
486 global BASE_CHIPINFO 491 global BASE_CHIPINFO
487 global CHIPINFO 492 global CHIPINFO
488 global MSISDN 493 global MSISDN
489 494
490 try: 495 try:
491 redis_pipe = redis_client.pipeline() 496 redis_pipe = redis_client.pipeline()
492 redis_client.set('balance.gw:' + BASE_CHIPINFO + '.signal', value) 497 redis_client.set('balance.gw:' + BASE_CHIPINFO + '.signal', value)
493 redis_client.expire('balance.gw:' + BASE_CHIPINFO + '.signal', 15 * 60) 498 redis_client.expire('balance.gw:' + BASE_CHIPINFO + '.signal', 15 * 60)
494 except: 499 except:
495 logger.warning('Failed to save signal strength to redis') 500 logger.warning('Failed to save signal strength to redis')
496 501
497 502
498 def pull(modem): 503 def pull(modem):
499 global PRODUCTS 504 global PRODUCTS
500 global PULL_COUNT 505 global PULL_COUNT
501 global BALANCE 506 global BALANCE
502 global DISABLE_SEM 507 global DISABLE_SEM
503 global MIN_SIGNAL_STRENGTH 508 global MIN_SIGNAL_STRENGTH
504 509
505 if not PRODUCTS: 510 if not PRODUCTS:
506 sleep(60) 511 sleep(60)
507 return 512 return
508 513
509 signalStrength = modem.signalStrength 514 signalStrength = modem.signalStrength
510 if signalStrength < MIN_SIGNAL_STRENGTH: 515 if signalStrength < MIN_SIGNAL_STRENGTH:
511 return 516 return
512 517
513 pull_per_minute = 60 / PULL_INTERVAL 518 pull_per_minute = 60 / PULL_INTERVAL
514 519
515 PULL_COUNT += 1 520 PULL_COUNT += 1
516 if PULL_COUNT % (5 * pull_per_minute) == 0: 521 if PULL_COUNT % (5 * pull_per_minute) == 0:
517 checkBalance(modem) 522 checkBalance(modem)
518 sleep(15) 523 sleep(15)
519 PULL_COUNT = 0 524 PULL_COUNT = 0
520 525
521 if DISABLE_SEM > 0: 526 if DISABLE_SEM > 0:
522 logger.info('SEMAPHORE is still on, delaying pull') 527 logger.info('SEMAPHORE is still on, delaying pull')
523 DISABLE_SEM -= 1 528 DISABLE_SEM -= 1
524 return 529 return
525 530
526 if not isPullEnable(): 531 if not isPullEnable():
527 sleep(60) 532 sleep(60)
528 return 533 return
529 534
530 r = None 535 r = None
531 url = AAA_HOST + '/pull?city=' + CITY + '&nom=' + PRODUCTS 536 url = AAA_HOST + '/pull?city=' + CITY + '&nom=' + PRODUCTS
532 try: 537 try:
533 r = requests.get(url) 538 r = requests.get(url)
534 except: 539 except:
535 logger.warning("Error requesting to AAA") 540 logger.warning("Error requesting to AAA")
536 return 541 return
537 542
538 if not r: 543 if not r:
539 return 544 return
540 545
541 task = sate24.parsePullMessage(r.text) 546 task = sate24.parsePullMessage(r.text)
542 547
543 if task['status'] == 'OK': 548 if task['status'] == 'OK':
544 549
545 logger.info('PULL ' + url + ' => ' + r.text) 550 logger.info('PULL ' + url + ' => ' + r.text)
546 publishAAATaskToRedis(task) 551 publishAAATaskToRedis(task)
547 552
548 if not checkBalance(modem) or BALANCE == 0: 553 if not checkBalance(modem) or BALANCE == 0:
549 pushTopupStatus(task['requestId'], '91', 'Transaksi dibatalkan karena gagal check balance') 554 pushTopupStatus(task['requestId'], '91', 'Transaksi dibatalkan karena gagal check balance')
550 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) 555 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP)
551 return 556 return
552 557
553 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) 558 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP)
554 559
555 topupTask(task, modem) 560 topupTask(task, modem)
556 sleep(SLEEP_AFTER_TOPUP) 561 sleep(SLEEP_AFTER_TOPUP)
557 562
558 def publishAAATaskToRedis(task): 563 def publishAAATaskToRedis(task):
559 try: 564 try:
560 key = 'kimochi.aaa_pull.gw:' + BASE_CHIPINFO 565 key = 'kimochi.aaa_pull.gw:' + BASE_CHIPINFO
561 plain_text = task['timestamp'] + ' - ' + task['member'] + ' isi ' + task['product'] + ' ke ' + task['destination']; 566 plain_text = task['timestamp'] + ' - ' + task['member'] + ' isi ' + task['product'] + ' ke ' + task['destination'];
562 567
563 redis_client.publish(key + '.json', json.dumps(task)) 568 redis_client.publish(key + '.json', json.dumps(task))
564 redis_client.publish(key + '.text', plain_text); 569 redis_client.publish(key + '.text', plain_text);
565 except: 570 except:
566 logger.warning('Error publishing kimochi') 571 logger.warning('Error publishing kimochi')
567 572
568 def publishMessageToRedis(): 573 def publishMessageToRedis():
569 pass 574 pass
570 575
571 def pullLoop(modem): 576 def pullLoop(modem):
572 global TERMINATING 577 global TERMINATING
573 578
574 while True: 579 while True:
575 signalStrength = modem.signalStrength 580 signalStrength = modem.signalStrength
576 saveSignalStrengthToRedis(signalStrength) 581 saveSignalStrengthToRedis(signalStrength)
577 582
578 if TERMINATING: 583 if TERMINATING:
579 logger.info('Terminated by request signal') 584 logger.info('Terminated by request signal')
580 sys.exit(0) 585 sys.exit(0)
581 586
582 pull(modem) 587 pull(modem)
583 588
584 sleep(PULL_INTERVAL) 589 sleep(PULL_INTERVAL)
585 590
586 def checkSignal(modem): 591 def checkSignal(modem):
587 logger.info('Signal: {0}'.format(modem.signalStrength)) 592 logger.info('Signal: {0}'.format(modem.signalStrength))
588 try: 593 try:
589 redis_client.set(CHIPINFO + '.signal', modem.signalStrength) 594 redis_client.set(CHIPINFO + '.signal', modem.signalStrength)
590 redis_client.expire(CHIPINFO + '.signal', 3600*24) 595 redis_client.expire(CHIPINFO + '.signal', 3600*24)
591 except: 596 except:
592 logger.warning("Can not save signal strength to redis") 597 logger.warning("Can not save signal strength to redis")
593 598
594 def checkAccount(modem): 599 def checkAccount(modem):
595 try: 600 try:
596 ussd_string = '*123*120*8*3#' 601 ussd_string = '*123*120*8*3#'
597 response = modem.sendUssd(ussd_string, 30) 602 response = modem.sendUssd(ussd_string, 30)
598 logger.info('Account Info: {0}'.format(response.message)) 603 logger.info('Account Info: {0}'.format(response.message))
599 604
600 if response.sessionActive: 605 if response.sessionActive:
601 response.cancel() 606 response.cancel()
602 except: 607 except:
603 logger.warning('Error when requesting account info') 608 logger.warning('Error when requesting account info')
604 return False 609 return False
605 610
606 def checkBalance(modem, do_not_update = False, return_result = False): 611 def checkBalance(modem, do_not_update = False, return_result = False):
607 global BALANCE 612 global BALANCE
608 613
609 _BALANCE = 0 614 _BALANCE = 0
610 615
611 try: 616 try:
612 617
613 ussd_string = '*123*120#' 618 ussd_string = '*123*120#'
614 response = modem.sendUssd(ussd_string, 30) 619 response = modem.sendUssd(ussd_string, 30)
615 _BALANCE = xltunai.getBalanceFromUSSDResponse(response.message) 620 _BALANCE = xltunai.getBalanceFromUSSDResponse(response.message)
616 621
617 if not do_not_update: 622 if not do_not_update:
618 BALANCE = _BALANCE 623 BALANCE = _BALANCE
619 saveBalanceToRedis(BALANCE) 624 saveBalanceToRedis(BALANCE)
620 625
621 logger.info('Balance: {0}'.format(_BALANCE)) 626 logger.info('Balance: {0}'.format(_BALANCE))
622 if response.sessionActive: 627 if response.sessionActive:
623 response.cancel() 628 response.cancel()
624 629
625 if _BALANCE != 0 and _BALANCE < MIN_BALANCE: 630 if _BALANCE != 0 and _BALANCE < MIN_BALANCE:
626 logger.info('Disabling pull, balance {0} < {1}'.format(_BALANCE, MIN_BALANCE)) 631 logger.info('Disabling pull, balance {0} < {1}'.format(_BALANCE, MIN_BALANCE))
627 disablePull() 632 disablePull()
628 633
629 except: 634 except:
630 logger.warning('Error when requesting BALANCE by USSD') 635 logger.warning('Error when requesting BALANCE by USSD')
631 if return_result: 636 if return_result:
632 return 0 637 return 0
633 else: 638 else:
634 return False 639 return False
635 640
636 try: 641 try:
637 redis_client.set(CHIPINFO + '.balance', BALANCE) 642 redis_client.set(CHIPINFO + '.balance', BALANCE)
638 except: 643 except:
639 logger.warning('Failed to save balance to redis') 644 logger.warning('Failed to save balance to redis')
640 645
641 if return_result: 646 if return_result:
642 return _BALANCE 647 return _BALANCE
643 else: 648 else:
644 return True 649 return True
645 650
646 def getPulsaInfo(modem): 651 def getPulsaInfo(modem):
647 global PULSA 652 global PULSA
648 global MASA_AKTIF 653 global MASA_AKTIF
649 654
650 try: 655 try:
651 ussd_string = "*123#" 656 ussd_string = "*123#"
652 response = modem.sendUssd(ussd_string) 657 response = modem.sendUssd(ussd_string)
653 658
654 message = response.message.strip() 659 message = response.message.strip()
655 logger.info('PULSA: {0}'.format(message)) 660 logger.info('PULSA: {0}'.format(message))
656 if response.sessionActive: 661 if response.sessionActive:
657 response.cancel() 662 response.cancel()
658 663
659 PULSA = xltunai.getPulsaFromUssdResponseMessage(message) 664 PULSA = xltunai.getPulsaFromUssdResponseMessage(message)
660 MASA_AKTIF =xltunai.getMasaAktifFromUssdResponseMessage(message) 665 MASA_AKTIF =xltunai.getMasaAktifFromUssdResponseMessage(message)
661 logger.info('PULSA: {0} -- MASA AKTIF: {1}'.format(PULSA, MASA_AKTIF)) 666 logger.info('PULSA: {0} -- MASA AKTIF: {1}'.format(PULSA, MASA_AKTIF))
662 667
663 return message 668 return message
664 669
665 except: 670 except:
666 logger.warning('Error when requesting pulsa info by USSD') 671 logger.warning('Error when requesting pulsa info by USSD')
667 return '' 672 return ''
668 673
669 def getSIMCardInfo(modem): 674 def getSIMCardInfo(modem):
670 try: 675 try:
671 ussd_string = xltunai.getSIMCardInfoUSSDCommand() 676 ussd_string = xltunai.getSIMCardInfoUSSDCommand()
672 response = modem.sendUssd(ussd_string) 677 response = modem.sendUssd(ussd_string)
673 678
674 message = response.message.strip() 679 message = response.message.strip()
675 logger.info('SIM INFO: {0}'.format(message)) 680 logger.info('SIM INFO: {0}'.format(message))
676 if response.sessionActive: 681 if response.sessionActive:
677 response.cancel() 682 response.cancel()
678 683
679 return message 684 return message
680 685
681 except: 686 except:
682 logger.warning('Error when requesting SIM card info by USSD') 687 logger.warning('Error when requesting SIM card info by USSD')
683 return '' 688 return ''
684 689
685 def updateChipInfo(msisdn): 690 def updateChipInfo(msisdn):
686 global BASE_CHIPINFO 691 global BASE_CHIPINFO
687 global CHIPINFO 692 global CHIPINFO
688 global MSISDN 693 global MSISDN
689 694
690 MSISDN = msisdn 695 MSISDN = msisdn
691 if CHIPINFO.find(msisdn) == -1: 696 if CHIPINFO.find(msisdn) == -1:
692 CHIPINFO = BASE_CHIPINFO + '-' + msisdn 697 CHIPINFO = BASE_CHIPINFO + '-' + msisdn
693 698
694 logger.info('CHIPINFO: {0}'.format(CHIPINFO)) 699 logger.info('CHIPINFO: {0}'.format(CHIPINFO))
695 700
696 def main(): 701 def main():
697 global logger 702 global logger
698 703
699 log_format = '%(asctime)s %(levelname)s: %(message)s' 704 log_format = '%(asctime)s %(levelname)s: %(message)s'
700 705
701 logging.basicConfig(format=log_format, level=logging.INFO) 706 logging.basicConfig(format=log_format, level=logging.INFO)
702 logger = logging.getLogger(__name__) 707 logger = logging.getLogger(__name__)
703 708
704 logger_formatter = logging.Formatter(log_format) 709 logger_formatter = logging.Formatter(log_format)
705 logger_handler = TimedRotatingFileHandler('logs/log', when='midnight') 710 logger_handler = TimedRotatingFileHandler('logs/log', when='midnight')
706 logger_handler.setFormatter(logger_formatter) 711 logger_handler.setFormatter(logger_formatter)
707 logger.addHandler(logger_handler) 712 logger.addHandler(logger_handler)
708 713
709 requests_logger = logging.getLogger('requests') 714 requests_logger = logging.getLogger('requests')
710 requests_logger.setLevel(logging.WARNING) 715 requests_logger.setLevel(logging.WARNING)
711 716
712 logger.info('Initializing modem...') 717 logger.info('Initializing modem...')
713 718
714 modem = GsmModem(PORT, BAUDRATE, smsReceivedCallbackFunc=handleSms) 719 modem = GsmModem(PORT, BAUDRATE, smsReceivedCallbackFunc=handleSms)
715 modem.smsTextMode = True 720 modem.smsTextMode = True
716 modem.connect(PIN) 721 modem.connect(PIN)
717 722
718 logger.info('Waiting for network coverage...') 723 logger.info('Waiting for network coverage...')
719 modem.waitForNetworkCoverage(10) 724 modem.waitForNetworkCoverage(10)
720 725
721 logger.info('Modem ready') 726 logger.info('Modem ready')
722 727
723 getPulsaInfo(modem) 728 getPulsaInfo(modem)
724 sleep(2) 729 sleep(2)
725 730
726 simcard_info = getSIMCardInfo(modem) 731 simcard_info = getSIMCardInfo(modem)
727 msisdn = xltunai.getMSISDNFromSIMCardInfo(simcard_info) 732 msisdn = xltunai.getMSISDNFromSIMCardInfo(simcard_info)
728 733
729 if not msisdn: 734 if not msisdn:
730 logger.warning('Gagal mendapatkan msisdn, terminating') 735 logger.warning('Gagal mendapatkan msisdn, terminating')
731 sleep(5) 736 sleep(5)
732 sys.exit(2) 737 sys.exit(2)
733 738
734 imsi = modem.imsi 739 imsi = modem.imsi
735 logger.info('MSISDN: {0} -- IMSI: {1}'.format(msisdn, imsi)) 740 logger.info('MSISDN: {0} -- IMSI: {1}'.format(msisdn, imsi))
736 741
737 updateChipInfo(msisdn) 742 updateChipInfo(msisdn)
738 saveSimCardInfo(imsi, msisdn) 743 saveSimCardInfo(imsi, msisdn)
739 744
740 sleep(2) 745 sleep(2)
741 746
742 saveSignalStrengthToRedis(modem.signalStrength) 747 saveSignalStrengthToRedis(modem.signalStrength)
743 748
744 logger.info('Process stored SMS') 749 logger.info('Process stored SMS')
745 try: 750 try:
746 modem.processStoredSms() 751 modem.processStoredSms()
747 except: 752 except:
748 logger.warning('Failed on Process stored SMS') 753 logger.warning('Failed on Process stored SMS')
749 754
750 logger.info('Delete stored SMS') 755 logger.info('Delete stored SMS')
751 try: 756 try:
752 modem.deleteMultipleStoredSms() 757 modem.deleteMultipleStoredSms()
753 except: 758 except:
754 #logger.warning('Failed on delete SMS') 759 #logger.warning('Failed on delete SMS')
755 pass 760 pass
756 761
757 sleep(2) 762 sleep(2)
758 763
759 checkAccount(modem) 764 checkAccount(modem)
760 sleep(5) 765 sleep(5)
761 766
762 enablePull() 767 enablePull()
763 768
764 checkBalance(modem) 769 checkBalance(modem)
765 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) 770 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP)
766 771
767 pullLoop(modem) 772 pullLoop(modem)
768 logger.info('Waiting for SMS message...') 773 logger.info('Waiting for SMS message...')
769 try: 774 try:
770 modem.rxThread.join(2**31) # Specify a (huge) timeout so that it essentially blocks indefinitely, but still receives CTRL+C interrupt signal 775 modem.rxThread.join(2**31) # Specify a (huge) timeout so that it essentially blocks indefinitely, but still receives CTRL+C interrupt signal
771 finally: 776 finally:
772 modem.close(); 777 modem.close();
773 778
774 def saveSimCardInfo(imsi, msisdn): 779 def saveSimCardInfo(imsi, msisdn):
775 logger.info('Save sim card info to redis') 780 logger.info('Save sim card info to redis')
776 781
777 data = { 782 data = {
778 'gw': BASE_CHIPINFO, 783 'gw': BASE_CHIPINFO,
779 'imsi': imsi, 784 'imsi': imsi,
780 'msisdn': msisdn, 785 'msisdn': msisdn,
781 'pulsa': PULSA, 786 'pulsa': PULSA,
782 'masa_aktif': MASA_AKTIF 787 'masa_aktif': MASA_AKTIF
783 } 788 }
784 789
785 json_data = json.dumps(data) 790 json_data = json.dumps(data)
786 791
787 with open('simcardinfo.txt', 'w') as f: 792 with open('simcardinfo.txt', 'w') as f:
788 f.write(json_data) 793 f.write(json_data)
789 f.closed 794 f.closed
790 795
791 796
792 map_data = { 797 map_data = {
793 BASE_CHIPINFO + '.simcardinfo': json_data, 798 BASE_CHIPINFO + '.simcardinfo': json_data,
794 'simcardinfo.gw:' + BASE_CHIPINFO: json_data, 799 'simcardinfo.gw:' + BASE_CHIPINFO: json_data,
795 'simcardinfo.imsi:' + imsi: json_data, 800 'simcardinfo.imsi:' + imsi: json_data,
796 'simcardinfo.msisdn:' + msisdn: json_data 801 'simcardinfo.msisdn:' + msisdn: json_data
797 } 802 }
798 803
799 logger.info(map_data) 804 logger.info(map_data)
800 805
801 redis_pipe = redis_client.pipeline() 806 redis_pipe = redis_client.pipeline()
802 807
803 try: 808 try:
804 redis_pipe.mset(map_data) 809 redis_pipe.mset(map_data)
805 810
806 for k in data: 811 for k in data:
807 redis_pipe.expire(k, 3600 * 24 * 60) 812 redis_pipe.expire(k, 3600 * 24 * 60)
808 813
809 except: 814 except:
810 logger.warning('Failed to save simcardinfo to redis') 815 logger.warning('Failed to save simcardinfo to redis')
811 finally: 816 finally:
812 redis_pipe.execute() 817 redis_pipe.execute()
813 818
814 if __name__ == '__main__': 819 if __name__ == '__main__':
815 pidfile = open('pid.txt', 'w') 820 pidfile = open('pid.txt', 'w')
816 pidfile.write(str(getpid())) 821 pidfile.write(str(getpid()))
817 pidfile.close() 822 pidfile.close()
818 823
819 # trap CTRL-C 824 # trap CTRL-C
820 signal.signal(signal.SIGINT, signalHandler) 825 signal.signal(signal.SIGINT, signalHandler)
821 # trap supervisor stop 826 # trap supervisor stop
822 signal.signal(signal.SIGTERM, signalHandler) 827 signal.signal(signal.SIGTERM, signalHandler)
823 828
824 main() 829 main()
825 830
1 import xltunai 1 import xltunai
2 2
3 def test_getOperatorFromProduct(): 3 def test_getOperatorFromProduct():
4 assert xltunai.getOperatorFromProduct('XL5') == 'XL' 4 assert xltunai.getOperatorFromProduct('XL5') == 'XL'
5 assert xltunai.getOperatorFromProduct('XL10') == 'XL' 5 assert xltunai.getOperatorFromProduct('XL10') == 'XL'
6 assert xltunai.getOperatorFromProduct('XL25') == 'XL' 6 assert xltunai.getOperatorFromProduct('XL25') == 'XL'
7 assert xltunai.getOperatorFromProduct('XL50') == 'XL' 7 assert xltunai.getOperatorFromProduct('XL50') == 'XL'
8 assert xltunai.getOperatorFromProduct('XL100') == 'XL' 8 assert xltunai.getOperatorFromProduct('XL100') == 'XL'
9 9
10 assert xltunai.getOperatorFromProduct('XA5') == 'XA' 10 assert xltunai.getOperatorFromProduct('XA5') == 'XA'
11 assert xltunai.getOperatorFromProduct('XA10') == 'XA' 11 assert xltunai.getOperatorFromProduct('XA10') == 'XA'
12 assert xltunai.getOperatorFromProduct('XA25') == 'XA' 12 assert xltunai.getOperatorFromProduct('XA25') == 'XA'
13 assert xltunai.getOperatorFromProduct('XA50') == 'XA' 13 assert xltunai.getOperatorFromProduct('XA50') == 'XA'
14 assert xltunai.getOperatorFromProduct('XA100') == 'XA' 14 assert xltunai.getOperatorFromProduct('XA100') == 'XA'
15 15
16 assert xltunai.getOperatorFromProduct('XL100H') == 'XL' 16 assert xltunai.getOperatorFromProduct('XL100H') == 'XL'
17 17
18 def test_getNominalFromProduct(): 18 def test_getNominalFromProduct():
19 assert xltunai.getNominalFromProduct('XL5') == 5000 19 assert xltunai.getNominalFromProduct('XL5') == 5000
20 assert xltunai.getNominalFromProduct('XL10') == 10000 20 assert xltunai.getNominalFromProduct('XL10') == 10000
21 assert xltunai.getNominalFromProduct('XL25') == 25000 21 assert xltunai.getNominalFromProduct('XL25') == 25000
22 assert xltunai.getNominalFromProduct('XL50') == 50000 22 assert xltunai.getNominalFromProduct('XL50') == 50000
23 assert xltunai.getNominalFromProduct('XL100') == 100000 23 assert xltunai.getNominalFromProduct('XL100') == 100000
24 24
25 assert xltunai.getNominalFromProduct('XA5') == 5000 25 assert xltunai.getNominalFromProduct('XA5') == 5000
26 assert xltunai.getNominalFromProduct('XA10') == 10000 26 assert xltunai.getNominalFromProduct('XA10') == 10000
27 assert xltunai.getNominalFromProduct('XA25') == 25000 27 assert xltunai.getNominalFromProduct('XA25') == 25000
28 assert xltunai.getNominalFromProduct('XA50') == 50000 28 assert xltunai.getNominalFromProduct('XA50') == 50000
29 assert xltunai.getNominalFromProduct('XA100') == 100000 29 assert xltunai.getNominalFromProduct('XA100') == 100000
30 30
31 assert xltunai.getNominalFromProduct('XL100H') == 100000 31 assert xltunai.getNominalFromProduct('XL100H') == 100000
32 32
33 def test_getDenomCodeFromProduct(): 33 def test_getDenomCodeFromProduct():
34 assert xltunai.getDenomCodeFromProduct('XL5') == 1 34 assert xltunai.getDenomCodeFromProduct('XL5') == 1
35 assert xltunai.getDenomCodeFromProduct('XL10') == 2 35 assert xltunai.getDenomCodeFromProduct('XL10') == 2
36 assert xltunai.getDenomCodeFromProduct('XL25') == 3 36 assert xltunai.getDenomCodeFromProduct('XL25') == 3
37 assert xltunai.getDenomCodeFromProduct('XL50') == 4 37 assert xltunai.getDenomCodeFromProduct('XL50') == 4
38 assert xltunai.getDenomCodeFromProduct('XL100') == 5 38 assert xltunai.getDenomCodeFromProduct('XL100') == 5
39 assert xltunai.getDenomCodeFromProduct('XL200') == 6 39 assert xltunai.getDenomCodeFromProduct('XL200') == 6
40 40
41 assert xltunai.getDenomCodeFromProduct('XL300') == None 41 assert xltunai.getDenomCodeFromProduct('XL300') == None
42 42
43 def test_getCostFromProduct(): 43 def test_getCostFromProduct():
44 assert xltunai.getCostFromProduct('XL5') == 5500 44 assert xltunai.getCostFromProduct('XL5') == 5500
45 assert xltunai.getCostFromProduct('XL10') == 10500 45 assert xltunai.getCostFromProduct('XL10') == 10500
46 assert xltunai.getCostFromProduct('XL25') == 25000 46 assert xltunai.getCostFromProduct('XL25') == 25000
47 assert xltunai.getCostFromProduct('XL50') == 50000 47 assert xltunai.getCostFromProduct('XL50') == 50000
48 assert xltunai.getCostFromProduct('XL100') == 100000 48 assert xltunai.getCostFromProduct('XL100') == 100000
49 assert xltunai.getCostFromProduct('XL200') == 200000 49 assert xltunai.getCostFromProduct('XL200') == 200000
50 50
51 assert xltunai.getCostFromProduct('XL300') == 0 51 assert xltunai.getCostFromProduct('XL300') == 0
52 52
53 def test_getSNFromMessage(): 53 def test_getSNFromMessage():
54 assert xltunai.getSNFromMessage('Nomor 6287884153131 telah berhasil diisi pulsa sebesar Rp.5000. Nikmati transaksi XL Tunai lainnya. Ref ID :75614092695337') == '75614092695337' 54 assert xltunai.getSNFromMessage('Nomor 6287884153131 telah berhasil diisi pulsa sebesar Rp.5000. Nikmati transaksi XL Tunai lainnya. Ref ID :75614092695337') == '75614092695337'
55 assert xltunai.getSNFromMessage('Nomor 6287884153131 telah berhasil diisi pulsa sebesar Rp.5000. Nikmati transaksi XL Tunai lainnya. SN ID :75614092695337') == '' 55 assert xltunai.getSNFromMessage('Nomor 6287884153131 telah berhasil diisi pulsa sebesar Rp.5000. Nikmati transaksi XL Tunai lainnya. SN ID :75614092695337') == ''
56 assert xltunai.getSNFromMessage('Nomor 6287889517766 telah berhasil diisi pulsa sebesar Rp 10000.Sisa Saldo Rp 3004500. Ref No 43280489064186') == '43280489064186' 56 assert xltunai.getSNFromMessage('Nomor 6287889517766 telah berhasil diisi pulsa sebesar Rp 10000.Sisa Saldo Rp 3004500. Ref No 43280489064186') == '43280489064186'
57 57
58 def test_toInternationalNumber(): 58 def test_toInternationalNumber():
59 assert xltunai.toInternationalNumber('081808180818') == '6281808180818' 59 assert xltunai.toInternationalNumber('081808180818') == '6281808180818'
60 assert xltunai.toInternationalNumber('6281808180818') == '6281808180818' 60 assert xltunai.toInternationalNumber('6281808180818') == '6281808180818'
61 assert xltunai.toInternationalNumber('4114') == '4114' 61 assert xltunai.toInternationalNumber('4114') == '4114'
62 62
63 def test_getDestinationFromMessage(): 63 def test_getDestinationFromMessage():
64 assert xltunai.getDestinationFromMessage('Nomor 6287884153131 telah berhasil diisi pulsa sebesar Rp.5000. Nikmati transaksi XL Tunai lainnya. Ref ID :75614092695337') == '6287884153131' 64 assert xltunai.getDestinationFromMessage('Nomor 6287884153131 telah berhasil diisi pulsa sebesar Rp.5000. Nikmati transaksi XL Tunai lainnya. Ref ID :75614092695337') == '6287884153131'
65 65
66 def test_getNominalFromMessage(): 66 def test_getNominalFromMessage():
67 assert xltunai.getNominalFromMessage('Nomor 6287770722609 telah berhasil diisi pulsa sebesar 5000. Sisa Saldo Rp 1949500. Ref No 41040432037489') == '5000' 67 assert xltunai.getNominalFromMessage('Nomor 6287770722609 telah berhasil diisi pulsa sebesar 5000. Sisa Saldo Rp 1949500. Ref No 41040432037489') == '5000'
68 assert xltunai.getNominalFromMessage('Bla bla') == '' 68 assert xltunai.getNominalFromMessage('Bla bla') == ''
69 69
70 def test_getBalanceFromMessage(): 70 def test_getBalanceFromMessage():
71 assert xltunai.getBalanceFromMessage('Nomor 6287889517766 telah berhasil diisi pulsa sebesar Rp 10000.Sisa Saldo Rp 3004500. Ref No 43280489064186') == 3004500 71 assert xltunai.getBalanceFromMessage('Nomor 6287889517766 telah berhasil diisi pulsa sebesar Rp 10000.Sisa Saldo Rp 3004500. Ref No 43280489064186') == 3004500
72 72
73 def test_getBalanceFromUSSDResponse(): 73 def test_getBalanceFromUSSDResponse():
74 message = """USSD response message: Saldo Rp134500 74 message = """USSD response message: Saldo Rp134500
75 Isi Pulsa 5000, Pilih menu no.2 75 Isi Pulsa 5000, Pilih menu no.2
76 1 Belanja di toko 76 1 Belanja di toko
77 2 Isi Pulsa 77 2 Isi Pulsa
78 3 Pembayaran 78 3 Pembayaran
79 4 Belanja Online 79 4 Belanja Online
80 5 Kirim Uang 80 5 Kirim Uang
81 6 Tarik Uang 81 6 Tarik Uang
82 7 Pengaturan 82 7 Pengaturan
83 8 Info""" 83 8 Info"""
84 assert xltunai.getBalanceFromUSSDResponse(message) == 134500 84 assert xltunai.getBalanceFromUSSDResponse(message) == 134500
85 85
86 def test_getTopupUSSDCommand(): 86 def test_getTopupUSSDCommand():
87 assert xltunai.getTopupUSSDCommand('081808180818', 'XL2', '1234') == None 87 assert xltunai.getTopupUSSDCommand('081808180818', 'XL2', '1234') == None
88 assert xltunai.getTopupUSSDCommand('081808180818', 'XL5', '1234') == '*123*120*2*2*081808180818*1*1234#' 88 assert xltunai.getTopupUSSDCommand('081808180818', 'XL5', '1234') == '*123*120*2*2*081808180818*1*1234#'
89 assert xltunai.getTopupUSSDCommand('6281808180818', 'XL5', '1234') == '*123*120*2*2*6281808180818*1*1234#' 89 assert xltunai.getTopupUSSDCommand('6281808180818', 'XL5', '1234') == '*123*120*2*2*6281808180818*1*1234#'
90 assert xltunai.getTopupUSSDCommand('081808180818', 'XL50', '1234') == '*123*120*2*2*081808180818*4*1234#' 90 assert xltunai.getTopupUSSDCommand('081808180818', 'XL50', '1234') == '*123*120*2*2*081808180818*4*1234#'
91 91
92 def test_valid_sender(): 92 def test_valid_sender():
93 assert xltunai.isValidSender('120') == True 93 assert xltunai.isValidSender('120') == True
94 assert xltunai.isValidSender('121') == False 94 assert xltunai.isValidSender('121') == False
95 95
96 def test_getResponseCodeByMessage(): 96 def test_getResponseCodeByMessage():
97 assert xltunai.getResponseCodeByMessage('Nomor 6287884153131 telah berhasil diisi pulsa sebesar Rp.5000. Nikmati transaksi XL Tunai lainnya. Ref ID :75614092695337') == '00' 97 assert xltunai.getResponseCodeByMessage('Nomor 6287884153131 telah berhasil diisi pulsa sebesar Rp.5000. Nikmati transaksi XL Tunai lainnya. Ref ID :75614092695337') == '00'
98 assert xltunai.getResponseCodeByMessage('Bla bla bla') == '68' 98 assert xltunai.getResponseCodeByMessage('Bla bla bla') == '68'
99 99
100 def test_getResponseCodeByUSSDResponse(): 100 def test_getResponseCodeByUSSDResponse():
101 assert xltunai.getResponseCodeByUSSDResponse('Mohon maaf, nomor yang Anda masukkan tidak valid') == '14' 101 assert xltunai.getResponseCodeByUSSDResponse('Mohon maaf, nomor yang Anda masukkan tidak valid') == '14'
102 assert xltunai.getResponseCodeByUSSDResponse('Bla bla bla') == '68' 102 assert xltunai.getResponseCodeByUSSDResponse('Bla bla bla') == '68'
103 103
104 def test_getMSISDNFromSIMCardInfo(): 104 def test_getMSISDNFromSIMCardInfo():
105 assert xltunai.getMSISDNFromSIMCardInfo('Nomor 6287880852347 adalah nomor dengan POC JK0 dengan ICCID 8962116820756544479') == '6287880852347' 105 assert xltunai.getMSISDNFromSIMCardInfo('Nomor 6287880852347 adalah nomor dengan POC JK0 dengan ICCID 8962116820756544479') == '6287880852347'
106 assert xltunai.getMSISDNFromSIMCardInfo('bla bla bla') == '' 106 assert xltunai.getMSISDNFromSIMCardInfo('bla bla bla') == ''
107 107
108 def test_getIMSIFromSIMCardInfo(): 108 def test_getIMSIFromSIMCardInfo():
109 assert xltunai.getIMSIFromSIMCardInfo('Nomor 6287880852347 adalah nomor dengan POC JK0 dengan ICCID 8962116820756544479') == '8962116820756544479' 109 assert xltunai.getIMSIFromSIMCardInfo('Nomor 6287880852347 adalah nomor dengan POC JK0 dengan ICCID 8962116820756544479') == '8962116820756544479'
110 assert xltunai.getIMSIFromSIMCardInfo('bla bla bla') == '' 110 assert xltunai.getIMSIFromSIMCardInfo('bla bla bla') == ''
111 111
112 def test_getPulsaFromUssdResponseMessage(): 112 def test_getPulsaFromUssdResponseMessage():
113 assert xltunai.getPulsaFromUssdResponseMessage('Pulsa 41875 s/d 16Sep15. Mendadak DISKON 1 JUTA pelanggan pertama!') == 41875 113 assert xltunai.getPulsaFromUssdResponseMessage('Pulsa 41875 s/d 16Sep15. Mendadak DISKON 1 JUTA pelanggan pertama!') == 41875
114 assert xltunai.getPulsaFromUssdResponseMessage('''Pulsa 41875 s/d 16Sep15. Mendadak DISKON 1 JUTA pelanggan pertama! 114 assert xltunai.getPulsaFromUssdResponseMessage('''Pulsa 41875 s/d 16Sep15. Mendadak DISKON 1 JUTA pelanggan pertama!
115 1 Mau 115 1 Mau
116 2 Info 4G 116 2 Info 4G
117 3 Internet 117 3 Internet
118 4 Pkt Nelp&SMS 118 4 Pkt Nelp&SMS
119 5 Pkt Seru 119 5 Pkt Seru
120 6 mPulsa 120 6 mPulsa
121 7 60Mazda2''') == 41875 121 7 60Mazda2''') == 41875
122 assert xltunai.getPulsaFromUssdResponseMessage('') == None 122 assert xltunai.getPulsaFromUssdResponseMessage('') == None
123 assert xltunai.getPulsaFromUssdResponseMessage('Pulsa habis s/d') == None 123 assert xltunai.getPulsaFromUssdResponseMessage('Pulsa habis s/d') == None
124 124
125 def test_getPulsaFromUssdResponseMessage(): 125 def test_getPulsaFromUssdResponseMessage():
126 assert xltunai.getMasaAktifFromUssdResponseMessage('Pulsa 41875 s/d 16Sep15. Mendadak DISKON 1 JUTA pelanggan pertama!') == '2015-09-16' 126 assert xltunai.getMasaAktifFromUssdResponseMessage('Pulsa 41875 s/d 16Sep15. Mendadak DISKON 1 JUTA pelanggan pertama!') == '2015-09-16'
127 assert xltunai.getMasaAktifFromUssdResponseMessage('Pulsa 53000 s.d 10Sep15. Pkt TalkMania-XTRA 250Mnt, Rp3375!') == '2015-09-10' 127 assert xltunai.getMasaAktifFromUssdResponseMessage('Pulsa 53000 s.d 10Sep15. Pkt TalkMania-XTRA 250Mnt, Rp3375!') == '2015-09-10'
128 assert xltunai.getMasaAktifFromUssdResponseMessage('Pulsa 41875 s/d. Mendadak DISKON 1 JUTA pelanggan pertama!') == None 128 assert xltunai.getMasaAktifFromUssdResponseMessage('Pulsa 41875 s/d. Mendadak DISKON 1 JUTA pelanggan pertama!') == None
129 129
130 130
131 def test_getLastSNFromMessage(): 131 def test_getLastSNFromMessage():
132 assert xltunai.getLastSNFromHistoryMessage('Transaksi Terakhir : 20063778248257/5500/12-02-2016 14:37:08/M201312021528418273770285/P201511211752675316198716/RELOAD XL 5000') == '20063778248257' 132 assert xltunai.getLastSNFromHistoryMessage('Transaksi Terakhir : 20063778248257/5500/12-02-2016 14:37:08/M201312021528418273770285/P201511211752675316198716/RELOAD XL 5000') == '20063778248257'
133 assert xltunai.getLastSNFromHistoryMessage('Transaksi Terakhir :\n20063778248257/5500/12-02-2016 14:37:08/M201312021528418273770285/P201511211752675316198716/RELOAD XL 5000') == '20063778248257' 133 assert xltunai.getLastSNFromHistoryMessage('Transaksi Terakhir :\n20063778248257/5500/12-02-2016 14:37:08/M201312021528418273770285/P201511211752675316198716/RELOAD XL 5000') == '20063778248257'
134 134
135 def test_getSNFromReceiveTransferMessage(): 135 def test_getSNFromReceiveTransferMessage():
136 assert xltunai.getSNFromReceiveTransferMessage('Anda terima uang XLTunai Rp2500000 dr 6287886957792 DIDIT ARIYANTO pada 19/02/2016 16:14:32.Cek saldo di *123*120#.RefID 49498359729433. Info hub 817') == '49498359729433' 136 assert xltunai.getSNFromReceiveTransferMessage('Anda terima uang XLTunai Rp2500000 dr 6287886957792 DIDIT ARIYANTO pada 19/02/2016 16:14:32.Cek saldo di *123*120#.RefID 49498359729433. Info hub 817') == '49498359729433'
137 137
138 def test_getSNFromCashInMessage(): 138 def test_getSNFromCashInMessage():
139 assert xltunai.getSNFromCashInMessage('Terimakasih, transaksi CASH IN ke akun 6287886957792 berhasil. Jumlah transaksi Rp 5000000, biaya 0. Saldo anda saat ini 5000000 . Ref ID: 96346333194106') == '96346333194106' 139 assert xltunai.getSNFromCashInMessage('Terimakasih, transaksi CASH IN ke akun 6287886957792 berhasil. Jumlah transaksi Rp 5000000, biaya 0. Saldo anda saat ini 5000000 . Ref ID: 96346333194106') == '96346333194106'
140
141 def test_getSNFromSentTransferMessage():
142 assert xltunai.getSNFromSentTransferMessage('Kirim uang ke 6287886957795 an DIDIT ARIYANTO sebesar Rp 580000 berhasil pada 20/02/2016 21:48:54.Ref id 79811319924606. Info hub 817') == '79811319924606'
140 143
1 import re 1 import re
2 import time 2 import time
3 3
4 nominalCodes = { 4 nominalCodes = {
5 5000: 1, 5 5000: 1,
6 10000: 2, 6 10000: 2,
7 25000: 3, 7 25000: 3,
8 50000: 4, 8 50000: 4,
9 100000: 5, 9 100000: 5,
10 200000: 6 10 200000: 6
11 } 11 }
12 12
13 nominalCosts = { 13 nominalCosts = {
14 5000: 5500, 14 5000: 5500,
15 10000: 10500, 15 10000: 10500,
16 25000: 25000, 16 25000: 25000,
17 50000: 50000, 17 50000: 50000,
18 100000: 100000, 18 100000: 100000,
19 200000: 200000 19 200000: 200000
20 } 20 }
21 21
22 valid_senders = ['120',] 22 valid_senders = ['120',]
23 message_codes = { 23 message_codes = {
24 'telah berhasil diisi pulsa sebesar': '00', 24 'telah berhasil diisi pulsa sebesar': '00',
25 'Maaf, transaksi Anda masih dalam proses': '40' 25 'Maaf, transaksi Anda masih dalam proses': '40'
26 } 26 }
27 27
28 ussd_response_codes = { 28 ussd_response_codes = {
29 'nomor yang Anda masukkan tidak valid': '14', 29 'nomor yang Anda masukkan tidak valid': '14',
30 'Maaf, transaksi Anda masih dalam proses': '40', 30 'Maaf, transaksi Anda masih dalam proses': '40',
31 'Mohon maaf, transaksi Anda melebihi limit': '40', 31 'Mohon maaf, transaksi Anda melebihi limit': '40',
32 'http url not found': '40', 32 'http url not found': '40',
33 'operation timeout': '40' 33 'operation timeout': '40'
34 } 34 }
35 35
36 def getOperatorFromProduct(product): 36 def getOperatorFromProduct(product):
37 return re.sub(r'\d+.*', '', product) 37 return re.sub(r'\d+.*', '', product)
38 38
39 def getNominalFromProduct(product): 39 def getNominalFromProduct(product):
40 return int("".join(re.findall(r'\d+', product))) * 1000 40 return int("".join(re.findall(r'\d+', product))) * 1000
41 41
42 def getNominalFromMessage(message): 42 def getNominalFromMessage(message):
43 nominal = "".join(re.findall(r'pulsa sebesar \d+\.', message)) 43 nominal = "".join(re.findall(r'pulsa sebesar \d+\.', message))
44 nominal = "".join(re.findall(r'\d+', nominal)) 44 nominal = "".join(re.findall(r'\d+', nominal))
45 return nominal 45 return nominal
46 46
47 def getDenomCodeFromProduct(product): 47 def getDenomCodeFromProduct(product):
48 nominal = getNominalFromProduct(product) 48 nominal = getNominalFromProduct(product)
49 try: 49 try:
50 result = nominalCodes[nominal] 50 result = nominalCodes[nominal]
51 except: 51 except:
52 result = None 52 result = None
53 53
54 return result 54 return result
55 55
56 def getCostFromProduct(product): 56 def getCostFromProduct(product):
57 nominal = getNominalFromProduct(product) 57 nominal = getNominalFromProduct(product)
58 try: 58 try:
59 result = nominalCosts[nominal] 59 result = nominalCosts[nominal]
60 except: 60 except:
61 result = 0 61 result = 0
62 62
63 return int(result) 63 return int(result)
64 64
65 def getDestinationFromMessage(message): 65 def getDestinationFromMessage(message):
66 result = "".join(re.findall(r'^Nomor \d+ telah berhasil', message)) 66 result = "".join(re.findall(r'^Nomor \d+ telah berhasil', message))
67 result = "".join(re.findall(r'\d+', result)) 67 result = "".join(re.findall(r'\d+', result))
68 return result 68 return result
69 69
70 def getSNFromMessage(message): 70 def getSNFromMessage(message):
71 try: 71 try:
72 sn = "".join(re.findall(r'Ref (?:ID :|No )(\d+)', message)) 72 sn = "".join(re.findall(r'Ref (?:ID :|No )(\d+)', message))
73 sn = "".join(re.findall(r'\d+', sn)) 73 sn = "".join(re.findall(r'\d+', sn))
74 except: 74 except:
75 sn = "" 75 sn = ""
76 76
77 return sn 77 return sn
78 78
79 def getBalanceFromMessage(message): 79 def getBalanceFromMessage(message):
80 try: 80 try:
81 sn = "".join(re.findall(r'Saldo Rp (\d+)', message)) 81 sn = "".join(re.findall(r'Saldo Rp (\d+)', message))
82 return int(sn) 82 return int(sn)
83 except: 83 except:
84 return 0 84 return 0
85 85
86 def getSNFromReceiveTransferMessage(message): 86 def getSNFromReceiveTransferMessage(message):
87 try: 87 try:
88 sn = "".join(re.findall(r'RefID (\d+)', message)) 88 sn = "".join(re.findall(r'RefID (\d+)', message))
89 return sn 89 return sn
90 except: 90 except:
91 return 91 return
92 92
93 def getSNFromSentTransferMessage(message):
94 try:
95 sn = "".join(re.findall(r'Ref id (\d+)', message))
96 return sn
97 except:
98 return
99
93 def getSNFromCashInMessage(message): 100 def getSNFromCashInMessage(message):
94 try: 101 try:
95 sn = "".join(re.findall(r'Ref ID: (\d+)$', message)) 102 sn = "".join(re.findall(r'Ref ID: (\d+)$', message))
96 return sn 103 return sn
97 except: 104 except:
98 return 105 return
99 106
100 def toInternationalNumber(number): 107 def toInternationalNumber(number):
101 return re.sub(r'^0', '62', number) 108 return re.sub(r'^0', '62', number)
102 109
103 def getSIMCardInfoUSSDCommand(): 110 def getSIMCardInfoUSSDCommand():
104 return '*123*7*3*1*1#' 111 return '*123*7*3*1*1#'
105 112
106 def getHistoryUSSDCommand(): 113 def getHistoryUSSDCommand():
107 return '*123*120*8*3#' 114 return '*123*120*8*3#'
108 115
109 def getMSISDNFromSIMCardInfo(message): 116 def getMSISDNFromSIMCardInfo(message):
110 msisdn = "".join(re.findall(r'Nomor \d+ adalah nomor', message)) 117 msisdn = "".join(re.findall(r'Nomor \d+ adalah nomor', message))
111 msisdn = "".join(re.findall(r'\d+', msisdn)) 118 msisdn = "".join(re.findall(r'\d+', msisdn))
112 return msisdn 119 return msisdn
113 120
114 def getIMSIFromSIMCardInfo(message): 121 def getIMSIFromSIMCardInfo(message):
115 imsi = "".join(re.findall(r'dengan ICCID \d+', message)) 122 imsi = "".join(re.findall(r'dengan ICCID \d+', message))
116 imsi = "".join(re.findall(r'\d+', imsi)) 123 imsi = "".join(re.findall(r'\d+', imsi))
117 return imsi 124 return imsi
118 125
119 def getBalanceFromUSSDResponse(message): 126 def getBalanceFromUSSDResponse(message):
120 balance = "".join(re.findall(r'Saldo Rp\d+', message)) 127 balance = "".join(re.findall(r'Saldo Rp\d+', message))
121 balance = re.sub('Saldo Rp', '', balance) 128 balance = re.sub('Saldo Rp', '', balance)
122 try: 129 try:
123 return int(balance) 130 return int(balance)
124 except: 131 except:
125 return 0 132 return 0
126 133
127 def getTopupUSSDCommand(destination, product, pin_trx): 134 def getTopupUSSDCommand(destination, product, pin_trx):
128 denom_code = getDenomCodeFromProduct(product) 135 denom_code = getDenomCodeFromProduct(product)
129 if not denom_code: 136 if not denom_code:
130 return None 137 return None
131 138
132 ussdCommand = u'*123*120*2*2*{0}*{1}*{2}#'.format(destination, denom_code, pin_trx); 139 ussdCommand = u'*123*120*2*2*{0}*{1}*{2}#'.format(destination, denom_code, pin_trx);
133 return ussdCommand 140 return ussdCommand
134 141
135 def isValidSender(sender): 142 def isValidSender(sender):
136 return str(sender) in valid_senders 143 return str(sender) in valid_senders
137 144
138 def getResponseCodeByMessage(message): 145 def getResponseCodeByMessage(message):
139 for pattern in message_codes: 146 for pattern in message_codes:
140 if message.find(pattern) >= 0: 147 if message.find(pattern) >= 0:
141 return message_codes[pattern] 148 return message_codes[pattern]
142 149
143 return '68' 150 return '68'
144 151
145 def getResponseCodeByUSSDResponse(response_message): 152 def getResponseCodeByUSSDResponse(response_message):
146 for pattern in ussd_response_codes: 153 for pattern in ussd_response_codes:
147 if response_message.find(pattern) >= 0: 154 if response_message.find(pattern) >= 0:
148 return ussd_response_codes[pattern] 155 return ussd_response_codes[pattern]
149 156
150 return '68' 157 return '68'
151 158
152 def getPulsaFromUssdResponseMessage(message): 159 def getPulsaFromUssdResponseMessage(message):
153 pulsa = re.findall(r"Pulsa (\d+) s", message) 160 pulsa = re.findall(r"Pulsa (\d+) s", message)
154 if pulsa: 161 if pulsa:
155 return int(pulsa[0]) 162 return int(pulsa[0])
156 163
157 def getMasaAktifFromUssdResponseMessage(message): 164 def getMasaAktifFromUssdResponseMessage(message):
158 masa_aktif = re.findall(' s[\./]d (\w+)\.', message) 165 masa_aktif = re.findall(' s[\./]d (\w+)\.', message)
159 if not masa_aktif: 166 if not masa_aktif:
160 return 167 return
161 168
162 masa_aktif = time.strptime(masa_aktif[0], '%d%b%y') 169 masa_aktif = time.strptime(masa_aktif[0], '%d%b%y')
163 return time.strftime("%Y-%m-%d", masa_aktif) 170 return time.strftime("%Y-%m-%d", masa_aktif)
164 171
165 def getLastSNFromHistoryMessage(message): 172 def getLastSNFromHistoryMessage(message):
166 if not re.findall(r"RELOAD", message): 173 if not re.findall(r"RELOAD", message):
167 return 'NON RELOAD' 174 return 'NON RELOAD'
168 175
169 sn = re.findall(r"Transaksi Terakhir\s:\s(\d+)", message) 176 sn = re.findall(r"Transaksi Terakhir\s:\s(\d+)", message)
170 if sn: 177 if sn:
171 return sn[0] 178 return sn[0]
172 179