Show
Ignore:
Timestamp:
07/13/07 00:30:08 (17 years ago)
Author:
jerome
Message:

Upgraded to the latest version sent by George Farris.

Location:
pykota/trunk/contributed/itcprint
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/contributed/itcprint/itcprint.glade

    r3199 r3207  
    131131 </b> 
    1321321) Insert you smart card and click "<i>Get Balance".</i> 
    133 2) Enter your computer username. 
     1332) Enter your computer username then press <i>TAB</i> key 
    1341343) Increase the "<i>Add Amount"</i> area to a desired amount. 
    1351354) Click the "<i>Transfer to Printing Account"</i> button. 
    136 5) Click the "<i>Eject Card Now"</i> button to retrieve your card. 
     1365) Card will automatically eject after successful transaction. 
    137137</big> 
    138138&lt;b&gt;Note:&lt;/b&gt; Add amount will not exceed card amount.</property> 
     
    246246            <widget class="GtkEntry" id="UsernameEntry"> 
    247247              <property name="visible">True</property> 
     248              <property name="tooltip" translatable="yes" context="yes">Enter your username then press the TAB key</property> 
    248249              <property name="can_focus">True</property> 
    249250              <property name="editable">True</property> 
     
    256257              <signal name="changed" handler="on_UsernameEntry_changed" last_modification_time="Wed, 04 Jul 2007 18:44:48 GMT"/> 
    257258              <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"/> 
    258260            </widget> 
    259261            <packing> 
     
    415417              <property name="wrap">False</property> 
    416418              <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"/> 
    417420            </widget> 
    418421            <packing> 
  • pykota/trunk/contributed/itcprint/itcxfer.py

    r3199 r3207  
    11#! /usr/bin/python 
    22# 
    3 # itcprint.py 
     3# itcxfer.py 
    44# (c) 2007 George Farris <farrisg@shaw.ca>       
    55# 
     
    6464#     Char line      : <STX><NUL><SOH>$<NUL><NUL><NUL><NUL><NUL><NUL><DLE><EOT><SOH><ETX><NUL>?<FF>  
    6565#     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#                                          [______________________________________] [____________________________] 
    6969# 
    7070#   Receive from successful transaction from Reader 
     
    7272#     Hex translation: 0x02 0x00 0x01 0x16 0x03 0x00 0x1C 0x08 
    7373# ===================================================================================================== 
    74  
     74#0200011703001d08 
    7575 
    7676# ----------------------------------------------------------------------------------------------------- 
     
    9090import gtk, gtk.glade, gobject, pg 
    9191 
     92# -------------- User modifiable settings ----------------------------- 
    9293# Database server settings 
    93 HOST = 'localhost' 
     94HOST = '10.31.50.3' 
    9495PORT = 5432 
    9596DBNAME = 'pykota' 
     
    9798PASS = 'secret' 
    9899 
    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. 
     104SEARCH = True 
     105SEARCHLENGTH = 6 
     106 
     107# Serial port settings 
     108SERIAL_PORT = '/dev/ttyUSB0' 
     109BAUD_RATE = 9600 
     110 
     111# Set this to True or False 
     112# If set to True it will not update any cards 
     113TESTMODE = True 
     114 
     115# ------------- End of user modifiable settings ----------------------- 
    100116 
    101117class gui: 
     
    111127                self.printlabel = self.xml.get_widget("PrintBalanceLabel") 
    112128                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) 
    114134                self.cardlabel.set_label('<big><b>unknown</b></big>') 
    115135                self.printlabel.set_label('<big><b>unknown</b></big>') 
    116136                 
    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) 
    137146                 
    138147                #If you wanted to pass an argument, you would use a tuple like this: 
     
    143152                                "on_quit_activate" : (gtk.main_quit), 
    144153                                "on_UsernameEntry_changed" : self.username_changed, 
     154                                "on_Spinbutton_value_changed" : self.spinvalue_changed, 
    145155                                "on_UsernameEntry_focus_out_event" : self.username_entered, 
     156                                "on_UsernameEntry_activate" : (self.username_entered, None), 
    146157                                "on_ItcPrint_destroy" : (gtk.main_quit) } 
    147158                                 
    148159                self.xml.signal_autoconnect (dic) 
    149160                 
     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                 
    150170                return 
    151171 
     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                 
    152179        # I might want to do username search as you type later 
    153180        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                                         
    156204        def username_entered (self, widget, event): 
    157                 self.username = self.utext.get_text() 
    158                 print "Username is ->", self.username 
     205                uname = self.utext.get_text() 
     206                print "Username is ->", uname 
    159207                # This is where we need to look up username in wbinfo 
    160208                 
    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: 
    167223                        result = gtk.RESPONSE_CANCEL 
    168224                        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,  
    170226                                "Your username is invalid or does not exist.\nPlease try re-entering it", ) 
    171227                        result = dlg.run() 
    172228                        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                         
    188261        def xferbutton_clicked (self, widget): 
    189262                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) 
    194276                self.ejectbutton_clicked(None) 
     277                self.spinbutton.set_range(0,float(0)) 
     278                 
    195279                                 
    196280        def getcardbalance_clicked(self, widget): 
     
    201285                        self.cardstate = 1 
    202286                        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 
    203288                        self.spinbutton.set_range(0,float(self.cardbalance)) 
     289                 
     290                if self.cardbalance > 0.1 and self.validuser: 
     291                        self.spinbutton.set_sensitive(True) 
    204292                         
    205293        def ejectbutton_clicked(self, widget): 
    206                 # TODO put a pop dialog here 
    207294                self.sc.eject_card() 
    208295                self.cardlabel.set_label('<big><b>unknown</b></big>') 
     
    210297                self.cardstate = 0 
    211298                self.cardbalance = 0.0 
    212                 self.username = '' 
     299                self.validuser = False 
    213300                self.utext.set_text('') 
    214301                self.addbalance = 0.0 
    215                 self.pykotabalance = 0.0 
    216                 self.pykotalifebalance = 0.0 
    217302                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                                 
    219308                # Is it possible this might not be set 
    220309                try: 
     
    222311                except: 
    223312                        pass 
    224                  
    225313                 
    226314                 
    227315class smartcard: 
    228316        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                         
    232327        # Need comms to contiune to keep card in machine. 
    233328        # This loop keeps the card in until it stops so basically the print  
    234329        # job can release the card after it is finished 
    235330        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) 
    236334                self.ser.write(binascii.a2b_hex("0200010103000704")) 
    237335                s = self.ser.read(8) 
     
    273371        # Get current value from card 
    274372        def get_balance(self): 
     373                # TODO Test checksum 
    275374                self.ser.write(binascii.a2b_hex("0200012103002704")) 
    276375                s1 = self.ser.read(16) 
     376                print binascii.b2a_hex(s1) 
    277377                print "  %s%.2f" % ("Card valued at -> $",float(string.atoi(binascii.b2a_hex(s1[3:11]), 16))/1000) 
    278378                return float(string.atoi(binascii.b2a_hex(s1[3:11]), 16))/1000 
    279379 
    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 
    311402        def eject_card(self): 
    312403                print "  Ejecting card ..." 
     
    320411                return True 
    321412 
     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         
    322423        def close_port(self):    
    323424                self.ser.close() 
     425 
     426 
     427class 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 
    324508 
    325509 
     
    327511        hwg = gui() 
    328512        gtk.main() 
    329         hwg.sql.close()  
    330513        print "Goodbye..." 
     514