Changeset 3207 for pykota/trunk
- Timestamp:
- 07/13/07 00:30:08 (17 years ago)
- Location:
- pykota/trunk/contributed/itcprint
- Files:
-
- 2 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/trunk/contributed/itcprint/itcprint.glade
r3199 r3207 131 131 </b> 132 132 1) Insert you smart card and click "<i>Get Balance".</i> 133 2) Enter your computer username .133 2) Enter your computer username then press <i>TAB</i> key 134 134 3) Increase the "<i>Add Amount"</i> area to a desired amount. 135 135 4) Click the "<i>Transfer to Printing Account"</i> button. 136 5) C lick the "<i>Eject Card Now"</i> button to retrieve your card.136 5) Card will automatically eject after successful transaction. 137 137 </big> 138 138 <b>Note:</b> Add amount will not exceed card amount.</property> … … 246 246 <widget class="GtkEntry" id="UsernameEntry"> 247 247 <property name="visible">True</property> 248 <property name="tooltip" translatable="yes" context="yes">Enter your username then press the TAB key</property> 248 249 <property name="can_focus">True</property> 249 250 <property name="editable">True</property> … … 256 257 <signal name="changed" handler="on_UsernameEntry_changed" last_modification_time="Wed, 04 Jul 2007 18:44:48 GMT"/> 257 258 <signal name="focus_out_event" handler="on_UsernameEntry_focus_out_event" last_modification_time="Fri, 06 Jul 2007 18:40:45 GMT"/> 259 <signal name="activate" handler="on_UsernameEntry_activate" last_modification_time="Mon, 09 Jul 2007 18:49:55 GMT"/> 258 260 </widget> 259 261 <packing> … … 415 417 <property name="wrap">False</property> 416 418 <property name="adjustment">0 0 100 0.10000000149 10 10</property> 419 <signal name="value_changed" handler="on_Spinbutton_value_changed" last_modification_time="Mon, 09 Jul 2007 17:58:30 GMT"/> 417 420 </widget> 418 421 <packing> -
pykota/trunk/contributed/itcprint/itcxfer.py
r3199 r3207 1 1 #! /usr/bin/python 2 2 # 3 # itc print.py3 # itcxfer.py 4 4 # (c) 2007 George Farris <farrisg@shaw.ca> 5 5 # … … 64 64 # Char line : <STX><NUL><SOH>$<NUL><NUL><NUL><NUL><NUL><NUL><DLE><EOT><SOH><ETX><NUL>?<FF> 65 65 # Hex translation: 0x02 0x00 0x01 0x24 0x00 0x00 0x00 0x00 0x00 0x00 0x10 0x04 0x01 0x03 0x00 0x3F 0x0C 66 # [ Dollar value in this case 0x10 0x04 ] 67 # [ 0x1004 = 4100 = $4.10 ] 68 # [______________________________________] 66 # [ Dollar value in this case 0x10 0x04 ] ________[ chkm]__________ 67 # [ 0x1004 = 4100 = $4.10 ] [ checksum add bytes 1 to 15 ] 68 # [______________________________________] [____________________________] 69 69 # 70 70 # Receive from successful transaction from Reader … … 72 72 # Hex translation: 0x02 0x00 0x01 0x16 0x03 0x00 0x1C 0x08 73 73 # ===================================================================================================== 74 74 #0200011703001d08 75 75 76 76 # ----------------------------------------------------------------------------------------------------- … … 90 90 import gtk, gtk.glade, gobject, pg 91 91 92 # -------------- User modifiable settings ----------------------------- 92 93 # Database server settings 93 HOST = ' localhost'94 HOST = '10.31.50.3' 94 95 PORT = 5432 95 96 DBNAME = 'pykota' … … 97 98 PASS = 'secret' 98 99 99 100 # Search database as you type function 101 # These settings control if a database search of the username is performed 102 # automatically when they reach a desired length. This helps in a University 103 # setting where all student username are the same length. 104 SEARCH = True 105 SEARCHLENGTH = 6 106 107 # Serial port settings 108 SERIAL_PORT = '/dev/ttyUSB0' 109 BAUD_RATE = 9600 110 111 # Set this to True or False 112 # If set to True it will not update any cards 113 TESTMODE = True 114 115 # ------------- End of user modifiable settings ----------------------- 100 116 101 117 class gui: … … 111 127 self.printlabel = self.xml.get_widget("PrintBalanceLabel") 112 128 self.spinbutton = self.xml.get_widget("Spinbutton") 113 129 self.xferbutton = self.xml.get_widget("TransferButton") 130 131 self.spinbutton.set_range(0,0) 132 self.spinbutton.set_sensitive(False) 133 self.xferbutton.set_sensitive(False) 114 134 self.cardlabel.set_label('<big><b>unknown</b></big>') 115 135 self.printlabel.set_label('<big><b>unknown</b></big>') 116 136 117 self.cardbalance = '' 118 self.username = '' 119 self.addbalance = '' 120 self.pykotauid = '' 121 self.pykotabalance = 0.0 122 123 # TODO put try except around here 124 #connect([dbname], [host], [port], [opt], [tty], [user], [passwd]) 125 try: 126 self.sql = pg.connect(dbname=DBNAME, host=HOST, port=PORT, user=USER, passwd=PASS) 127 except: 128 pass 129 130 # query = self.sql.query("""SELECT printername FROM printers WHERE printername='cc200-LaserJet' """) 131 #query = db.get(printers, "cc200-laserjet") 132 # if len(query.getresult()) > 0: 133 # d2 = query.dictresult() 134 # print d2 #['username'] 135 136 self.sc = smartcard(self.sql) 137 self.cardbalance = 0.0 138 self.validuser = False 139 self.addbalance = 0.0 140 141 if not TESTMODE : 142 print "We are in test mode...." 143 144 self.db = pgsql() 145 self.sc = smartcard(self.db) 137 146 138 147 #If you wanted to pass an argument, you would use a tuple like this: … … 143 152 "on_quit_activate" : (gtk.main_quit), 144 153 "on_UsernameEntry_changed" : self.username_changed, 154 "on_Spinbutton_value_changed" : self.spinvalue_changed, 145 155 "on_UsernameEntry_focus_out_event" : self.username_entered, 156 "on_UsernameEntry_activate" : (self.username_entered, None), 146 157 "on_ItcPrint_destroy" : (gtk.main_quit) } 147 158 148 159 self.xml.signal_autoconnect (dic) 149 160 161 self.completion = gtk.EntryCompletion() 162 self.utext.set_completion(self.completion) 163 self.liststore = gtk.ListStore(gobject.TYPE_STRING) 164 self.completion.set_model(self.liststore) 165 self.completion.set_text_column(0) 166 self.completion.connect("match-selected", self.username_found) 167 168 #self.liststore.append(['string text']) 169 150 170 return 151 171 172 # Don't allow the transfer button to be senitive unless there is a valid value 173 def spinvalue_changed(self, widget): 174 if self.spinbutton.get_value() > 0.0: 175 self.xferbutton.set_sensitive(True) 176 else: 177 self.xferbutton.set_sensitive(False) 178 152 179 # I might want to do username search as you type later 153 180 def username_changed (self, widget): 154 print "Text is now ->", self.utext.get_text() 155 181 if SEARCH : 182 if len(self.utext.get_text()) == SEARCHLENGTH: 183 if not self.db.alreadyopen: 184 if not self.db.pgopen(): 185 result = gtk.RESPONSE_CANCEL 186 dlg = gtk.MessageDialog(None,gtk.DIALOG_MODAL | 187 gtk.DIALOG_DESTROY_WITH_PARENT,gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, 188 "Cannot connect or open the database.\nPlease contact technical suppport...", ) 189 result = dlg.run() 190 dlg.destroy() 191 return 192 if self.db.get_userslist(self.utext.get_text(), self.liststore): 193 pass 194 else: 195 return 196 197 #self.username_entered(None, None) 198 199 def username_found(self, completion, model, iter): 200 self.username = model[iter][0], 'was selected' 201 self.utext.set_text(model[iter][0]) 202 self.username_entered(self, None) 203 156 204 def username_entered (self, widget, event): 157 self.username = self.utext.get_text()158 print "Username is ->", self.username205 uname = self.utext.get_text() 206 print "Username is ->", uname 159 207 # This is where we need to look up username in wbinfo 160 208 161 try: 162 query = self.sql.query("SELECT id FROM users WHERE username='%s'" % (self.username)) 163 self.pykotauid = (query.dictresult()[0])['id'] 164 print "User ID is ->", self.pykotauid 165 except: 166 print "Username is invalid" 209 210 if not self.db.alreadyopen: 211 if not self.db.pgopen(): 212 result = gtk.RESPONSE_CANCEL 213 dlg = gtk.MessageDialog(None,gtk.DIALOG_MODAL | 214 gtk.DIALOG_DESTROY_WITH_PARENT,gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, 215 "Cannot connect or open the database.\nPlease contact technical suppport...", ) 216 result = dlg.run() 217 dlg.destroy() 218 return 219 220 if self.db.get_pykotaid(uname): 221 self.validuser = True 222 else: 167 223 result = gtk.RESPONSE_CANCEL 168 224 dlg = gtk.MessageDialog(None,gtk.DIALOG_MODAL | 169 gtk.DIALOG_DESTROY_WITH_PARENT,gtk.MESSAGE_ INFO, gtk.BUTTONS_CLOSE,225 gtk.DIALOG_DESTROY_WITH_PARENT,gtk.MESSAGE_WARNING, gtk.BUTTONS_CLOSE, 170 226 "Your username is invalid or does not exist.\nPlease try re-entering it", ) 171 227 result = dlg.run() 172 228 dlg.destroy() 173 try: 174 query = self.sql.query("SELECT balance FROM users WHERE id='%s'" % (self.pykotauid)) 175 self.pykotabalance = float((query.dictresult()[0])['balance']) 176 self.printlabel.set_label("%s%.2f%s" % ("<big><b>$",self.pykotabalance,"</b></big>")) 177 except: 178 print "balance sql error..." 179 try: 180 query = self.sql.query("SELECT lifetimepaid FROM users WHERE id='%s'" % (self.pykotauid)) 181 self.pykotalifebalance = float((query.dictresult()[0])['lifetimepaid']) 182 print "%s%.2f" % ("$", self.pykotalifebalance) 183 except: 184 print "lifetimepaid sql error..." 185 186 187 229 return 230 231 #self.liststore.append(['string text']) 232 233 balance = self.db.get_pykotabalance() 234 if balance : 235 self.printlabel.set_label("%s%.2f%s" % ("<big><b>$",balance,"</b></big>")) 236 else: 237 result = gtk.RESPONSE_CANCEL 238 dlg = gtk.MessageDialog(None,gtk.DIALOG_MODAL | 239 gtk.DIALOG_DESTROY_WITH_PARENT,gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, 240 "Cannot retrieve your printing balance.\nPlease contact technical suppport...", ) 241 result = dlg.run() 242 dlg.destroy() 243 self.validuser = False 244 return 245 246 if not self.db.get_pykotalifebalance(): 247 result = gtk.RESPONSE_CANCEL 248 dlg = gtk.MessageDialog(None,gtk.DIALOG_MODAL | 249 gtk.DIALOG_DESTROY_WITH_PARENT,gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, 250 "Cannot retrieve your life time printing balance.\nPlease contact technical suppport...", ) 251 result = dlg.run() 252 dlg.destroy() 253 self.validuser = False 254 return 255 256 # Only set transfer button if both card balance and username valid 257 if self.cardbalance > 0.1 and self.validuser: 258 self.spinbutton.set_sensitive(True) 259 260 188 261 def xferbutton_clicked (self, widget): 189 262 print "xfer button clicked...." 190 self.addbalance = self.spinbutton.get_value() 191 newbalance = self.addbalance + self.pykotabalance 192 lifetimebalance = self.pykotalifebalance + self.addbalance 193 self.sc.set_balance(newbalance, lifetimebalance, self.pykotauid) 263 addbalance = self.spinbutton.get_value() 264 265 if not self.db.set_pykotabalances(addbalance): 266 result = gtk.RESPONSE_CANCEL 267 dlg = gtk.MessageDialog(None,gtk.DIALOG_MODAL | 268 gtk.DIALOG_DESTROY_WITH_PARENT,gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, 269 "An error was encountered while updating your record.\nPlease contact technical support.") 270 result = dlg.run() 271 dlg.destroy() 272 return 273 274 self.sc.set_balance(addbalance, self.cardbalance) 275 time.sleep(3) 194 276 self.ejectbutton_clicked(None) 277 self.spinbutton.set_range(0,float(0)) 278 195 279 196 280 def getcardbalance_clicked(self, widget): … … 201 285 self.cardstate = 1 202 286 self.source_id = gobject.timeout_add(2000, self.sc.inhibit_eject) 287 # Only allow the spin button to go up to the value of the card 203 288 self.spinbutton.set_range(0,float(self.cardbalance)) 289 290 if self.cardbalance > 0.1 and self.validuser: 291 self.spinbutton.set_sensitive(True) 204 292 205 293 def ejectbutton_clicked(self, widget): 206 # TODO put a pop dialog here207 294 self.sc.eject_card() 208 295 self.cardlabel.set_label('<big><b>unknown</b></big>') … … 210 297 self.cardstate = 0 211 298 self.cardbalance = 0.0 212 self. username = ''299 self.validuser = False 213 300 self.utext.set_text('') 214 301 self.addbalance = 0.0 215 self.pykotabalance = 0.0216 self.pykotalifebalance = 0.0217 302 self.spinbutton.set_range(0,0) 218 303 self.spinbutton.set_sensitive(False) 304 self.xferbutton.set_sensitive(False) 305 306 self.db.pgclose() 307 219 308 # Is it possible this might not be set 220 309 try: … … 222 311 except: 223 312 pass 224 225 313 226 314 227 315 class smartcard: 228 316 def __init__(self, sql): 229 self.ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1) 230 self.scsql = sql 231 317 try: 318 self.ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) 319 except: 320 result = gtk.RESPONSE_CANCEL 321 dlg = gtk.MessageDialog(None,gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, 322 gtk.BUTTONS_CLOSE, "Fatal error - Could not open serial port...", ) 323 result = dlg.run() 324 dlg.destroy() 325 exit(1) 326 232 327 # Need comms to contiune to keep card in machine. 233 328 # This loop keeps the card in until it stops so basically the print 234 329 # job can release the card after it is finished 235 330 def checkforcardready(self): 331 # A bit of a sleep here prevents the card dialog popping up if 332 # the card is already inserted. 333 time.sleep(1) 236 334 self.ser.write(binascii.a2b_hex("0200010103000704")) 237 335 s = self.ser.read(8) … … 273 371 # Get current value from card 274 372 def get_balance(self): 373 # TODO Test checksum 275 374 self.ser.write(binascii.a2b_hex("0200012103002704")) 276 375 s1 = self.ser.read(16) 376 print binascii.b2a_hex(s1) 277 377 print " %s%.2f" % ("Card valued at -> $",float(string.atoi(binascii.b2a_hex(s1[3:11]), 16))/1000) 278 378 return float(string.atoi(binascii.b2a_hex(s1[3:11]), 16))/1000 279 379 280 def set_balance(self, new, life, uid): 281 #self.ser.write(binascii.a2b_hex("0200012400000000000010040103003F0C")) 282 #s2 = self.ser.read(8) 283 #print binascii.b2a_hex(s2) 284 285 try: 286 query = self.scsql.query("UPDATE users SET balance=%s, lifetimepaid=%s WHERE id='%s'" % 287 (new, life, uid)) 288 except: 289 print "sql error..." 290 result = gtk.RESPONSE_CANCEL 291 dlg = gtk.MessageDialog(None,gtk.DIALOG_MODAL | 292 gtk.DIALOG_DESTROY_WITH_PARENT,gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, 293 "An error was encountered while updating your record.\nPlease contact technical support.") 294 result = dlg.run() 295 dlg.destroy() 296 297 """ 298 def writeUserAccountBalance(self, user, newbalance, newlifetimepaid=None) : 299 #Sets the new account balance and eventually new lifetime paid. 300 if newlifetimepaid is not None : 301 self.doModify("UPDATE users SET balance=%s, lifetimepaid=%s WHERE id=%s" % (self.doQuote(newbalance), self.doQuote(newlifetimepaid), self.doQuote(user.ident))) 302 else : 303 self.doModify("UPDATE users SET balance=%s WHERE id=%s" % (self.doQuote(newbalance), self.doQuote(user.ident))) 304 305 def writeNewPayment(self, user, amount, comment="") : 306 #Adds a new payment to the payments history. 307 self.doModify("INSERT INTO payments (userid, amount, description) VALUES (%s, %s, %s)" % (self.doQuote(user.ident), self.doQuote(amount), self.doQuote(comment))) 308 309 """ 310 380 def set_balance(self, subvalue, cardbalance): 381 newbalance = cardbalance - subvalue 382 a = (str(newbalance)).split('.') 383 b = a[0] + string.ljust(a[1],3,'0') 384 c = "%X" % (string.atoi(b)) 385 d = string.zfill(c,16) 386 chksum = self.checksum(d) 387 decrementvalue = "02000124" + d + "0103" + chksum + "0C" 388 389 if TESTMODE: 390 print "Current card balance -> ", cardbalance 391 print "Amount to subtract from card -> ", subvalue 392 print "New card balance -> ", newbalance 393 print "Checksum -> ", chksum 394 print "Sent to card -> ",decrementvalue 395 return 396 397 print "Sent to card -> ",decrementvalue 398 self.ser.write(binascii.a2b_hex(decrementvalue)) 399 s2 = self.ser.read(8) 400 print "Result -> ", binascii.b2a_hex(s2) 401 311 402 def eject_card(self): 312 403 print " Ejecting card ..." … … 320 411 return True 321 412 413 def checksum(self, s): 414 i = 0 415 j = int('0', 16) 416 417 while i < len(s): 418 j = int(s[i:i+2], 16) + j 419 i = i+2 420 j = j + int('2B', 16) # 2B is the header command and footer bytes previously added 421 return string.zfill(("%X" % j), 4) 422 322 423 def close_port(self): 323 424 self.ser.close() 425 426 427 class pgsql: 428 def __init__(self): 429 self.sql = None 430 self.username = '' 431 self.pykotauid = '' 432 self.balance = 0 433 self.lifebalance = 0 434 self.alreadyopen = False 435 436 def pgopen(self): 437 try: 438 self.sql = pg.connect(dbname=DBNAME, host=HOST, port=PORT, user=USER, passwd=PASS) 439 self.alreadyopen = True 440 return True 441 except: 442 print "Problem opening database on server " + HOST + "...." 443 return False 444 445 def pgclose(self): 446 self.username = '' 447 self.pykotauid = '' 448 self.balance = 0 449 self.lifebalance = 0 450 self.alreadyopen = False 451 self.sql.close() 452 453 def get_userslist(self, uname,ls): 454 try: 455 query = self.sql.query("SELECT username FROM users WHERE username LIKE '%s'" % (uname+'%')) 456 users = query.getresult() 457 print "Users are ->", users 458 ls.clear() 459 for i in users: 460 ls.append([i[0]]) 461 #self.username = uname 462 return True 463 except: 464 #print "Username is invalid" 465 return False 466 467 468 def get_pykotaid(self, uname): 469 try: 470 query = self.sql.query("SELECT id FROM users WHERE username='%s'" % (uname)) 471 self.pykotauid = (query.dictresult()[0])['id'] 472 print "User ID is ->", self.pykotauid 473 self.username = uname 474 return True 475 except: 476 print "Username is invalid" 477 return False 478 479 def get_pykotabalance(self): 480 try: 481 query = self.sql.query("SELECT balance FROM users WHERE id='%s'" % (self.pykotauid)) 482 self.balance = float((query.dictresult()[0])['balance']) 483 return self.balance 484 except: 485 print "balance sql error..." 486 return None 487 488 def get_pykotalifebalance(self): 489 try: 490 query = self.sql.query("SELECT lifetimepaid FROM users WHERE id='%s'" % (self.pykotauid)) 491 self.lifebalance = float((query.dictresult()[0])['lifetimepaid']) 492 print "%s%.2f" % ("pykotalifebalance -> $", self.lifebalance) 493 return True 494 except: 495 print "lifetimepaid sql error..." 496 return False 497 498 def set_pykotabalances(self, addbalance): 499 newbalance = addbalance + self.balance 500 newlifebalance = self.lifebalance + addbalance 501 try: 502 query = self.sql.query("UPDATE users SET balance=%s, lifetimepaid=%s WHERE id='%s'" % 503 (newbalance, newlifebalance, self.pykotauid)) 504 return True 505 except: 506 print "sql update error..." 507 return False 324 508 325 509 … … 327 511 hwg = gui() 328 512 gtk.main() 329 hwg.sql.close()330 513 print "Goodbye..." 514