Initial commit for unified repo.
8
Linux/LICENSE
Normal file
@ -0,0 +1,8 @@
|
||||
MIT License
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
BIN
Linux/PECOS.ico
Normal file
After Width: | Height: | Size: 28 KiB |
3
Linux/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# pecos
|
||||
|
||||
Polaris Emergency Check Out System
|
BIN
Linux/archive/PECOS-Icon.png
Normal file
After Width: | Height: | Size: 15 KiB |
13
Linux/archive/PECOS-Icon.svg
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
Linux/archive/PECOS.ico
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
Linux/bg-01.png
Normal file
After Width: | Height: | Size: 371 KiB |
BIN
Linux/checkouts.db
Normal file
BIN
Linux/emptybase.db
Normal file
24
Linux/export.html
Normal file
@ -0,0 +1,24 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
PECOS Export - 13:36:32 on Tuesday, November 17, 2020
|
||||
</title>
|
||||
<h2>PECOS Export File – 13:36:32 on Tuesday, November 17, 2020</h2>
|
||||
<hr>
|
||||
<style type="text/css">
|
||||
.tg {border-collapse:collapse;border-spacing:0;}
|
||||
.tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px; overflow:hidden;padding:10px 5px;word-break:normal;}
|
||||
.tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
|
||||
.tg .tg-cly1{text-align:left;vertical-align:middle}
|
||||
</style>
|
||||
<table class="tg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tg-cly1"><strong>Patron Library Card</strong></th><th class="tg-cly1"><strong>Batch Number</strong></th><th class="tg-cly1"><strong>Item Barcode</strong>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="tg-cly1"><img src="patron/1230004231819.svg" width=200></th><th class="tg-cly1"><strong>Batch: </strong>2</th><th class="tg-cly1"><img src="item/1234567890.svg" width=200>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="tg-cly1"><img src="patron/1230004231819.svg" width=200></th><th class="tg-cly1"><strong>Batch: </strong>2</th><th class="tg-cly1"><img src="item/1234567891.svg" width=200>
|
||||
</tr>
|
1
Linux/item/Item data will go here.txt
Normal file
@ -0,0 +1 @@
|
||||
Item data will go here.
|
1
Linux/patron/Patron data will go here.txt
Normal file
@ -0,0 +1 @@
|
||||
Patron data will go here.
|
288
Linux/pecos.py
Normal file
@ -0,0 +1,288 @@
|
||||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# GUI module generated by PAGE version 5.4
|
||||
# in conjunction with Tcl version 8.6
|
||||
# Sep 30, 2020 01:32:51 PM CDT platform: Linux
|
||||
|
||||
import sys
|
||||
from PIL import Image, ImageTk
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
from datetime import date
|
||||
import os
|
||||
import shutil
|
||||
from tkinter import messagebox
|
||||
from xlsxwriter.workbook import Workbook
|
||||
from barcode import Code39
|
||||
from barcode.writer import ImageWriter
|
||||
import subprocess
|
||||
|
||||
try:
|
||||
import Tkinter as tk
|
||||
except ImportError:
|
||||
import tkinter as tk
|
||||
|
||||
try:
|
||||
import ttk
|
||||
py3 = False
|
||||
except ImportError:
|
||||
import tkinter.ttk as ttk
|
||||
py3 = True
|
||||
|
||||
import pecos_support
|
||||
|
||||
# --- SET UP A TIMESTAMP FUNCTION THAT UPDATES PROPERLY ---
|
||||
def timestamp():
|
||||
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
def ReportTime():
|
||||
return datetime.now().strftime('%H:%M:%S on %A, %B %d, %Y')
|
||||
|
||||
|
||||
def vp_start_gui():
|
||||
'''Starting point when module is the main routine.'''
|
||||
global val, w, root
|
||||
root = tk.Tk()
|
||||
top = Toplevel1 (root)
|
||||
pecos_support.init(root, top)
|
||||
root.iconbitmap('PECOS.ico')
|
||||
root.mainloop()
|
||||
|
||||
w = None
|
||||
def create_Toplevel1(rt, *args, **kwargs):
|
||||
'''Starting point when module is imported by another module.
|
||||
Correct form of call: 'create_Toplevel1(root, *args, **kwargs)' .'''
|
||||
global w, w_win, root
|
||||
#rt = root
|
||||
root = rt
|
||||
w = tk.Toplevel (root)
|
||||
top = Toplevel1 (w)
|
||||
pecos_support.init(w, top, *args, **kwargs)
|
||||
return (w, top)
|
||||
|
||||
def destroy_Toplevel1():
|
||||
global w
|
||||
w.destroy()
|
||||
w = None
|
||||
# Close database connection
|
||||
conn.close()
|
||||
|
||||
class Toplevel1:
|
||||
def __init__(self, top=None):
|
||||
'''This class configures and populates the toplevel window.
|
||||
top is the toplevel containing window.'''
|
||||
_bgcolor = '#d9d9d9' # X11 color: 'gray85'
|
||||
_fgcolor = '#000000' # X11 color: 'black'
|
||||
_compcolor = '#d9d9d9' # X11 color: 'gray85'
|
||||
_ana1color = '#d9d9d9' # X11 color: 'gray85'
|
||||
_ana2color = '#ececec' # Closest X11 color: 'gray92'
|
||||
|
||||
top.geometry("600x500+650+150")
|
||||
top.minsize(1, 1)
|
||||
top.maxsize(1905, 1050)
|
||||
top.resizable(0, 0)
|
||||
top.title("PECOS - Polaris Emergency Check Out System 1.0b (Windows)")
|
||||
|
||||
# --- CHECKOUT ITEM AND UPDATE DATABASE ---
|
||||
def CheckOutItem(event=None):
|
||||
if len(self.item_entry.get()) == 0:
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
|
||||
row = c.execute("SELECT BatchNumber FROM Batches ORDER BY BatchNumber DESC LIMIT 1").fetchone()
|
||||
if row is not None:
|
||||
GetLastBatchNumber = row[0]
|
||||
CurrentBatchNumber = GetLastBatchNumber + 1
|
||||
|
||||
c.execute("INSERT INTO Batches VALUES (:BatchNumber, :PatronID)",
|
||||
{
|
||||
'BatchNumber': CurrentBatchNumber,
|
||||
'PatronID': self.patron_entry.get()
|
||||
}
|
||||
)
|
||||
# Commit changes
|
||||
conn.commit()
|
||||
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.item_entry.delete(0, tk.END)
|
||||
self.patron_entry.configure(state='normal')
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.patron_entry.focus_set()
|
||||
|
||||
else:
|
||||
# Set up database connections
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
|
||||
row = c.execute("SELECT BatchNumber FROM Batches ORDER BY BatchNumber DESC LIMIT 1").fetchone()
|
||||
if row is not None:
|
||||
GetLastBatchNumber = row[0]
|
||||
CurrentBatchNumber = GetLastBatchNumber + 1
|
||||
|
||||
c.execute("INSERT INTO CheckOuts VALUES (:PatronID, :ItemID, :TransactionDateTime, :ItemLink, :PatronLink, :BatchNumber)",
|
||||
{
|
||||
'PatronID': self.patron_entry.get(),
|
||||
'ItemID': self.item_entry.get(),
|
||||
'TransactionDateTime': timestamp(),
|
||||
'ItemLink': ("item/" + self.item_entry.get()),
|
||||
'PatronLink': ("patron/" + self.patron_entry.get()),
|
||||
'BatchNumber': CurrentBatchNumber
|
||||
}
|
||||
)
|
||||
# Commit changes
|
||||
conn.commit()
|
||||
|
||||
#PatronBarcode = self.patron_entry.get()
|
||||
PatCode = Code39(self.patron_entry.get(), add_checksum=False)
|
||||
PatCode.save("patron/"+self.patron_entry.get())
|
||||
|
||||
ItemCode = Code39(self.item_entry.get(), add_checksum=False)
|
||||
ItemCode.save("item/"+self.item_entry.get())
|
||||
|
||||
self.item_entry.delete(0, tk.END)
|
||||
|
||||
# --- PATRON SCANNED - MOVE TO ITEM FIELD ---
|
||||
def ChangeFocus(event):
|
||||
self.item_entry.focus_set()
|
||||
self.patron_entry.configure(state='disabled')
|
||||
|
||||
|
||||
# --- FINISH CHECKOUT AND CLEAR FIELDS ---
|
||||
def CheckOutComplete():
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
|
||||
row = c.execute("SELECT BatchNumber FROM Batches ORDER BY BatchNumber DESC LIMIT 1").fetchone()
|
||||
if row is not None:
|
||||
GetLastBatchNumber = row[0]
|
||||
CurrentBatchNumber = GetLastBatchNumber + 1
|
||||
|
||||
c.execute("INSERT INTO Batches VALUES (:BatchNumber, :PatronID)",
|
||||
{
|
||||
'BatchNumber': CurrentBatchNumber,
|
||||
'PatronID': self.patron_entry.get()
|
||||
}
|
||||
)
|
||||
# Commit changes
|
||||
conn.commit()
|
||||
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.item_entry.delete(0, tk.END)
|
||||
self.patron_entry.configure(state='normal')
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.patron_entry.focus_set()
|
||||
|
||||
|
||||
# --- DELETE THE CURRENT DATABASE AND SUPPLANT WITH AN EMPTY ONE ---
|
||||
def ClearDatabase():
|
||||
self.ClearConfirm = tk.messagebox.askquestion ('PECOS - Clear Database','Are you sure you wish to clear the database? This cannot be undone!')
|
||||
if self.ClearConfirm == 'yes':
|
||||
# Next two lines commented out in Windows version - the connection commands work on macOS
|
||||
#conn = sqlite3.connect('checkouts.db') # Re-establish connection to the database
|
||||
#conn.close # Close out the current database
|
||||
os.remove("checkouts.db") # Delete the current database
|
||||
shutil.copy("emptybase.db", "checkouts.db") # Copy over an empty database
|
||||
shutil.rmtree('item')
|
||||
shutil.rmtree('patron')
|
||||
os.makedirs('item')
|
||||
os.makedirs('patron')
|
||||
# Next two lines commented out in Windows version - the connection commands work on macOS
|
||||
#conn = sqlite3.connect('checkouts.db') # Restablish connection to the database
|
||||
#c = conn.cursor()
|
||||
else:
|
||||
messagebox.showinfo('PECOS - Database Retained','Database retained. No changes made.')
|
||||
|
||||
# --- EXPORT DATABASE TO HTML ---
|
||||
def ExportDatabase():
|
||||
if os.path.exists("export.html"):
|
||||
os.remove("export.html")
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
with open("export.html", "w") as f:
|
||||
f.write("<html>\n")
|
||||
f.write("<head>\n")
|
||||
f.write("<title>\n")
|
||||
f.write("PECOS Export - " + ReportTime() + "\n")
|
||||
f.write("</title>\n")
|
||||
f.write("<h2>PECOS Export File – " + ReportTime() + "</h2>\n<hr>\n")
|
||||
f.write("<style type=\"text/css\">\n")
|
||||
f.write(".tg {border-collapse:collapse;border-spacing:0;}\n")
|
||||
f.write(".tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px; overflow:hidden;padding:10px 5px;word-break:normal;}\n")
|
||||
f.write(".tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}\n")
|
||||
f.write(".tg .tg-cly1{text-align:left;vertical-align:middle}\n")
|
||||
f.write("</style>\n")
|
||||
f.write("<table class=\"tg\">\n")
|
||||
f.write("<thead>\n")
|
||||
f.write("<tr>\n")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Patron Library Card</strong></th>")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Batch Number</strong></th>")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Item Barcode</strong>\n")
|
||||
f.write("</tr>\n")
|
||||
for row in c.execute("SELECT BatchNumber, PatronLink, ItemLink FROM CheckOuts ORDER By BatchNumber"):
|
||||
f.write("<tr>\n")
|
||||
f.write("<th class=\"tg-cly1\"><img src=\"" + row[1] + ".svg\" width=200></th>")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Batch: </strong>" + str(row[0]) + "</th>")
|
||||
f.write("<th class=\"tg-cly1\"><img src=\"" + row[2] + ".svg\" width=200>\n")
|
||||
f.write("</tr>\n")
|
||||
|
||||
subprocess.run(['open', 'export.html'], check=True) # Open export.html in the default web browser (macOS)
|
||||
#os.startfile('export.html') # Open export.html in the default web browser (Windows)
|
||||
|
||||
|
||||
|
||||
self.Canvas1 = tk.Canvas(top)
|
||||
self.image = ImageTk.PhotoImage(Image.open("bg-01.png"))
|
||||
self.Canvas1.create_image(0,0,anchor="nw",image=self.image)
|
||||
self.Canvas1.place(relx=0.0, rely=0.0, relheight=1.0, relwidth=1.0)
|
||||
self.Canvas1.configure(borderwidth="2")
|
||||
self.Canvas1.configure(relief="ridge")
|
||||
self.Canvas1.configure(selectbackground="blue")
|
||||
self.Canvas1.configure(selectforeground="white")
|
||||
|
||||
self.Frame1 = tk.Frame(self.Canvas1)
|
||||
self.Frame1.place(relx=0.05, rely=0.06, relheight=0.17, relwidth=0.908)
|
||||
self.Frame1.configure(relief='sunken')
|
||||
self.Frame1.configure(borderwidth="2")
|
||||
self.Frame1.configure(relief="sunken")
|
||||
|
||||
self.patron_label = tk.Label(self.Canvas1)
|
||||
self.patron_label.place(relx=0.067, rely=0.08, height=19, width=100)
|
||||
self.patron_label.configure(text='''Patron barcode:''')
|
||||
|
||||
self.patron_entry = tk.Entry(self.Canvas1)
|
||||
self.patron_entry.place(relx=0.25, rely=0.08,height=25, relwidth=0.377)
|
||||
self.patron_entry.configure(background="white")
|
||||
self.patron_entry.configure(font="TkFixedFont")
|
||||
self.patron_entry.bind('<Return>', ChangeFocus)
|
||||
|
||||
self.item_label = tk.Label(self.Canvas1)
|
||||
self.item_label.place(relx=0.067, rely=0.16, height=19, width=89)
|
||||
self.item_label.configure(text='''Item barcode:''')
|
||||
|
||||
self.item_entry = tk.Entry(self.Canvas1)
|
||||
self.item_entry.place(relx=0.25, rely=0.16,height=25, relwidth=0.377)
|
||||
self.item_entry.configure(background="white")
|
||||
self.item_entry.configure(font="TkFixedFont")
|
||||
self.item_entry.bind('<Return>', CheckOutItem)
|
||||
|
||||
self.finish_button = tk.Button(self.Canvas1, command=CheckOutComplete)
|
||||
self.finish_button.place(relx=0.7, rely=0.12, height=29, width=123)
|
||||
self.finish_button.configure(text='''Finish checkout''')
|
||||
|
||||
self.LowerFrame = tk.Frame(self.Canvas1)
|
||||
self.LowerFrame.place(relx=0.05, rely=0.78, relheight=0.13, relwidth=0.908)
|
||||
self.LowerFrame.configure(relief='sunken')
|
||||
self.LowerFrame.configure(borderwidth="2")
|
||||
self.LowerFrame.configure(relief="sunken")
|
||||
|
||||
self.export_button = tk.Button(self.LowerFrame, command=ExportDatabase)
|
||||
self.export_button.place(relx=0.092, rely=0.308, height=29, width=130)
|
||||
self.export_button.configure(text='''Export Checkouts''')
|
||||
|
||||
self.clear_button = tk.Button(self.LowerFrame, command=ClearDatabase)
|
||||
self.clear_button.place(relx=0.679, rely=0.308, height=29, width=130)
|
||||
self.clear_button.configure(text='''Clear Database''')
|
||||
|
||||
if __name__ == '__main__':
|
||||
vp_start_gui()
|
43
Linux/pecos_support.py
Normal file
@ -0,0 +1,43 @@
|
||||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Support module generated by PAGE version 5.4
|
||||
# in conjunction with Tcl version 8.6
|
||||
# Sep 30, 2020 01:33:24 PM CDT platform: Linux
|
||||
|
||||
import sys
|
||||
from PIL import Image, ImageTk
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
from datetime import date
|
||||
|
||||
try:
|
||||
import Tkinter as tk
|
||||
except ImportError:
|
||||
import tkinter as tk
|
||||
|
||||
try:
|
||||
import ttk
|
||||
py3 = False
|
||||
except ImportError:
|
||||
import tkinter.ttk as ttk
|
||||
py3 = True
|
||||
|
||||
# --- DEFINE FUNCTIONS ---
|
||||
|
||||
def init(top, gui, *args, **kwargs):
|
||||
global w, top_level, root
|
||||
w = gui
|
||||
top_level = top
|
||||
root = top
|
||||
|
||||
def destroy_window():
|
||||
# Function which closes the window.
|
||||
global top_level
|
||||
top_level.destroy()
|
||||
top_level = None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import pecos
|
||||
pecos.vp_start_gui()
|
BIN
PECOS Manual.pages
Executable file
@ -1,3 +1,3 @@
|
||||
# pecos-unified
|
||||
# PECOS Unified
|
||||
|
||||
Polaris Emergency Check Out System - unified code repository for Windows, macOS, and Linux.
|
8
Windows/LICENSE
Normal file
@ -0,0 +1,8 @@
|
||||
MIT License
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
BIN
Windows/PECOS.ico
Normal file
After Width: | Height: | Size: 28 KiB |
3
Windows/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# pecos
|
||||
|
||||
Polaris Emergency Check Out System
|
BIN
Windows/archive/PECOS-Icon.png
Normal file
After Width: | Height: | Size: 15 KiB |
13
Windows/archive/PECOS-Icon.svg
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
Windows/archive/PECOS.ico
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
Windows/bg-01.png
Normal file
After Width: | Height: | Size: 371 KiB |
BIN
Windows/checkouts.db
Normal file
BIN
Windows/emptybase.db
Normal file
36
Windows/export.html
Normal file
@ -0,0 +1,36 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
PECOS Export - 06:14:31 on Wednesday, November 11, 2020
|
||||
</title>
|
||||
<h2>PECOS Export File – 06:14:31 on Wednesday, November 11, 2020</h2>
|
||||
<hr>
|
||||
<style type="text/css">
|
||||
.tg {border-collapse:collapse;border-spacing:0;}
|
||||
.tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px; overflow:hidden;padding:10px 5px;word-break:normal;}
|
||||
.tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
|
||||
.tg .tg-cly1{text-align:left;vertical-align:middle}
|
||||
</style>
|
||||
<table class="tg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tg-cly1"><strong>Patron Library Card</strong></th><th class="tg-cly1"><strong>Batch Number</strong></th><th class="tg-cly1"><strong>Item Barcode</strong>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="tg-cly1"><img src="patron/1230004231819.svg" width=200></th><th class="tg-cly1"><strong>Batch: </strong>2</th><th class="tg-cly1"><img src="item/1234567890.svg" width=200>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="tg-cly1"><img src="patron/1230004231819.svg" width=200></th><th class="tg-cly1"><strong>Batch: </strong>2</th><th class="tg-cly1"><img src="item/1234567891.svg" width=200>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="tg-cly1"><img src="patron/1230004231819.svg" width=200></th><th class="tg-cly1"><strong>Batch: </strong>2</th><th class="tg-cly1"><img src="item/1234567892.svg" width=200>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="tg-cly1"><img src="patron/1230004233141.svg" width=200></th><th class="tg-cly1"><strong>Batch: </strong>3</th><th class="tg-cly1"><img src="item/1234567893.svg" width=200>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="tg-cly1"><img src="patron/1230004233141.svg" width=200></th><th class="tg-cly1"><strong>Batch: </strong>3</th><th class="tg-cly1"><img src="item/1234567894.svg" width=200>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="tg-cly1"><img src="patron/1230004233141.svg" width=200></th><th class="tg-cly1"><strong>Batch: </strong>3</th><th class="tg-cly1"><img src="item/1234567895.svg" width=200>
|
||||
</tr>
|
1
Windows/item/Item data will go here.txt
Normal file
@ -0,0 +1 @@
|
||||
Item data will go here.
|
1
Windows/patron/Patron data will go here.txt
Normal file
@ -0,0 +1 @@
|
||||
Patron data will go here.
|
288
Windows/pecos.py
Normal file
@ -0,0 +1,288 @@
|
||||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# GUI module generated by PAGE version 5.4
|
||||
# in conjunction with Tcl version 8.6
|
||||
# Sep 30, 2020 01:32:51 PM CDT platform: Linux
|
||||
|
||||
import sys
|
||||
from PIL import Image, ImageTk
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
from datetime import date
|
||||
import os
|
||||
import shutil
|
||||
from tkinter import messagebox
|
||||
from xlsxwriter.workbook import Workbook
|
||||
from barcode import Code39
|
||||
from barcode.writer import ImageWriter
|
||||
import subprocess
|
||||
|
||||
try:
|
||||
import Tkinter as tk
|
||||
except ImportError:
|
||||
import tkinter as tk
|
||||
|
||||
try:
|
||||
import ttk
|
||||
py3 = False
|
||||
except ImportError:
|
||||
import tkinter.ttk as ttk
|
||||
py3 = True
|
||||
|
||||
import pecos_support
|
||||
|
||||
# --- SET UP A TIMESTAMP FUNCTION THAT UPDATES PROPERLY ---
|
||||
def timestamp():
|
||||
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
def ReportTime():
|
||||
return datetime.now().strftime('%H:%M:%S on %A, %B %d, %Y')
|
||||
|
||||
|
||||
def vp_start_gui():
|
||||
'''Starting point when module is the main routine.'''
|
||||
global val, w, root
|
||||
root = tk.Tk()
|
||||
top = Toplevel1 (root)
|
||||
pecos_support.init(root, top)
|
||||
root.iconbitmap('PECOS.ico')
|
||||
root.mainloop()
|
||||
|
||||
w = None
|
||||
def create_Toplevel1(rt, *args, **kwargs):
|
||||
'''Starting point when module is imported by another module.
|
||||
Correct form of call: 'create_Toplevel1(root, *args, **kwargs)' .'''
|
||||
global w, w_win, root
|
||||
#rt = root
|
||||
root = rt
|
||||
w = tk.Toplevel (root)
|
||||
top = Toplevel1 (w)
|
||||
pecos_support.init(w, top, *args, **kwargs)
|
||||
return (w, top)
|
||||
|
||||
def destroy_Toplevel1():
|
||||
global w
|
||||
w.destroy()
|
||||
w = None
|
||||
# Close database connection
|
||||
conn.close()
|
||||
|
||||
class Toplevel1:
|
||||
def __init__(self, top=None):
|
||||
'''This class configures and populates the toplevel window.
|
||||
top is the toplevel containing window.'''
|
||||
_bgcolor = '#d9d9d9' # X11 color: 'gray85'
|
||||
_fgcolor = '#000000' # X11 color: 'black'
|
||||
_compcolor = '#d9d9d9' # X11 color: 'gray85'
|
||||
_ana1color = '#d9d9d9' # X11 color: 'gray85'
|
||||
_ana2color = '#ececec' # Closest X11 color: 'gray92'
|
||||
|
||||
top.geometry("600x500+650+150")
|
||||
top.minsize(1, 1)
|
||||
top.maxsize(1905, 1050)
|
||||
top.resizable(0, 0)
|
||||
top.title("PECOS - Polaris Emergency Check Out System 1.0b (Windows)")
|
||||
|
||||
# --- CHECKOUT ITEM AND UPDATE DATABASE ---
|
||||
def CheckOutItem(event=None):
|
||||
if len(self.item_entry.get()) == 0:
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
|
||||
row = c.execute("SELECT BatchNumber FROM Batches ORDER BY BatchNumber DESC LIMIT 1").fetchone()
|
||||
if row is not None:
|
||||
GetLastBatchNumber = row[0]
|
||||
CurrentBatchNumber = GetLastBatchNumber + 1
|
||||
|
||||
c.execute("INSERT INTO Batches VALUES (:BatchNumber, :PatronID)",
|
||||
{
|
||||
'BatchNumber': CurrentBatchNumber,
|
||||
'PatronID': self.patron_entry.get()
|
||||
}
|
||||
)
|
||||
# Commit changes
|
||||
conn.commit()
|
||||
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.item_entry.delete(0, tk.END)
|
||||
self.patron_entry.configure(state='normal')
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.patron_entry.focus_set()
|
||||
|
||||
else:
|
||||
# Set up database connections
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
|
||||
row = c.execute("SELECT BatchNumber FROM Batches ORDER BY BatchNumber DESC LIMIT 1").fetchone()
|
||||
if row is not None:
|
||||
GetLastBatchNumber = row[0]
|
||||
CurrentBatchNumber = GetLastBatchNumber + 1
|
||||
|
||||
c.execute("INSERT INTO CheckOuts VALUES (:PatronID, :ItemID, :TransactionDateTime, :ItemLink, :PatronLink, :BatchNumber)",
|
||||
{
|
||||
'PatronID': self.patron_entry.get(),
|
||||
'ItemID': self.item_entry.get(),
|
||||
'TransactionDateTime': timestamp(),
|
||||
'ItemLink': ("item/" + self.item_entry.get()),
|
||||
'PatronLink': ("patron/" + self.patron_entry.get()),
|
||||
'BatchNumber': CurrentBatchNumber
|
||||
}
|
||||
)
|
||||
# Commit changes
|
||||
conn.commit()
|
||||
|
||||
#PatronBarcode = self.patron_entry.get()
|
||||
PatCode = Code39(self.patron_entry.get(), add_checksum=False)
|
||||
PatCode.save("patron/"+self.patron_entry.get())
|
||||
|
||||
ItemCode = Code39(self.item_entry.get(), add_checksum=False)
|
||||
ItemCode.save("item/"+self.item_entry.get())
|
||||
|
||||
self.item_entry.delete(0, tk.END)
|
||||
|
||||
# --- PATRON SCANNED - MOVE TO ITEM FIELD ---
|
||||
def ChangeFocus(event):
|
||||
self.item_entry.focus_set()
|
||||
self.patron_entry.configure(state='disabled')
|
||||
|
||||
|
||||
# --- FINISH CHECKOUT AND CLEAR FIELDS ---
|
||||
def CheckOutComplete():
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
|
||||
row = c.execute("SELECT BatchNumber FROM Batches ORDER BY BatchNumber DESC LIMIT 1").fetchone()
|
||||
if row is not None:
|
||||
GetLastBatchNumber = row[0]
|
||||
CurrentBatchNumber = GetLastBatchNumber + 1
|
||||
|
||||
c.execute("INSERT INTO Batches VALUES (:BatchNumber, :PatronID)",
|
||||
{
|
||||
'BatchNumber': CurrentBatchNumber,
|
||||
'PatronID': self.patron_entry.get()
|
||||
}
|
||||
)
|
||||
# Commit changes
|
||||
conn.commit()
|
||||
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.item_entry.delete(0, tk.END)
|
||||
self.patron_entry.configure(state='normal')
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.patron_entry.focus_set()
|
||||
|
||||
|
||||
# --- DELETE THE CURRENT DATABASE AND SUPPLANT WITH AN EMPTY ONE ---
|
||||
def ClearDatabase():
|
||||
self.ClearConfirm = tk.messagebox.askquestion ('PECOS - Clear Database','Are you sure you wish to clear the database? This cannot be undone!')
|
||||
if self.ClearConfirm == 'yes':
|
||||
# Next two lines commented out in Windows version - the connection commands work on macOS
|
||||
#conn = sqlite3.connect('checkouts.db') # Re-establish connection to the database
|
||||
#conn.close # Close out the current database
|
||||
os.remove("checkouts.db") # Delete the current database
|
||||
shutil.copy("emptybase.db", "checkouts.db") # Copy over an empty database
|
||||
shutil.rmtree('item')
|
||||
shutil.rmtree('patron')
|
||||
os.makedirs('item')
|
||||
os.makedirs('patron')
|
||||
# Next two lines commented out in Windows version - the connection commands work on macOS
|
||||
#conn = sqlite3.connect('checkouts.db') # Restablish connection to the database
|
||||
#c = conn.cursor()
|
||||
else:
|
||||
messagebox.showinfo('PECOS - Database Retained','Database retained. No changes made.')
|
||||
|
||||
# --- EXPORT DATABASE TO HTML ---
|
||||
def ExportDatabase():
|
||||
if os.path.exists("export.html"):
|
||||
os.remove("export.html")
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
with open("export.html", "w") as f:
|
||||
f.write("<html>\n")
|
||||
f.write("<head>\n")
|
||||
f.write("<title>\n")
|
||||
f.write("PECOS Export - " + ReportTime() + "\n")
|
||||
f.write("</title>\n")
|
||||
f.write("<h2>PECOS Export File – " + ReportTime() + "</h2>\n<hr>\n")
|
||||
f.write("<style type=\"text/css\">\n")
|
||||
f.write(".tg {border-collapse:collapse;border-spacing:0;}\n")
|
||||
f.write(".tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px; overflow:hidden;padding:10px 5px;word-break:normal;}\n")
|
||||
f.write(".tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}\n")
|
||||
f.write(".tg .tg-cly1{text-align:left;vertical-align:middle}\n")
|
||||
f.write("</style>\n")
|
||||
f.write("<table class=\"tg\">\n")
|
||||
f.write("<thead>\n")
|
||||
f.write("<tr>\n")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Patron Library Card</strong></th>")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Batch Number</strong></th>")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Item Barcode</strong>\n")
|
||||
f.write("</tr>\n")
|
||||
for row in c.execute("SELECT BatchNumber, PatronLink, ItemLink FROM CheckOuts ORDER By BatchNumber"):
|
||||
f.write("<tr>\n")
|
||||
f.write("<th class=\"tg-cly1\"><img src=\"" + row[1] + ".svg\" width=200></th>")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Batch: </strong>" + str(row[0]) + "</th>")
|
||||
f.write("<th class=\"tg-cly1\"><img src=\"" + row[2] + ".svg\" width=200>\n")
|
||||
f.write("</tr>\n")
|
||||
|
||||
#subprocess.run(['open', 'export.html'], check=True) # Open export.html in the default web browser (macOS)
|
||||
os.startfile('export.html') # Open export.html in the default web browser (Windows)
|
||||
|
||||
|
||||
|
||||
self.Canvas1 = tk.Canvas(top)
|
||||
self.image = ImageTk.PhotoImage(Image.open("bg-01.png"))
|
||||
self.Canvas1.create_image(0,0,anchor="nw",image=self.image)
|
||||
self.Canvas1.place(relx=0.0, rely=0.0, relheight=1.0, relwidth=1.0)
|
||||
self.Canvas1.configure(borderwidth="2")
|
||||
self.Canvas1.configure(relief="ridge")
|
||||
self.Canvas1.configure(selectbackground="blue")
|
||||
self.Canvas1.configure(selectforeground="white")
|
||||
|
||||
self.Frame1 = tk.Frame(self.Canvas1)
|
||||
self.Frame1.place(relx=0.05, rely=0.06, relheight=0.17, relwidth=0.908)
|
||||
self.Frame1.configure(relief='sunken')
|
||||
self.Frame1.configure(borderwidth="2")
|
||||
self.Frame1.configure(relief="sunken")
|
||||
|
||||
self.patron_label = tk.Label(self.Canvas1)
|
||||
self.patron_label.place(relx=0.067, rely=0.08, height=19, width=100)
|
||||
self.patron_label.configure(text='''Patron barcode:''')
|
||||
|
||||
self.patron_entry = tk.Entry(self.Canvas1)
|
||||
self.patron_entry.place(relx=0.25, rely=0.08,height=25, relwidth=0.377)
|
||||
self.patron_entry.configure(background="white")
|
||||
self.patron_entry.configure(font="TkFixedFont")
|
||||
self.patron_entry.bind('<Return>', ChangeFocus)
|
||||
|
||||
self.item_label = tk.Label(self.Canvas1)
|
||||
self.item_label.place(relx=0.067, rely=0.16, height=19, width=89)
|
||||
self.item_label.configure(text='''Item barcode:''')
|
||||
|
||||
self.item_entry = tk.Entry(self.Canvas1)
|
||||
self.item_entry.place(relx=0.25, rely=0.16,height=25, relwidth=0.377)
|
||||
self.item_entry.configure(background="white")
|
||||
self.item_entry.configure(font="TkFixedFont")
|
||||
self.item_entry.bind('<Return>', CheckOutItem)
|
||||
|
||||
self.finish_button = tk.Button(self.Canvas1, command=CheckOutComplete)
|
||||
self.finish_button.place(relx=0.7, rely=0.12, height=29, width=123)
|
||||
self.finish_button.configure(text='''Finish checkout''')
|
||||
|
||||
self.LowerFrame = tk.Frame(self.Canvas1)
|
||||
self.LowerFrame.place(relx=0.05, rely=0.78, relheight=0.13, relwidth=0.908)
|
||||
self.LowerFrame.configure(relief='sunken')
|
||||
self.LowerFrame.configure(borderwidth="2")
|
||||
self.LowerFrame.configure(relief="sunken")
|
||||
|
||||
self.export_button = tk.Button(self.LowerFrame, command=ExportDatabase)
|
||||
self.export_button.place(relx=0.092, rely=0.308, height=29, width=130)
|
||||
self.export_button.configure(text='''Export Checkouts''')
|
||||
|
||||
self.clear_button = tk.Button(self.LowerFrame, command=ClearDatabase)
|
||||
self.clear_button.place(relx=0.679, rely=0.308, height=29, width=130)
|
||||
self.clear_button.configure(text='''Clear Database''')
|
||||
|
||||
if __name__ == '__main__':
|
||||
vp_start_gui()
|
43
Windows/pecos_support.py
Normal file
@ -0,0 +1,43 @@
|
||||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Support module generated by PAGE version 5.4
|
||||
# in conjunction with Tcl version 8.6
|
||||
# Sep 30, 2020 01:33:24 PM CDT platform: Linux
|
||||
|
||||
import sys
|
||||
from PIL import Image, ImageTk
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
from datetime import date
|
||||
|
||||
try:
|
||||
import Tkinter as tk
|
||||
except ImportError:
|
||||
import tkinter as tk
|
||||
|
||||
try:
|
||||
import ttk
|
||||
py3 = False
|
||||
except ImportError:
|
||||
import tkinter.ttk as ttk
|
||||
py3 = True
|
||||
|
||||
# --- DEFINE FUNCTIONS ---
|
||||
|
||||
def init(top, gui, *args, **kwargs):
|
||||
global w, top_level, root
|
||||
w = gui
|
||||
top_level = top
|
||||
root = top
|
||||
|
||||
def destroy_window():
|
||||
# Function which closes the window.
|
||||
global top_level
|
||||
top_level.destroy()
|
||||
top_level = None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import pecos
|
||||
pecos.vp_start_gui()
|
8
macOS/LICENSE
Normal file
@ -0,0 +1,8 @@
|
||||
MIT License
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
BIN
macOS/PECOS.ico
Normal file
After Width: | Height: | Size: 28 KiB |
3
macOS/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# pecos
|
||||
|
||||
Polaris Emergency Check Out System
|
BIN
macOS/archive/PECOS-Icon.png
Normal file
After Width: | Height: | Size: 15 KiB |
13
macOS/archive/PECOS-Icon.svg
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
macOS/archive/PECOS.ico
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
macOS/bg-01.png
Normal file
After Width: | Height: | Size: 371 KiB |
BIN
macOS/checkouts.db
Normal file
BIN
macOS/emptybase.db
Normal file
24
macOS/export.html
Normal file
@ -0,0 +1,24 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
PECOS Export - 13:36:32 on Tuesday, November 17, 2020
|
||||
</title>
|
||||
<h2>PECOS Export File – 13:36:32 on Tuesday, November 17, 2020</h2>
|
||||
<hr>
|
||||
<style type="text/css">
|
||||
.tg {border-collapse:collapse;border-spacing:0;}
|
||||
.tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px; overflow:hidden;padding:10px 5px;word-break:normal;}
|
||||
.tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
|
||||
.tg .tg-cly1{text-align:left;vertical-align:middle}
|
||||
</style>
|
||||
<table class="tg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tg-cly1"><strong>Patron Library Card</strong></th><th class="tg-cly1"><strong>Batch Number</strong></th><th class="tg-cly1"><strong>Item Barcode</strong>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="tg-cly1"><img src="patron/1230004231819.svg" width=200></th><th class="tg-cly1"><strong>Batch: </strong>2</th><th class="tg-cly1"><img src="item/1234567890.svg" width=200>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="tg-cly1"><img src="patron/1230004231819.svg" width=200></th><th class="tg-cly1"><strong>Batch: </strong>2</th><th class="tg-cly1"><img src="item/1234567891.svg" width=200>
|
||||
</tr>
|
1
macOS/item/Item data will go here.txt
Normal file
@ -0,0 +1 @@
|
||||
Item data will go here.
|
1
macOS/patron/Patron data will go here.txt
Normal file
@ -0,0 +1 @@
|
||||
Patron data will go here.
|
288
macOS/pecos.py
Normal file
@ -0,0 +1,288 @@
|
||||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# GUI module generated by PAGE version 5.4
|
||||
# in conjunction with Tcl version 8.6
|
||||
# Sep 30, 2020 01:32:51 PM CDT platform: Linux
|
||||
|
||||
import sys
|
||||
from PIL import Image, ImageTk
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
from datetime import date
|
||||
import os
|
||||
import shutil
|
||||
from tkinter import messagebox
|
||||
from xlsxwriter.workbook import Workbook
|
||||
from barcode import Code39
|
||||
from barcode.writer import ImageWriter
|
||||
import subprocess
|
||||
|
||||
try:
|
||||
import Tkinter as tk
|
||||
except ImportError:
|
||||
import tkinter as tk
|
||||
|
||||
try:
|
||||
import ttk
|
||||
py3 = False
|
||||
except ImportError:
|
||||
import tkinter.ttk as ttk
|
||||
py3 = True
|
||||
|
||||
import pecos_support
|
||||
|
||||
# --- SET UP A TIMESTAMP FUNCTION THAT UPDATES PROPERLY ---
|
||||
def timestamp():
|
||||
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
def ReportTime():
|
||||
return datetime.now().strftime('%H:%M:%S on %A, %B %d, %Y')
|
||||
|
||||
|
||||
def vp_start_gui():
|
||||
'''Starting point when module is the main routine.'''
|
||||
global val, w, root
|
||||
root = tk.Tk()
|
||||
top = Toplevel1 (root)
|
||||
pecos_support.init(root, top)
|
||||
root.iconbitmap('PECOS.ico')
|
||||
root.mainloop()
|
||||
|
||||
w = None
|
||||
def create_Toplevel1(rt, *args, **kwargs):
|
||||
'''Starting point when module is imported by another module.
|
||||
Correct form of call: 'create_Toplevel1(root, *args, **kwargs)' .'''
|
||||
global w, w_win, root
|
||||
#rt = root
|
||||
root = rt
|
||||
w = tk.Toplevel (root)
|
||||
top = Toplevel1 (w)
|
||||
pecos_support.init(w, top, *args, **kwargs)
|
||||
return (w, top)
|
||||
|
||||
def destroy_Toplevel1():
|
||||
global w
|
||||
w.destroy()
|
||||
w = None
|
||||
# Close database connection
|
||||
conn.close()
|
||||
|
||||
class Toplevel1:
|
||||
def __init__(self, top=None):
|
||||
'''This class configures and populates the toplevel window.
|
||||
top is the toplevel containing window.'''
|
||||
_bgcolor = '#d9d9d9' # X11 color: 'gray85'
|
||||
_fgcolor = '#000000' # X11 color: 'black'
|
||||
_compcolor = '#d9d9d9' # X11 color: 'gray85'
|
||||
_ana1color = '#d9d9d9' # X11 color: 'gray85'
|
||||
_ana2color = '#ececec' # Closest X11 color: 'gray92'
|
||||
|
||||
top.geometry("600x500+650+150")
|
||||
top.minsize(1, 1)
|
||||
top.maxsize(1905, 1050)
|
||||
top.resizable(0, 0)
|
||||
top.title("PECOS - Polaris Emergency Check Out System 1.0b (Windows)")
|
||||
|
||||
# --- CHECKOUT ITEM AND UPDATE DATABASE ---
|
||||
def CheckOutItem(event=None):
|
||||
if len(self.item_entry.get()) == 0:
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
|
||||
row = c.execute("SELECT BatchNumber FROM Batches ORDER BY BatchNumber DESC LIMIT 1").fetchone()
|
||||
if row is not None:
|
||||
GetLastBatchNumber = row[0]
|
||||
CurrentBatchNumber = GetLastBatchNumber + 1
|
||||
|
||||
c.execute("INSERT INTO Batches VALUES (:BatchNumber, :PatronID)",
|
||||
{
|
||||
'BatchNumber': CurrentBatchNumber,
|
||||
'PatronID': self.patron_entry.get()
|
||||
}
|
||||
)
|
||||
# Commit changes
|
||||
conn.commit()
|
||||
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.item_entry.delete(0, tk.END)
|
||||
self.patron_entry.configure(state='normal')
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.patron_entry.focus_set()
|
||||
|
||||
else:
|
||||
# Set up database connections
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
|
||||
row = c.execute("SELECT BatchNumber FROM Batches ORDER BY BatchNumber DESC LIMIT 1").fetchone()
|
||||
if row is not None:
|
||||
GetLastBatchNumber = row[0]
|
||||
CurrentBatchNumber = GetLastBatchNumber + 1
|
||||
|
||||
c.execute("INSERT INTO CheckOuts VALUES (:PatronID, :ItemID, :TransactionDateTime, :ItemLink, :PatronLink, :BatchNumber)",
|
||||
{
|
||||
'PatronID': self.patron_entry.get(),
|
||||
'ItemID': self.item_entry.get(),
|
||||
'TransactionDateTime': timestamp(),
|
||||
'ItemLink': ("item/" + self.item_entry.get()),
|
||||
'PatronLink': ("patron/" + self.patron_entry.get()),
|
||||
'BatchNumber': CurrentBatchNumber
|
||||
}
|
||||
)
|
||||
# Commit changes
|
||||
conn.commit()
|
||||
|
||||
#PatronBarcode = self.patron_entry.get()
|
||||
PatCode = Code39(self.patron_entry.get(), add_checksum=False)
|
||||
PatCode.save("patron/"+self.patron_entry.get())
|
||||
|
||||
ItemCode = Code39(self.item_entry.get(), add_checksum=False)
|
||||
ItemCode.save("item/"+self.item_entry.get())
|
||||
|
||||
self.item_entry.delete(0, tk.END)
|
||||
|
||||
# --- PATRON SCANNED - MOVE TO ITEM FIELD ---
|
||||
def ChangeFocus(event):
|
||||
self.item_entry.focus_set()
|
||||
self.patron_entry.configure(state='disabled')
|
||||
|
||||
|
||||
# --- FINISH CHECKOUT AND CLEAR FIELDS ---
|
||||
def CheckOutComplete():
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
|
||||
row = c.execute("SELECT BatchNumber FROM Batches ORDER BY BatchNumber DESC LIMIT 1").fetchone()
|
||||
if row is not None:
|
||||
GetLastBatchNumber = row[0]
|
||||
CurrentBatchNumber = GetLastBatchNumber + 1
|
||||
|
||||
c.execute("INSERT INTO Batches VALUES (:BatchNumber, :PatronID)",
|
||||
{
|
||||
'BatchNumber': CurrentBatchNumber,
|
||||
'PatronID': self.patron_entry.get()
|
||||
}
|
||||
)
|
||||
# Commit changes
|
||||
conn.commit()
|
||||
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.item_entry.delete(0, tk.END)
|
||||
self.patron_entry.configure(state='normal')
|
||||
self.patron_entry.delete(0, tk.END)
|
||||
self.patron_entry.focus_set()
|
||||
|
||||
|
||||
# --- DELETE THE CURRENT DATABASE AND SUPPLANT WITH AN EMPTY ONE ---
|
||||
def ClearDatabase():
|
||||
self.ClearConfirm = tk.messagebox.askquestion ('PECOS - Clear Database','Are you sure you wish to clear the database? This cannot be undone!')
|
||||
if self.ClearConfirm == 'yes':
|
||||
# Next two lines commented out in Windows version - the connection commands work on macOS
|
||||
#conn = sqlite3.connect('checkouts.db') # Re-establish connection to the database
|
||||
#conn.close # Close out the current database
|
||||
os.remove("checkouts.db") # Delete the current database
|
||||
shutil.copy("emptybase.db", "checkouts.db") # Copy over an empty database
|
||||
shutil.rmtree('item')
|
||||
shutil.rmtree('patron')
|
||||
os.makedirs('item')
|
||||
os.makedirs('patron')
|
||||
# Next two lines commented out in Windows version - the connection commands work on macOS
|
||||
#conn = sqlite3.connect('checkouts.db') # Restablish connection to the database
|
||||
#c = conn.cursor()
|
||||
else:
|
||||
messagebox.showinfo('PECOS - Database Retained','Database retained. No changes made.')
|
||||
|
||||
# --- EXPORT DATABASE TO HTML ---
|
||||
def ExportDatabase():
|
||||
if os.path.exists("export.html"):
|
||||
os.remove("export.html")
|
||||
conn = sqlite3.connect('checkouts.db')
|
||||
c = conn.cursor()
|
||||
with open("export.html", "w") as f:
|
||||
f.write("<html>\n")
|
||||
f.write("<head>\n")
|
||||
f.write("<title>\n")
|
||||
f.write("PECOS Export - " + ReportTime() + "\n")
|
||||
f.write("</title>\n")
|
||||
f.write("<h2>PECOS Export File – " + ReportTime() + "</h2>\n<hr>\n")
|
||||
f.write("<style type=\"text/css\">\n")
|
||||
f.write(".tg {border-collapse:collapse;border-spacing:0;}\n")
|
||||
f.write(".tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px; overflow:hidden;padding:10px 5px;word-break:normal;}\n")
|
||||
f.write(".tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}\n")
|
||||
f.write(".tg .tg-cly1{text-align:left;vertical-align:middle}\n")
|
||||
f.write("</style>\n")
|
||||
f.write("<table class=\"tg\">\n")
|
||||
f.write("<thead>\n")
|
||||
f.write("<tr>\n")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Patron Library Card</strong></th>")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Batch Number</strong></th>")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Item Barcode</strong>\n")
|
||||
f.write("</tr>\n")
|
||||
for row in c.execute("SELECT BatchNumber, PatronLink, ItemLink FROM CheckOuts ORDER By BatchNumber"):
|
||||
f.write("<tr>\n")
|
||||
f.write("<th class=\"tg-cly1\"><img src=\"" + row[1] + ".svg\" width=200></th>")
|
||||
f.write("<th class=\"tg-cly1\"><strong>Batch: </strong>" + str(row[0]) + "</th>")
|
||||
f.write("<th class=\"tg-cly1\"><img src=\"" + row[2] + ".svg\" width=200>\n")
|
||||
f.write("</tr>\n")
|
||||
|
||||
subprocess.run(['open', 'export.html'], check=True) # Open export.html in the default web browser (macOS)
|
||||
#os.startfile('export.html') # Open export.html in the default web browser (Windows)
|
||||
|
||||
|
||||
|
||||
self.Canvas1 = tk.Canvas(top)
|
||||
self.image = ImageTk.PhotoImage(Image.open("bg-01.png"))
|
||||
self.Canvas1.create_image(0,0,anchor="nw",image=self.image)
|
||||
self.Canvas1.place(relx=0.0, rely=0.0, relheight=1.0, relwidth=1.0)
|
||||
self.Canvas1.configure(borderwidth="2")
|
||||
self.Canvas1.configure(relief="ridge")
|
||||
self.Canvas1.configure(selectbackground="blue")
|
||||
self.Canvas1.configure(selectforeground="white")
|
||||
|
||||
self.Frame1 = tk.Frame(self.Canvas1)
|
||||
self.Frame1.place(relx=0.05, rely=0.06, relheight=0.17, relwidth=0.908)
|
||||
self.Frame1.configure(relief='sunken')
|
||||
self.Frame1.configure(borderwidth="2")
|
||||
self.Frame1.configure(relief="sunken")
|
||||
|
||||
self.patron_label = tk.Label(self.Canvas1)
|
||||
self.patron_label.place(relx=0.067, rely=0.08, height=19, width=100)
|
||||
self.patron_label.configure(text='''Patron barcode:''')
|
||||
|
||||
self.patron_entry = tk.Entry(self.Canvas1)
|
||||
self.patron_entry.place(relx=0.25, rely=0.08,height=25, relwidth=0.377)
|
||||
self.patron_entry.configure(background="white")
|
||||
self.patron_entry.configure(font="TkFixedFont")
|
||||
self.patron_entry.bind('<Return>', ChangeFocus)
|
||||
|
||||
self.item_label = tk.Label(self.Canvas1)
|
||||
self.item_label.place(relx=0.067, rely=0.16, height=19, width=89)
|
||||
self.item_label.configure(text='''Item barcode:''')
|
||||
|
||||
self.item_entry = tk.Entry(self.Canvas1)
|
||||
self.item_entry.place(relx=0.25, rely=0.16,height=25, relwidth=0.377)
|
||||
self.item_entry.configure(background="white")
|
||||
self.item_entry.configure(font="TkFixedFont")
|
||||
self.item_entry.bind('<Return>', CheckOutItem)
|
||||
|
||||
self.finish_button = tk.Button(self.Canvas1, command=CheckOutComplete)
|
||||
self.finish_button.place(relx=0.7, rely=0.12, height=29, width=123)
|
||||
self.finish_button.configure(text='''Finish checkout''')
|
||||
|
||||
self.LowerFrame = tk.Frame(self.Canvas1)
|
||||
self.LowerFrame.place(relx=0.05, rely=0.78, relheight=0.13, relwidth=0.908)
|
||||
self.LowerFrame.configure(relief='sunken')
|
||||
self.LowerFrame.configure(borderwidth="2")
|
||||
self.LowerFrame.configure(relief="sunken")
|
||||
|
||||
self.export_button = tk.Button(self.LowerFrame, command=ExportDatabase)
|
||||
self.export_button.place(relx=0.092, rely=0.308, height=29, width=130)
|
||||
self.export_button.configure(text='''Export Checkouts''')
|
||||
|
||||
self.clear_button = tk.Button(self.LowerFrame, command=ClearDatabase)
|
||||
self.clear_button.place(relx=0.679, rely=0.308, height=29, width=130)
|
||||
self.clear_button.configure(text='''Clear Database''')
|
||||
|
||||
if __name__ == '__main__':
|
||||
vp_start_gui()
|
43
macOS/pecos_support.py
Normal file
@ -0,0 +1,43 @@
|
||||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Support module generated by PAGE version 5.4
|
||||
# in conjunction with Tcl version 8.6
|
||||
# Sep 30, 2020 01:33:24 PM CDT platform: Linux
|
||||
|
||||
import sys
|
||||
from PIL import Image, ImageTk
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
from datetime import date
|
||||
|
||||
try:
|
||||
import Tkinter as tk
|
||||
except ImportError:
|
||||
import tkinter as tk
|
||||
|
||||
try:
|
||||
import ttk
|
||||
py3 = False
|
||||
except ImportError:
|
||||
import tkinter.ttk as ttk
|
||||
py3 = True
|
||||
|
||||
# --- DEFINE FUNCTIONS ---
|
||||
|
||||
def init(top, gui, *args, **kwargs):
|
||||
global w, top_level, root
|
||||
w = gui
|
||||
top_level = top
|
||||
root = top
|
||||
|
||||
def destroy_window():
|
||||
# Function which closes the window.
|
||||
global top_level
|
||||
top_level.destroy()
|
||||
top_level = None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import pecos
|
||||
pecos.vp_start_gui()
|