Commit 60f64816524e21d8f656b7ac23a721ead63ef737

Authored by Adhidarma Hadiwinoto
1 parent 545eb797b0
Exists in master

perbaikan advice

Showing 3 changed files with 12 additions and 3 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}'.format(sn, message) 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
289 elif lastSNFromHistory == 'P2P TRANSFER':
290 topupMessage = "Topup gagal berdasarkan advice. Trx terakhir adalah P2P Transfer."
291 pushTopupStatus(requestId, '40', topupMessage)
292 DISABLE_SEM = 0
288 293
289 elif lastSNFromHistory == LAST_SN: 294 elif lastSNFromHistory == LAST_SN:
290 topupMessage = "Topup gagal berdasarkan advice. {0} = {1}. {2}".format(lastSNFromHistory, LAST_SN, message) 295 topupMessage = "Topup gagal berdasarkan advice. {0} = {1}. {2}".format(lastSNFromHistory, LAST_SN, message)
291 pushTopupStatus(requestId, '40', topupMessage) 296 pushTopupStatus(requestId, '40', topupMessage)
292 DISABLE_SEM = 0 297 DISABLE_SEM = 0
293 298
294 299
295 else: 300 else:
296 topupMessage = "SN={0}; Topup berhasil berdasarkan advice. {1}".format(lastSNFromHistory, message) 301 topupMessage = "SN={0}; Topup berhasil berdasarkan advice. {1}".format(lastSNFromHistory, message)
297 LAST_SN = lastSNFromHistory 302 LAST_SN = lastSNFromHistory
298 pushTopupStatus(requestId, '00', topupMessage, True) 303 pushTopupStatus(requestId, '00', topupMessage, True)
299 DISABLE_SEM = 0 304 DISABLE_SEM = 0
300 305
301 except: 306 except:
302 message = "USSD Error: Something wrong when executing USSD advice. Signal strength: {0}".format(modem.signalStrength) 307 message = "USSD Error: Something wrong when executing USSD advice. Signal strength: {0}".format(modem.signalStrength)
303 logger.warning(message) 308 logger.warning(message)
304 pushTopupStatus(requestId, '68', message) 309 pushTopupStatus(requestId, '68', message)
305 310
306 sleep(60) 311 sleep(60)
307 adviceLastSN(requestId, modem) 312 adviceLastSN(requestId, modem)
308 #waitForResultSmsAfterUssdError(modem, task['requestId'], message) 313 #waitForResultSmsAfterUssdError(modem, task['requestId'], message)
309 return 314 return
310 315
311 316
312 317
313 def topupTask(task, modem): 318 def topupTask(task, modem):
314 global LAST_REQUEST_ID 319 global LAST_REQUEST_ID
315 320
316 if not task: 321 if not task:
317 return 322 return
318 323
319 if task['status'] != 'OK': 324 if task['status'] != 'OK':
320 return 325 return
321 326
322 LAST_REQUEST_ID = task['requestId'] 327 LAST_REQUEST_ID = task['requestId']
323 LAST_PRODUCT = task['product'].upper() 328 LAST_PRODUCT = task['product'].upper()
324 329
325 redis_key = sate24.keyByRequestId(CHIPINFO, task['requestId']) 330 redis_key = sate24.keyByRequestId(CHIPINFO, task['requestId'])
326 redis_client.set(redis_key, task) 331 redis_client.set(redis_key, task)
327 redis_client.expire(redis_key, REDIS_TTL) 332 redis_client.expire(redis_key, REDIS_TTL)
328 333
329 nominal = xltunai.getNominalFromProduct(task['product']) 334 nominal = xltunai.getNominalFromProduct(task['product'])
330 intl_destination = xltunai.toInternationalNumber(task['destination']) 335 intl_destination = xltunai.toInternationalNumber(task['destination'])
331 336
332 redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, intl_destination) 337 redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, intl_destination)
333 #redis_client.sadd(redis_key, task['requestId']) 338 #redis_client.sadd(redis_key, task['requestId'])
334 try: 339 try:
335 redis_client.rpush(redis_key, task['requestId']) 340 redis_client.rpush(redis_key, task['requestId'])
336 except: 341 except:
337 redis_client.delete(redis_key) 342 redis_client.delete(redis_key)
338 redis_client.rpush(redis_key, task['requestId']) 343 redis_client.rpush(redis_key, task['requestId'])
339 finally: 344 finally:
340 redis_client.expire(redis_key, REDIS_TTL) 345 redis_client.expire(redis_key, REDIS_TTL)
341 346
342 #pushTopupStatus(task['requestId'], '68', 'Siap mengirimkan trx ke operator') 347 #pushTopupStatus(task['requestId'], '68', 'Siap mengirimkan trx ke operator')
343 348
344 message = 'Executing USSD' 349 message = 'Executing USSD'
345 response_code = '68' 350 response_code = '68'
346 351
347 ussd_command = xltunai.getTopupUSSDCommand(task['destination'], task['product'], PIN_TRX) 352 ussd_command = xltunai.getTopupUSSDCommand(task['destination'], task['product'], PIN_TRX)
348 353
349 logger.info(u'Executing {0}'.format(ussd_command)) 354 logger.info(u'Executing {0}'.format(ussd_command))
350 try: 355 try:
351 response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT) 356 response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT)
352 357
353 message = response.message.strip() 358 message = response.message.strip()
354 logger.info(u'USSD response: {0}'.format(message)) 359 logger.info(u'USSD response: {0}'.format(message))
355 360
356 response_code = xltunai.getResponseCodeByUSSDResponse(message) 361 response_code = xltunai.getResponseCodeByUSSDResponse(message)
357 362
358 if response.sessionActive: 363 if response.sessionActive:
359 response.cancel() 364 response.cancel()
360 365
361 except TimeoutException: 366 except TimeoutException:
362 message = "USSD Error: Timeout when executing USSD topup. Signal strength: {0}".format(modem.signalStrength) 367 message = "USSD Error: Timeout when executing USSD topup. Signal strength: {0}".format(modem.signalStrength)
363 logger.warning(message) 368 logger.warning(message)
364 pushTopupStatus(task['requestId'], '68', message) 369 pushTopupStatus(task['requestId'], '68', message)
365 #waitForResultSmsAfterUssdError(modem, task['requestId'], message) 370 #waitForResultSmsAfterUssdError(modem, task['requestId'], message)
366 sleep(15) 371 sleep(15)
367 adviceLastSN(task['requestId'], modem) 372 adviceLastSN(task['requestId'], modem)
368 return 373 return
369 except: 374 except:
370 message = "USSD Error: Something wrong when executing USSD topup. Signal strength: {0}".format(modem.signalStrength) 375 message = "USSD Error: Something wrong when executing USSD topup. Signal strength: {0}".format(modem.signalStrength)
371 logger.warning(message) 376 logger.warning(message)
372 pushTopupStatus(task['requestId'], '68', message) 377 pushTopupStatus(task['requestId'], '68', message)
373 #waitForResultSmsAfterUssdError(modem, task['requestId'], message) 378 #waitForResultSmsAfterUssdError(modem, task['requestId'], message)
374 sleep(15) 379 sleep(15)
375 adviceLastSN(task['requestId'], modem) 380 adviceLastSN(task['requestId'], modem)
376 return 381 return
377 382
378 DISABLE_SEM = DISABLE_SEM_ON_TRX 383 DISABLE_SEM = DISABLE_SEM_ON_TRX
379 pushTopupStatus(task['requestId'], response_code, message) 384 pushTopupStatus(task['requestId'], response_code, message)
380 385
381 def waitForResultSmsAfterUssdError(modem, request_id, last_error_message = ''): 386 def waitForResultSmsAfterUssdError(modem, request_id, last_error_message = ''):
382 logger.info('Sleeping for {0} seconds after an USSD error'.format(SLEEP_AFTER_USSD_ERROR)) 387 logger.info('Sleeping for {0} seconds after an USSD error'.format(SLEEP_AFTER_USSD_ERROR))
383 sleep(SLEEP_AFTER_USSD_ERROR) 388 sleep(SLEEP_AFTER_USSD_ERROR)
384 389
385 redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code' 390 redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code'
386 response_code = redis_client.get(redis_key) 391 response_code = redis_client.get(redis_key)
387 392
388 if response_code == '68' or response_code == None: 393 if response_code == '68' or response_code == None:
389 394
390 prev_balance = BALANCE 395 prev_balance = BALANCE
391 current_balance = checkBalance(modem, do_not_update = True, return_result = True) 396 current_balance = checkBalance(modem, do_not_update = True, return_result = True)
392 397
393 if current_balance == 0: 398 if current_balance == 0:
394 return 399 return
395 400
396 if current_balance < prev_balance: 401 if current_balance < prev_balance:
397 delta = prev_balance - current_balance 402 delta = prev_balance - current_balance
398 pushTopupStatus( 403 pushTopupStatus(
399 request_id, 404 request_id,
400 '00', 405 '00',
401 'Transaksi dianggap sukses karena saldo berkurang {0}. Last error message: {1}'.format( 406 'Transaksi dianggap sukses karena saldo berkurang {0}. Last error message: {1}'.format(
402 delta, 407 delta,
403 last_error_message 408 last_error_message
404 ) 409 )
405 ) 410 )
406 else: 411 else:
407 pushTopupStatus( 412 pushTopupStatus(
408 request_id, 413 request_id,
409 '40', 414 '40',
410 'Transaksi dianggap gagal karena saldo tidak berkurang. Last error message: {0}'.format(last_error_message) 415 'Transaksi dianggap gagal karena saldo tidak berkurang. Last error message: {0}'.format(last_error_message)
411 ) 416 )
412 417
413 def _saveBalanceToRedis(balance_key, balance_value): 418 def _saveBalanceToRedis(balance_key, balance_value):
414 try: 419 try:
415 redis_client.set(balance_key, balance_value) 420 redis_client.set(balance_key, balance_value)
416 redis_client.expire(balance_key, 3600*24*60) 421 redis_client.expire(balance_key, 3600*24*60)
417 except: 422 except:
418 logger.warning('Failed to save balance to redis') 423 logger.warning('Failed to save balance to redis')
419 424
420 def saveBalanceToRedis(balance): 425 def saveBalanceToRedis(balance):
421 global BASE_CHIPINFO 426 global BASE_CHIPINFO
422 global CHIPINFO 427 global CHIPINFO
423 global MSISDN 428 global MSISDN
424 429
425 try: 430 try:
426 balance = int(balance) 431 balance = int(balance)
427 except ValueError: 432 except ValueError:
428 return 433 return
429 434
430 435
431 data = { 436 data = {
432 'balance.gw:' + BASE_CHIPINFO: balance, 437 'balance.gw:' + BASE_CHIPINFO: balance,
433 'balance.gw:' + CHIPINFO: balance, 438 'balance.gw:' + CHIPINFO: balance,
434 'balance.gw:' + MSISDN: balance 439 'balance.gw:' + MSISDN: balance
435 } 440 }
436 441
437 redis_pipe = redis_client.pipeline() 442 redis_pipe = redis_client.pipeline()
438 443
439 try: 444 try:
440 redis_pipe.mset(data) 445 redis_pipe.mset(data)
441 446
442 for k in data: 447 for k in data:
443 redis_pipe.expire(k, 3600 * 24 * 60) 448 redis_pipe.expire(k, 3600 * 24 * 60)
444 449
445 except: 450 except:
446 logger.warning('Failed to save balance to redis') 451 logger.warning('Failed to save balance to redis')
447 finally: 452 finally:
448 redis_pipe.execute() 453 redis_pipe.execute()
449 454
450 def saveSignalStrengthToRedis(value): 455 def saveSignalStrengthToRedis(value):
451 global BASE_CHIPINFO 456 global BASE_CHIPINFO
452 global CHIPINFO 457 global CHIPINFO
453 global MSISDN 458 global MSISDN
454 459
455 try: 460 try:
456 redis_pipe = redis_client.pipeline() 461 redis_pipe = redis_client.pipeline()
457 redis_client.set('balance.gw:' + BASE_CHIPINFO + '.signal', value) 462 redis_client.set('balance.gw:' + BASE_CHIPINFO + '.signal', value)
458 redis_client.expire('balance.gw:' + BASE_CHIPINFO + '.signal', 15 * 60) 463 redis_client.expire('balance.gw:' + BASE_CHIPINFO + '.signal', 15 * 60)
459 except: 464 except:
460 logger.warning('Failed to save signal strength to redis') 465 logger.warning('Failed to save signal strength to redis')
461 466
462 467
463 def pull(modem): 468 def pull(modem):
464 global PRODUCTS 469 global PRODUCTS
465 global PULL_COUNT 470 global PULL_COUNT
466 global BALANCE 471 global BALANCE
467 global DISABLE_SEM 472 global DISABLE_SEM
468 global MIN_SIGNAL_STRENGTH 473 global MIN_SIGNAL_STRENGTH
469 474
470 if not PRODUCTS: 475 if not PRODUCTS:
471 return 476 return
472 477
473 signalStrength = modem.signalStrength 478 signalStrength = modem.signalStrength
474 if signalStrength < MIN_SIGNAL_STRENGTH: 479 if signalStrength < MIN_SIGNAL_STRENGTH:
475 #logger.warn('Signal strength {0} < {1}, skipping pull'.format(signalStrength, MIN_SIGNAL_STRENGTH)) 480 #logger.warn('Signal strength {0} < {1}, skipping pull'.format(signalStrength, MIN_SIGNAL_STRENGTH))
476 return 481 return
477 482
478 pull_per_minute = 60 / PULL_INTERVAL 483 pull_per_minute = 60 / PULL_INTERVAL
479 484
480 PULL_COUNT += 1 485 PULL_COUNT += 1
481 if PULL_COUNT % (5 * pull_per_minute) == 0: 486 if PULL_COUNT % (5 * pull_per_minute) == 0:
482 checkBalance(modem) 487 checkBalance(modem)
483 sleep(15) 488 sleep(15)
484 PULL_COUNT = 0 489 PULL_COUNT = 0
485 490
486 if DISABLE_SEM > 0: 491 if DISABLE_SEM > 0:
487 logger.info('SEMAPHORE is still on, delaying pull') 492 logger.info('SEMAPHORE is still on, delaying pull')
488 DISABLE_SEM -= 1 493 DISABLE_SEM -= 1
489 return 494 return
490 495
491 if not isPullEnable(): 496 if not isPullEnable():
492 return 497 return
493 498
494 r = None 499 r = None
495 url = AAA_HOST + '/pull?city=' + CITY + '&nom=' + PRODUCTS 500 url = AAA_HOST + '/pull?city=' + CITY + '&nom=' + PRODUCTS
496 try: 501 try:
497 r = requests.get(url) 502 r = requests.get(url)
498 except: 503 except:
499 logger.warning("Error requesting to AAA") 504 logger.warning("Error requesting to AAA")
500 return 505 return
501 506
502 if not r: 507 if not r:
503 return 508 return
504 509
505 task = sate24.parsePullMessage(r.text) 510 task = sate24.parsePullMessage(r.text)
506 511
507 if task['status'] == 'OK': 512 if task['status'] == 'OK':
508 513
509 logger.info('PULL ' + url + ' => ' + r.text) 514 logger.info('PULL ' + url + ' => ' + r.text)
510 publishAAATaskToRedis(task) 515 publishAAATaskToRedis(task)
511 516
512 if not checkBalance(modem) or BALANCE == 0: 517 if not checkBalance(modem) or BALANCE == 0:
513 pushTopupStatus(task['requestId'], '91', 'Transaksi dibatalkan karena gagal check balance') 518 pushTopupStatus(task['requestId'], '91', 'Transaksi dibatalkan karena gagal check balance')
514 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) 519 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP)
515 return 520 return
516 521
517 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) 522 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP)
518 523
519 topupTask(task, modem) 524 topupTask(task, modem)
520 sleep(SLEEP_AFTER_TOPUP) 525 sleep(SLEEP_AFTER_TOPUP)
521 526
522 def publishAAATaskToRedis(task): 527 def publishAAATaskToRedis(task):
523 try: 528 try:
524 key = 'kimochi.aaa_pull.gw:' + BASE_CHIPINFO 529 key = 'kimochi.aaa_pull.gw:' + BASE_CHIPINFO
525 plain_text = task['timestamp'] + ' - ' + task['member'] + ' isi ' + task['product'] + ' ke ' + task['destination']; 530 plain_text = task['timestamp'] + ' - ' + task['member'] + ' isi ' + task['product'] + ' ke ' + task['destination'];
526 531
527 redis_client.publish(key + '.json', json.dumps(task)) 532 redis_client.publish(key + '.json', json.dumps(task))
528 redis_client.publish(key + '.text', plain_text); 533 redis_client.publish(key + '.text', plain_text);
529 except: 534 except:
530 logger.warning('Error publishing kimochi') 535 logger.warning('Error publishing kimochi')
531 536
532 def publishMessageToRedis(): 537 def publishMessageToRedis():
533 pass 538 pass
534 539
535 def pullLoop(modem): 540 def pullLoop(modem):
536 global TERMINATING 541 global TERMINATING
537 542
538 while True: 543 while True:
539 signalStrength = modem.signalStrength 544 signalStrength = modem.signalStrength
540 saveSignalStrengthToRedis(signalStrength) 545 saveSignalStrengthToRedis(signalStrength)
541 546
542 if TERMINATING: 547 if TERMINATING:
543 logger.info('Terminated by request signal') 548 logger.info('Terminated by request signal')
544 sys.exit(0) 549 sys.exit(0)
545 550
546 pull(modem) 551 pull(modem)
547 552
548 sleep(PULL_INTERVAL) 553 sleep(PULL_INTERVAL)
549 554
550 def checkSignal(modem): 555 def checkSignal(modem):
551 logger.info('Signal: {0}'.format(modem.signalStrength)) 556 logger.info('Signal: {0}'.format(modem.signalStrength))
552 try: 557 try:
553 redis_client.set(CHIPINFO + '.signal', modem.signalStrength) 558 redis_client.set(CHIPINFO + '.signal', modem.signalStrength)
554 redis_client.expire(CHIPINFO + '.signal', 3600*24) 559 redis_client.expire(CHIPINFO + '.signal', 3600*24)
555 except: 560 except:
556 logger.warning("Can not save signal strength to redis") 561 logger.warning("Can not save signal strength to redis")
557 562
558 def checkAccount(modem): 563 def checkAccount(modem):
559 try: 564 try:
560 ussd_string = '*123*120*8*3#' 565 ussd_string = '*123*120*8*3#'
561 response = modem.sendUssd(ussd_string, 30) 566 response = modem.sendUssd(ussd_string, 30)
562 logger.info('Account Info: {0}'.format(response.message)) 567 logger.info('Account Info: {0}'.format(response.message))
563 568
564 if response.sessionActive: 569 if response.sessionActive:
565 response.cancel() 570 response.cancel()
566 except: 571 except:
567 logger.warning('Error when requesting account info') 572 logger.warning('Error when requesting account info')
568 return False 573 return False
569 574
570 def checkBalance(modem, do_not_update = False, return_result = False): 575 def checkBalance(modem, do_not_update = False, return_result = False):
571 global BALANCE 576 global BALANCE
572 577
573 _BALANCE = 0 578 _BALANCE = 0
574 579
575 try: 580 try:
576 581
577 ussd_string = '*123*120#' 582 ussd_string = '*123*120#'
578 response = modem.sendUssd(ussd_string, 30) 583 response = modem.sendUssd(ussd_string, 30)
579 _BALANCE = xltunai.getBalanceFromUSSDResponse(response.message) 584 _BALANCE = xltunai.getBalanceFromUSSDResponse(response.message)
580 585
581 if not do_not_update: 586 if not do_not_update:
582 BALANCE = _BALANCE 587 BALANCE = _BALANCE
583 saveBalanceToRedis(BALANCE) 588 saveBalanceToRedis(BALANCE)
584 589
585 logger.info('Balance: {0}'.format(_BALANCE)) 590 logger.info('Balance: {0}'.format(_BALANCE))
586 if response.sessionActive: 591 if response.sessionActive:
587 response.cancel() 592 response.cancel()
588 593
589 if _BALANCE != 0 and _BALANCE < MIN_BALANCE: 594 if _BALANCE != 0 and _BALANCE < MIN_BALANCE:
590 logger.info('Disabling pull, balance {0} < {1}'.format(_BALANCE, MIN_BALANCE)) 595 logger.info('Disabling pull, balance {0} < {1}'.format(_BALANCE, MIN_BALANCE))
591 disablePull() 596 disablePull()
592 597
593 except: 598 except:
594 logger.warning('Error when requesting BALANCE by USSD') 599 logger.warning('Error when requesting BALANCE by USSD')
595 if return_result: 600 if return_result:
596 return 0 601 return 0
597 else: 602 else:
598 return False 603 return False
599 604
600 try: 605 try:
601 redis_client.set(CHIPINFO + '.balance', BALANCE) 606 redis_client.set(CHIPINFO + '.balance', BALANCE)
602 except: 607 except:
603 logger.warning('Failed to save balance to redis') 608 logger.warning('Failed to save balance to redis')
604 609
605 if return_result: 610 if return_result:
606 return _BALANCE 611 return _BALANCE
607 else: 612 else:
608 return True 613 return True
609 614
610 def getPulsaInfo(modem): 615 def getPulsaInfo(modem):
611 global PULSA 616 global PULSA
612 global MASA_AKTIF 617 global MASA_AKTIF
613 618
614 try: 619 try:
615 ussd_string = "*123#" 620 ussd_string = "*123#"
616 response = modem.sendUssd(ussd_string) 621 response = modem.sendUssd(ussd_string)
617 622
618 message = response.message.strip() 623 message = response.message.strip()
619 logger.info('PULSA: {0}'.format(message)) 624 logger.info('PULSA: {0}'.format(message))
620 if response.sessionActive: 625 if response.sessionActive:
621 response.cancel() 626 response.cancel()
622 627
623 PULSA = xltunai.getPulsaFromUssdResponseMessage(message) 628 PULSA = xltunai.getPulsaFromUssdResponseMessage(message)
624 MASA_AKTIF =xltunai.getMasaAktifFromUssdResponseMessage(message) 629 MASA_AKTIF =xltunai.getMasaAktifFromUssdResponseMessage(message)
625 logger.info('PULSA: {0} -- MASA AKTIF: {1}'.format(PULSA, MASA_AKTIF)) 630 logger.info('PULSA: {0} -- MASA AKTIF: {1}'.format(PULSA, MASA_AKTIF))
626 631
627 return message 632 return message
628 633
629 except: 634 except:
630 logger.warning('Error when requesting pulsa info by USSD') 635 logger.warning('Error when requesting pulsa info by USSD')
631 return '' 636 return ''
632 637
633 def getSIMCardInfo(modem): 638 def getSIMCardInfo(modem):
634 try: 639 try:
635 ussd_string = xltunai.getSIMCardInfoUSSDCommand() 640 ussd_string = xltunai.getSIMCardInfoUSSDCommand()
636 response = modem.sendUssd(ussd_string) 641 response = modem.sendUssd(ussd_string)
637 642
638 message = response.message.strip() 643 message = response.message.strip()
639 logger.info('SIM INFO: {0}'.format(message)) 644 logger.info('SIM INFO: {0}'.format(message))
640 if response.sessionActive: 645 if response.sessionActive:
641 response.cancel() 646 response.cancel()
642 647
643 return message 648 return message
644 649
645 except: 650 except:
646 logger.warning('Error when requesting SIM card info by USSD') 651 logger.warning('Error when requesting SIM card info by USSD')
647 return '' 652 return ''
648 653
649 def updateChipInfo(msisdn): 654 def updateChipInfo(msisdn):
650 global BASE_CHIPINFO 655 global BASE_CHIPINFO
651 global CHIPINFO 656 global CHIPINFO
652 global MSISDN 657 global MSISDN
653 658
654 MSISDN = msisdn 659 MSISDN = msisdn
655 if CHIPINFO.find(msisdn) == -1: 660 if CHIPINFO.find(msisdn) == -1:
656 CHIPINFO = BASE_CHIPINFO + '-' + msisdn 661 CHIPINFO = BASE_CHIPINFO + '-' + msisdn
657 662
658 logger.info('CHIPINFO: {0}'.format(CHIPINFO)) 663 logger.info('CHIPINFO: {0}'.format(CHIPINFO))
659 664
660 def main(): 665 def main():
661 global logger 666 global logger
662 667
663 log_format = '%(asctime)s %(levelname)s: %(message)s' 668 log_format = '%(asctime)s %(levelname)s: %(message)s'
664 669
665 logging.basicConfig(format=log_format, level=logging.INFO) 670 logging.basicConfig(format=log_format, level=logging.INFO)
666 logger = logging.getLogger(__name__) 671 logger = logging.getLogger(__name__)
667 672
668 logger_formatter = logging.Formatter(log_format) 673 logger_formatter = logging.Formatter(log_format)
669 logger_handler = TimedRotatingFileHandler('logs/log', when='midnight') 674 logger_handler = TimedRotatingFileHandler('logs/log', when='midnight')
670 logger_handler.setFormatter(logger_formatter) 675 logger_handler.setFormatter(logger_formatter)
671 logger.addHandler(logger_handler) 676 logger.addHandler(logger_handler)
672 677
673 requests_logger = logging.getLogger('requests') 678 requests_logger = logging.getLogger('requests')
674 requests_logger.setLevel(logging.WARNING) 679 requests_logger.setLevel(logging.WARNING)
675 680
676 logger.info('Initializing modem...') 681 logger.info('Initializing modem...')
677 682
678 modem = GsmModem(PORT, BAUDRATE, smsReceivedCallbackFunc=handleSms) 683 modem = GsmModem(PORT, BAUDRATE, smsReceivedCallbackFunc=handleSms)
679 modem.smsTextMode = True 684 modem.smsTextMode = True
680 modem.connect(PIN) 685 modem.connect(PIN)
681 686
682 logger.info('Waiting for network coverage...') 687 logger.info('Waiting for network coverage...')
683 modem.waitForNetworkCoverage(10) 688 modem.waitForNetworkCoverage(10)
684 689
685 logger.info('Modem ready') 690 logger.info('Modem ready')
686 691
687 getPulsaInfo(modem) 692 getPulsaInfo(modem)
688 sleep(2) 693 sleep(2)
689 694
690 simcard_info = getSIMCardInfo(modem) 695 simcard_info = getSIMCardInfo(modem)
691 msisdn = xltunai.getMSISDNFromSIMCardInfo(simcard_info) 696 msisdn = xltunai.getMSISDNFromSIMCardInfo(simcard_info)
692 697
693 if not msisdn: 698 if not msisdn:
694 logger.warning('Gagal mendapatkan msisdn, terminating') 699 logger.warning('Gagal mendapatkan msisdn, terminating')
695 sleep(5) 700 sleep(5)
696 sys.exit(2) 701 sys.exit(2)
697 702
698 imsi = modem.imsi 703 imsi = modem.imsi
699 logger.info('MSISDN: {0} -- IMSI: {1}'.format(msisdn, imsi)) 704 logger.info('MSISDN: {0} -- IMSI: {1}'.format(msisdn, imsi))
700 705
701 updateChipInfo(msisdn) 706 updateChipInfo(msisdn)
702 saveSimCardInfoToRedis(imsi, msisdn) 707 saveSimCardInfoToRedis(imsi, msisdn)
703 708
704 sleep(2) 709 sleep(2)
705 710
706 saveSignalStrengthToRedis(modem.signalStrength) 711 saveSignalStrengthToRedis(modem.signalStrength)
707 712
708 logger.info('Process stored SMS') 713 logger.info('Process stored SMS')
709 try: 714 try:
710 modem.processStoredSms() 715 modem.processStoredSms()
711 except: 716 except:
712 logger.warning('Failed on Process stored SMS') 717 logger.warning('Failed on Process stored SMS')
713 718
714 logger.info('Delete stored SMS') 719 logger.info('Delete stored SMS')
715 try: 720 try:
716 modem.deleteMultipleStoredSms() 721 modem.deleteMultipleStoredSms()
717 except: 722 except:
718 #logger.warning('Failed on delete SMS') 723 #logger.warning('Failed on delete SMS')
719 pass 724 pass
720 725
721 sleep(2) 726 sleep(2)
722 727
723 checkAccount(modem) 728 checkAccount(modem)
724 sleep(5) 729 sleep(5)
725 730
726 enablePull() 731 enablePull()
727 732
728 checkBalance(modem) 733 checkBalance(modem)
729 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) 734 sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP)
730 735
731 pullLoop(modem) 736 pullLoop(modem)
732 logger.info('Waiting for SMS message...') 737 logger.info('Waiting for SMS message...')
733 try: 738 try:
734 modem.rxThread.join(2**31) # Specify a (huge) timeout so that it essentially blocks indefinitely, but still receives CTRL+C interrupt signal 739 modem.rxThread.join(2**31) # Specify a (huge) timeout so that it essentially blocks indefinitely, but still receives CTRL+C interrupt signal
735 finally: 740 finally:
736 modem.close(); 741 modem.close();
737 742
738 def saveSimCardInfoToRedis(imsi, msisdn): 743 def saveSimCardInfoToRedis(imsi, msisdn):
739 logger.info('Save sim card info to redis') 744 logger.info('Save sim card info to redis')
740 745
741 data = { 746 data = {
742 'gw': BASE_CHIPINFO, 747 'gw': BASE_CHIPINFO,
743 'imsi': imsi, 748 'imsi': imsi,
744 'msisdn': msisdn, 749 'msisdn': msisdn,
745 'pulsa': PULSA, 750 'pulsa': PULSA,
746 'masa_aktif': MASA_AKTIF 751 'masa_aktif': MASA_AKTIF
747 } 752 }
748 753
749 json_data = json.dumps(data) 754 json_data = json.dumps(data)
750 755
751 map_data = { 756 map_data = {
752 BASE_CHIPINFO + '.simcardinfo': json_data, 757 BASE_CHIPINFO + '.simcardinfo': json_data,
753 'simcardinfo.gw:' + BASE_CHIPINFO: json_data, 758 'simcardinfo.gw:' + BASE_CHIPINFO: json_data,
754 'simcardinfo.imsi:' + imsi: json_data, 759 'simcardinfo.imsi:' + imsi: json_data,
755 'simcardinfo.msisdn:' + msisdn: json_data 760 'simcardinfo.msisdn:' + msisdn: json_data
756 } 761 }
757 762
758 logger.info(map_data) 763 logger.info(map_data)
759 764
760 redis_pipe = redis_client.pipeline() 765 redis_pipe = redis_client.pipeline()
761 766
762 try: 767 try:
763 redis_pipe.mset(map_data) 768 redis_pipe.mset(map_data)
764 769
765 for k in data: 770 for k in data:
766 redis_pipe.expire(k, 3600 * 24 * 60) 771 redis_pipe.expire(k, 3600 * 24 * 60)
767 772
768 except: 773 except:
769 logger.warning('Failed to save simcardinfo to redis') 774 logger.warning('Failed to save simcardinfo to redis')
770 finally: 775 finally:
771 redis_pipe.execute() 776 redis_pipe.execute()
772 777
773 if __name__ == '__main__': 778 if __name__ == '__main__':
774 pidfile = open('pid.txt', 'w') 779 pidfile = open('pid.txt', 'w')
775 pidfile.write(str(getpid())) 780 pidfile.write(str(getpid()))
776 pidfile.close() 781 pidfile.close()
777 782
778 # trap CTRL-C 783 # trap CTRL-C
779 signal.signal(signal.SIGINT, signalHandler) 784 signal.signal(signal.SIGINT, signalHandler)
780 # trap supervisor stop 785 # trap supervisor stop
781 signal.signal(signal.SIGTERM, signalHandler) 786 signal.signal(signal.SIGTERM, signalHandler)
782 787
783 main() 788 main()
784 789
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 134
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 :\s*(\d+)", message) 153 if re.findall(r"P2P TRANSFER", message):
154 return 'P2P TRANSFER'
155
156 sn = re.findall(r"Transaksi Terakhir\s:\s(\d+)", message)
154 if sn: 157 if sn:
155 return sn 158 return sn[0]
156 159