diff --git a/Linux/LICENSE b/Linux/LICENSE new file mode 100644 index 0000000..472ac23 --- /dev/null +++ b/Linux/LICENSE @@ -0,0 +1,8 @@ +MIT License +Copyright (c) + +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. diff --git a/Linux/PECOS.ico b/Linux/PECOS.ico new file mode 100644 index 0000000..917af48 Binary files /dev/null and b/Linux/PECOS.ico differ diff --git a/Linux/README.md b/Linux/README.md new file mode 100644 index 0000000..290a0f8 --- /dev/null +++ b/Linux/README.md @@ -0,0 +1,3 @@ +# pecos + +Polaris Emergency Check Out System \ No newline at end of file diff --git a/Linux/archive/PECOS-Icon.png b/Linux/archive/PECOS-Icon.png new file mode 100644 index 0000000..31127ef Binary files /dev/null and b/Linux/archive/PECOS-Icon.png differ diff --git a/Linux/archive/PECOS-Icon.svg b/Linux/archive/PECOS-Icon.svg new file mode 100644 index 0000000..1a09385 --- /dev/null +++ b/Linux/archive/PECOS-Icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/Linux/archive/PECOS.ico b/Linux/archive/PECOS.ico new file mode 100644 index 0000000..917af48 Binary files /dev/null and b/Linux/archive/PECOS.ico differ diff --git a/Linux/bg-01.png b/Linux/bg-01.png new file mode 100644 index 0000000..3b1441d Binary files /dev/null and b/Linux/bg-01.png differ diff --git a/Linux/checkouts.db b/Linux/checkouts.db new file mode 100644 index 0000000..294f359 Binary files /dev/null and b/Linux/checkouts.db differ diff --git a/Linux/emptybase.db b/Linux/emptybase.db new file mode 100644 index 0000000..294f359 Binary files /dev/null and b/Linux/emptybase.db differ diff --git a/Linux/export.html b/Linux/export.html new file mode 100644 index 0000000..17a0ed7 --- /dev/null +++ b/Linux/export.html @@ -0,0 +1,24 @@ + + + +PECOS Export - 13:36:32 on Tuesday, November 17, 2020 + +

PECOS Export File – 13:36:32 on Tuesday, November 17, 2020

+
+ + + + + + + + + diff --git a/Linux/item/Item data will go here.txt b/Linux/item/Item data will go here.txt new file mode 100644 index 0000000..c1322e1 --- /dev/null +++ b/Linux/item/Item data will go here.txt @@ -0,0 +1 @@ +Item data will go here. \ No newline at end of file diff --git a/Linux/patron/Patron data will go here.txt b/Linux/patron/Patron data will go here.txt new file mode 100644 index 0000000..75ff28c --- /dev/null +++ b/Linux/patron/Patron data will go here.txt @@ -0,0 +1 @@ +Patron data will go here. diff --git a/Linux/pecos.py b/Linux/pecos.py new file mode 100644 index 0000000..6a40ad2 --- /dev/null +++ b/Linux/pecos.py @@ -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("\n") + f.write("\n") + f.write("\n") + f.write("PECOS Export - " + ReportTime() + "\n") + f.write("\n") + f.write("

PECOS Export File – " + ReportTime() + "

\n
\n") + f.write("\n") + f.write("
Patron Library CardBatch NumberItem Barcode +
Batch: 2 +
Batch: 2 +
\n") + f.write("\n") + f.write("\n") + f.write("") + f.write("") + f.write("\n") + for row in c.execute("SELECT BatchNumber, PatronLink, ItemLink FROM CheckOuts ORDER By BatchNumber"): + f.write("\n") + f.write("") + f.write("") + f.write("\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('', 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('', 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() \ No newline at end of file diff --git a/Linux/pecos_support.py b/Linux/pecos_support.py new file mode 100644 index 0000000..77c72bd --- /dev/null +++ b/Linux/pecos_support.py @@ -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() \ No newline at end of file diff --git a/PECOS Manual.pages b/PECOS Manual.pages new file mode 100755 index 0000000..8486bdb Binary files /dev/null and b/PECOS Manual.pages differ diff --git a/README.md b/README.md index bdc42c7..2032ef9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# pecos-unified +# PECOS Unified Polaris Emergency Check Out System - unified code repository for Windows, macOS, and Linux. \ No newline at end of file diff --git a/Windows/LICENSE b/Windows/LICENSE new file mode 100644 index 0000000..472ac23 --- /dev/null +++ b/Windows/LICENSE @@ -0,0 +1,8 @@ +MIT License +Copyright (c) + +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. diff --git a/Windows/PECOS.ico b/Windows/PECOS.ico new file mode 100644 index 0000000..917af48 Binary files /dev/null and b/Windows/PECOS.ico differ diff --git a/Windows/README.md b/Windows/README.md new file mode 100644 index 0000000..290a0f8 --- /dev/null +++ b/Windows/README.md @@ -0,0 +1,3 @@ +# pecos + +Polaris Emergency Check Out System \ No newline at end of file diff --git a/Windows/archive/PECOS-Icon.png b/Windows/archive/PECOS-Icon.png new file mode 100644 index 0000000..31127ef Binary files /dev/null and b/Windows/archive/PECOS-Icon.png differ diff --git a/Windows/archive/PECOS-Icon.svg b/Windows/archive/PECOS-Icon.svg new file mode 100644 index 0000000..1a09385 --- /dev/null +++ b/Windows/archive/PECOS-Icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/Windows/archive/PECOS.ico b/Windows/archive/PECOS.ico new file mode 100644 index 0000000..917af48 Binary files /dev/null and b/Windows/archive/PECOS.ico differ diff --git a/Windows/bg-01.png b/Windows/bg-01.png new file mode 100644 index 0000000..3b1441d Binary files /dev/null and b/Windows/bg-01.png differ diff --git a/Windows/checkouts.db b/Windows/checkouts.db new file mode 100644 index 0000000..294f359 Binary files /dev/null and b/Windows/checkouts.db differ diff --git a/Windows/emptybase.db b/Windows/emptybase.db new file mode 100644 index 0000000..294f359 Binary files /dev/null and b/Windows/emptybase.db differ diff --git a/Windows/export.html b/Windows/export.html new file mode 100644 index 0000000..8eaac65 --- /dev/null +++ b/Windows/export.html @@ -0,0 +1,36 @@ + + + +PECOS Export - 06:14:31 on Wednesday, November 11, 2020 + +

PECOS Export File – 06:14:31 on Wednesday, November 11, 2020

+
+ +
Patron Library CardBatch NumberItem Barcode\n") + f.write("
Batch: " + str(row[0]) + "\n") + f.write("
+ + + + + + + + + + + + + + + diff --git a/Windows/item/Item data will go here.txt b/Windows/item/Item data will go here.txt new file mode 100644 index 0000000..c1322e1 --- /dev/null +++ b/Windows/item/Item data will go here.txt @@ -0,0 +1 @@ +Item data will go here. \ No newline at end of file diff --git a/Windows/patron/Patron data will go here.txt b/Windows/patron/Patron data will go here.txt new file mode 100644 index 0000000..75ff28c --- /dev/null +++ b/Windows/patron/Patron data will go here.txt @@ -0,0 +1 @@ +Patron data will go here. diff --git a/Windows/pecos.py b/Windows/pecos.py new file mode 100644 index 0000000..d0bf894 --- /dev/null +++ b/Windows/pecos.py @@ -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("\n") + f.write("\n") + f.write("\n") + f.write("PECOS Export - " + ReportTime() + "\n") + f.write("\n") + f.write("

PECOS Export File – " + ReportTime() + "

\n
\n") + f.write("\n") + f.write("
Patron Library CardBatch NumberItem Barcode +
Batch: 2 +
Batch: 2 +
Batch: 2 +
Batch: 3 +
Batch: 3 +
Batch: 3 +
\n") + f.write("\n") + f.write("\n") + f.write("") + f.write("") + f.write("\n") + for row in c.execute("SELECT BatchNumber, PatronLink, ItemLink FROM CheckOuts ORDER By BatchNumber"): + f.write("\n") + f.write("") + f.write("") + f.write("\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('', 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('', 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() \ No newline at end of file diff --git a/Windows/pecos_support.py b/Windows/pecos_support.py new file mode 100644 index 0000000..77c72bd --- /dev/null +++ b/Windows/pecos_support.py @@ -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() \ No newline at end of file diff --git a/macOS/LICENSE b/macOS/LICENSE new file mode 100644 index 0000000..472ac23 --- /dev/null +++ b/macOS/LICENSE @@ -0,0 +1,8 @@ +MIT License +Copyright (c) + +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. diff --git a/macOS/PECOS.ico b/macOS/PECOS.ico new file mode 100644 index 0000000..917af48 Binary files /dev/null and b/macOS/PECOS.ico differ diff --git a/macOS/README.md b/macOS/README.md new file mode 100644 index 0000000..290a0f8 --- /dev/null +++ b/macOS/README.md @@ -0,0 +1,3 @@ +# pecos + +Polaris Emergency Check Out System \ No newline at end of file diff --git a/macOS/archive/PECOS-Icon.png b/macOS/archive/PECOS-Icon.png new file mode 100644 index 0000000..31127ef Binary files /dev/null and b/macOS/archive/PECOS-Icon.png differ diff --git a/macOS/archive/PECOS-Icon.svg b/macOS/archive/PECOS-Icon.svg new file mode 100644 index 0000000..1a09385 --- /dev/null +++ b/macOS/archive/PECOS-Icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/macOS/archive/PECOS.ico b/macOS/archive/PECOS.ico new file mode 100644 index 0000000..917af48 Binary files /dev/null and b/macOS/archive/PECOS.ico differ diff --git a/macOS/bg-01.png b/macOS/bg-01.png new file mode 100644 index 0000000..3b1441d Binary files /dev/null and b/macOS/bg-01.png differ diff --git a/macOS/checkouts.db b/macOS/checkouts.db new file mode 100644 index 0000000..294f359 Binary files /dev/null and b/macOS/checkouts.db differ diff --git a/macOS/emptybase.db b/macOS/emptybase.db new file mode 100644 index 0000000..294f359 Binary files /dev/null and b/macOS/emptybase.db differ diff --git a/macOS/export.html b/macOS/export.html new file mode 100644 index 0000000..17a0ed7 --- /dev/null +++ b/macOS/export.html @@ -0,0 +1,24 @@ + + + +PECOS Export - 13:36:32 on Tuesday, November 17, 2020 + +

PECOS Export File – 13:36:32 on Tuesday, November 17, 2020

+
+ +
Patron Library CardBatch NumberItem Barcode\n") + f.write("
Batch: " + str(row[0]) + "\n") + f.write("
+ + + + + + + diff --git a/macOS/item/Item data will go here.txt b/macOS/item/Item data will go here.txt new file mode 100644 index 0000000..c1322e1 --- /dev/null +++ b/macOS/item/Item data will go here.txt @@ -0,0 +1 @@ +Item data will go here. \ No newline at end of file diff --git a/macOS/patron/Patron data will go here.txt b/macOS/patron/Patron data will go here.txt new file mode 100644 index 0000000..75ff28c --- /dev/null +++ b/macOS/patron/Patron data will go here.txt @@ -0,0 +1 @@ +Patron data will go here. diff --git a/macOS/pecos.py b/macOS/pecos.py new file mode 100644 index 0000000..6a40ad2 --- /dev/null +++ b/macOS/pecos.py @@ -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("\n") + f.write("\n") + f.write("\n") + f.write("PECOS Export - " + ReportTime() + "\n") + f.write("\n") + f.write("

PECOS Export File – " + ReportTime() + "

\n
\n") + f.write("\n") + f.write("
Patron Library CardBatch NumberItem Barcode +
Batch: 2 +
Batch: 2 +
\n") + f.write("\n") + f.write("\n") + f.write("") + f.write("") + f.write("\n") + for row in c.execute("SELECT BatchNumber, PatronLink, ItemLink FROM CheckOuts ORDER By BatchNumber"): + f.write("\n") + f.write("") + f.write("") + f.write("\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('', 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('', 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() \ No newline at end of file diff --git a/macOS/pecos_support.py b/macOS/pecos_support.py new file mode 100644 index 0000000..77c72bd --- /dev/null +++ b/macOS/pecos_support.py @@ -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() \ No newline at end of file
Patron Library CardBatch NumberItem Barcode\n") + f.write("
Batch: " + str(row[0]) + "\n") + f.write("