Commit 545eb797b0f1045184485126bcf3e5cdf04ce742

Authored by Adhidarma Hadiwinoto
1 parent caaf6687dc
Exists in master

remove signal

Showing 3 changed files with 6 additions and 2 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 DISABLE_SEM 88 global DISABLE_SEM
89 global PRODUCTS 89 global PRODUCTS
90 global LAST_PRODUCT 90 global LAST_PRODUCT
91 91
92 logger.info(u'Incoming SMS from: {0}; Time: {1}; Message: {2}'.format(sms.number, sms.time, sms.text)) 92 logger.info(u'Incoming SMS from: {0}; Time: {1}; Message: {2}'.format(sms.number, sms.time, sms.text))
93 93
94 if not xltunai.isValidSender(sms.number): 94 if not xltunai.isValidSender(sms.number):
95 logger.info('Ignoring incoming SMS from invalid sender') 95 logger.info('Ignoring incoming SMS from invalid sender')
96 return 96 return
97 97
98 if sms.text.find('Terimakasih, transaksi CASH IN ke akun') >= 0: 98 if sms.text.find('Terimakasih, transaksi CASH IN ke akun') >= 0:
99 logger.info('handleSms: CASH IN, aktivasi pull jika non aktif') 99 logger.info('handleSms: CASH IN, aktivasi pull jika non aktif')
100 enablePull() 100 enablePull()
101 return 101 return
102 102
103 if sms.text.find('Maaf, transaksi gagal') >= 0: 103 if sms.text.find('Maaf, transaksi gagal') >= 0:
104 pushTopupStatus(LAST_REQUEST_ID, '40', sms.text) 104 pushTopupStatus(LAST_REQUEST_ID, '40', sms.text)
105 return 105 return
106 106
107 elif sms.text.find('PIN yang Anda masukkan salah. Silahkan ulangi kembali') >= 0: 107 elif sms.text.find('PIN yang Anda masukkan salah. Silahkan ulangi kembali') >= 0:
108 pushTopupStatus(LAST_REQUEST_ID, '91', sms.text) 108 pushTopupStatus(LAST_REQUEST_ID, '91', sms.text)
109 return 109 return
110 110
111 elif sms.text.find('Maaf, layanan ini hanya untuk nomor tujuan prabayar XL') >= 0: 111 elif sms.text.find('Maaf, layanan ini hanya untuk nomor tujuan prabayar XL') >= 0:
112 pushTopupStatus(LAST_REQUEST_ID, '14', sms.text) 112 pushTopupStatus(LAST_REQUEST_ID, '14', sms.text)
113 return 113 return
114 114
115 elif sms.text.find('Mohon maaf, nomor yang Anda masukkan tidak valid') >= 0: 115 elif sms.text.find('Mohon maaf, nomor yang Anda masukkan tidak valid') >= 0:
116 pushTopupStatus(LAST_REQUEST_ID, '14', sms.text) 116 pushTopupStatus(LAST_REQUEST_ID, '14', sms.text)
117 return 117 return
118 118
119 elif sms.text.find('Mohon maaf, transaksi Anda melebihi limit nominal bulanan') >= 0: 119 elif sms.text.find('Mohon maaf, transaksi Anda melebihi limit nominal bulanan') >= 0:
120 pushTopupStatus(LAST_REQUEST_ID, '40', sms.text) 120 pushTopupStatus(LAST_REQUEST_ID, '40', sms.text)
121 121
122 logger.info('Monthly limit for "{0}" detected, removing from product list'.format(LAST_PRODUCT)) 122 logger.info('Monthly limit for "{0}" detected, removing from product list'.format(LAST_PRODUCT))
123 PRODUCTS = sate24.removeProduct(PRODUCTS, LAST_PRODUCT) 123 PRODUCTS = sate24.removeProduct(PRODUCTS, LAST_PRODUCT)
124 logger.warning('Monthly limit for "{0}" exceeded. New active products: "{1}"'.format(LAST_PRODUCT, PRODUCTS)) 124 logger.warning('Monthly limit for "{0}" exceeded. New active products: "{1}"'.format(LAST_PRODUCT, PRODUCTS))
125 return 125 return
126 126
127 elif sms.text.find('Maaf, transaksi Anda masih dalam proses') >= 0: 127 elif sms.text.find('Maaf, transaksi Anda masih dalam proses') >= 0:
128 pushTopupStatus(LAST_REQUEST_ID, '68', sms.text) 128 pushTopupStatus(LAST_REQUEST_ID, '68', sms.text)
129 return 129 return
130 130
131 destination = xltunai.getDestinationFromMessage(sms.text) 131 destination = xltunai.getDestinationFromMessage(sms.text)
132 if destination == '': 132 if destination == '':
133 logger.warning('handleSms: gagal parsing nomor tujuan') 133 logger.warning('handleSms: gagal parsing nomor tujuan')
134 return 134 return
135 135
136 nominal = xltunai.getNominalFromMessage(sms.text) 136 nominal = xltunai.getNominalFromMessage(sms.text)
137 if nominal == '': 137 if nominal == '':
138 logger.warning('handleSms: gagal parsing nominal') 138 logger.warning('handleSms: gagal parsing nominal')
139 return 139 return
140 140
141 sn = xltunai.getSNFromMessage(sms.text) 141 sn = xltunai.getSNFromMessage(sms.text)
142 if sn == '': 142 if sn == '':
143 logger.warning('handleSms: gagal parsing SN') 143 logger.warning('handleSms: gagal parsing SN')
144 144
145 145
146 DISABLE_SEM = 0 146 DISABLE_SEM = 0
147 147
148 response_code = xltunai.getResponseCodeByMessage(sms.text) 148 response_code = xltunai.getResponseCodeByMessage(sms.text)
149 149
150 request_id = getRequestIdByNominalDestination(nominal, destination) 150 request_id = getRequestIdByNominalDestination(nominal, destination)
151 if not request_id: 151 if not request_id:
152 logger.info('Unknown request id for nominal:{0} destination:{1}'.format(nominal, destination)) 152 logger.info('Unknown request id for nominal:{0} destination:{1}'.format(nominal, destination))
153 return 153 return
154 154
155 pushTopupStatus(request_id, response_code, sms.text) 155 pushTopupStatus(request_id, response_code, sms.text)
156 try: 156 try:
157 deleteMultipleStoredSms(2) 157 deleteMultipleStoredSms(2)
158 except: 158 except:
159 #logger.warning('Failed on delete SMS') 159 #logger.warning('Failed on delete SMS')
160 pass 160 pass
161 161
162 162
163 def getRequestIdByNominalDestination(nominal, destination): 163 def getRequestIdByNominalDestination(nominal, destination):
164 redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, destination) 164 redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, destination)
165 #return redis_client.spop(redis_key) 165 #return redis_client.spop(redis_key)
166 return redis_client.rpop(redis_key) 166 return redis_client.rpop(redis_key)
167 167
168 def pushTopupStatus(request_id, response_code, _message, dontparsesn = False): 168 def pushTopupStatus(request_id, response_code, _message, dontparsesn = False):
169 global BALANCE 169 global BALANCE
170 global CHIPINFO 170 global CHIPINFO
171 171
172 redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code' 172 redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code'
173 if response_code == '00': 173 if response_code == '00':
174 redis_client.set(redis_key, response_code) 174 redis_client.set(redis_key, response_code)
175 else: 175 else:
176 redis_response_code = redis_client.get(redis_key) 176 redis_response_code = redis_client.get(redis_key)
177 if redis_response_code == '00': 177 if redis_response_code == '00':
178 logger.info('Ignoring message from success trx ') 178 logger.info('Ignoring message from success trx ')
179 return 179 return
180 180
181 message = "{0} -- Prev balance: {1}".format(_message, BALANCE) 181 message = "{0} -- Prev balance: {1}".format(_message, BALANCE)
182 182
183 timestamp = strftime('%Y%m%d%H%M%S') 183 timestamp = strftime('%Y%m%d%H%M%S')
184 184
185 if response_code == '00' and not dontparsesn: 185 if response_code == '00' and not dontparsesn:
186 sn = xltunai.getSNFromMessage(message) 186 sn = xltunai.getSNFromMessage(message)
187 LAST_SN = sn 187 LAST_SN = sn
188 message = 'SN={0};{1}. Signal Strength: {2}'.format(sn, message, modem.signalStrength) 188 message = 'SN={0};{1}'.format(sn, message)
189 189
190 push_message = CHIPINFO + '$' + message 190 push_message = CHIPINFO + '$' + message
191 191
192 payload = { 192 payload = {
193 'trans_id': request_id, 193 'trans_id': request_id,
194 'trans_date': timestamp, 194 'trans_date': timestamp,
195 'resp_code': response_code, 195 'resp_code': response_code,
196 'ussd_msg': push_message 196 'ussd_msg': push_message
197 } 197 }
198 198
199 url = AAA_HOST + '/topup' 199 url = AAA_HOST + '/topup'
200 200
201 try: 201 try:
202 logger.info('Sending topup status to AAA') 202 logger.info('Sending topup status to AAA')
203 logger.info(payload) 203 logger.info(payload)
204 r = requests.get(url, params=payload) 204 r = requests.get(url, params=payload)
205 except: 205 except:
206 logger.warning('Error sending topup status to AAA') 206 logger.warning('Error sending topup status to AAA')
207 207
208 try: 208 try:
209 # publish echi topup report ke redis 209 # publish echi topup report ke redis
210 echi_key = 'echi.topup_report.gw:' + BASE_CHIPINFO 210 echi_key = 'echi.topup_report.gw:' + BASE_CHIPINFO
211 211
212 redis_client.publish(echi_key + '.json', json.dumps(payload)) 212 redis_client.publish(echi_key + '.json', json.dumps(payload))
213 213
214 echi_message = timestamp + ' - ' + response_code + ' - ' + message 214 echi_message = timestamp + ' - ' + response_code + ' - ' + message
215 redis_client.publish(echi_key + '.message', echi_message) 215 redis_client.publish(echi_key + '.message', echi_message)
216 except: 216 except:
217 logger.warning('Error publishing topup report to redis') 217 logger.warning('Error publishing topup report to redis')
218 218
219 def getIsDisableRedisKey(): 219 def getIsDisableRedisKey():
220 return CHIPINFO + '.pulldisable' 220 return CHIPINFO + '.pulldisable'
221 221
222 def isPullEnable(): 222 def isPullEnable():
223 redis_key = getIsDisableRedisKey() 223 redis_key = getIsDisableRedisKey()
224 result = 'FALSE' 224 result = 'FALSE'
225 225
226 try: 226 try:
227 result = redis_client.get(redis_key) 227 result = redis_client.get(redis_key)
228 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) 228 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL)
229 except: 229 except:
230 return False 230 return False
231 231
232 if not result: 232 if not result:
233 return True 233 return True
234 234
235 return result == 'FALSE' 235 return result == 'FALSE'
236 236
237 def enablePull(): 237 def enablePull():
238 logger.info('Enabling Pull on products {0}'.format(PRODUCTS)) 238 logger.info('Enabling Pull on products {0}'.format(PRODUCTS))
239 redis_key = getIsDisableRedisKey() 239 redis_key = getIsDisableRedisKey()
240 try: 240 try:
241 redis_client.set(redis_key, 'FALSE') 241 redis_client.set(redis_key, 'FALSE')
242 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) 242 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL)
243 except: 243 except:
244 return 244 return
245 245
246 def disablePull(): 246 def disablePull():
247 global DISABLE_SEM 247 global DISABLE_SEM
248 global DISABLE_SEM_ON_TRX 248 global DISABLE_SEM_ON_TRX
249 249
250 logger.info('Disabling Pull') 250 logger.info('Disabling Pull')
251 redis_key = getIsDisableRedisKey() 251 redis_key = getIsDisableRedisKey()
252 try: 252 try:
253 redis_client.set(redis_key, 'TRUE') 253 redis_client.set(redis_key, 'TRUE')
254 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) 254 redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL)
255 except: 255 except:
256 return 256 return
257 257
258 def adviceLastSN(requestId, modem): 258 def adviceLastSN(requestId, modem):
259 global DISABLE_SEM 259 global DISABLE_SEM
260 global LAST_SN 260 global LAST_SN
261 global TOPUP_USSD_TIMEOUT 261 global TOPUP_USSD_TIMEOUT
262 262
263 if not LAST_SN: 263 if not LAST_SN:
264 message = 'Tidak ada trx sebelumnya untuk perbandingan SN. Silahkan bandingkan prev balance dengan trx berikutnya di chip yang sama' 264 message = 'Tidak ada trx sebelumnya untuk perbandingan SN. Silahkan bandingkan prev balance dengan trx berikutnya di chip yang sama'
265 pushTopupStatus(requestId, '68', message) 265 pushTopupStatus(requestId, '68', message)
266 DISABLE_SEM = 0 266 DISABLE_SEM = 0
267 return 267 return
268 268
269 ussd_command = xltunai.getHistoryUSSDCommand() 269 ussd_command = xltunai.getHistoryUSSDCommand()
270 270
271 logger.info(u'Executing advice {0}'.format(ussd_command)) 271 logger.info(u'Executing advice {0}'.format(ussd_command))
272 try: 272 try:
273 response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT) 273 response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT)
274 274
275 message = response.message.strip() 275 message = response.message.strip()
276 logger.info(u'USSD response: {0}'.format(message)) 276 logger.info(u'USSD response: {0}'.format(message))
277 277
278 lastSNFromHistory = xltunai.getLastSNFromHistoryMessage(message) 278 lastSNFromHistory = xltunai.getLastSNFromHistoryMessage(message)
279 279
280 if response.sessionActive: 280 if response.sessionActive:
281 response.cancel() 281 response.cancel()
282 282
283 if not lastSNFromHistory: 283 if not lastSNFromHistory:
284 if DISABLE_SEM: 284 if DISABLE_SEM:
285 logger.info('Failed to get last sn from history, retrying in 15 secs') 285 logger.info('Failed to get last sn from history, retrying in 15 secs')
286 sleep(15) 286 sleep(15)
287 adviceLastSN(requestid, modem) 287 adviceLastSN(requestid, modem)
288 288
289 elif lastSNFromHistory == LAST_SN: 289 elif lastSNFromHistory == LAST_SN:
290 topupMessage = "Topup gagal berdasarkan advice. {0} = {1}. {2}".format(lastSNFromHistory, LAST_SN, message) 290 topupMessage = "Topup gagal berdasarkan advice. {0} = {1}. {2}".format(lastSNFromHistory, LAST_SN, message)
291 pushTopupStatus(requestId, '40', topupMessage) 291 pushTopupStatus(requestId, '40', topupMessage)
292 DISABLE_SEM = 0 292 DISABLE_SEM = 0
293 293
294 294
295 else: 295 else:
296 topupMessage = "SN={0}; Topup berhasil berdasarkan advice. {1}".format(lastSNFromHistory, message) 296 topupMessage = "SN={0}; Topup berhasil berdasarkan advice. {1}".format(lastSNFromHistory, message)
297 LAST_SN = lastSNFromHistory 297 LAST_SN = lastSNFromHistory
298 pushTopupStatus(requestId, '00', topupMessage, True) 298 pushTopupStatus(requestId, '00', topupMessage, True)
299 DISABLE_SEM = 0 299 DISABLE_SEM = 0
300 300
301 except: 301 except:
302 message = "USSD Error: Something wrong when executing USSD advice. Signal strength: {0}".format(modem.signalStrength) 302 message = "USSD Error: Something wrong when executing USSD advice. Signal strength: {0}".format(modem.signalStrength)
303 logger.warning(message) 303 logger.warning(message)
304 pushTopupStatus(requestId, '68', message) 304 pushTopupStatus(requestId, '68', message)
305 305
306 sleep(60) 306 sleep(60)
307 adviceLastSN(requestId, modem) 307 adviceLastSN(requestId, modem)
308 #waitForResultSmsAfterUssdError(modem, task['requestId'], message) 308 #waitForResultSmsAfterUssdError(modem, task['requestId'], message)
309 return 309 return
310 310
311 311
312 312
313 def topupTask(task, modem): 313 def topupTask(task, modem):
314 global LAST_REQUEST_ID 314 global LAST_REQUEST_ID
315 315
316 if not task: 316 if not task:
317 return 317 return
318 318
319 if task['status'] != 'OK': 319 if task['status'] != 'OK':
320 return 320 return
321 321
322 LAST_REQUEST_ID = task['requestId'] 322 LAST_REQUEST_ID = task['requestId']
323 LAST_PRODUCT = task['product'].upper() 323 LAST_PRODUCT = task['product'].upper()
324 324
325 redis_key = sate24.keyByRequestId(CHIPINFO, task['requestId']) 325 redis_key = sate24.keyByRequestId(CHIPINFO, task['requestId'])
326 redis_client.set(redis_key, task) 326 redis_client.set(redis_key, task)
327 redis_client.expire(redis_key, REDIS_TTL) 327 redis_client.expire(redis_key, REDIS_TTL)
328 328
329 nominal = xltunai.getNominalFromProduct(task['product']) 329 nominal = xltunai.getNominalFromProduct(task['product'])
330 intl_destination = xltunai.toInternationalNumber(task['destination']) 330 intl_destination = xltunai.toInternationalNumber(task['destination'])
331 331
332 redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, intl_destination) 332 redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, intl_destination)
333 #redis_client.sadd(redis_key, task['requestId']) 333 #redis_client.sadd(redis_key, task['requestId'])
334 try: 334 try:
335 redis_client.rpush(redis_key, task['requestId']) 335 redis_client.rpush(redis_key, task['requestId'])
336 except: 336 except:
337 redis_client.delete(redis_key) 337 redis_client.delete(redis_key)
338 redis_client.rpush(redis_key, task['requestId']) 338 redis_client.rpush(redis_key, task['requestId'])
339 finally: 339 finally:
340 redis_client.expire(redis_key, REDIS_TTL) 340 redis_client.expire(redis_key, REDIS_TTL)
341 341
342 #pushTopupStatus(task['requestId'], '68', 'Siap mengirimkan trx ke operator') 342 #pushTopupStatus(task['requestId'], '68', 'Siap mengirimkan trx ke operator')
343 343
344 message = 'Executing USSD' 344 message = 'Executing USSD'
345 response_code = '68' 345 response_code = '68'
346 346
347 ussd_command = xltunai.getTopupUSSDCommand(task['destination'], task['product'], PIN_TRX) 347 ussd_command = xltunai.getTopupUSSDCommand(task['destination'], task['product'], PIN_TRX)
348 348
349 logger.info(u'Executing {0}'.format(ussd_command)) 349 logger.info(u'Executing {0}'.format(ussd_command))
350 try: 350 try:
351 response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT) 351 response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT)
352 352
353 message = response.message.strip() 353 message = response.message.strip()
354 logger.info(u'USSD response: {0}'.format(message)) 354 logger.info(u'USSD response: {0}'.format(message))
355 355
356 response_code = xltunai.getResponseCodeByUSSDResponse(message) 356 response_code = xltunai.getResponseCodeByUSSDResponse(message)
357 357
358 if response.sessionActive: 358 if response.sessionActive:
359 response.cancel() 359 response.cancel()
360 360
361 except TimeoutException: 361 except TimeoutException:
362 message = "USSD Error: Timeout when executing USSD topup. Signal strength: {0}".format(modem.signalStrength) 362 message = "USSD Error: Timeout when executing USSD topup. Signal strength: {0}".format(modem.signalStrength)
363 logger.warning(message) 363 logger.warning(message)
364 pushTopupStatus(task['requestId'], '68', message) 364 pushTopupStatus(task['requestId'], '68', message)
365 #waitForResultSmsAfterUssdError(modem, task['requestId'], message) 365 #waitForResultSmsAfterUssdError(modem, task['requestId'], message)
366 sleep(15) 366 sleep(15)
367 adviceLastSN(task['requestId'], modem) 367 adviceLastSN(task['requestId'], modem)
368 return 368 return
369 except: 369 except:
370 message = "USSD Error: Something wrong when executing USSD topup. Signal strength: {0}".format(modem.signalStrength) 370 message = "USSD Error: Something wrong when executing USSD topup. Signal strength: {0}".format(modem.signalStrength)
371 logger.warning(message) 371 logger.warning(message)
372 pushTopupStatus(task['requestId'], '68', message) 372 pushTopupStatus(task['requestId'], '68', message)
373 #waitForResultSmsAfterUssdError(modem, task['requestId'], message) 373 #waitForResultSmsAfterUssdError(modem, task['requestId'], message)
374 sleep(15) 374 sleep(15)
375 adviceLastSN(task['requestId'], modem) 375 adviceLastSN(task['requestId'], modem)
376 return 376 return
377 377
378 DISABLE_SEM = DISABLE_SEM_ON_TRX 378 DISABLE_SEM = DISABLE_SEM_ON_TRX
379 pushTopupStatus(task['requestId'], response_code, message) 379 pushTopupStatus(task['requestId'], response_code, message)
380 380
381 def waitForResultSmsAfterUssdError(modem, request_id, last_error_message = ''): 381 def waitForResultSmsAfterUssdError(modem, request_id, last_error_message = ''):
382 logger.info('Sleeping for {0} seconds after an USSD error'.format(SLEEP_AFTER_USSD_ERROR)) 382 logger.info('Sleeping for {0} seconds after an USSD error'.format(SLEEP_AFTER_USSD_ERROR))
383 sleep(SLEEP_AFTER_USSD_ERROR) 383 sleep(SLEEP_AFTER_USSD_ERROR)
384 384
385 redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code' 385 redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code'
386 response_code = redis_client.get(redis_key) 386 response_code = redis_client.get(redis_key)
387 387
388 if response_code == '68' or response_code == None: 388 if response_code == '68' or response_code == None:
389 389
390 prev_balance = BALANCE 390 prev_balance = BALANCE
391 current_balance = checkBalance(modem, do_not_update = True, return_result = True) 391 current_balance = checkBalance(modem, do_not_update = True, return_result = True)
392 392
393 if current_balance == 0: 393 if current_balance == 0:
394 return 394 return
395 395
396 if current_balance < prev_balance: 396 if current_balance < prev_balance:
397 delta = prev_balance - current_balance 397 delta = prev_balance - current_balance
398 pushTopupStatus( 398 pushTopupStatus(
399 request_id, 399 request_id,
400 '00', 400 '00',
401 'Transaksi dianggap sukses karena saldo berkurang {0}. Last error message: {1}'.format( 401 'Transaksi dianggap sukses karena saldo berkurang {0}. Last error message: {1}'.format(
402 delta, 402 delta,
403 last_error_message 403 last_error_message
404 ) 404 )
405 ) 405 )
406 else: 406 else:
407 pushTopupStatus( 407 pushTopupStatus(
408 request_id, 408 request_id,
409 '40', 409 '40',
410 'Transaksi dianggap gagal karena saldo tidak berkurang. Last error message: {0}'.format(last_error_message) 410 'Transaksi dianggap gagal karena saldo tidak berkurang. Last error message: {0}'.format(last_error_message)
411 ) 411 )
412 412
413 def _saveBalanceToRedis(balance_key, balance_value): 413 def _saveBalanceToRedis(balance_key, balance_value):
414 try: 414 try:
415 redis_client.set(balance_key, balance_value) 415 redis_client.set(balance_key, balance_value)
416 redis_client.expire(balance_key, 3600*24*60) 416 redis_client.expire(balance_key, 3600*24*60)
417 except: 417 except:
418 logger.warning('Failed to save balance to redis') 418 logger.warning('Failed to save balance to redis')
419 419
420 def saveBalanceToRedis(balance): 420 def saveBalanceToRedis(balance):
421 global BASE_CHIPINFO 421 global BASE_CHIPINFO
422 global CHIPINFO 422 global CHIPINFO
423 global MSISDN 423 global MSISDN
424 424
425 try: 425 try:
426 balance = int(balance) 426 balance = int(balance)
427 except ValueError: 427 except ValueError:
428 return 428 return
429 429
430 430
431 data = { 431 data = {
432 'balance.gw:' + BASE_CHIPINFO: balance, 432 'balance.gw:' + BASE_CHIPINFO: balance,
433 'balance.gw:' + CHIPINFO: balance, 433 'balance.gw:' + CHIPINFO: balance,
434 'balance.gw:' + MSISDN: balance 434 'balance.gw:' + MSISDN: balance
435 } 435 }
436 436
437 redis_pipe = redis_client.pipeline() 437 redis_pipe = redis_client.pipeline()
438 438
439 try: 439 try:
440 redis_pipe.mset(data) 440 redis_pipe.mset(data)
441 441
442 for k in data: 442 for k in data:
443 redis_pipe.expire(k, 3600 * 24 * 60) 443 redis_pipe.expire(k, 3600 * 24 * 60)
444 444
445 except: 445 except:
446 logger.warning('Failed to save balance to redis') 446 logger.warning('Failed to save balance to redis')
447 finally: 447 finally:
448 redis_pipe.execute() 448 redis_pipe.execute()
449 449
450 def saveSignalStrengthToRedis(value): 450 def saveSignalStrengthToRedis(value):
451 global BASE_CHIPINFO 451 global BASE_CHIPINFO
452 global CHIPINFO 452 global CHIPINFO
453 global MSISDN 453 global MSISDN
454 454
455 try: 455 try:
456 redis_pipe = redis_client.pipeline() 456 redis_pipe = redis_client.pipeline()
457 redis_client.set('balance.gw:' + BASE_CHIPINFO + '.signal', value) 457 redis_client.set('balance.gw:' + BASE_CHIPINFO + '.signal', value)
458 redis_client.expire('balance.gw:' + BASE_CHIPINFO + '.signal', 15 * 60) 458 redis_client.expire('balance.gw:' + BASE_CHIPINFO + '.signal', 15 * 60)
459 except: 459 except:
460 logger.warning('Failed to save signal strength to redis') 460 logger.warning('Failed to save signal strength to redis')
461 461
462 462
463 def pull(modem): 463 def pull(modem):
464 global PRODUCTS 464 global PRODUCTS
465 global PULL_COUNT 465 global PULL_COUNT
466 global BALANCE 466 global BALANCE
467 global DISABLE_SEM 467 global DISABLE_SEM
468 global MIN_SIGNAL_STRENGTH 468 global MIN_SIGNAL_STRENGTH
469 469
470 if not PRODUCTS: 470 if not PRODUCTS:
471 return 471 return
472 472
473 signalStrength = modem.signalStrength 473 signalStrength = modem.signalStrength
474 if signalStrength < MIN_SIGNAL_STRENGTH: 474 if signalStrength < MIN_SIGNAL_STRENGTH:
475 #logger.warn('Signal strength {0} < {1}, skipping pull'.format(signalStrength, MIN_SIGNAL_STRENGTH)) 475 #logger.warn('Signal strength {0} < {1}, skipping pull'.format(signalStrength, MIN_SIGNAL_STRENGTH))
476 return 476 return
477 477
478 pull_per_minute = 60 / PULL_INTERVAL 478 pull_per_minute = 60 / PULL_INTERVAL
479 479
480 PULL_COUNT += 1 480 PULL_COUNT += 1
481 if PULL_COUNT % (5 * pull_per_minute) == 0: 481 if PULL_COUNT % (5 * pull_per_minute) == 0:
482 checkBalance(modem) 482 checkBalance(modem)
483 sleep(15) 483 sleep(15)
484 PULL_COUNT = 0 484 PULL_COUNT = 0
485 485
486 if DISABLE_SEM > 0: 486 if DISABLE_SEM > 0:
487 logger.info('SEMAPHORE is still on, delaying pull') 487 logger.info('SEMAPHORE is still on, delaying pull')
488 DISABLE_SEM -= 1 488 DISABLE_SEM -= 1
489 return 489 return
490 490
491 if not isPullEnable(): 491 if not isPullEnable():
492 return 492 return
493 493
494 r = None 494 r = None
495 url = AAA_HOST + '/pull?city=' + CITY + '&nom=' + PRODUCTS 495 url = AAA_HOST + '/pull?city=' + CITY + '&nom=' + PRODUCTS
496 try: 496 try:
497 r = requests.get(url) 497 r = requests.get(url)
498 except: 498 except:
499 logger.warning("Error requesting to AAA") 499 logger.warning("Error requesting to AAA")
500 return 500 return
501 501
502 if not r: 502 if not r:
503 return 503 return
504 504
505 task = sate24.parsePullMessage(r.text) 505 task = sate24.parsePullMessage(r.text)
506 506
507 if task['status'] == 'OK': 507 if task['status'] == 'OK':
508 508
509 logger.info('PULL ' + url + ' => ' + r.text) 509 logger.info('PULL ' + url + ' => ' + r.text)
510 publishAAATaskToRedis(task) 510 publishAAATaskToRedis(task)
511 511
512 if not checkBalance(modem) or BALANCE == 0: 512 if not checkBalance(modem) or BALANCE == 0:
513 pushTopupStatus(task['requestId'], '91', 'Transaksi dibatalkan karena gagal check balance') 513 pushTopupStatus(task['requestId'], '91', 'Transaksi dibatalkan karena gagal check balance')
514 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) 514 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP)
515 return 515 return
516 516
517 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) 517 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP)
518 518
519 topupTask(task, modem) 519 topupTask(task, modem)
520 sleep(SLEEP_AFTER_TOPUP) 520 sleep(SLEEP_AFTER_TOPUP)
521 521
522 def publishAAATaskToRedis(task): 522 def publishAAATaskToRedis(task):
523 try: 523 try:
524 key = 'kimochi.aaa_pull.gw:' + BASE_CHIPINFO 524 key = 'kimochi.aaa_pull.gw:' + BASE_CHIPINFO
525 plain_text = task['timestamp'] + ' - ' + task['member'] + ' isi ' + task['product'] + ' ke ' + task['destination']; 525 plain_text = task['timestamp'] + ' - ' + task['member'] + ' isi ' + task['product'] + ' ke ' + task['destination'];
526 526
527 redis_client.publish(key + '.json', json.dumps(task)) 527 redis_client.publish(key + '.json', json.dumps(task))
528 redis_client.publish(key + '.text', plain_text); 528 redis_client.publish(key + '.text', plain_text);
529 except: 529 except:
530 logger.warning('Error publishing kimochi') 530 logger.warning('Error publishing kimochi')
531 531
532 def publishMessageToRedis(): 532 def publishMessageToRedis():
533 pass 533 pass
534 534
535 def pullLoop(modem): 535 def pullLoop(modem):
536 global TERMINATING 536 global TERMINATING
537 537
538 while True: 538 while True:
539 signalStrength = modem.signalStrength 539 signalStrength = modem.signalStrength
540 saveSignalStrengthToRedis(signalStrength) 540 saveSignalStrengthToRedis(signalStrength)
541 541
542 if TERMINATING: 542 if TERMINATING:
543 logger.info('Terminated by request signal') 543 logger.info('Terminated by request signal')
544 sys.exit(0) 544 sys.exit(0)
545 545
546 pull(modem) 546 pull(modem)
547 547
548 sleep(PULL_INTERVAL) 548 sleep(PULL_INTERVAL)
549 549
550 def checkSignal(modem): 550 def checkSignal(modem):
551 logger.info('Signal: {0}'.format(modem.signalStrength)) 551 logger.info('Signal: {0}'.format(modem.signalStrength))
552 try: 552 try:
553 redis_client.set(CHIPINFO + '.signal', modem.signalStrength) 553 redis_client.set(CHIPINFO + '.signal', modem.signalStrength)
554 redis_client.expire(CHIPINFO + '.signal', 3600*24) 554 redis_client.expire(CHIPINFO + '.signal', 3600*24)
555 except: 555 except:
556 logger.warning("Can not save signal strength to redis") 556 logger.warning("Can not save signal strength to redis")
557 557
558 def checkAccount(modem): 558 def checkAccount(modem):
559 try: 559 try:
560 ussd_string = '*123*120*8*3#' 560 ussd_string = '*123*120*8*3#'
561 response = modem.sendUssd(ussd_string, 30) 561 response = modem.sendUssd(ussd_string, 30)
562 logger.info('Account Info: {0}'.format(response.message)) 562 logger.info('Account Info: {0}'.format(response.message))
563 563
564 if response.sessionActive: 564 if response.sessionActive:
565 response.cancel() 565 response.cancel()
566 except: 566 except:
567 logger.warning('Error when requesting account info') 567 logger.warning('Error when requesting account info')
568 return False 568 return False
569 569
570 def checkBalance(modem, do_not_update = False, return_result = False): 570 def checkBalance(modem, do_not_update = False, return_result = False):
571 global BALANCE 571 global BALANCE
572 572
573 _BALANCE = 0 573 _BALANCE = 0
574 574
575 try: 575 try:
576 576
577 ussd_string = '*123*120#' 577 ussd_string = '*123*120#'
578 response = modem.sendUssd(ussd_string, 30) 578 response = modem.sendUssd(ussd_string, 30)
579 _BALANCE = xltunai.getBalanceFromUSSDResponse(response.message) 579 _BALANCE = xltunai.getBalanceFromUSSDResponse(response.message)
580 580
581 if not do_not_update: 581 if not do_not_update:
582 BALANCE = _BALANCE 582 BALANCE = _BALANCE
583 saveBalanceToRedis(BALANCE) 583 saveBalanceToRedis(BALANCE)
584 584
585 logger.info('Balance: {0}'.format(_BALANCE)) 585 logger.info('Balance: {0}'.format(_BALANCE))
586 if response.sessionActive: 586 if response.sessionActive:
587 response.cancel() 587 response.cancel()
588 588
589 if _BALANCE != 0 and _BALANCE < MIN_BALANCE: 589 if _BALANCE != 0 and _BALANCE < MIN_BALANCE:
590 logger.info('Disabling pull, balance {0} < {1}'.format(_BALANCE, MIN_BALANCE)) 590 logger.info('Disabling pull, balance {0} < {1}'.format(_BALANCE, MIN_BALANCE))
591 disablePull() 591 disablePull()
592 592
593 except: 593 except:
594 logger.warning('Error when requesting BALANCE by USSD') 594 logger.warning('Error when requesting BALANCE by USSD')
595 if return_result: 595 if return_result:
596 return 0 596 return 0
597 else: 597 else:
598 return False 598 return False
599 599
600 try: 600 try:
601 redis_client.set(CHIPINFO + '.balance', BALANCE) 601 redis_client.set(CHIPINFO + '.balance', BALANCE)
602 except: 602 except:
603 logger.warning('Failed to save balance to redis') 603 logger.warning('Failed to save balance to redis')
604 604
605 if return_result: 605 if return_result:
606 return _BALANCE 606 return _BALANCE
607 else: 607 else:
608 return True 608 return True
609 609
610 def getPulsaInfo(modem): 610 def getPulsaInfo(modem):
611 global PULSA 611 global PULSA
612 global MASA_AKTIF 612 global MASA_AKTIF
613 613
614 try: 614 try:
615 ussd_string = "*123#" 615 ussd_string = "*123#"
616 response = modem.sendUssd(ussd_string) 616 response = modem.sendUssd(ussd_string)
617 617
618 message = response.message.strip() 618 message = response.message.strip()
619 logger.info('PULSA: {0}'.format(message)) 619 logger.info('PULSA: {0}'.format(message))
620 if response.sessionActive: 620 if response.sessionActive:
621 response.cancel() 621 response.cancel()
622 622
623 PULSA = xltunai.getPulsaFromUssdResponseMessage(message) 623 PULSA = xltunai.getPulsaFromUssdResponseMessage(message)
624 MASA_AKTIF =xltunai.getMasaAktifFromUssdResponseMessage(message) 624 MASA_AKTIF =xltunai.getMasaAktifFromUssdResponseMessage(message)
625 logger.info('PULSA: {0} -- MASA AKTIF: {1}'.format(PULSA, MASA_AKTIF)) 625 logger.info('PULSA: {0} -- MASA AKTIF: {1}'.format(PULSA, MASA_AKTIF))
626 626
627 return message 627 return message
628 628
629 except: 629 except:
630 logger.warning('Error when requesting pulsa info by USSD') 630 logger.warning('Error when requesting pulsa info by USSD')
631 return '' 631 return ''
632 632
633 def getSIMCardInfo(modem): 633 def getSIMCardInfo(modem):
634 try: 634 try:
635 ussd_string = xltunai.getSIMCardInfoUSSDCommand() 635 ussd_string = xltunai.getSIMCardInfoUSSDCommand()
636 response = modem.sendUssd(ussd_string) 636 response = modem.sendUssd(ussd_string)
637 637
638 message = response.message.strip() 638 message = response.message.strip()
639 logger.info('SIM INFO: {0}'.format(message)) 639 logger.info('SIM INFO: {0}'.format(message))
640 if response.sessionActive: 640 if response.sessionActive:
641 response.cancel() 641 response.cancel()
642 642
643 return message 643 return message
644 644
645 except: 645 except:
646 logger.warning('Error when requesting SIM card info by USSD') 646 logger.warning('Error when requesting SIM card info by USSD')
647 return '' 647 return ''
648 648
649 def updateChipInfo(msisdn): 649 def updateChipInfo(msisdn):
650 global BASE_CHIPINFO 650 global BASE_CHIPINFO
651 global CHIPINFO 651 global CHIPINFO
652 global MSISDN 652 global MSISDN
653 653
654 MSISDN = msisdn 654 MSISDN = msisdn
655 if CHIPINFO.find(msisdn) == -1: 655 if CHIPINFO.find(msisdn) == -1:
656 CHIPINFO = BASE_CHIPINFO + '-' + msisdn 656 CHIPINFO = BASE_CHIPINFO + '-' + msisdn
657 657
658 logger.info('CHIPINFO: {0}'.format(CHIPINFO)) 658 logger.info('CHIPINFO: {0}'.format(CHIPINFO))
659 659
660 def main(): 660 def main():
661 global logger 661 global logger
662 662
663 log_format = '%(asctime)s %(levelname)s: %(message)s' 663 log_format = '%(asctime)s %(levelname)s: %(message)s'
664 664
665 logging.basicConfig(format=log_format, level=logging.INFO) 665 logging.basicConfig(format=log_format, level=logging.INFO)
666 logger = logging.getLogger(__name__) 666 logger = logging.getLogger(__name__)
667 667
668 logger_formatter = logging.Formatter(log_format) 668 logger_formatter = logging.Formatter(log_format)
669 logger_handler = TimedRotatingFileHandler('logs/log', when='midnight') 669 logger_handler = TimedRotatingFileHandler('logs/log', when='midnight')
670 logger_handler.setFormatter(logger_formatter) 670 logger_handler.setFormatter(logger_formatter)
671 logger.addHandler(logger_handler) 671 logger.addHandler(logger_handler)
672 672
673 requests_logger = logging.getLogger('requests') 673 requests_logger = logging.getLogger('requests')
674 requests_logger.setLevel(logging.WARNING) 674 requests_logger.setLevel(logging.WARNING)
675 675
676 logger.info('Initializing modem...') 676 logger.info('Initializing modem...')
677 677
678 modem = GsmModem(PORT, BAUDRATE, smsReceivedCallbackFunc=handleSms) 678 modem = GsmModem(PORT, BAUDRATE, smsReceivedCallbackFunc=handleSms)
679 modem.smsTextMode = True 679 modem.smsTextMode = True
680 modem.connect(PIN) 680 modem.connect(PIN)
681 681
682 logger.info('Waiting for network coverage...') 682 logger.info('Waiting for network coverage...')
683 modem.waitForNetworkCoverage(10) 683 modem.waitForNetworkCoverage(10)
684 684
685 logger.info('Modem ready') 685 logger.info('Modem ready')
686 686
687 getPulsaInfo(modem) 687 getPulsaInfo(modem)
688 sleep(2) 688 sleep(2)
689 689
690 simcard_info = getSIMCardInfo(modem) 690 simcard_info = getSIMCardInfo(modem)
691 msisdn = xltunai.getMSISDNFromSIMCardInfo(simcard_info) 691 msisdn = xltunai.getMSISDNFromSIMCardInfo(simcard_info)
692 692
693 if not msisdn: 693 if not msisdn:
694 logger.warning('Gagal mendapatkan msisdn, terminating') 694 logger.warning('Gagal mendapatkan msisdn, terminating')
695 sleep(5) 695 sleep(5)
696 sys.exit(2) 696 sys.exit(2)
697 697
698 imsi = modem.imsi 698 imsi = modem.imsi
699 logger.info('MSISDN: {0} -- IMSI: {1}'.format(msisdn, imsi)) 699 logger.info('MSISDN: {0} -- IMSI: {1}'.format(msisdn, imsi))
700 700
701 updateChipInfo(msisdn) 701 updateChipInfo(msisdn)
702 saveSimCardInfoToRedis(imsi, msisdn) 702 saveSimCardInfoToRedis(imsi, msisdn)
703 703
704 sleep(2) 704 sleep(2)
705 705
706 saveSignalStrengthToRedis(modem.signalStrength) 706 saveSignalStrengthToRedis(modem.signalStrength)
707 707
708 logger.info('Process stored SMS') 708 logger.info('Process stored SMS')
709 try: 709 try:
710 modem.processStoredSms() 710 modem.processStoredSms()
711 except: 711 except:
712 logger.warning('Failed on Process stored SMS') 712 logger.warning('Failed on Process stored SMS')
713 713
714 logger.info('Delete stored SMS') 714 logger.info('Delete stored SMS')
715 try: 715 try:
716 modem.deleteMultipleStoredSms() 716 modem.deleteMultipleStoredSms()
717 except: 717 except:
718 #logger.warning('Failed on delete SMS') 718 #logger.warning('Failed on delete SMS')
719 pass 719 pass
720 720
721 sleep(2) 721 sleep(2)
722 722
723 checkAccount(modem) 723 checkAccount(modem)
724 sleep(5) 724 sleep(5)
725 725
726 enablePull() 726 enablePull()
727 727
728 checkBalance(modem) 728 checkBalance(modem)
729 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) 729 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP)
730 730
731 pullLoop(modem) 731 pullLoop(modem)
732 logger.info('Waiting for SMS message...') 732 logger.info('Waiting for SMS message...')
733 try: 733 try:
734 modem.rxThread.join(2**31) # Specify a (huge) timeout so that it essentially blocks indefinitely, but still receives CTRL+C interrupt signal 734 modem.rxThread.join(2**31) # Specify a (huge) timeout so that it essentially blocks indefinitely, but still receives CTRL+C interrupt signal
735 finally: 735 finally:
736 modem.close(); 736 modem.close();
737 737
738 def saveSimCardInfoToRedis(imsi, msisdn): 738 def saveSimCardInfoToRedis(imsi, msisdn):
739 logger.info('Save sim card info to redis') 739 logger.info('Save sim card info to redis')
740 740
741 data = { 741 data = {
742 'gw': BASE_CHIPINFO, 742 'gw': BASE_CHIPINFO,
743 'imsi': imsi, 743 'imsi': imsi,
744 'msisdn': msisdn, 744 'msisdn': msisdn,
745 'pulsa': PULSA, 745 'pulsa': PULSA,
746 'masa_aktif': MASA_AKTIF 746 'masa_aktif': MASA_AKTIF
747 } 747 }
748 748
749 json_data = json.dumps(data) 749 json_data = json.dumps(data)
750 750
751 map_data = { 751 map_data = {
752 BASE_CHIPINFO + '.simcardinfo': json_data, 752 BASE_CHIPINFO + '.simcardinfo': json_data,
753 'simcardinfo.gw:' + BASE_CHIPINFO: json_data, 753 'simcardinfo.gw:' + BASE_CHIPINFO: json_data,
754 'simcardinfo.imsi:' + imsi: json_data, 754 'simcardinfo.imsi:' + imsi: json_data,
755 'simcardinfo.msisdn:' + msisdn: json_data 755 'simcardinfo.msisdn:' + msisdn: json_data
756 } 756 }
757 757
758 logger.info(map_data) 758 logger.info(map_data)
759 759
760 redis_pipe = redis_client.pipeline() 760 redis_pipe = redis_client.pipeline()
761 761
762 try: 762 try:
763 redis_pipe.mset(map_data) 763 redis_pipe.mset(map_data)
764 764
765 for k in data: 765 for k in data:
766 redis_pipe.expire(k, 3600 * 24 * 60) 766 redis_pipe.expire(k, 3600 * 24 * 60)
767 767
768 except: 768 except:
769 logger.warning('Failed to save simcardinfo to redis') 769 logger.warning('Failed to save simcardinfo to redis')
770 finally: 770 finally:
771 redis_pipe.execute() 771 redis_pipe.execute()
772 772
773 if __name__ == '__main__': 773 if __name__ == '__main__':
774 pidfile = open('pid.txt', 'w') 774 pidfile = open('pid.txt', 'w')
775 pidfile.write(str(getpid())) 775 pidfile.write(str(getpid()))
776 pidfile.close() 776 pidfile.close()
777 777
778 # trap CTRL-C 778 # trap CTRL-C
779 signal.signal(signal.SIGINT, signalHandler) 779 signal.signal(signal.SIGINT, signalHandler)
780 # trap supervisor stop 780 # trap supervisor stop
781 signal.signal(signal.SIGTERM, signalHandler) 781 signal.signal(signal.SIGTERM, signalHandler)
782 782
783 main() 783 main()
784 784
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
130
131 def test_getLastSNFromMessage():
132 assert xltunai.getLastSNFromHistoryMessage('Transaksi Terakhir : 20063778248257/5500/12-02-2016 14:37:08/M201312021528418273770285/P201511211752675316198716/RELOAD XL 5000') == '20063778248257'
129 133
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 86
87 def toInternationalNumber(number): 87 def toInternationalNumber(number):
88 return re.sub(r'^0', '62', number) 88 return re.sub(r'^0', '62', number)
89 89
90 def getSIMCardInfoUSSDCommand(): 90 def getSIMCardInfoUSSDCommand():
91 return '*123*7*3*1*1#' 91 return '*123*7*3*1*1#'
92 92
93 def getHistoryUSSDCommand(): 93 def getHistoryUSSDCommand():
94 return '*123*120*8*3#' 94 return '*123*120*8*3#'
95 95
96 def getMSISDNFromSIMCardInfo(message): 96 def getMSISDNFromSIMCardInfo(message):
97 msisdn = "".join(re.findall(r'Nomor \d+ adalah nomor', message)) 97 msisdn = "".join(re.findall(r'Nomor \d+ adalah nomor', message))
98 msisdn = "".join(re.findall(r'\d+', msisdn)) 98 msisdn = "".join(re.findall(r'\d+', msisdn))
99 return msisdn 99 return msisdn
100 100
101 def getIMSIFromSIMCardInfo(message): 101 def getIMSIFromSIMCardInfo(message):
102 imsi = "".join(re.findall(r'dengan ICCID \d+', message)) 102 imsi = "".join(re.findall(r'dengan ICCID \d+', message))
103 imsi = "".join(re.findall(r'\d+', imsi)) 103 imsi = "".join(re.findall(r'\d+', imsi))
104 return imsi 104 return imsi
105 105
106 def getBalanceFromUSSDResponse(message): 106 def getBalanceFromUSSDResponse(message):
107 balance = "".join(re.findall(r'Saldo Rp\d+', message)) 107 balance = "".join(re.findall(r'Saldo Rp\d+', message))
108 balance = re.sub('Saldo Rp', '', balance) 108 balance = re.sub('Saldo Rp', '', balance)
109 try: 109 try:
110 return int(balance) 110 return int(balance)
111 except: 111 except:
112 return 0 112 return 0
113 113
114 def getTopupUSSDCommand(destination, product, pin_trx): 114 def getTopupUSSDCommand(destination, product, pin_trx):
115 denom_code = getDenomCodeFromProduct(product) 115 denom_code = getDenomCodeFromProduct(product)
116 if not denom_code: 116 if not denom_code:
117 return None 117 return None
118 118
119 ussdCommand = u'*123*120*2*2*{0}*{1}*{2}#'.format(destination, denom_code, pin_trx); 119 ussdCommand = u'*123*120*2*2*{0}*{1}*{2}#'.format(destination, denom_code, pin_trx);
120 return ussdCommand 120 return ussdCommand
121 121
122 def isValidSender(sender): 122 def isValidSender(sender):
123 return str(sender) in valid_senders 123 return str(sender) in valid_senders
124 124
125 def getResponseCodeByMessage(message): 125 def getResponseCodeByMessage(message):
126 for pattern in message_codes: 126 for pattern in message_codes:
127 if message.find(pattern) >= 0: 127 if message.find(pattern) >= 0:
128 return message_codes[pattern] 128 return message_codes[pattern]
129 129
130 return '68' 130 return '68'
131 131
132 def getResponseCodeByUSSDResponse(response_message): 132 def getResponseCodeByUSSDResponse(response_message):
133 for pattern in ussd_response_codes: 133 for pattern in ussd_response_codes:
134 if response_message.find(pattern) >= 0: 134 if response_message.find(pattern) >= 0:
135 return ussd_response_codes[pattern] 135 return ussd_response_codes[pattern]
136 136
137 return '68' 137 return '68'
138 138
139 def getPulsaFromUssdResponseMessage(message): 139 def getPulsaFromUssdResponseMessage(message):
140 pulsa = re.findall(r"Pulsa (\d+) s", message) 140 pulsa = re.findall(r"Pulsa (\d+) s", message)
141 if pulsa: 141 if pulsa:
142 return int(pulsa[0]) 142 return int(pulsa[0])
143 143
144 def getMasaAktifFromUssdResponseMessage(message): 144 def getMasaAktifFromUssdResponseMessage(message):
145 masa_aktif = re.findall(' s[\./]d (\w+)\.', message) 145 masa_aktif = re.findall(' s[\./]d (\w+)\.', message)
146 if not masa_aktif: 146 if not masa_aktif:
147 return; 147 return;
148 148
149 masa_aktif = time.strptime(masa_aktif[0], '%d%b%y') 149 masa_aktif = time.strptime(masa_aktif[0], '%d%b%y')
150 return time.strftime("%Y-%m-%d", masa_aktif) 150 return time.strftime("%Y-%m-%d", masa_aktif)
151 151
152 def getLastSNFromHistoryMessage(message): 152 def getLastSNFromHistoryMessage(message):
153 sn = re.findall(r"Transaksi Terakhir: (\d+)", message) 153 sn = re.findall(r"Transaksi Terakhir :\s*(\d+)", message)
154 if sn: 154 if sn:
155 return sn 155 return sn
156 156