├── .gitattributes
├── .project
├── .pydevproject
├── .settings
└── org.eclipse.core.resources.prefs
├── .vs
└── Accounting-System
│ └── v15
│ └── .suo
├── AccountDB.py
├── Accounting-System-alpha-release.zip
├── Accounting-System.pyproj
├── Accounting-System.sln
├── AccountingSystemOrganization.png
├── Blank General Journal.png
├── Blank General Ledger.png
├── Example python code printing with win32 .odt
├── FormDialogs.py
├── LICENSE
├── OpenAccounting.db
├── OpenAccounting.py
├── OpenAccounting.sql
├── Printfile.ps
├── README.md
├── ReportPreps.py
├── Tooltips.py
├── __pycache__
├── AccountDB.cpython-37.pyc
├── FormDialogs.cpython-37.pyc
├── ReportPreps.cpython-37.pyc
├── Tooltips.cpython-37.pyc
└── splash.cpython-37.pyc
├── _config.yml
├── cruncherCr3.gif
├── cruncherCr3.jpg
├── cruncherCr3.png
├── images
├── AccountingSystemOrganization.dia
├── AccountingSystemOrganization.png
├── ChartAccts.png
├── Journal1.png
├── Journal1.xcf
├── Journal2.png
├── Journal2.xcf
├── Journal3.png
├── Journal3.xcf
├── Journal4.png
├── Journal4.xcf
├── Journal5.png
├── Journal5.xcf
├── Journal6.png
├── Journal6.xcf
├── Journal7.png
├── Journal7.xcf
├── Ldgeracct1.png
├── Ldgeracct1.xcf
├── Number_cruncherCr3.ico
├── Number_cruncherCr3.png
├── README.md
├── RevnExp1.png
├── ScreenChartTab.png
├── ScreenChartTab2.png
├── ScreenJournalTab.png
├── ScreenLedgerTab.png
├── ScreenMaintenanceTab.png
├── ScreenMemoTab.png
├── ScreenReportTab1.png
├── ScreenReportTab2.png
├── balancesheet1.png
├── cruncherCr3.gif
├── medmatix.ico
├── medmatix.png
├── medmatix_tilt.ico
├── medmatix_tilt.png
└── trialbalance1.png
├── medmatix_tilt.png
├── splash.py
└── testcode.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | Accounting-System
4 |
5 |
6 |
7 |
8 |
9 | org.python.pydev.PyDevBuilder
10 |
11 |
12 |
13 |
14 |
15 | org.python.pydev.pythonNature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.pydevproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | /${PROJECT_DIR_NAME}
5 |
6 | python interpreter
7 | Default
8 |
9 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding/Tooltips.py=utf-8
3 |
--------------------------------------------------------------------------------
/.vs/Accounting-System/v15/.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/.vs/Accounting-System/v15/.suo
--------------------------------------------------------------------------------
/AccountDB.py:
--------------------------------------------------------------------------------
1 | '''
2 | AccountDB module
3 | Created on Oct 29, 2018
4 | @summary: This module provides all the database access methods for the accounting system
5 | @author: david york
6 | '''
7 | import sqlite3
8 | import tkinter as tk
9 | from tkinter import messagebox as mBox
10 |
11 |
12 | class AccountDB(object):
13 | '''
14 | Class with Account Database manipulation methods for SQLite3 Database
15 | '''
16 |
17 |
18 | def __init__(self, params):
19 | '''
20 | Constructor
21 | '''
22 |
23 | # #################################
24 | # Database Functions
25 | # #################################
26 |
27 |
28 | def createAccounts(self):
29 | '''
30 | Create New Database and Tables if not existing
31 | @summary: Creates a fully new accounting set-up. The System accounts are
32 | fixed by accounting convention and may not be changed of reused for
33 | other purposes.
34 | @warning: Will not allow overwriting so any old data tables should be moved from the directory.
35 | '''
36 | # Check that a fully new set-up is intended
37 | proceedAnswer = mBox.askyesno("Initial Set-up","This is The New System Set-up.\nThere should be no old data tables in directory,\n Proceed?")
38 | if (not proceedAnswer):
39 | print('aborted new setup')
40 | return
41 | # Some local, set-up related message boxes
42 | def setupError(self):
43 | mBox.showerror(title='Set-up Error', message='Chart of Accounts already populated, you may not overwrite')
44 | def setupInfo(self):
45 | mBox.showinfo('Set-up Information' , 'Adding System Accounts to Chart of Accounts.')
46 |
47 | #If Not Existing, Create batabase, data tables and system ledger accounts
48 | db = sqlite3.connect('OpenAccounting.db')
49 | db.execute('''CREATE TABLE IF NOT EXISTS journal
50 | (Transact INTEGER PRIMARY KEY NOT NULL,
51 | Date DATETIME NOT NULL,
52 | Description STRING(50) NOT NULL,
53 | DebitAccount INT(4) NOT NULL,
54 | CreditAccount INT(4) NOT NULL,
55 | Amount DECIMAL NOT NULL)''')
56 |
57 | db.execute('''CREATE TABLE IF NOT EXISTS ledger
58 | (Account INTEGER NOT NULL,
59 | Transact INTEGER KEY NOT NULL,
60 | Amount REAL NOT NULL,
61 | Balance REAL NOT NULL)''')
62 |
63 | db.execute('''CREATE TABLE IF NOT EXISTS chart
64 | (Account INTEGER PRIMARY KEY NOT NULL,
65 | Name STRING(60) NOT NULL,
66 | Type STRING(10) NOT NULL,
67 | Balance REAL NOT NULL)''')
68 |
69 | db.execute('''CREATE TABLE IF NOT EXISTS accountmemos
70 | (MemoID INTEGER PRIMARY KEY NOT NULL,
71 | Transact INTEGER NOT NULL,
72 | Date DATETIME NOT NULL,
73 | Memo BLOB NOT NULL)''')
74 |
75 | # Check if Chart of Accounts already set-up, may not be overwritten
76 | count = db.execute("SELECT count(Account) FROM chart")
77 | for row in count:
78 | tableFull=bool(row[0])
79 | if (not tableFull):
80 | setupInfo(self)
81 | db.execute('''INSERT INTO chart VALUES (100, "ASSETS", "DEBIT", 0),
82 | (120, "RECEIVABLES","DEBIT",0),
83 | (200, "LIABILITIES","CREDIT",0),
84 | (220, "PAYABLES","CREDIT",0),
85 | (300, "EQUITY","CREDIT",0),
86 | (399, "RETAINED EARNINGS", "CREDIT",0),
87 | (400, "REVENUE","CREDIT",0),
88 | (500, "EXPENSES","DEBIT",0)
89 | ''')
90 | db.commit()
91 | else:
92 | setupError(self)
93 |
94 | db.close()
95 |
96 | def getChartAccounts(self):
97 | '''
98 | Return all Chart of Accounts
99 | '''
100 | chart = list()
101 | db = sqlite3.connect('OpenAccounting.db')
102 | cursor = db.cursor()
103 | cursor.execute("SELECT * FROM chart ORDER BY Account")
104 | for row in cursor:
105 | chart.append(row)
106 | db.close()
107 | return chart
108 |
109 | def getBalSheetAccounts(self, accRange):
110 | '''
111 | Return a Block of Accounts
112 | '''
113 | accBlock = list()
114 | db = sqlite3.connect('OpenAccounting.db')
115 | cursor = db.cursor()
116 | cursor.execute("SELECT * FROM chart WHERE Account >= {} AND Account <= {} ORDER BY Account".format(accRange[0], accRange[1]))
117 | for row in cursor:
118 | accBlock.append(row)
119 | db.close()
120 | return accBlock
121 |
122 | def existChartAccount(self, account):
123 | '''
124 | '''
125 | pass
126 |
127 | def getLedgerAccount(self,account):
128 | '''
129 | Return all entries for an account
130 | '''
131 | ledger = list()
132 | db = sqlite3.connect('OpenAccounting.db')
133 | cursor = db.cursor()
134 | if int(account) == 0:
135 | cursor.execute("SELECT * FROM ledger ORDER BY Account")
136 | else:
137 | cursor.execute("SELECT * FROM ledger WHERE Account = {} ORDER BY Transact".format(account,))
138 | for row in cursor:
139 | ledger.append(row)
140 | db.close()
141 | return ledger
142 |
143 | def getJournalEntries(self, jDates):
144 | '''
145 | Return all of a journal date range
146 | '''
147 | journal = list()
148 | db = sqlite3.connect('OpenAccounting.db')
149 | cursor = db.cursor()
150 | if jDates == (0,0):
151 | cursor.execute("SELECT * FROM journal ORDER BY Date")
152 | else:
153 | cursor.execute("SELECT * FROM journal WHERE Date = {} ORDER BY Transact".format(jDates[0]))
154 | for row in cursor:
155 | journal.append(row)
156 | db.close()
157 | return journal
158 |
159 | def getJournalTransact(self, jTransact):
160 | '''
161 | Return a journal transaction
162 | '''
163 | transact = list()
164 | db = sqlite3.connect('OpenAccounting.db')
165 | cursor = db.cursor()
166 | if int(jTransact) == 0:
167 | cursor.execute("SELECT * FROM journal ORDER BY Date")
168 | else:
169 | cursor.execute("SELECT * FROM journal WHERE Transact = {} ORDER BY Date".format(jTransact))
170 | for row in cursor:
171 | transact.append(row)
172 | db.close()
173 | return transact
174 |
175 | def getTransactMemo(self, jTransact):
176 | '''
177 | Return a transaction accounting memos
178 | '''
179 | transact = list()
180 | db = sqlite3.connect('OpenAccounting.db')
181 | cursor = db.cursor()
182 | if int(jTransact) == 0:
183 | cursor.execute("SELECT * FROM accountMemos ORDER BY Date")
184 | else:
185 | cursor.execute("SELECT * FROM accountMemos WHERE Transact = {} ORDER BY MemoDate".format(jTransact))
186 | for row in cursor:
187 | transact.append(row)
188 | db.close()
189 | return transact
190 |
191 | def insertJournalEntry(self, jrow):
192 | '''
193 | Insert an entry into Journal
194 | '''
195 | db = sqlite3.connect('OpenAccounting.db')
196 | db.execute("INSERT INTO journal VALUES {}".format(jrow))
197 | db.commit()
198 | db.close()
199 |
200 | def insertLedgerEntry(self, lrow):
201 | '''
202 | Post journal debit or credit to Ledger
203 | '''
204 | db = sqlite3.connect('OpenAccounting.db')
205 | db.execute("INSERT INTO ledger VALUES {}".format(lrow))
206 | db.commit()
207 | db.close()
208 |
209 | def insertChartAccount(self, row):
210 | '''
211 | Update an Balance into Chart Account
212 | '''
213 | db = sqlite3.connect('OpenAccounting.db')
214 | db.execute("INSERT INTO chart VALUES {}".format(row))
215 | db.commit()
216 | db.close()
217 |
218 | def insertAccountMemos(self, row):
219 | '''
220 | Update an Balance into Chart Account
221 | '''
222 | db = sqlite3.connect('OpenAccounting.db')
223 | db.execute("INSERT INTO accountMemos VALUES {}".format(row))
224 | db.commit()
225 | db.close()
226 |
227 | def updateChartBalance(self, account, balance): # Account balance in chart of accounts
228 | db = sqlite3.connect('OpenAccounting.db')
229 | cursor = db.cursor()
230 | cursor.execute("UPDATE Chart SET Balance = {} WHERE Account = {}".format(balance, account))
231 | db.commit()
232 | db.close()
233 |
234 | def getAccountNumbers(self, accrange, acctype):
235 | '''
236 | Get a list of account numbers from chart
237 | '''
238 | acctNos = list()
239 | db = sqlite3.connect('OpenAccounting.db')
240 | if accrange == (0,0):
241 | if acctype == 'DEBIT':
242 | cursor = db.cursor()
243 | cursor.execute("SELECT Account FROM chart WHERE ActyType ='DEBIT' ORDER BY Account".format(accrange))
244 | else: # AccType = CREDIT
245 | cursor = db.cursor()
246 | cursor.execute("SELECT * FROM chart WHERE ActyType = 'CREDIT' ORDER BY Account".format(accrange))
247 | else:
248 | cursor = db.cursor()
249 | cursor.execute("SELECT * FROM chart WHERE Account > {} and Account < {} ORDER BY Account".format(accrange))
250 | for row in cursor:
251 | acctNos.append(row)
252 | db.close()
253 | return acctNos
254 |
255 | def getAccountType(self,laccount):
256 | '''
257 | Get LAST ledger balance for specified account
258 | '''
259 | atype = list()
260 | db = sqlite3.connect('OpenAccounting.db')
261 | cursor = db.cursor()
262 | cursor.execute("SELECT ActyType FROM Chart WHERE Account = {}".format(laccount,))
263 | for row in cursor:
264 | atype.append(row)
265 | rtype = atype[0][0]
266 | db.close()
267 | return rtype
268 |
269 | def getAccountBalance(self,laccount):
270 | '''
271 | Get LAST ledger balance for specified account
272 | '''
273 | balance = list()
274 | db = sqlite3.connect('OpenAccounting.db')
275 | cursor = db.cursor()
276 | cursor.execute("SELECT Balance FROM Chart WHERE Account = {}".format(laccount,))
277 | for row in cursor:
278 | balance.append(row)
279 | oldBalance = balance[0][0]
280 | db.close()
281 | return oldBalance
282 |
283 | def getsgnAdjust(self, laccount, txType):
284 | actyType = list()
285 | db = sqlite3.connect('OpenAccounting.db')
286 | cursor = db.cursor()
287 | cursor.execute("SELECT actyType FROM Chart WHERE Account = {}".format(laccount,))
288 | for row in cursor:
289 | actyType.append(row)
290 | aType = actyType[0][0]
291 | if (txType=='DEBIT' and aType=='DEBIT') or (txType=='CREDIT' and aType=='CREDIT' ):
292 | db.close()
293 | return 1
294 | else:
295 | db.close()
296 | return -1
297 |
298 | # return balance
299 |
300 | def packDatabase(self):
301 | db = sqlite3.connect('OpenAccounting.db')
302 | mBox.showinfo('Maintenance' , 'PACKING Database for Clean-up, Defragmentation and Improved Performance.')
303 | db.execute('VACUUM')
304 | db.close()
--------------------------------------------------------------------------------
/Accounting-System-alpha-release.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/Accounting-System-alpha-release.zip
--------------------------------------------------------------------------------
/Accounting-System.pyproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | 2.0
6 | {36b71360-ba1b-4c61-be93-2b584588523e}
7 |
8 | OpenAccounting.py
9 |
10 | .
11 | .
12 | {888888a0-9f3d-457c-b088-3a5042f75d52}
13 | Standard Python launcher
14 |
15 |
16 |
17 |
18 |
19 | 10.0
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Accounting-System.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28010.2036
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "Accounting-System", "Accounting-System.pyproj", "{36B71360-BA1B-4C61-BE93-2B584588523E}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {36B71360-BA1B-4C61-BE93-2B584588523E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {36B71360-BA1B-4C61-BE93-2B584588523E}.Release|Any CPU.ActiveCfg = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | GlobalSection(ExtensibilityGlobals) = postSolution
21 | SolutionGuid = {D3102E44-3EA1-46C6-842A-B6E71D02C677}
22 | EndGlobalSection
23 | EndGlobal
24 |
--------------------------------------------------------------------------------
/AccountingSystemOrganization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/AccountingSystemOrganization.png
--------------------------------------------------------------------------------
/Blank General Journal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/Blank General Journal.png
--------------------------------------------------------------------------------
/Blank General Ledger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/Blank General Ledger.png
--------------------------------------------------------------------------------
/Example python code printing with win32 .odt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/Example python code printing with win32 .odt
--------------------------------------------------------------------------------
/FormDialogs.py:
--------------------------------------------------------------------------------
1 | '''
2 | Module for view and report forms and input form dialogs
3 | Created on Oct 30, 2018
4 | @license: MIT
5 | @author: David York
6 | @copyright: 2018 D A York
7 | '''
8 |
9 | # ######################################
10 | # Imports
11 | # ######################################
12 | import tkinter as tk
13 | from tkinter import ttk, LabelFrame
14 | from tkinter import scrolledtext
15 | from tkinter import Canvas
16 | from tkinter import font
17 | from PIL import Image, ImageTk
18 |
19 |
20 | import math as mt
21 | import numpy as np
22 | import datetime as dt
23 | import pytz
24 |
25 | from AccountDB import AccountDB
26 | from Tooltips import createToolTip
27 | import os
28 | import pathlib
29 | # #######################################################
30 | # Classes, Independently constructed Forms, Dialogs etc
31 | # #######################################################
32 | '''
33 | Classes, External, independently constructed Forms, Dialogs etc
34 | '''
35 |
36 |
37 |
38 |
39 |
40 | class insertJournalForm(object):
41 | '''
42 | A form-dialog class insertion Form to building and display for Journal Access
43 | in it's own pop-up Dialog window
44 | @summary: A form to collect journal item data to add to journal table,. A Part of Accounting System application
45 | @see: refer to main module (AccountingSystem) documentation
46 | created: Oct 17, 2018
47 | '''
48 | here = pytz.timezone('America/New_York')
49 | currentDT = dt.datetime.now(here)
50 |
51 | def __init__(self, goal):
52 | '''
53 | Constructor for Add to Journal in it's own pop-up data dialog window
54 | '''
55 |
56 | # Create instance
57 | self.goal=goal
58 | self.frm = tk.Tk()
59 | # Add a title
60 | self.frm.title("Insert a Journal Entry")
61 | self.journalForm()
62 | self.frm.mainloop()
63 |
64 |
65 |
66 | def journalForm(self):
67 | '''
68 | The form for journal access for anew transaction entry
69 | '''
70 | # Whole form label frame---------------------------------------
71 | lbfr = ttk.LabelFrame(self.frm, text=' Input Form ')
72 | lbfr.grid(column=0, row=0, padx=10, pady=10, sticky='W')
73 | # Transaction Entry field -------------------------------------
74 | self.lbl0 = tk.Label(lbfr, text="Transaction").grid(column=0, row=0)
75 | self.e0 = tk.Entry(lbfr, width=16)
76 | self.e0.grid(column=1, row=0, padx=5, pady=4, sticky='W')
77 | # Associated tool tip
78 | transEnter = 'Unique transaction ID number. Is all numeric'
79 | createToolTip(self.e0, transEnter)
80 | # -------------------------------------------------------------
81 | self.lbl1 = tk.Label(lbfr, text="Date").grid(column=0, row=1)
82 | self.e1 = tk.Entry(lbfr,width=10)
83 | self.e1.grid(column=1, row=1, padx=5, pady=4, sticky='W')
84 | rnow = str(self.currentDT.year)+'-'+str(self.currentDT.month)+'-'+str(self.currentDT.day)
85 | self.e1.insert(0, rnow)
86 | # Associated tool tip
87 | dateEnter = 'Date transaction entered, yyyy-mm-dd, defaults to today, '
88 | createToolTip(self.e1, dateEnter)
89 | # -------------------------------------------------------------
90 | self.lbl2 = tk.Label(lbfr, text="Time").grid(column=0, row=2)
91 | self.e2 = tk.Entry(lbfr,width=9)
92 | self.e2.grid(column=1, row=2, padx=5, pady=4, sticky='W')
93 | rtime = str(self.currentDT.hour)+':'+str(self.currentDT.minute)+':'+str(self.currentDT.second)
94 | self.e2.insert(0, rtime)
95 | # Associated tool tip
96 | timeEnter = 'Time transaction is entered. [hh:mm:ss] optional, defaults to Now'
97 | createToolTip(self.e2, timeEnter)
98 | # -------------------------------------------------------------
99 | self.lbl3 = tk.Label(lbfr, text="Description").grid(column=0, row=3)
100 | self.e3 = tk.Entry(lbfr,width=50)
101 | self.e3.grid(column=1, row=3, padx=5, pady=4, sticky='W')
102 | # Associated tool tip
103 | descEnter = 'transaction description.'
104 | createToolTip(self.e3, descEnter)
105 | # -------------------------------------------------------------
106 | self.lbl4 = tk.Label(lbfr, text="DebitAccount").grid(column=0, row=4)
107 | self.e4 = tk.Entry(lbfr,width=4)
108 | self.e4.grid(column=1, row=4, padx=5, pady=4, sticky='W')
109 | # Associated tool tip
110 | dAcctsEnter = 'Account to Debit'
111 | createToolTip(self.e4, dAcctsEnter)
112 | # -------------------------------------------------------------
113 | self.lbl5 = tk.Label(lbfr, text="DebitAmount").grid(column=0, row=5)
114 | self.e5 = tk.Entry(lbfr,width=8)
115 | self.e5.grid(column=1, row=5, padx=5, pady=4, sticky='W')
116 | # Associated tool tip
117 | dAmtEnter = 'Amount to debit, dollars and cents, no not include sign, will be added by system'
118 | createToolTip(self.e5, dAmtEnter)
119 | # -------------------------------------------------------------
120 | self.lbl6 = tk.Label(lbfr, text="CreditAccount").grid(column=0, row=6)
121 | self.e6 = tk.Entry(lbfr,width=4)
122 | self.e6.grid(column=1, row=6, padx=5, pady=4, sticky='W')
123 | # Associated tool tip
124 | cAcctEnter = 'Account to Credit'
125 | createToolTip(self.e6, cAcctEnter)
126 | # -------------------------------------------------------------
127 | self.lbl7 = tk.Label(lbfr, text="CreditAmount").grid(column=0, row=7)
128 | self.e7 = tk.Entry(lbfr,width=8)
129 | self.e7.grid(column=1, row=7, padx=5, pady=4, sticky='W')
130 | # Associated tool tip
131 | cAmtEnter = 'Amount to credit, dollars and cents, no not include sign, will be added by system'
132 | createToolTip(self.e7, cAmtEnter)
133 | # --------------------------------------------------------------
134 | self.btn1 = ttk.Button(lbfr, text="Commit", command=lambda: self.on_click()).grid(column=0,row=9,padx=8, pady=4, sticky='W')
135 | self.btn2 = ttk.Button(lbfr, text="Cancel", command=lambda: self.on_cancel()).grid(column=1,row=9,padx=8, pady=4, sticky='W')
136 |
137 |
138 | def on_click(self):
139 | '''
140 | Save new Journal Entry and update associated General Ledger accounts
141 | '''
142 | # get debit account balance
143 | daccount = int(self.e4.get())
144 | txType = 'DEBIT'
145 | debitBalance = AccountDB.getAccountBalance(self,daccount)
146 | debitSgn = AccountDB.getsgnAdjust(self,daccount,txType)
147 | debitAmount = debitSgn * round(float(self.e7.get()),2)
148 | # get credit account balance
149 | caccount = int(self.e6.get())
150 | txType = 'CREDIT'
151 | creditBalance= AccountDB.getAccountBalance(self, caccount)
152 | creditSgn = AccountDB.getsgnAdjust(self, caccount,txType)
153 | creditAmount = creditSgn * round(float(self.e5.get()),2)
154 | newDBalance=(debitBalance + debitAmount)
155 | newCBalance=(creditBalance + creditAmount)
156 | posted = 1
157 | jrow = (int(self.e0.get()), self.e1.get(), self.e2.get(), self.e3.get(), int(self.e4.get()), debitAmount, int(self.e6.get()),creditAmount, posted)
158 | lDRow = (int(self.e4.get()),int(self.e0.get()), debitAmount, newDBalance)
159 | lCRow = (int(self.e6.get()),int(self.e0.get()), creditAmount, newCBalance)
160 | ''' the activation of the form'''
161 | if (abs(creditAmount) == abs(debitAmount)):
162 | print("commit")
163 | AccountDB.insertJournalEntry(self, jrow)
164 | lrow = lDRow
165 | AccountDB.insertLedgerEntry(self, lrow)
166 | lrow = lCRow
167 | AccountDB.insertLedgerEntry(self, lrow)
168 | AccountDB.updateChartBalance(self, daccount, newDBalance)
169 | AccountDB.updateChartBalance(self, caccount, newCBalance)
170 | print("journalForm closed")
171 | self.frm.destroy()
172 | else:
173 | print("ERROR: Credits and Debits do not balance")
174 |
175 | def on_cancel(self):
176 | print("Cancelled action")
177 | self.frm.destroy()
178 |
179 | class insertChartForm(object):
180 | '''
181 | A form-dialog class insertion Form for building and display Chart of Account
182 | access in it's own pop-up Dialog window
183 | @summary: A form to collect new account to add to Chart, and send to database.
184 | created: Oct 14, 2018
185 | '''
186 | def __init__(self, goal):
187 | '''
188 | Constructor for Add New Account dialog window
189 | '''
190 |
191 | # Create instance
192 | self.frm = tk.Tk()
193 | # Add a title
194 | self.frm.title("Add Entry into Chart of Accounts")
195 | self.chartForm()
196 | self.frm.mainloop()
197 |
198 | def chartForm(self):
199 | '''
200 | The form for Chart of Account access
201 | '''
202 | # Whole form label frame --------------------------------------
203 | lbfr = ttk.LabelFrame(self.frm, text=' Input Form ')
204 | lbfr.grid(column=0, row=0, padx=10, pady=10, sticky='W')
205 | # -------------------------------------------------------------
206 | self.lbl0 = tk.Label(lbfr, text="Account").grid(column=0, row=0)
207 | self.e0 = tk.Entry(lbfr, width=16)
208 | self.e0.grid(column=1, row=0, padx=5, pady=4, sticky='W')
209 | acctEnter = 'Number of the New Account being Opened'
210 | createToolTip(self.e0, acctEnter)
211 | # -------------------------------------------------------------
212 | self.lbl2 = tk.Label(lbfr, text="Name").grid(column=0, row=2)
213 | self.e2 = tk.Entry(lbfr,width=50)
214 | self.e2.grid(column=1, row=2, padx=5, pady=4, sticky='W')
215 | nameEnter = 'Name or Description of the new account'
216 | createToolTip(self.e2, nameEnter)
217 | # -------------------------------------------------------------
218 | self.lbl3 = tk.Label(lbfr, text="Type of Account").grid(column=0, row=3)
219 | choices = ['DEBIT', 'CREDIT']
220 | self.vtype = tk.StringVar()
221 | self.e3 = tk.OptionMenu(lbfr, self.vtype, *choices, command=self.func)
222 | self.e3.configure(width = 12)
223 | self.e3.grid(column=1, row=3, padx=5, pady=4, sticky='W')
224 | atypeEnter = 'SELECT the Type of account, Credit vs Debit. Used to determine if transactions add to or subtract from balance'
225 | createToolTip(self.e3, atypeEnter)
226 | # -------------------------------------------------------------
227 | self.lbl4 = tk.Label(lbfr, text="Starting Balance").grid(column=0, row=4)
228 | self.e4 = tk.Entry(lbfr,width=10)
229 | self.e4.grid(column=1, row=4, padx=5, pady=4, sticky='W')
230 | self.e4.insert(0, 0)
231 | balEnter = 'Starting Account balance when opened'
232 | createToolTip(self.e4, balEnter)
233 | # -------------------------------------------------------------
234 | self.btn3 = ttk.Button(lbfr, text="Commit", command=lambda: self.on_click()).grid(column=0,row=7,padx=8, pady=4, sticky='W')
235 | self.btn4 = ttk.Button(lbfr, text="Cancel", command=lambda: self.on_cancel()).grid(column=1,row=7,padx=8, pady=4, sticky='W')
236 |
237 | def func(self,value):
238 | pass
239 |
240 | def on_click(self):
241 |
242 | account = self.e0.get()
243 | if(account in (100,200,300,400,500,120,220,320,399)):
244 | print("ERROR, account is system reserved account, do not use.")
245 | self.on_cancel()
246 | # Check if account exits
247 | if (self.e0.get() == ''):
248 | self.on_cancel()
249 | else:
250 | account = int(self.e0.get())
251 | existAccount = AccountDB.existChartAccount(self,account)
252 | atype = self.vtype.get()
253 |
254 | row = (int(self.e0.get()), self.e2.get(), atype, self.e4.get())
255 | ''' the activation of the form'''
256 | if (not existAccount):
257 | print("commit")
258 | print(row)
259 | AccountDB.insertChartAccount(self, row)
260 | print("journalForm closed")
261 | self.frm.destroy()
262 | else:
263 | print("ERROR: An Account Already Exists with this Number")
264 | self.on_cancel()
265 |
266 | def on_cancel(self):
267 | print("Cancelled action")
268 | self.frm.destroy()
269 |
270 | class insertMemoForm(object):
271 | '''
272 | A form-dialog class insertion Form for building and display Memo Composition
273 | in it's own pop-up Dialog window
274 | @summary: A form to collect memo input,
275 | created: Oct 14, 2018
276 | '''
277 | here = pytz.timezone('America/New_York')
278 | currentDT = dt.datetime.now(here)
279 |
280 | def __init__(self, goal):
281 | '''
282 | Constructor for Add New Memo dialog window
283 | '''
284 |
285 | # Create instance
286 | self.frmFD3 = tk.Tk()
287 | # Add a title
288 | self.frmFD3.title("Add a Memorandum")
289 | self.memoForm()
290 | self.frmFD3.mainloop()
291 |
292 | def memoForm(self):
293 | '''
294 | The form for Memo Composition and adding
295 | '''
296 | # frame for reference fields for memo--------------------------
297 | lbfr = ttk.LabelFrame(self.frmFD3, width= 560, height=200)
298 | lbfr.grid(column=0, row=0, padx=10, pady=10)
299 | # -------------------------------------------------------------
300 | self.lbl0 = tk.Label(lbfr, text="Memo Number").grid(column=0, row=0, sticky="W")
301 | self.e0 = tk.Entry(lbfr, width=11)
302 | self.e0.grid(column=1, row=0, padx=5, pady=4, sticky='W')
303 | # -------------------------------------------------------------
304 | self.lbl1 = tk.Label(lbfr, text="Transaction").grid(column=2, row=0, sticky='W')
305 | self.e1 = tk.Entry(lbfr, width=16)
306 | self.e1.grid(column=3, row=0, padx=5, pady=4, sticky='W')
307 | # -------------------------------------------------------------
308 | self.lbl2 = tk.Label(lbfr, text="Date Time").grid(column=4, row=0, sticky='W')
309 | self.e2 = tk.Entry(lbfr,width=18)
310 | self.e2.grid(column=5, row=0, padx=5, pady=4, sticky='W')
311 | self.e2.insert(0, self.currentDT)
312 | # -------------------------------------------------------------
313 | lbfr2 = ttk.LabelFrame(self.frmFD3, text='Memo Attaching', width= 560, height=200)
314 | lbfr2.grid(column=0, row=1, padx=10, pady=10)
315 | # frame around memo text --------------------------------------
316 | scrolW1 = 80; scrolH1 = 20
317 | self.scr_memo = scrolledtext.ScrolledText(lbfr2, width=scrolW1, height=scrolH1, wrap=tk.WORD)
318 | self.scr_memo.grid(column=0, row=0, padx=4, pady=4, sticky='WE', columnspan=3)
319 | # -------------------------------------------------------------
320 | self.btn5 = ttk.Button(lbfr2, text="Commit", command=lambda: self.on_commit3()).grid(column=0,row=27,padx=8, pady=4, sticky='W')
321 | self.btn6 = ttk.Button(lbfr2, text="Cancel", command=lambda: self.on_cancel()).grid(column=1,row=27,padx=8, pady=4, sticky='W')
322 |
323 | def on_commit3(self):
324 | '''
325 | Save a Memo
326 | '''
327 | if (self.e0.get() == ''):
328 | self.on_cancel()
329 | else:
330 | row = (self.e0.get(),self.e1.get(),self.e2.get(),self.scr_memo.get(1.0, tk.END))
331 | ''' the activation of the form'''
332 | print("commit")
333 | AccountDB.insertAccountMemos(self, row)
334 | print("memoForm closed")
335 | self.frmFD3.destroy()
336 |
337 | def on_cancel(self):
338 | print("Cancelled action")
339 | self.frmFD3.destroy()
340 |
341 | class ReportFormats():
342 |
343 | def do_reptLedger(self, account):
344 | '''
345 | Report formating and data retrieval for Ledger account reports
346 | '''
347 | self.win.update()
348 | self.tab4.focus_force()
349 | self.tabControl.update()
350 | self.tab4.lift(aboveThis=None)
351 | self.tabControl.update()
352 | ledgerAcct=AccountDB.getLedgerAccount(self,account)
353 | self.reportWin.delete("all")
354 | self.reportWin.create_text(5,18,anchor=tk.NW, text='Account')
355 | self.reportWin.create_text(56,18,anchor=tk.NW, text='Transaction: ')
356 | # self.reportWin.create_text(150,18,anchor=tk.NW, text='Date')
357 | # self.reportWin.create_text(196,18,anchor=tk.NW, text='Time')
358 | self.reportWin.create_text(150,18,anchor=tk.NW, text='Description')
359 | self.reportWin.create_text(430,18,anchor=tk.NW, text='Amount')
360 | self.reportWin.create_text(495,18,anchor=tk.NW, text='Balance')
361 | cline = 18
362 | cline = cline + 20
363 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
364 | cline = cline + 3
365 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
366 | for row in ledgerAcct:
367 |
368 | cline = cline + 13
369 | maccount = str(row[0])
370 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
371 | maccount = maccount.ljust(maccountLength)
372 | self.reportWin.create_text(10,cline,anchor=tk.NW, text=maccount)
373 | mTransact = str(row[1])
374 | transactLength = 16 # 16 x 7 = 112
375 | mTransact = mTransact.ljust(transactLength)
376 | self.reportWin.create_text(62,cline,anchor=tk.NW, text=mTransact)
377 | transact = AccountDB.getJournalTransact(self,mTransact)
378 | for line in transact:
379 | mDescription = line[3]
380 | descLength = len(mDescription)+(30-len(mDescription))
381 | mDescription = mDescription.ljust(descLength)
382 | self.reportWin.create_text(150,cline,anchor=tk.NW, text=mDescription)
383 | mAmount = str(round(row[2],2))
384 | mamountLength = len(mAmount)+(8-len(mAmount)) # 8 x 7 = 56
385 | mAmount = mAmount.rjust(mamountLength)
386 | self.reportWin.create_text(430,cline,anchor=tk.NW, text=mAmount)
387 | mBalance = str(round(row[3],2))
388 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
389 | mBalance = mBalance.rjust(mbalanceLength)
390 | self.reportWin.create_text(495,cline,anchor=tk.NW, text=mBalance)
391 | cline = cline + 20
392 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
393 | cline = cline + 3
394 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
395 |
396 | def do_reptTransact(self, jTransact):
397 | '''
398 | Show formatted journal transaction
399 | font conversion factor is 7 = 10pt
400 | '''
401 | self.win.update()
402 | self.tab4.focus_force()
403 | self.tabControl.update()
404 | self.tab4.lift(aboveThis=None)
405 | self.tabControl.update()
406 | transaction = AccountDB.getJournalTransact(self,jTransact)
407 | self.reportWin.delete("all")
408 | self.reportWin.create_text(10,18,anchor=tk.NW, text='Transaction: ')
409 | self.reportWin.create_text(112,18,anchor=tk.NW, text='Date')
410 | self.reportWin.create_text(189,18,anchor=tk.NW, text='Time')
411 | self.reportWin.create_text(252,18,anchor=tk.NW, text='Description')
412 | self.reportWin.create_text(522,18,anchor=tk.NW, text='Debit')
413 | self.reportWin.create_text(606,18,anchor=tk.NW, text='Credit')
414 | cline = 18
415 | cline = cline + 20
416 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
417 | cline = cline + 3
418 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
419 | for row in transaction:
420 | cline = cline + 13
421 | mTransact = str(row[0])
422 | transactLength = 16 # 16 x 7 = 112
423 | mTransact = mTransact.ljust(transactLength)
424 | self.reportWin.create_text(10,cline,anchor=tk.NW, text=mTransact)
425 | mDate = row[1]
426 | #mDate ="2018-10-24"
427 | dateLength = 11 # 11 x 7 = 77
428 | mDate = mDate.ljust(dateLength)
429 | self.reportWin.create_text(112,cline,anchor=tk.NW, text=mDate)
430 | mTime = row[2]
431 | #mTime = "12:40:00"
432 | timeLength = 9 # 9 x 7 = 63
433 | mTime = mTime.ljust(timeLength)
434 | self.reportWin.create_text(189,cline,anchor=tk.NW, text=mTime)
435 | mDescription = row[3]
436 | #mDescription ="Pay bills" # 30 x 9 = 270
437 | descLength = len(mDescription)+(30-len(mDescription))
438 | mDescription = mDescription.ljust(descLength)
439 | self.reportWin.create_text(252,cline,anchor=tk.NW, text=mDescription)
440 | mdAccount = str(row[4])
441 | #mdAccount = "100" # 4 x 7 =28
442 | daccountLength = len(mdAccount)+(4-len(mdAccount))
443 | mdAccount = mdAccount.ljust(daccountLength)
444 | self.reportWin.create_text(522,cline,anchor=tk.NW, text=mdAccount)
445 | mdAmount = str(round(row[5],2))
446 | #mdAmount = "-24.91 " # 8 x 7 = 56
447 | damountLength = len(mdAmount)+(8-len(mdAmount))
448 | mdAmount = mdAmount.rjust(damountLength)
449 | self.reportWin.create_text(550,cline,anchor=tk.NW, text=mdAmount)
450 | mcAccount = str(row[6])
451 | #mcAccount = "220"
452 | caccountLength = len(mcAccount)+(4-len(mcAccount))
453 | mcAccount = mcAccount.ljust(caccountLength)
454 | self.reportWin.create_text(606,cline,anchor=tk.NW, text=mcAccount)
455 | mcAmount = str(round(row[7],2))
456 | #mcAmount = "-24.91 "
457 | camountLength = len(mcAmount)+(8-len(mcAmount))
458 | mcAmount = mcAmount.rjust(camountLength)
459 | self.reportWin.create_text(634,cline,anchor=tk.NW, text=mcAmount)
460 |
461 | cline = cline + 20
462 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
463 | cline = cline + 3
464 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
465 | if (int(jTransact) != 0):
466 | '''
467 | If only a single transaction is to be reported,
468 | then include all associated accounting memos with it
469 | '''
470 | memo = AccountDB.getTransactMemo(self,jTransact)
471 | cline = cline + 26
472 | self.reportWin.create_text(10,cline,anchor=tk.NW, text='Memos')
473 | cline = cline + 13
474 | self.reportWin.create_text(10,cline,anchor=tk.NW, text='Number')
475 | self.reportWin.create_text(112,cline,anchor=tk.NW, text='Date')
476 | self.reportWin.create_text(189,cline,anchor=tk.NW, text='Time')
477 | for mrow in memo:
478 | cline = cline + 13
479 | memoDate = mrow[2]
480 | dateLength = 11 # 11 x 7 = 77
481 | memoDate = memoDate.ljust(dateLength)
482 | self.reportWin.create_text(112,cline,anchor=tk.NW, text=memoDate)
483 |
484 | cline = cline + 13
485 | memoID = mrow[0]
486 | self.reportWin.create_text(10,cline,anchor=tk.NW, text=memoID)
487 | memoText = mrow[3]
488 | self.reportWin.create_text(55,cline,anchor=tk.NW, text=memoText)
489 |
490 | def do_reptChart(self):
491 | '''
492 | '''
493 | self.win.update()
494 | self.tab4.focus_force()
495 | self.tabControl.update()
496 | self.tab4.lift(aboveThis=None)
497 | self.tabControl.update()
498 | chartAcct=AccountDB.getChartAccounts(self)
499 | self.reportWin.delete("all")
500 | self.reportWin.create_text(5,18,anchor=tk.NW, text='Account')
501 | self.reportWin.create_text(56,18,anchor=tk.NW, text='Description')
502 | self.reportWin.create_text(420,18,anchor=tk.NW, text='Type')
503 | self.reportWin.create_text(485,18,anchor=tk.NW, text='Balance')
504 | cline = 18
505 | cline = cline + 20
506 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
507 | cline = cline + 3
508 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
509 | for row in chartAcct:
510 | cline = cline + 13
511 | maccount = str(row[0])
512 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
513 | maccount = maccount.ljust(maccountLength)
514 | self.reportWin.create_text(10,cline,anchor=tk.NW, text=maccount)
515 | mDescription = row[1]
516 | descLength = len(mDescription)+(30-len(mDescription))
517 | mDescription = mDescription.ljust(descLength)
518 | self.reportWin.create_text(56,cline,anchor=tk.NW, text=mDescription)
519 | mType = row[2]
520 | mTypeLength = len(mType)+(8-len(mType)) # 6 x 7 = 42
521 | mType = mType.rjust(mTypeLength)
522 | self.reportWin.create_text(420,cline,anchor=tk.NW, text=mType)
523 | mBalance = str(round(row[3],2))
524 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
525 | mBalance = mBalance.rjust(mbalanceLength)
526 | self.reportWin.create_text(485,cline,anchor=tk.NW, text=mBalance)
527 | cline = cline + 20
528 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
529 | cline = cline + 3
530 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
531 |
532 | def do_reptRevandExp(self):
533 | '''
534 | '''
535 | # Fetch revenue accounts
536 | #Fetch Expense accounts
537 |
538 | # Get Balance totals for each account
539 |
540 | # Display the Revenue and Expense accounts in a table
541 | self.reportWin.delete("all")
542 | self.reportWin.create_text(335,12, font=font.BOLD, text='THE REVENUE STATEMENT')
543 | self.reportWin.create_text(150,38, anchor=tk.NW, font=font.BOLD, text='Revenue', fill='blue')
544 | self.reportWin.create_text(460,38,anchor=tk.NW, font=font.BOLD, text='Expenses',fill='blue')
545 | self.reportWin.create_text(12,55,anchor=tk.NW, text='Account', fill='blue')
546 | self.reportWin.create_text(63,55,anchor=tk.NW, text='Name', fill='blue')
547 | self.reportWin.create_text(273,55,anchor=tk.NW, text='Balance', fill='blue')
548 | self.reportWin.create_text(344,55,anchor=tk.NW, text='Account', fill='blue')
549 | self.reportWin.create_text(395,55,anchor=tk.NW, text='Name', fill='blue')
550 | self.reportWin.create_text(605,55,anchor=tk.NW, text='Balance', fill='blue')
551 | cline = 55
552 | cline = cline + 20
553 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
554 | cline = cline + 3
555 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
556 | # get assets block
557 | blockAcct=AccountDB.getBalSheetAccounts(self,(400,499))
558 | revenueTotal = 0.0
559 | for row in blockAcct:
560 | revenueTotal = revenueTotal + float(row[3])
561 | cline = cline + 13
562 | maccount = str(row[0])
563 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
564 | maccount = maccount.ljust(maccountLength)
565 | self.reportWin.create_text(12,cline,anchor=tk.NW, text=maccount)
566 | mDescription = row[1]
567 | descLength = len(mDescription)+(30-len(mDescription))
568 | mDescription = mDescription.ljust(descLength)
569 | self.reportWin.create_text(63,cline,anchor=tk.NW, text=mDescription)
570 | mBalance = str(round(row[3],2))
571 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
572 | mBalance = mBalance.rjust(mbalanceLength)
573 | self.reportWin.create_text(273,cline,anchor=tk.NW, text=mBalance)
574 |
575 | #get liabilities
576 | # get liability block
577 | blockAcct=AccountDB.getBalSheetAccounts(self,(500,599))
578 | expenseTotal = 0.0
579 | # reset cline to top right
580 | cline = 78
581 | for row in blockAcct:
582 | expenseTotal = expenseTotal + float(row[3])
583 | cline = cline + 13
584 | maccount = str(row[0])
585 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
586 | maccount = maccount.ljust(maccountLength)
587 | self.reportWin.create_text(344,cline,anchor=tk.NW, text=maccount)
588 | mDescription = row[1]
589 | descLength = len(mDescription)+(30-len(mDescription))
590 | mDescription = mDescription.ljust(descLength)
591 | self.reportWin.create_text(395,cline,anchor=tk.NW, text=mDescription)
592 | mBalance = str(round(row[3],2))
593 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
594 | mBalance = mBalance.rjust(mbalanceLength)
595 | self.reportWin.create_text(605,cline,anchor=tk.NW, text=mBalance)
596 |
597 | retainedEarnings = revenueTotal - expenseTotal
598 |
599 | cline = cline + 33
600 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
601 | cline = cline + 3
602 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
603 | cline = cline + 13
604 | # Revenue total
605 | mlTotal = str(round(revenueTotal,2))
606 | mlTotalLength = len(mlTotal)+(10-len(mlTotal)) # 8 x 7 = 56
607 | mlTotal = mlTotal.rjust(mlTotalLength)
608 | self.reportWin.create_text(265,cline,anchor=tk.NW, text=mlTotal)
609 | # expense total
610 | mrTotal = str(round(expenseTotal,2))
611 | mrTotalLength = len(mrTotal)+(10-len(mrTotal)) # 8 x 7 = 56
612 | mrTotal = mrTotal.rjust(mrTotalLength)
613 | self.reportWin.create_text(598,cline,anchor=tk.NW, text=mrTotal)
614 |
615 | cline = cline + 39
616 | maccount = str(399)
617 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
618 | maccount = maccount.ljust(maccountLength)
619 | self.reportWin.create_text(12,cline,anchor=tk.NW, text=maccount)
620 | mDescription = 'Retained Earnings'
621 | descLength = len(mDescription)+(30-len(mDescription))
622 | mDescription = mDescription.ljust(descLength)
623 | self.reportWin.create_text(63,cline,anchor=tk.NW, text=mDescription)
624 | mBalance = str(round(retainedEarnings,2))
625 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
626 | mBalance = mBalance.rjust(mbalanceLength)
627 | self.reportWin.create_text(273,cline,anchor=tk.NW, text=mBalance)
628 |
629 |
630 |
631 | def do_reptBalSheet(self):
632 | '''
633 | '''
634 | # Fetch all Account Balances
635 |
636 | # Do trial Balances of each account, notify if any balances do not
637 | # agree with Chart of Account balances
638 |
639 |
640 | #Make and display the Balance Sheet
641 | self.reportWin.delete("all")
642 | self.reportWin.create_text(335,12, font=font.BOLD, text='THE BALANCE SHEET')
643 | self.reportWin.create_text(150,38, anchor=tk.NW, font=font.BOLD, text='ASSETS', fill='blue')
644 | self.reportWin.create_text(460,38,anchor=tk.NW, font=font.BOLD, text='LIABILITIES',fill='blue')
645 | self.reportWin.create_text(12,55,anchor=tk.NW, text='Account', fill='blue')
646 | self.reportWin.create_text(63,55,anchor=tk.NW, text='Name', fill='blue')
647 | self.reportWin.create_text(273,55,anchor=tk.NW, text='Balance', fill='blue')
648 | self.reportWin.create_text(344,55,anchor=tk.NW, text='Account', fill='blue')
649 | self.reportWin.create_text(395,55,anchor=tk.NW, text='Name', fill='blue')
650 | self.reportWin.create_text(605,55,anchor=tk.NW, text='Balance', fill='blue')
651 | cline = 55
652 | cline = cline + 20
653 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
654 | cline = cline + 3
655 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
656 | # get assets block
657 | blockAcct=AccountDB.getBalSheetAccounts(self,(100,199))
658 | assetTotal = 0.0
659 | for row in blockAcct:
660 | assetTotal = assetTotal + float(row[3])
661 | cline = cline + 13
662 | maccount = str(row[0])
663 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
664 | maccount = maccount.ljust(maccountLength)
665 | self.reportWin.create_text(12,cline,anchor=tk.NW, text=maccount)
666 | mDescription = row[1]
667 | descLength = len(mDescription)+(30-len(mDescription))
668 | mDescription = mDescription.ljust(descLength)
669 | self.reportWin.create_text(63,cline,anchor=tk.NW, text=mDescription)
670 | mBalance = str(round(row[3],2))
671 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
672 | mBalance = mBalance.rjust(mbalanceLength)
673 | self.reportWin.create_text(273,cline,anchor=tk.NW, text=mBalance)
674 |
675 | cline = cline + 20
676 | self.reportWin.create_line(265,cline, 325,cline, fill="blue")
677 | cline = cline + 13
678 | mTotal = str(round(assetTotal,2))
679 | mTotalLength = len(mTotal)+(10-len(mTotal)) # 8 x 7 = 56
680 | mTotal = mTotal.rjust(mTotalLength)
681 | self.reportWin.create_text(265,cline,anchor=tk.NW, text=mTotal)
682 |
683 | #get liabilities
684 | # get liability block
685 | blockAcct=AccountDB.getBalSheetAccounts(self,(200,299))
686 | liabilityTotal = 0.0
687 | # reset cline to top right
688 | cline = 78
689 | for row in blockAcct:
690 | assetTotal = assetTotal + float(row[3])
691 | cline = cline + 13
692 | maccount = str(row[0])
693 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
694 | maccount = maccount.ljust(maccountLength)
695 | self.reportWin.create_text(344,cline,anchor=tk.NW, text=maccount)
696 | mDescription = row[1]
697 | descLength = len(mDescription)+(30-len(mDescription))
698 | mDescription = mDescription.ljust(descLength)
699 | self.reportWin.create_text(395,cline,anchor=tk.NW, text=mDescription)
700 | mBalance = str(round(row[3],2))
701 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
702 | mBalance = mBalance.rjust(mbalanceLength)
703 | self.reportWin.create_text(605,cline,anchor=tk.NW, text=mBalance)
704 |
705 | cline = cline + 20
706 | self.reportWin.create_line(598,cline, 663,cline, fill="blue")
707 | cline = cline + 13
708 | msTotal = str(round(liabilityTotal,2))
709 | msTotalLength = len(msTotal)+(10-len(msTotal)) # 8 x 7 = 56
710 | msTotal = msTotal.rjust(msTotalLength)
711 | self.reportWin.create_text(598,cline,anchor=tk.NW, text=msTotal)
712 |
713 | cline = cline + 33
714 | self.reportWin.create_text(467,cline,anchor=tk.NW, font=font.BOLD, text='Equity',fill='blue')
715 |
716 | cline = cline + 20
717 | self.reportWin.create_line(335,cline, 670,cline, fill="blue")
718 | cline = cline + 3
719 | self.reportWin.create_line(335,cline, 670,cline, fill="blue")
720 |
721 | # get income block total
722 | blockAcct=AccountDB.getBalSheetAccounts(self,(400,499))
723 | incomeTotal = 0.0
724 | for row in blockAcct:
725 | incomeTotal = incomeTotal + float(row[3])
726 | # get expense block total
727 | blockAcct=AccountDB.getBalSheetAccounts(self,(500,599))
728 | expenseTotal = 0.0
729 | for row in blockAcct:
730 | expenseTotal = expenseTotal + float(row[3])
731 | retainedEarnings = incomeTotal - expenseTotal
732 |
733 | # get equity block
734 | blockAcct=AccountDB.getBalSheetAccounts(self,(300,399))
735 | equityTotal = 0.0
736 | # reset cline to top right
737 | for row in blockAcct:
738 | equityTotal = equityTotal + float(row[3])
739 | cline = cline + 13
740 | maccount = str(row[0])
741 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
742 | maccount = maccount.ljust(maccountLength)
743 | self.reportWin.create_text(344,cline,anchor=tk.NW, text=maccount)
744 | mDescription = row[1]
745 | descLength = len(mDescription)+(30-len(mDescription))
746 | mDescription = mDescription.ljust(descLength)
747 | self.reportWin.create_text(395,cline,anchor=tk.NW, text=mDescription)
748 | mBalance = str(round(row[3],2))
749 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
750 | mBalance = mBalance.rjust(mbalanceLength)
751 | self.reportWin.create_text(605,cline,anchor=tk.NW, text=mBalance)
752 |
753 | cline = cline + 13
754 | maccount = str(399)
755 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
756 | maccount = maccount.ljust(maccountLength)
757 | self.reportWin.create_text(344,cline,anchor=tk.NW, text=maccount)
758 | mDescription = 'Retained Earnings'
759 | descLength = len(mDescription)+(30-len(mDescription))
760 | mDescription = mDescription.ljust(descLength)
761 | self.reportWin.create_text(395,cline,anchor=tk.NW, text=mDescription)
762 | mBalance = str(round(retainedEarnings,2))
763 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
764 | mBalance = mBalance.rjust(mbalanceLength)
765 | self.reportWin.create_text(612,cline,anchor=tk.NW, text=mBalance)
766 |
767 | cline = cline + 20
768 | self.reportWin.create_line(598,cline, 663,cline, fill="blue")
769 | cline = cline + 13
770 | msTotal = str(round((equityTotal + retainedEarnings),2))
771 |
772 | msTotalLength = len(msTotal)+(10-len(msTotal))
773 | msTotal = msTotal.rjust(msTotalLength)
774 | self.reportWin.create_text(598,cline,anchor=tk.NW, text=msTotal)
775 |
776 | cline = cline + 20
777 | self.reportWin.create_line(598,cline, 663,cline, fill="blue")
778 |
779 | cline = cline + 43
780 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
781 | cline = cline + 3
782 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
783 | cline = cline + 13
784 |
785 | self.reportWin.create_text(265,cline,anchor=tk.NW, text=mTotal)
786 | mrTotal = str(round((equityTotal + liabilityTotal),2))
787 | mrTotalLength = len(mrTotal)+(10-len(mrTotal))
788 | mrTotal = msTotal.rjust(mrTotalLength)
789 | self.reportWin.create_text(598,cline,anchor=tk.NW, text=mrTotal)
790 |
791 | def do_reptTrialBalance(self):
792 | '''
793 | '''
794 | # Fetch revenue accounts
795 | # Fetch Expense accounts
796 | # Get Balance totals for each account
797 | # Display the Revenue and Expense accounts in a table
798 | self.reportWin.delete("all")
799 | self.reportWin.create_text(335,12, font=font.BOLD, text='Trial Balance Display')
800 | self.reportWin.create_text(150,38, anchor=tk.NW, font=font.BOLD, text='DEBITS', fill='blue')
801 | self.reportWin.create_text(460,38,anchor=tk.NW, font=font.BOLD, text='CREDITS',fill='blue')
802 | self.reportWin.create_text(12,55,anchor=tk.NW, text='Account', fill='blue')
803 | self.reportWin.create_text(63,55,anchor=tk.NW, text='Name', fill='blue')
804 | self.reportWin.create_text(273,55,anchor=tk.NW, text='Balance', fill='blue')
805 | self.reportWin.create_text(344,55,anchor=tk.NW, text='Account', fill='blue')
806 | self.reportWin.create_text(395,55,anchor=tk.NW, text='Name', fill='blue')
807 | self.reportWin.create_text(605,55,anchor=tk.NW, text='Balance', fill='blue')
808 | cline = 55
809 | # -------------------------------------------------------------
810 | cline = cline + 20
811 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
812 | cline = cline + 3
813 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
814 | # -------------------------------------------------------------
815 | # -------------------------------------------------------------
816 | # Get Debits
817 | # get assets block
818 | blockAcct=AccountDB.getBalSheetAccounts(self,(100,199))
819 | assetsTotal = 0.0
820 | for row in blockAcct:
821 | account = row[0]
822 | ldgrAccount = AccountDB.getLedgerAccount(self,account)
823 | acctTotal = 0.0
824 | for mtransact in ldgrAccount:
825 | acctTotal = acctTotal + mtransact[2]
826 | assetsTotal = assetsTotal + float(acctTotal)
827 | cline = cline + 13
828 | maccount = str(row[0])
829 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
830 | maccount = maccount.ljust(maccountLength)
831 | self.reportWin.create_text(12,cline,anchor=tk.NW, text=maccount)
832 | mDescription = row[1]
833 | descLength = len(mDescription)+(30-len(mDescription))
834 | mDescription = mDescription.ljust(descLength)
835 | self.reportWin.create_text(63,cline,anchor=tk.NW, text=mDescription)
836 | mBalance = str(round(acctTotal,2))
837 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
838 | mBalance = mBalance.rjust(mbalanceLength)
839 | self.reportWin.create_text(273,cline,anchor=tk.NW, text=mBalance)
840 |
841 | cline = cline + 20
842 | self.reportWin.create_line(265,cline, 325,cline, fill="blue")
843 | cline = cline + 13
844 | mTotal = str(round(assetsTotal,2))
845 | mTotalLength = len(mTotal)+(10-len(mTotal)) # 8 x 7 = 56
846 | mTotal = mTotal.rjust(mTotalLength)
847 | self.reportWin.create_text(265,cline,anchor=tk.NW, text=mTotal)
848 | cline = cline + 13
849 |
850 | # -------------------------------------------------------------
851 | # get Expense block
852 | blockAcct=AccountDB.getBalSheetAccounts(self,(500,599))
853 | expenseTotal = 0.0
854 | # reset cline to top right
855 | for row in blockAcct:
856 | account = row[0]
857 | ldgrAccount = AccountDB.getLedgerAccount(self,account)
858 | acctTotal = 0.0
859 | for mtransact in ldgrAccount:
860 | acctTotal = acctTotal + mtransact[2]
861 | expenseTotal = expenseTotal + float(acctTotal)
862 | cline = cline + 13
863 | maccount = str(row[0])
864 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
865 | maccount = maccount.ljust(maccountLength)
866 | self.reportWin.create_text(12,cline,anchor=tk.NW, text=maccount)
867 | mDescription = row[1]
868 | descLength = len(mDescription)+(30-len(mDescription))
869 | mDescription = mDescription.ljust(descLength)
870 | self.reportWin.create_text(63,cline,anchor=tk.NW, text=mDescription)
871 | mBalance = str(round(acctTotal,2))
872 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
873 | mBalance = mBalance.rjust(mbalanceLength)
874 | self.reportWin.create_text(273,cline,anchor=tk.NW, text=mBalance)
875 |
876 | cline = cline + 20
877 | self.reportWin.create_line(265,cline, 325,cline, fill="blue")
878 | cline = cline + 13
879 | mlTotal = str(round(expenseTotal,2))
880 | mlTotalLength = len(mlTotal)+(10-len(mlTotal)) # 8 x 7 = 56
881 | mlTotal = mlTotal.rjust(mlTotalLength)
882 | self.reportWin.create_text(265,cline,anchor=tk.NW, text=mlTotal)
883 | cline = cline + 13
884 | lcline = cline
885 |
886 | # -------------------------------------------------------------
887 | # -------------------------------------------------------------
888 | # get Credits
889 | # get Liabilities and Equity block
890 | blockAcct=AccountDB.getBalSheetAccounts(self,(200,399))
891 | liabilitiesTotal = 0.0
892 | # reset cline to top right
893 | cline = 78
894 | for row in blockAcct:
895 | account = row[0]
896 | ldgrAccount = AccountDB.getLedgerAccount(self,account)
897 | acctTotal = 0.0
898 | for mtransact in ldgrAccount:
899 | acctTotal = acctTotal + mtransact[2]
900 | liabilitiesTotal = liabilitiesTotal + float(acctTotal)
901 | cline = cline + 13
902 | maccount = str(row[0])
903 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
904 | maccount = maccount.ljust(maccountLength)
905 | self.reportWin.create_text(344,cline,anchor=tk.NW, text=maccount)
906 | mDescription = row[1]
907 | descLength = len(mDescription)+(30-len(mDescription))
908 | mDescription = mDescription.ljust(descLength)
909 | self.reportWin.create_text(395,cline,anchor=tk.NW, text=mDescription)
910 | mBalance = str(round(acctTotal,2))
911 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
912 | mBalance = mBalance.rjust(mbalanceLength)
913 | self.reportWin.create_text(612,cline,anchor=tk.NW, text=mBalance)
914 |
915 | cline = cline + 20
916 | self.reportWin.create_line(598,cline, 663,cline, fill="blue")
917 | cline = cline + 13
918 | mrTotal = str(round(liabilitiesTotal,2))
919 | mrTotalLength = len(mrTotal)+(10-len(mrTotal)) # 8 x 7 = 56
920 | mrTotal = mrTotal.rjust(mrTotalLength)
921 | self.reportWin.create_text(598,cline,anchor=tk.NW, text=mrTotal)
922 |
923 | # -------------------------------------------------------------
924 | # get revenue block
925 | cline = cline + 13
926 | blockAcct=AccountDB.getBalSheetAccounts(self,(400,499))
927 | revenueTotal = 0.0
928 | for row in blockAcct:
929 | account = row[0]
930 | ldgrAccount = AccountDB.getLedgerAccount(self,account)
931 | acctTotal = 0.0
932 | for mtransact in ldgrAccount:
933 | revenueTotal = revenueTotal + mtransact[2]
934 | assetsTotal = assetsTotal + float(acctTotal)
935 | cline = cline + 13
936 | maccount = str(row[0])
937 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
938 | maccount = maccount.ljust(maccountLength)
939 | self.reportWin.create_text(344,cline,anchor=tk.NW, text=maccount)
940 | mDescription = row[1]
941 | descLength = len(mDescription)+(30-len(mDescription))
942 | mDescription = mDescription.ljust(descLength)
943 | self.reportWin.create_text(395,cline,anchor=tk.NW, text=mDescription)
944 | mBalance = str(round(acctTotal,2))
945 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
946 | mBalance = mBalance.rjust(mbalanceLength)
947 | self.reportWin.create_text(612,cline,anchor=tk.NW, text=mBalance)
948 |
949 | cline = cline + 20
950 | self.reportWin.create_line(598,cline, 663,cline, fill="blue")
951 |
952 | cline = cline + 13
953 | mrTotal = str(round(revenueTotal,2))
954 | mrTotalLength = len(mrTotal)+(10-len(mrTotal)) # 8 x 7 = 56
955 | mrTotal = mrTotal.rjust(mrTotalLength)
956 | self.reportWin.create_text(598,cline,anchor=tk.NW, text=mrTotal)
957 | cline = cline + 13
958 | rcline = cline
959 | # -------------------------------------------------------------
960 | # check which column is longer and use it
961 | if lcline > rcline:
962 | cline = lcline
963 | else:
964 | cline = rcline
965 | cline = cline + 26
966 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
967 | cline = cline + 3
968 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
969 | cline = cline + 26
970 | debitTotal = assetsTotal + expenseTotal
971 | self.reportWin.create_text(63,cline,anchor=tk.NW, text="Total Debits")
972 | self.reportWin.create_text(265,cline,anchor=tk.NW, text=debitTotal)
973 | creditTotal = liabilitiesTotal + revenueTotal
974 | self.reportWin.create_text(395,cline,anchor=tk.NW, text="Total Credits")
975 | self.reportWin.create_text(598,cline,anchor=tk.NW, text=creditTotal)
976 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 David A York
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/OpenAccounting.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/OpenAccounting.db
--------------------------------------------------------------------------------
/OpenAccounting.py:
--------------------------------------------------------------------------------
1 | '''
2 | OpenAccounting
3 | Created on Oct 17, 2018
4 | @summary: An open source double entry accounting system based on SQLite and written in python
5 | @note: Project pages at: https://medmatix.github.io/Accounting-System/
6 | @author: David York
7 | @version: 0.21
8 | @copyright: David A York 2018
9 | @license: MIT
10 | @contact: http://crunches-data.appspot.com/contact.html
11 | '''
12 |
13 | # #####################
14 | # Imports
15 | # #####################
16 | # Standard library and third party imports
17 | # tkinter imports
18 | import tkinter as tk
19 | from tkinter import ttk
20 | from tkinter import scrolledtext
21 | from tkinter import Menu
22 | from tkinter import messagebox as mBox
23 | from tkinter import simpledialog
24 | from tkinter import Scrollbar
25 | from tkinter import Canvas
26 | from tkinter import font
27 | from PIL import Image, ImageTk
28 | # other standard and third party imports
29 | # all 3rd party are pip installable
30 | import sqlite3
31 | import datetime as dt
32 | import pytz
33 | import math as mt
34 | import numpy as np
35 | import sys
36 | import os
37 | import pathlib
38 | import time
39 |
40 | # Custom module imports
41 | from AccountDB import AccountDB
42 | import FormDialogs
43 | from FormDialogs import insertJournalForm, insertChartForm, insertMemoForm
44 | from FormDialogs import ReportFormats
45 | from Tooltips import createToolTip, ToolTip
46 | from ReportPreps import TrialBalance
47 | import splash
48 |
49 |
50 |
51 | class AccountingSystem():
52 | '''
53 | Class for the Main Application
54 | @summary: Application tkinter GUI interface and accounting function access
55 | @note: From this module all the functionality of the accounting system is accessible
56 | '''
57 | def __init__(self):
58 | '''
59 | Constructor Setup the Application
60 | '''
61 | # Create instance
62 | self.win = tk.Tk()
63 |
64 | # Add a title
65 | self.win.title("Open Accounting")
66 |
67 |
68 | # Add a icon
69 | if not sys.platform.startswith('linux'):
70 | self.win.iconbitmap('./images/medmatix_tilt.ico')
71 |
72 | # Initialize widgets
73 | self.createWidgets()
74 |
75 | # #################################
76 | # GUI callback functions
77 | # #################################
78 | # -- Exit GUI cleanly -------------
79 | def _quit(self):
80 | self.win.quit()
81 | self.win.destroy()
82 | print('run is done, exited normally!')
83 | exit()
84 |
85 | def do_showChart(self):
86 | self.scrolList3.delete(1.0,tk.END)
87 | listAll = AccountDB.getChartAccounts(self)
88 | for row in listAll:
89 | #self.do_formatedList(row)
90 | self.scrolList3.insert(tk.END,row[0])
91 | self.scrolList3.insert(tk.END,'\t ')
92 | mName = row[1]
93 | nameLength = len(mName)+(40-len(mName))
94 | mName = mName.ljust(nameLength)
95 | self.scrolList3.insert(tk.END,mName)
96 | self.scrolList3.insert(tk.END,' ')
97 | mType = row[2]
98 | typeLength = len(row[2])+(12-len(row[2]))
99 | mType = mType.ljust(typeLength)
100 | self.scrolList3.insert(tk.END,mType)
101 | self.scrolList3.insert(tk.END,'\t')
102 | mBalance = str(round(row[3],2))
103 | balanceLength = len(mBalance)+(8-len(mBalance))
104 | mBalance = mBalance.rjust(balanceLength)
105 | self.scrolList3.insert(tk.END,mBalance)
106 | self.scrolList3.insert(tk.END,'\n')
107 |
108 | def do_showLedger(self, account):
109 | self.scrolList2.delete(1.0,tk.END)
110 | account = int(account)
111 |
112 | listAll = AccountDB.getLedgerAccount(self,account)
113 | for row in listAll:
114 | #self.do_formatedList(row)
115 | self.scrolList2.insert(tk.END,row[0])
116 | self.scrolList2.insert(tk.END,'\t ')
117 | mTransact = str(row[1])
118 | transactLength = len(mTransact)+(10-len(mTransact))
119 | mTransact = mTransact.ljust(transactLength)
120 | self.scrolList2.insert(tk.END,mTransact)
121 | self.scrolList2.insert(tk.END,'\t ')
122 | mAmount = str(row[2])
123 | amountLength = len(mAmount)+(8-len(mAmount))
124 | mAmount = mAmount.ljust(amountLength)
125 | self.scrolList2.insert(tk.END,mAmount)
126 | self.scrolList2.insert(tk.END,'\t')
127 | mBalance = str(round(row[3],2))
128 | balanceLength = len(mBalance)+(8-len(mBalance))
129 | mBalance = mBalance.rjust(balanceLength)
130 | self.scrolList2.insert(tk.END,mBalance)
131 | self.scrolList2.insert(tk.END,'\n')
132 |
133 | def do_showJournal(self, jDates):
134 | '''
135 | Show formatted journal
136 | '''
137 | self.scrolList1.delete(1.0,tk.END)
138 | listAll = AccountDB.getJournalEntries(self,jDates)
139 | for row in listAll:
140 | self.scrolList1.insert(tk.END,row[0])
141 | self.scrolList1.insert(tk.END,'\t')
142 | mDate = row[1]
143 | dateLength = 10
144 | mDate = mDate.ljust(dateLength)
145 | self.scrolList1.insert(tk.END,mDate)
146 | self.scrolList1.insert(tk.END,' ')
147 | mTime = row[2]
148 | timeLength = 9
149 | mTime = mTime.ljust(timeLength)
150 | self.scrolList1.insert(tk.END,mTime)
151 | self.scrolList1.insert(tk.END,' ')
152 | mDescription = row[3]
153 | descLength = len(row[3])+(30-len(row[3]))
154 | mDescription = mDescription.ljust(descLength)
155 | self.scrolList1.insert(tk.END,mDescription)
156 | self.scrolList1.insert(tk.END,' \t')
157 | mdAccount = str(row[4])
158 | daccountLength = len(mdAccount)+(4-len(mdAccount))
159 | mdAccount = mdAccount.ljust(daccountLength)
160 | self.scrolList1.insert(tk.END,mdAccount)
161 | self.scrolList1.insert(tk.END,' ')
162 | mdAmount = str(round(row[5],2))
163 | damountLength = len(mdAmount)+(8-len(mdAmount))
164 | mdAmount = mdAmount.rjust(damountLength)
165 | self.scrolList1.insert(tk.END,mdAmount)
166 | self.scrolList1.insert(tk.END,'\t\t ')
167 | mcAccount = str(row[6])
168 | caccountLength = len(mcAccount)+(4-len(mcAccount))
169 | mcAccount = mcAccount.ljust(caccountLength)
170 | self.scrolList1.insert(tk.END,mcAccount)
171 | self.scrolList1.insert(tk.END,'\t')
172 | mcAmount = str(round(row[7],2))
173 | camountLength = len(mcAmount)+(8-len(mcAmount))
174 | mcAmount = mcAmount.rjust(camountLength)
175 | self.scrolList1.insert(tk.END,mcAmount)
176 | self.scrolList1.insert(tk.END,'\n')
177 |
178 | def do_reptTransact(self, jTransact):
179 | '''
180 | Show formatted journal transaction
181 | font conversion factor is 7 = 10pt
182 | '''
183 | self.win.update()
184 | self.tab4.focus_force()
185 | self.tabControl.update()
186 | self.tab4.lift(aboveThis=None)
187 | self.tabControl.update()
188 | transaction = AccountDB.getJournalTransact(self,jTransact)
189 | self.reportWin.delete("all")
190 | self.reportWin.create_text(10,18,anchor=tk.NW, text='Transaction: ')
191 | self.reportWin.create_text(112,18,anchor=tk.NW, text='Date')
192 | self.reportWin.create_text(189,18,anchor=tk.NW, text='Time')
193 | self.reportWin.create_text(252,18,anchor=tk.NW, text='Description')
194 | self.reportWin.create_text(522,18,anchor=tk.NW, text='Debit')
195 | self.reportWin.create_text(606,18,anchor=tk.NW, text='Credit')
196 | cline = 18
197 | cline = cline + 20
198 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
199 | cline = cline + 3
200 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
201 | for row in transaction:
202 | cline = cline + 13
203 | mTransact = str(row[0])
204 | transactLength = 16 # 16 x 7 = 112
205 | mTransact = mTransact.ljust(transactLength)
206 | self.reportWin.create_text(10,cline,anchor=tk.NW, text=mTransact)
207 | mDate = row[1]
208 | #mDate ="2018-10-24"
209 | dateLength = 11 # 11 x 7 = 77
210 | mDate = mDate.ljust(dateLength)
211 | self.reportWin.create_text(112,cline,anchor=tk.NW, text=mDate)
212 | mTime = row[2]
213 | #mTime = "12:40:00"
214 | timeLength = 9 # 9 x 7 = 63
215 | mTime = mTime.ljust(timeLength)
216 | self.reportWin.create_text(189,cline,anchor=tk.NW, text=mTime)
217 | mDescription = row[3]
218 | #mDescription ="Pay bills" # 30 x 9 = 270
219 | descLength = len(mDescription)+(30-len(mDescription))
220 | mDescription = mDescription.ljust(descLength)
221 | self.reportWin.create_text(252,cline,anchor=tk.NW, text=mDescription)
222 | mdAccount = str(row[4])
223 | #mdAccount = "100" # 4 x 7 =28
224 | daccountLength = len(mdAccount)+(4-len(mdAccount))
225 | mdAccount = mdAccount.ljust(daccountLength)
226 | self.reportWin.create_text(522,cline,anchor=tk.NW, text=mdAccount)
227 | mdAmount = str(round(row[5],2))
228 | #mdAmount = "-24.91 " # 8 x 7 = 56
229 | damountLength = len(mdAmount)+(8-len(mdAmount))
230 | mdAmount = mdAmount.rjust(damountLength)
231 | self.reportWin.create_text(550,cline,anchor=tk.NW, text=mdAmount)
232 | mcAccount = str(row[6])
233 | #mcAccount = "220"
234 | caccountLength = len(mcAccount)+(4-len(mcAccount))
235 | mcAccount = mcAccount.ljust(caccountLength)
236 | self.reportWin.create_text(606,cline,anchor=tk.NW, text=mcAccount)
237 | mcAmount = str(round(row[7],2))
238 | #mcAmount = "-24.91 "
239 | camountLength = len(mcAmount)+(8-len(mcAmount))
240 | mcAmount = mcAmount.rjust(camountLength)
241 | self.reportWin.create_text(634,cline,anchor=tk.NW, text=mcAmount)
242 |
243 | cline = cline + 20
244 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
245 | cline = cline + 3
246 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
247 | if (int(jTransact) != 0):
248 | '''
249 | If only a single transaction is to be reported,
250 | then include all associated accounting memos with it
251 | '''
252 | memo = AccountDB.getTransactMemo(self,jTransact)
253 | cline = cline + 26
254 | self.reportWin.create_text(10,cline,anchor=tk.NW, text='Memos')
255 | cline = cline + 13
256 | self.reportWin.create_text(10,cline,anchor=tk.NW, text='Number')
257 | self.reportWin.create_text(112,cline,anchor=tk.NW, text='Date')
258 | self.reportWin.create_text(189,cline,anchor=tk.NW, text='Time')
259 | for mrow in memo:
260 | cline = cline + 13
261 | memoDate = mrow[2]
262 | dateLength = 11 # 11 x 7 = 77
263 | memoDate = memoDate.ljust(dateLength)
264 | self.reportWin.create_text(112,cline,anchor=tk.NW, text=memoDate)
265 |
266 | cline = cline + 13
267 | memoID = mrow[0]
268 | self.reportWin.create_text(10,cline,anchor=tk.NW, text=memoID)
269 | memoText = mrow[3]
270 | self.reportWin.create_text(55,cline,anchor=tk.NW, text=memoText)
271 |
272 | def do_reptChart(self):
273 | '''
274 | '''
275 | self.win.update()
276 | self.tab4.focus_force()
277 | self.tabControl.update()
278 | self.tab4.lift(aboveThis=None)
279 | self.tabControl.update()
280 | chartAcct=AccountDB.getChartAccounts(self)
281 | self.reportWin.delete("all")
282 | self.reportWin.create_text(5,18,anchor=tk.NW, text='Account')
283 | self.reportWin.create_text(56,18,anchor=tk.NW, text='Description')
284 | self.reportWin.create_text(420,18,anchor=tk.NW, text='Type')
285 | self.reportWin.create_text(485,18,anchor=tk.NW, text='Balance')
286 | cline = 18
287 | cline = cline + 20
288 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
289 | cline = cline + 3
290 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
291 | for row in chartAcct:
292 | cline = cline + 13
293 | maccount = str(row[0])
294 | maccountLength = len(maccount)+(4-len(maccount)) # 4 x 7 =28
295 | maccount = maccount.ljust(maccountLength)
296 | self.reportWin.create_text(10,cline,anchor=tk.NW, text=maccount)
297 | mDescription = row[1]
298 | descLength = len(mDescription)+(30-len(mDescription))
299 | mDescription = mDescription.ljust(descLength)
300 | self.reportWin.create_text(56,cline,anchor=tk.NW, text=mDescription)
301 | mType = row[2]
302 | mTypeLength = len(mType)+(8-len(mType)) # 6 x 7 = 42
303 | mType = mType.rjust(mTypeLength)
304 | self.reportWin.create_text(420,cline,anchor=tk.NW, text=mType)
305 | mBalance = str(round(row[3],2))
306 | mbalanceLength = len(mBalance)+(8-len(mBalance)) # 8 x 7 = 56
307 | mBalance = mBalance.rjust(mbalanceLength)
308 | self.reportWin.create_text(485,cline,anchor=tk.NW, text=mBalance)
309 | cline = cline + 20
310 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
311 | cline = cline + 3
312 | self.reportWin.create_line(10,cline, 670,cline, fill="blue")
313 |
314 |
315 |
316 | # #################################
317 | # Other Control Functions etc.
318 | # #################################
319 |
320 | def click_on_widget(self, widget, button=1):
321 | widget.focus_force()
322 | self.win.update()
323 | widget.event_generate("".format(button))
324 | self.win.update()
325 |
326 | def newMemo(self):
327 | '''
328 | Method to start a new accounting memo
329 | '''
330 | proceedAnswer = mBox.askyesno("New Memo","Save current memo and start a new one?")
331 | if proceedAnswer==True:
332 | '''
333 | Insert an entry into Journal
334 | '''
335 | id = int(self.ememoID.get())
336 | transact = int(self.ememoTransact.get())
337 | memo=str(self.scr_memo.get(1.0,tk.END))
338 | row = (id, transact,self.ememoDate.get(),memo)
339 | try:
340 | AccountDB.insertAccountMemos(row)
341 | except:
342 | print("not saved, probable duplicate memo")
343 | # clear the memo
344 | self.scr_memo.delete(1.0,tk.END)
345 | self.scr_memo.see(tk.END)
346 | print('cleared the notes pad')
347 | else:
348 | pass
349 |
350 | def printMemo(self):
351 | '''
352 | Method to Print a selected accounting memo
353 | '''
354 | proceedAnswer = mBox.askyesno("print Memo","Send the current memo to the printer?")
355 | if proceedAnswer==True:
356 | pass
357 | else:
358 | pass
359 |
360 | def saveMemo(self):
361 | '''
362 | Method to save the current accounting memo
363 | '''
364 | proceedAnswer = mBox.askyesno("Save Memo","Save current memo and continue?")
365 | if (proceedAnswer):
366 | '''
367 | Save a Memo
368 | '''
369 | mid = int(self.ememoID.get())
370 | transact = int(self.ememoTransact.get())
371 | memo=str(self.scr_memo.get(1.0,tk.END))
372 | row = (mid, transact,self.ememoDate.get(),memo)
373 | try:
374 | AccountDB.insertAccountMemos(row)
375 | except:
376 | print("not saved, probable duplicate memo")
377 |
378 |
379 | def fetchMemo(self):
380 | '''
381 | Method to fetch a selected accounting memo
382 | '''
383 | answer1 = simpledialog.askstring("Input", "How Do you want to retrieve, MemoNo or Date-Transact", parent=self.win)
384 | if answer1=="MemoNo":
385 | answer2 = simpledialog.askstring("Input", "Enter the Memo ID Number", parent=self.win)
386 | elif answer1=="Date-Transact":
387 | answer2 = simpledialog.askstring("Input", "Enter Date and Transaction (separated by a comma", parent=self.win)
388 | else:
389 | pass
390 |
391 | def do_balSheet(self):
392 | '''
393 | '''
394 |
395 | proceedAnswer = mBox.askyesno("Balance Sheet Report","This can take a while.\nPrepare report now?")
396 | if (proceedAnswer):
397 | debandcred = TrialBalance.trialBalance(self)
398 | if (debandcred[0]-debandcred[1]==0):
399 | ReportFormats.do_reptBalSheet(self)
400 | else:
401 | mBox.showinfo('Failed trial balance' , 'The Ledger appears to be out of balance. \n A balance sheet may have errors\nPerform a Trial Balance to Investigate')
402 | def do_LedgerAcct(self):
403 | '''
404 | '''
405 | proceedAnswer = mBox.askyesno("Ledger Account Report","Prepare report now?")
406 | pass
407 |
408 |
409 | def do_RevandExp(self):
410 | '''
411 | '''
412 |
413 | proceedAnswer = mBox.askyesno("Revenue and Expense Report","Prepare report now?")
414 | if (proceedAnswer):
415 | debandcred = TrialBalance.trialBalance(self)
416 | if (debandcred[0]-debandcred[1]==0):
417 | ReportFormats.do_reptRevandExp(self)
418 | else:
419 | mBox.showinfo('Failed trial balance' , 'The Ledger appears to be out of balance. \nAn Income statment may have errors\nPerform a Trial Balance to Investigate')
420 |
421 |
422 | def do_trialBalance(self):
423 | '''
424 | Calculate net balances for each chart account and compare to Chart of
425 | Account balances. If any do not agree, notify which are out and return results
426 | '''
427 | proceedAnswer = mBox.askyesno("Trial Balance Report","This can take a while.\nPerform a trail balance now?")
428 | if (proceedAnswer):
429 | ReportFormats.do_reptTrialBalance(self)
430 |
431 | def do_printCurrentView(self):
432 | '''
433 | '''
434 | proceedAnswer = mBox.askyesno("Print Current Report","Postcript write to file 'Printfile.ps'?")
435 | if (proceedAnswer):
436 | self.reportWin.postscript(file='Printfile.ps')
437 |
438 | # #####################################
439 | # Create GUI Functions (Visualization)
440 | # #####################################
441 | def createWidgets(self):
442 | '''
443 | Create the GUI interfaces
444 | '''
445 | # Messages and Dialogs -------------------------------------------
446 | def info(self):
447 | mBox.showinfo('About OpenAccounting, ' , 'Application to Perform Basic GAAP Accounting functions.\n\n (c) David A York, 2018\n http:crunches-data.appspot.com \nVersion: 0.2alpha, development version 0.21 \nlicense: MIT')
448 |
449 |
450 | def notImplementedInfo(self):
451 | mBox.showinfo('Function Not Implemented Yet, ' , 'Sorry this is not implemented in full yet.\n\n Note For Printing: This is a high priority for me but tkinter is not very amenable to printing widget contents. However, at this time, you can take a screen shot and print from clipboard')
452 |
453 | def notImplementedPayroll(self):
454 | mBox.showinfo('Payroll Not Implemented Yet, ' , 'Sorry this functionality is not implemented yet.\n\n This specialized journal will be developed after all basic accounting \nfunctionality is in place. Your support is appreciated')
455 |
456 | def notImplementedInventory(self):
457 | mBox.showinfo('Inventory Not Implemented Yet, ' , 'Sorry this functionality is not implemented yet.\n\n This specialized journal will be developed after all basic accounting \nfunctionality is in place. Your support is appreciated')
458 |
459 | def notImplementedHelp(self):
460 | mBox.showinfo('Help Not Implemented Yet, ' , 'Sorry the Help is not implemented in full yet.\n\n This is part of the basic application functionality and is next in priority. \nFor now the background in the github repository readme \nmay be helpful. See about, in help.')
461 |
462 | def notImplementedEndofCycle(self):
463 | mBox.showinfo('End of Cycle Not Implemented Yet, ' , 'Sorry the comprehensive End of Cycle is not implemented in full yet.\n\n This is part of the basic application functionality and is a high priority for me.\n\nFor now, all closing activities can be carried out with the \nGeneral Journal if you are familiar with those tasks.')
464 |
465 | def fetchLedgerAccount(self):
466 | answer = simpledialog.askstring("Get Ledger Account", "What Account Number to retrieve?\n Enter '0' for ALL\n", parent=self.win)
467 | if answer is not None:
468 | ReportFormats.do_reptLedger(self,answer)
469 | else:
470 | print("No Value entered")
471 | return 0
472 |
473 | def getJournalDates(self):
474 | answer = simpledialog.askstring("Get Journal Range", "Start and End Date for Journal Retrieval\n, a comma separated pair. \n Enter '0,0' for ALL\n", parent=self.win)
475 | if answer is not None:
476 | jDates = (answer,)
477 | self.do_showJournal((jDates))
478 | else:
479 | print("No Value entered")
480 | return 0
481 |
482 | def getTransact(self):
483 | answer = simpledialog.askstring("Get Transaction", "Transaction to retrieve?\n\nEnter a Transaction Number\n Enter '0' for ALL \n", parent=self.win)
484 | if answer is not None:
485 | jTransact = (answer)
486 | self.do_reptTransact(jTransact)
487 | else:
488 | print("No Value entered")
489 | return 0
490 |
491 |
492 | # Tab Controls created here --------------------------------------
493 | self.tabControl = ttk.Notebook(self.win) # Create Tab Controls
494 |
495 | self.tab1 = ttk.Frame(self.tabControl)
496 | self.tabControl.add(self.tab1, text='Journal')
497 |
498 | self.tab2 = ttk.Frame(self.tabControl)
499 | self.tabControl.add(self.tab2, text='Ledger')
500 |
501 | self.tab3 = ttk.Frame(self.tabControl)
502 | self.tabControl.add(self.tab3, text='Chart of Accounts')
503 |
504 | self.tab4 = ttk.Frame(self.tabControl)
505 | self.tabControl.add(self.tab4, text='Views and Reports')
506 |
507 | self.tab5 = ttk.Frame(self.tabControl)
508 | self.tabControl.add(self.tab5, text='Accounting Memo')
509 |
510 | self.tab6 = ttk.Frame(self.tabControl)
511 | self.tabControl.add(self.tab6, text='Maintenance')
512 |
513 | self.tabControl.grid() # Pack to make visible
514 |
515 | frm1 = ttk.Labelframe(self.tab1, text='General Journal', width= 650, height=600)
516 | frm1.grid()
517 | ttk.Label(frm1, text="The General Journal is the book of first entry in the accounting system. It is accessed directly in the course of recording the daily activities of the enterprise.\n All other related books are accessible as appropriate for addition and update from the general journal.").grid(column=0, row=0, padx=4, pady=4,sticky='W')
518 | frm1a = ttk.Labelframe(frm1, width= 550, height=500)
519 | frm1a.grid(column=0,row=1)
520 | jDates = (0,0)
521 | self.updateJournal = ttk.Button(frm1a, text="Update Display", command=lambda: self.do_showJournal(jDates)).grid(column=0,row=1,padx=4, pady=4)
522 | self.printJournal = ttk.Button(frm1a, text="PRINT", command=lambda: notImplementedInfo(self)).grid(column=1,row=1,padx=4, pady=4)
523 | self.newEntry = ttk.Button(frm1a, text="New Entry", command=lambda: insertJournalForm(self)).grid(column=2,row=1,padx=4, pady=4)
524 | ttk.Label(frm1, text="Transact\t Date\t\t Time\t\tDescription\t\t\tDebit: Account Amount\t Credit: Account Amount").grid(column=0, row=2, padx=4, pady=4,sticky='W')
525 | scrolW1 = 100; scrolH1 = 35
526 | self.scrolList1 = scrolledtext.ScrolledText(frm1, width=scrolW1, height=scrolH1, wrap=tk.WORD)
527 | self.scrolList1.grid(column=0, row=3, padx=4, pady=4, sticky='WE', columnspan=3)
528 | self.do_showJournal((0,0))
529 |
530 | frm2 = ttk.Labelframe(self.tab2, text='General Ledger', width= 650, height=600)
531 | frm2.grid()
532 | ttk.Label(frm2, text="The General Ledger is the main book in the accounting system. It is accessed indirectly by the General Journal in the \ncourse of daily activity. As a result there will be found no menu or button actions that allow direct entry or edit of \nthe Ledger accounts.").grid(column=0, row=0, padx=4, pady=4,sticky='W')
533 | frm2a = ttk.Labelframe(frm2, width= 400, height=500)
534 | frm2a.grid(column=0,row=1)
535 | self.updateLedger = ttk.Button(frm2a, text="Update Display", command=lambda: self.do_showLedger(0)).grid(column=0,row=0,padx=4, pady=4)
536 | self.printLedger = ttk.Button(frm2a, text="PRINT", command=lambda: notImplementedInfo(self)).grid(column=1,row=0,padx=4, pady=4)
537 | self.newAccount = ttk.Button(frm2a, text="Show Another").grid(column=2,row=0,padx=4, pady=4)
538 | ttk.Label(frm2, text="Account \tTransaction\t Amount \tBalance \t\t").grid(column=0, row=2, padx=4, pady=4,sticky='W')
539 | scrolW1 = 80; scrolH1 = 35
540 | self.scrolList2 = scrolledtext.ScrolledText(frm2, width=scrolW1, height=scrolH1, wrap=tk.WORD)
541 | self.scrolList2.grid(column=0, row=3, padx=4, pady=4, sticky='WE', columnspan=3)
542 | self.do_showLedger(0)
543 |
544 | ## Set tab and contents for the Chart of Accounts
545 | frm3 = ttk.Labelframe(self.tab3, text='Chart of Accounts', width= 650, height=600)
546 | frm3.grid()
547 | ttk.Label(frm3, text="The Chart of Accounts is the organizing principle of the accounting system. It is accessed directly in defining the business\n activities for the of the enterprise.\n\n At system initialization the basic default accounts are automatically configured. Subsequently the chart is accessible as\n needed to set up new customer and supplier accounts for ongoing operation of the business").grid(column=0, row=0, padx=4, pady=4,sticky='W')
548 | frm3a = ttk.Labelframe(frm3, width= 400, height=450)
549 | frm3a.grid()
550 | self.updateChart = ttk.Button(frm3a, text="Update Display", command=lambda: self.do_showChart()).grid(column=0,row=0,padx=4, pady=4)
551 | self.printChart = ttk.Button(frm3a, text="PRINT", command=lambda: notImplementedInfo(self)).grid(column=1,row=0,padx=4, pady=4)
552 | self.newAccount = ttk.Button(frm3a, text="New Account", command=lambda: insertChartForm(self)).grid(column=2,row=0,padx=4, pady=4)
553 | ttk.Label(frm3, text="Account \t Name \t\t\t\t\t\t\tType\t\tBalance").grid(column=0, row=2, padx=4, pady=4,sticky='W')
554 | scrolW1 = 80; scrolH1 = 32
555 | self.scrolList3 = scrolledtext.ScrolledText(frm3, width=scrolW1, height=scrolH1, wrap=tk.WORD)
556 | self.scrolList3.grid(column=0, row=3, padx=4, pady=4, sticky='WE', columnspan=3)
557 | self.do_showChart()
558 |
559 | frm4 = ttk.Labelframe(self.tab4, text='Accounting Reports', width= 800, height=590)
560 | frm4.grid(padx=8, pady=4)
561 | self.reportctl = ttk.LabelFrame(frm4, text = "List of Reports")
562 | self.reportctl.grid(column=0, row=0, padx=8, pady=4, sticky='W')
563 | frm4b = ttk.Frame(frm4, width= 700, height=450)
564 | frm4b.grid(column=0, row=3)
565 | self.action_balanceSheet = ttk.Button(self.reportctl, text="Balance Sheet", command=lambda: self.do_balSheet())
566 | self.action_balanceSheet.grid(column=0, row=0, padx=4, pady=6)
567 | self.action_journalReport = ttk.Button(self.reportctl, text="Journal Report", command=lambda: self.do_reptTransact(0))
568 | self.action_journalReport.grid(column=1, row=0, padx=4, pady=6)
569 | self.action_journalReport = ttk.Button(self.reportctl, text="Single Transact", command=lambda: getTransact(self))
570 | self.action_journalReport.grid(column=2, row=0, padx=4, pady=6)
571 | self.action_ledgerAccount = ttk.Button(self.reportctl, text="Ledger Account", command=lambda: fetchLedgerAccount(self))
572 | self.action_ledgerAccount.grid(column=3, row=0, padx=4, pady=6)
573 | self.action_listAccounts = ttk.Button(self.reportctl, text="List Accounts", command=lambda: self.do_reptChart())
574 | self.action_listAccounts.grid(column=4, row=0, padx=4, pady=6)
575 | self.action_revenueExpense = ttk.Button(self.reportctl, text="Revenue and Expenses", command=lambda: self.do_RevandExp())
576 | self.action_revenueExpense.grid(column=5, row=0, padx=4, pady=6)
577 | self.action_viewPrint = ttk.Button(self.reportctl, text="Print", command=lambda: self.do_printCurrentView())
578 | self.action_viewPrint.grid(column=6, row=0, padx=4, pady=6)
579 | self.reportWin = Canvas(frm4b, width=700, height=550,bg='#FFFFFF',scrollregion=(0,0,1000,2000))
580 | hbar=Scrollbar(frm4b,orient=tk.HORIZONTAL)
581 | hbar.pack(side=tk.BOTTOM,fill=tk.X)
582 | hbar.config(command=self.reportWin.xview)
583 | vbar=Scrollbar(frm4b,orient=tk.VERTICAL)
584 | vbar.pack(side=tk.RIGHT,fill=tk.Y)
585 | vbar.config(command=self.reportWin.yview)
586 | self.reportWin.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
587 | self.reportWin.pack(side=tk.LEFT,expand=True,fill=tk.BOTH)
588 |
589 | self.reportWin.create_text(10,10, anchor=tk.NW, text="Select a view or report, it will display here")
590 |
591 | frm5 = ttk.Labelframe(self.tab5, text='Journal or Ledger Associated Note', width= 650, height=600)
592 | frm5.grid()
593 | self.memofields = ttk.LabelFrame(frm5, width=56)
594 | self.memofields.grid(column=0, row=1, padx=8, pady=4, sticky='W')
595 | self.lblmemoID = tk.Label(self.memofields, text="ID").grid(column=0, row=1)
596 | self.ememoID = tk.Entry(self.memofields, width=10)
597 | self.ememoID.grid(column=1, row=1, padx=5, pady=4, sticky='W')
598 | self.lblmemoTransact = tk.Label(self.memofields, text="Transact").grid(column=2, row=1)
599 | self.ememoTransact = tk.Entry(self.memofields, width=16)
600 | self.ememoTransact.grid(column=3, row=1, padx=5, pady=4, sticky='W')
601 | self.lblmemoDate = tk.Label(self.memofields, text="Date").grid(column=4, row=1)
602 | self.ememoDate = tk.Entry(self.memofields,width=18)
603 | self.ememoDate.grid(column=5, row=1, padx=5, pady=4, sticky='W')
604 |
605 | scrolW1 = 80; scrolH1 = 20
606 | self.scr_memo = scrolledtext.ScrolledText(frm5, width=scrolW1, height=scrolH1, wrap=tk.WORD)
607 | self.scr_memo.grid(column=0, row=7, padx=4, pady=4, sticky='WE', columnspan=3)
608 |
609 | self.memoctl = ttk.LabelFrame(frm5, width=56)
610 | self.memoctl.grid(column=0, row=0, padx=8, pady=4, sticky='W')
611 | self.action_clrmemo = ttk.Button(self.memoctl, text="NEW MEMO", command=lambda: self.newMemo())
612 | self.action_clrmemo.grid(column=0, row=0, padx=4, pady=6)
613 | self.action_prtmemo = ttk.Button(self.memoctl, text="PRINT MEMO", command=lambda: notImplementedInfo(self))
614 | self.action_prtmemo.grid(column=1, row=0, padx=4, pady=6)
615 | self.action_savememo = ttk.Button(self.memoctl, text="SAVE MEMO", command=lambda: self.saveMemo())
616 | self.action_savememo.grid(column=3, row=0, padx=4, pady=6)
617 | self.action_loadmemo = ttk.Button(self.memoctl, text="GET ANOTHER", command=lambda: self.fetchMemo())
618 | self.action_loadmemo.grid(column=4, row=0, padx=4, pady=6)
619 |
620 | frm6 = ttk.Labelframe(self.tab6, text='System Maintenance', width= 650, height=600)
621 | frm6.grid()
622 | self.action_sysSetup = ttk.Button(frm6, text=" NEW SET-UP ", command=lambda:AccountDB.createAccounts(self)).grid(column=0,row=0, padx=8, pady=4)
623 | self.action_sysPack = ttk.Button(frm6, text=" PACK DB ", command=lambda:AccountDB.packDatabase(self)).grid(column=1,row=0, padx=8, pady=4)
624 | self.action_sysSetup = ttk.Button(frm6, text="BACK-UP FILES", command=lambda:AccountDB.packDatabase(self)).grid(column=2,row=0, padx=8, pady=4)
625 | self.action_sysPack = ttk.Button(frm6, text=" RESTORE FILES", command=lambda:AccountDB.packDatabase(self)).grid(column=3,row=0, padx=8, pady=4)
626 | self.action_sysTrialBal = ttk.Button(frm6, text="COMPANY NAME", command=lambda:notImplementedInfo(self)).grid(column=0,row=1, padx=8, pady=4)
627 | self.action_sysTrialBal = ttk.Button(frm6, text="TRIAL BALANCE").grid(column=1,row=1, padx=8, pady=4)
628 | self.action_sysFiscalClose = ttk.Button(frm6, text="FISCAL CLOSE").grid(column=2,row=1, padx=8, pady=4)
629 | self.action_sysFiscalClose = ttk.Button(frm6, text="Unassigned").grid(column=3,row=1, padx=8, pady=4)
630 |
631 | # meubar created here --------------------------------------------
632 | menuBar = Menu(self.win)
633 | self.win.config(menu=menuBar)
634 | # Add menu items
635 | # Add System Menu
636 | sysMenu = Menu(menuBar, tearoff=0)
637 | sysMenu.add_command(label="New Set-up", command=lambda: AccountDB.createAccounts())
638 | sysMenu.add_command(label="Open")
639 | sysMenu.add_command(label="Save")
640 | sysMenu.add_command(label="Print", command=lambda: notImplementedInfo(self))
641 | sysMenu.add_command(label="Back-up Database")
642 | sysMenu.add_command(label="Restore Database")
643 | sysMenu.add_separator()
644 | sysMenu.add_command(label="Exit", command=self._quit)
645 | menuBar.add_cascade(label="System", menu=sysMenu)
646 |
647 | # Add an Edit Menu
648 | editMenu = Menu(menuBar, tearoff=0)
649 | editMenu.add_command(label="Cut")
650 | editMenu.add_command(label="Copy")
651 | editMenu.add_command(label="Paste")
652 | editMenu.add_command(label="Delete")
653 | editMenu.add_command(label="Clear")
654 | editMenu.add_command(label="Select")
655 | editMenu.add_separator()
656 | editMenu.add_command(label="Options")
657 | menuBar.add_cascade(label="Edit", menu=editMenu)
658 |
659 | # Add an Data entry Menu
660 | entryMenu = Menu(menuBar, tearoff=0)
661 | entryMenu.add_command(label="Journal Entry", command=lambda: insertJournalForm(self))
662 | entryMenu.add_command(label="New Account", command=lambda: insertChartForm(self))
663 | entryMenu.add_command(label="Make Memo", command=lambda: insertMemoForm(self))
664 | entryMenu.add_separator()
665 | entryMenu.add_command(label="Perform Trial Balance", command=lambda: self.do_trialBalance())
666 | entryMenu.add_command(label="Perform End of Cycle", command=lambda: notImplementedEndofCycle(self))
667 | menuBar.add_cascade(label="Activity", menu=entryMenu)
668 |
669 | # Add an Data entry Menu
670 | viewMenu = Menu(menuBar, tearoff=0)
671 | viewMenu.add_command(label="View Journal", command=lambda: self.do_reptTransact(0))
672 | viewMenu.add_command(label="View Transaction", command=lambda: getTransact(self))
673 | viewMenu.add_command(label="View Accounts", command=lambda: self.do_reptChart())
674 | viewMenu.add_command(label="View Ledger", command=lambda: fetchLedgerAccount(self))
675 | viewMenu.add_command(label="View a Memo", command=lambda: getTransact(self))
676 | viewMenu.add_separator()
677 | viewMenu.add_command(label="Trial Balance", command=lambda: self.do_trialBalance())
678 | viewMenu.add_command(label="End of Year")
679 | menuBar.add_cascade(label="View", menu=viewMenu)
680 |
681 | # Add an Edit Menu
682 | reportMenu = Menu(menuBar, tearoff=0)
683 | reportMenu.add_command(label="Balance Sheet", command=lambda: self.do_balSheet())
684 | reportMenu.add_command(label="Ledger Account", command=lambda: fetchLedgerAccount(self))
685 | reportMenu.add_command(label="Income Report", command=lambda: self.do_RevandExp())
686 | reportMenu.add_command(label="Expense Report", command=lambda: self.do_RevandExp())
687 | reportMenu.add_command(label="Payroll Report", command=lambda: notImplementedPayroll(self))
688 | reportMenu.add_command(label="Inventory Report",command=lambda: notImplementedInventory(self))
689 | menuBar.add_cascade(label="Reports", menu=reportMenu)
690 |
691 | # Add a Help Menu
692 | helpMenu = Menu(menuBar, tearoff=0)
693 | helpMenu.add_command(label="Context Help",command=lambda: notImplementedHelp(self))
694 | helpMenu.add_command(label="Documentation",command=lambda: notImplementedHelp(self))
695 | helpMenu.add_command(label="About", command=lambda: info(self))
696 | menuBar.add_cascade(label="Help", menu=helpMenu)
697 |
698 |
699 | if __name__ == '__main__':
700 | '''
701 | Main Method, OpenAccounting application start-up
702 | @summary: Starts the splash screen the when that is closed, the application window opens
703 | @warning: the application starts with what ever data is in the app directory, AccountDB.db
704 | If no such database files exist they can be created as new.
705 | @author: David York 11/7/2018
706 | @version: 0.20
707 | '''
708 | spl = splash.splashScreen()
709 | asys = AccountingSystem()
710 | w = (2*asys.win.winfo_screenwidth())/3
711 | h = (3*asys.win.winfo_screenheight())/4
712 | asys.win.geometry("%dx%d+0+0" % (w, h))
713 | '''
714 | @attention: the following solution to center the app comes from stackoverflow:
715 | @author: idbrii Jan 17 '17 at 19:11,
716 | https://stackoverflow.com/questions/3352918/how-to-center-a-window-on-the-screen-in-tkinter
717 | @accessed: 11/7/2018 12:35PM
718 | '''
719 | asys.win.eval('tk::PlaceWindow %s center' % asys.win.winfo_toplevel())
720 | asys.win.mainloop()
--------------------------------------------------------------------------------
/OpenAccounting.sql:
--------------------------------------------------------------------------------
1 | CREATE DATABASE OpenAccounting;
2 | USE OpenAccounting;
3 |
4 | CREATE TABLE chart (
5 | Account INTEGER PRIMARY KEY
6 | NOT NULL,
7 | Name STRING (50) NOT NULL,
8 | ActyType STRING (6) NOT NULL,
9 | Balance REAL
10 | );
11 |
12 | CREATE TABLE journal (
13 | [Transaction] INT PRIMARY KEY
14 | NOT NULL,
15 | Date DATETIME NOT NULL,
16 | Time DATETIME,
17 | Description STRING (40) NOT NULL,
18 | DebitAccount INTEGER (4) NOT NULL,
19 | DebitAmount REAL NOT NULL,
20 | CreditAccount INTEGER (4) NOT NULL,
21 | CreditAmount DECIMAL NOT NULL,
22 | Posted BOOLEAN NOT NULL
23 | DEFAULT (0)
24 | );
25 |
26 | CREATE TABLE ledger (
27 | Account INTEGER NOT NULL,
28 | Transact [INTEGER KEY] NOT NULL,
29 | Amount REAL NOT NULL,
30 | Balance REAL NOT NULL
31 | );
32 |
33 | CREATE TABLE accountmemos (
34 | MemoID INTEGER PRIMARY KEY
35 | UNIQUE
36 | NOT NULL,
37 | [Transaction] INTEGER REFERENCES journal ([Transaction])
38 | NOT NULL,
39 | MemoDate DATETIME NOT NULL,
40 | Memo BLOB NOT NULL
41 | );
42 |
43 | INSERT INTO chart VALUES ((100, "ASSETS", "DEBIT", 0),
44 | (120, "RECEIVABLES","DEBIT",0),
45 | (200, "LIABILITIES","CREDIT",0),
46 | (220, "PAYABLES","CREDIT",0),
47 | (300, "EQUITY","CREDIT",0),
48 | (400, "REVENUE","CREDIT",0),
49 | (500, "EXPENSES","DEBIT",0));
50 |
51 |
--------------------------------------------------------------------------------
/Printfile.ps:
--------------------------------------------------------------------------------
1 | %!PS-Adobe-3.0 EPSF-3.0
2 | %%Creator: Tk Canvas Widget
3 | %%Title: Window .!notebook.!frame4.!labelframe.!frame.!canvas
4 | %%CreationDate: Sun Nov 18 14:35:05 2018
5 | %%BoundingBox: 41 188 571 604
6 | %%Pages: 1
7 | %%DocumentData: Clean7Bit
8 | %%Orientation: Portrait
9 | %%DocumentNeededResources: font SegoeUi
10 | %%+ font Helvetica
11 | %%EndComments
12 |
13 | %%BeginProlog
14 | % This is a standard prolog for Postscript generated by Tk's canvas
15 | % widget.
16 | /CurrentEncoding [
17 | /space/space/space/space/space/space/space/space
18 | /space/space/space/space/space/space/space/space
19 | /space/space/space/space/space/space/space/space
20 | /space/space/space/space/space/space/space/space
21 | /space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quotesingle
22 | /parenleft/parenright/asterisk/plus/comma/hyphen/period/slash
23 | /zero/one/two/three/four/five/six/seven
24 | /eight/nine/colon/semicolon/less/equal/greater/question
25 | /at/A/B/C/D/E/F/G
26 | /H/I/J/K/L/M/N/O
27 | /P/Q/R/S/T/U/V/W
28 | /X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore
29 | /grave/a/b/c/d/e/f/g
30 | /h/i/j/k/l/m/n/o
31 | /p/q/r/s/t/u/v/w
32 | /x/y/z/braceleft/bar/braceright/asciitilde/space
33 | /space/space/space/space/space/space/space/space
34 | /space/space/space/space/space/space/space/space
35 | /space/space/space/space/space/space/space/space
36 | /space/space/space/space/space/space/space/space
37 | /space/exclamdown/cent/sterling/currency/yen/brokenbar/section
38 | /dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered/macron
39 | /degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered
40 | /cedilla/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters/questiondown
41 | /Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla
42 | /Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis
43 | /Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply
44 | /Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
45 | /agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla
46 | /egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
47 | /eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide
48 | /oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis
49 | ] def
50 | 50 dict begin
51 | /baseline 0 def
52 | /stipimage 0 def
53 | /height 0 def
54 | /justify 0 def
55 | /lineLength 0 def
56 | /spacing 0 def
57 | /stipple 0 def
58 | /strings 0 def
59 | /xoffset 0 def
60 | /yoffset 0 def
61 | /tmpstip null def
62 | /baselineSampler ( TXygqPZ) def
63 | baselineSampler 0 196 put
64 | /cstringshow {{ dup type /stringtype eq { show } { glyphshow } ifelse } forall } bind def
65 | /cstringwidth {0 exch 0 exch { dup type /stringtype eq { stringwidth } { currentfont /Encoding get exch 1 exch put (\001) stringwidth } ifelse exch 3 1 roll add 3 1 roll add exch } forall } bind def
66 | /ISOEncode {dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding CurrentEncoding def currentdict end /Temporary exch definefont } bind def
67 | /StrokeClip {{strokepath} stopped { (This Postscript printer gets limitcheck overflows when) = (stippling dashed lines; lines will be printed solid instead.) = [] 0 setdash strokepath} if clip } bind def
68 | /EvenPixels {dup 0 matrix currentmatrix dtransform dup mul exch dup mul add sqrt dup round dup 1 lt {pop 1} if exch div mul } bind def
69 | /StippleFill {/tmpstip 1 index def 1 EvenPixels dup scale pathbbox 4 2 roll 5 index div dup 0 lt {1 sub} if cvi 5 index mul 4 1 roll 6 index div dup 0 lt {1 sub} if cvi 6 index mul 3 2 roll 6 index exch { 2 index 5 index 3 index { gsave 1 index exch translate 5 index 5 index true matrix tmpstip imagemask grestore } for pop } for pop pop pop pop pop } bind def
70 | /AdjustColor {CL 2 lt { currentgray CL 0 eq { .5 lt {0} {1} ifelse } if setgray } if } bind def
71 | /DrawText {/stipple exch def /justify exch def /yoffset exch def /xoffset exch def /spacing exch def /strings exch def /lineLength 0 def strings { cstringwidth pop dup lineLength gt {/lineLength exch def} {pop} ifelse newpath } forall 0 0 moveto baselineSampler false charpath pathbbox dup /baseline exch def exch pop exch sub /height exch def pop newpath translate rotate lineLength xoffset mul strings length 1 sub spacing mul height add yoffset mul translate justify lineLength mul baseline neg translate strings { dup cstringwidth pop justify neg mul 0 moveto stipple { gsave /char (X) def { dup type /stringtype eq { { char 0 3 -1 roll put currentpoint gsave char true charpath clip StippleText grestore char stringwidth translate moveto } forall } { currentfont /Encoding get exch 1 exch put currentpoint gsave (\001) true charpath clip StippleText grestore (\001) stringwidth translate moveto } ifelse } forall grestore } {cstringshow} ifelse 0 spacing neg translate } forall } bind def
72 | /TkPhotoColor {gsave 32 dict begin /tinteger exch def /transparent 1 string def transparent 0 tinteger put /olddict exch def olddict /DataSource get dup type /filetype ne { olddict /DataSource 3 -1 roll 0 () /SubFileDecode filter put } { pop } ifelse /newdict olddict maxlength dict def olddict newdict copy pop /w newdict /Width get def /crpp newdict /Decode get length 2 idiv def /str w string def /pix w crpp mul string def /substrlen 2 w log 2 log div floor exp cvi def /substrs [ { substrlen string 0 1 substrlen 1 sub { 1 index exch tinteger put } for /substrlen substrlen 2 idiv def substrlen 0 eq {exit} if } loop ] def /h newdict /Height get def 1 w div 1 h div matrix scale olddict /ImageMatrix get exch matrix concatmatrix matrix invertmatrix concat newdict /Height 1 put newdict /DataSource pix put /mat [w 0 0 h 0 0] def newdict /ImageMatrix mat put 0 1 h 1 sub { mat 5 3 -1 roll neg put olddict /DataSource get str readstring pop pop /tail str def /x 0 def olddict /DataSource get pix readstring pop pop { tail transparent search dup /done exch not def {exch pop exch pop} if /w1 exch length def w1 0 ne { newdict /DataSource pix x crpp mul w1 crpp mul getinterval put newdict /Width w1 put mat 4 x neg put /x x w1 add def newdict image /tail tail w1 tail length w1 sub getinterval def } if done {exit} if tail substrs { anchorsearch {pop} if } forall /tail exch def tail length 0 eq {exit} if /x w tail length sub def } loop } for end grestore } bind def
73 | /TkPhotoMono {gsave 32 dict begin /dummyInteger exch def /olddict exch def olddict /DataSource get dup type /filetype ne { olddict /DataSource 3 -1 roll 0 () /SubFileDecode filter put } { pop } ifelse /newdict olddict maxlength dict def olddict newdict copy pop /w newdict /Width get def /pix w 7 add 8 idiv string def /h newdict /Height get def 1 w div 1 h div matrix scale olddict /ImageMatrix get exch matrix concatmatrix matrix invertmatrix concat newdict /Height 1 put newdict /DataSource pix put /mat [w 0 0 h 0 0] def newdict /ImageMatrix mat put 0 1 h 1 sub { mat 5 3 -1 roll neg put 0.000 0.000 0.000 setrgbcolor olddict /DataSource get pix readstring pop pop newdict /DataSource pix put newdict imagemask 1.000 1.000 1.000 setrgbcolor olddict /DataSource get pix readstring pop pop newdict /DataSource pix put newdict imagemask } for end grestore } bind def
74 | %%EndProlog
75 | %%BeginSetup
76 | /CL 2 def
77 | %%IncludeResource: font SegoeUi
78 | %%IncludeResource: font Helvetica
79 | %%EndSetup
80 |
81 | %%Page: 1 1
82 | save
83 | 306.0 396.0 translate
84 | 0.7508 0.7508 scale
85 | -350 -277 translate
86 | -2 554 moveto 702 554 lineto 702 0 lineto -2 0 lineto closepath clip newpath
87 | gsave
88 | /Helvetica findfont 12 scalefont ISOEncode setfont
89 | 0.000 0.000 0.000 setrgbcolor AdjustColor
90 | 0 335 542 [
91 | [(THE BALANCE SHEET)]
92 | ] 18 -0.5 0.5 0 false DrawText
93 | grestore
94 | gsave
95 | /Helvetica findfont 12 scalefont ISOEncode setfont
96 | 0.000 0.000 1.000 setrgbcolor AdjustColor
97 | 0 150 516 [
98 | [(ASSETS)]
99 | ] 18 -0 0 0 false DrawText
100 | grestore
101 | gsave
102 | /Helvetica findfont 12 scalefont ISOEncode setfont
103 | 0.000 0.000 1.000 setrgbcolor AdjustColor
104 | 0 460 516 [
105 | [(LIABILITIES)]
106 | ] 18 -0 0 0 false DrawText
107 | grestore
108 | gsave
109 | /SegoeUi findfont 9 scalefont ISOEncode setfont
110 | 0.000 0.000 1.000 setrgbcolor AdjustColor
111 | 0 12 499 [
112 | [(Account)]
113 | ] 15 -0 0 0 false DrawText
114 | grestore
115 | gsave
116 | /SegoeUi findfont 9 scalefont ISOEncode setfont
117 | 0.000 0.000 1.000 setrgbcolor AdjustColor
118 | 0 63 499 [
119 | [(Name)]
120 | ] 15 -0 0 0 false DrawText
121 | grestore
122 | gsave
123 | /SegoeUi findfont 9 scalefont ISOEncode setfont
124 | 0.000 0.000 1.000 setrgbcolor AdjustColor
125 | 0 273 499 [
126 | [(Balance)]
127 | ] 15 -0 0 0 false DrawText
128 | grestore
129 | gsave
130 | /SegoeUi findfont 9 scalefont ISOEncode setfont
131 | 0.000 0.000 1.000 setrgbcolor AdjustColor
132 | 0 344 499 [
133 | [(Account)]
134 | ] 15 -0 0 0 false DrawText
135 | grestore
136 | gsave
137 | /SegoeUi findfont 9 scalefont ISOEncode setfont
138 | 0.000 0.000 1.000 setrgbcolor AdjustColor
139 | 0 395 499 [
140 | [(Name)]
141 | ] 15 -0 0 0 false DrawText
142 | grestore
143 | gsave
144 | /SegoeUi findfont 9 scalefont ISOEncode setfont
145 | 0.000 0.000 1.000 setrgbcolor AdjustColor
146 | 0 605 499 [
147 | [(Balance)]
148 | ] 15 -0 0 0 false DrawText
149 | grestore
150 | gsave
151 | 10 479 moveto
152 | 670 479 lineto
153 | 0 setlinecap
154 | 1 setlinejoin
155 | 1 setlinewidth
156 | [] 0 setdash
157 | 0.000 0.000 1.000 setrgbcolor AdjustColor
158 | stroke
159 | grestore
160 | gsave
161 | 10 476 moveto
162 | 670 476 lineto
163 | 0 setlinecap
164 | 1 setlinejoin
165 | 1 setlinewidth
166 | [] 0 setdash
167 | 0.000 0.000 1.000 setrgbcolor AdjustColor
168 | stroke
169 | grestore
170 | gsave
171 | /SegoeUi findfont 9 scalefont ISOEncode setfont
172 | 0.000 0.000 0.000 setrgbcolor AdjustColor
173 | 0 12 463 [
174 | [(100 )]
175 | ] 15 -0 0 0 false DrawText
176 | grestore
177 | gsave
178 | /SegoeUi findfont 9 scalefont ISOEncode setfont
179 | 0.000 0.000 0.000 setrgbcolor AdjustColor
180 | 0 63 463 [
181 | [(ASSETS )]
182 | ] 15 -0 0 0 false DrawText
183 | grestore
184 | gsave
185 | /SegoeUi findfont 9 scalefont ISOEncode setfont
186 | 0.000 0.000 0.000 setrgbcolor AdjustColor
187 | 0 273 463 [
188 | [( 0.0)]
189 | ] 15 -0 0 0 false DrawText
190 | grestore
191 | gsave
192 | /SegoeUi findfont 9 scalefont ISOEncode setfont
193 | 0.000 0.000 0.000 setrgbcolor AdjustColor
194 | 0 12 450 [
195 | [(110 )]
196 | ] 15 -0 0 0 false DrawText
197 | grestore
198 | gsave
199 | /SegoeUi findfont 9 scalefont ISOEncode setfont
200 | 0.000 0.000 0.000 setrgbcolor AdjustColor
201 | 0 63 450 [
202 | [(BANK )]
203 | ] 15 -0 0 0 false DrawText
204 | grestore
205 | gsave
206 | /SegoeUi findfont 9 scalefont ISOEncode setfont
207 | 0.000 0.000 0.000 setrgbcolor AdjustColor
208 | 0 273 450 [
209 | [( 903.19)]
210 | ] 15 -0 0 0 false DrawText
211 | grestore
212 | gsave
213 | /SegoeUi findfont 9 scalefont ISOEncode setfont
214 | 0.000 0.000 0.000 setrgbcolor AdjustColor
215 | 0 12 437 [
216 | [(120 )]
217 | ] 15 -0 0 0 false DrawText
218 | grestore
219 | gsave
220 | /SegoeUi findfont 9 scalefont ISOEncode setfont
221 | 0.000 0.000 0.000 setrgbcolor AdjustColor
222 | 0 63 437 [
223 | [(RECEIVABLES )]
224 | ] 15 -0 0 0 false DrawText
225 | grestore
226 | gsave
227 | /SegoeUi findfont 9 scalefont ISOEncode setfont
228 | 0.000 0.000 0.000 setrgbcolor AdjustColor
229 | 0 273 437 [
230 | [( 100.0)]
231 | ] 15 -0 0 0 false DrawText
232 | grestore
233 | gsave
234 | 265 417 moveto
235 | 325 417 lineto
236 | 0 setlinecap
237 | 1 setlinejoin
238 | 1 setlinewidth
239 | [] 0 setdash
240 | 0.000 0.000 1.000 setrgbcolor AdjustColor
241 | stroke
242 | grestore
243 | gsave
244 | /SegoeUi findfont 9 scalefont ISOEncode setfont
245 | 0.000 0.000 0.000 setrgbcolor AdjustColor
246 | 0 265 404 [
247 | [( 1003.19)]
248 | ] 15 -0 0 0 false DrawText
249 | grestore
250 | gsave
251 | /SegoeUi findfont 9 scalefont ISOEncode setfont
252 | 0.000 0.000 0.000 setrgbcolor AdjustColor
253 | 0 344 463 [
254 | [(200 )]
255 | ] 15 -0 0 0 false DrawText
256 | grestore
257 | gsave
258 | /SegoeUi findfont 9 scalefont ISOEncode setfont
259 | 0.000 0.000 0.000 setrgbcolor AdjustColor
260 | 0 395 463 [
261 | [(LIABILITIES )]
262 | ] 15 -0 0 0 false DrawText
263 | grestore
264 | gsave
265 | /SegoeUi findfont 9 scalefont ISOEncode setfont
266 | 0.000 0.000 0.000 setrgbcolor AdjustColor
267 | 0 605 463 [
268 | [( 0.0)]
269 | ] 15 -0 0 0 false DrawText
270 | grestore
271 | gsave
272 | /SegoeUi findfont 9 scalefont ISOEncode setfont
273 | 0.000 0.000 0.000 setrgbcolor AdjustColor
274 | 0 344 450 [
275 | [(220 )]
276 | ] 15 -0 0 0 false DrawText
277 | grestore
278 | gsave
279 | /SegoeUi findfont 9 scalefont ISOEncode setfont
280 | 0.000 0.000 0.000 setrgbcolor AdjustColor
281 | 0 395 450 [
282 | [(PAYABLES )]
283 | ] 15 -0 0 0 false DrawText
284 | grestore
285 | gsave
286 | /SegoeUi findfont 9 scalefont ISOEncode setfont
287 | 0.000 0.000 0.000 setrgbcolor AdjustColor
288 | 0 605 450 [
289 | [( 0.0)]
290 | ] 15 -0 0 0 false DrawText
291 | grestore
292 | gsave
293 | 598 430 moveto
294 | 663 430 lineto
295 | 0 setlinecap
296 | 1 setlinejoin
297 | 1 setlinewidth
298 | [] 0 setdash
299 | 0.000 0.000 1.000 setrgbcolor AdjustColor
300 | stroke
301 | grestore
302 | gsave
303 | /SegoeUi findfont 9 scalefont ISOEncode setfont
304 | 0.000 0.000 0.000 setrgbcolor AdjustColor
305 | 0 598 417 [
306 | [( 0.0)]
307 | ] 15 -0 0 0 false DrawText
308 | grestore
309 | gsave
310 | /Helvetica findfont 12 scalefont ISOEncode setfont
311 | 0.000 0.000 1.000 setrgbcolor AdjustColor
312 | 0 467 384 [
313 | [(Equity)]
314 | ] 18 -0 0 0 false DrawText
315 | grestore
316 | gsave
317 | 335 364 moveto
318 | 670 364 lineto
319 | 0 setlinecap
320 | 1 setlinejoin
321 | 1 setlinewidth
322 | [] 0 setdash
323 | 0.000 0.000 1.000 setrgbcolor AdjustColor
324 | stroke
325 | grestore
326 | gsave
327 | 335 361 moveto
328 | 670 361 lineto
329 | 0 setlinecap
330 | 1 setlinejoin
331 | 1 setlinewidth
332 | [] 0 setdash
333 | 0.000 0.000 1.000 setrgbcolor AdjustColor
334 | stroke
335 | grestore
336 | gsave
337 | /SegoeUi findfont 9 scalefont ISOEncode setfont
338 | 0.000 0.000 0.000 setrgbcolor AdjustColor
339 | 0 344 348 [
340 | [(300 )]
341 | ] 15 -0 0 0 false DrawText
342 | grestore
343 | gsave
344 | /SegoeUi findfont 9 scalefont ISOEncode setfont
345 | 0.000 0.000 0.000 setrgbcolor AdjustColor
346 | 0 395 348 [
347 | [(EQUITY )]
348 | ] 15 -0 0 0 false DrawText
349 | grestore
350 | gsave
351 | /SegoeUi findfont 9 scalefont ISOEncode setfont
352 | 0.000 0.000 0.000 setrgbcolor AdjustColor
353 | 0 605 348 [
354 | [( 1000.0)]
355 | ] 15 -0 0 0 false DrawText
356 | grestore
357 | gsave
358 | /SegoeUi findfont 9 scalefont ISOEncode setfont
359 | 0.000 0.000 0.000 setrgbcolor AdjustColor
360 | 0 344 335 [
361 | [(399 )]
362 | ] 15 -0 0 0 false DrawText
363 | grestore
364 | gsave
365 | /SegoeUi findfont 9 scalefont ISOEncode setfont
366 | 0.000 0.000 0.000 setrgbcolor AdjustColor
367 | 0 395 335 [
368 | [(RETAINED EARNINGS )]
369 | ] 15 -0 0 0 false DrawText
370 | grestore
371 | gsave
372 | /SegoeUi findfont 9 scalefont ISOEncode setfont
373 | 0.000 0.000 0.000 setrgbcolor AdjustColor
374 | 0 605 335 [
375 | [( 0.0)]
376 | ] 15 -0 0 0 false DrawText
377 | grestore
378 | gsave
379 | /SegoeUi findfont 9 scalefont ISOEncode setfont
380 | 0.000 0.000 0.000 setrgbcolor AdjustColor
381 | 0 344 322 [
382 | [(399 )]
383 | ] 15 -0 0 0 false DrawText
384 | grestore
385 | gsave
386 | /SegoeUi findfont 9 scalefont ISOEncode setfont
387 | 0.000 0.000 0.000 setrgbcolor AdjustColor
388 | 0 395 322 [
389 | [(Retained Earnings )]
390 | ] 15 -0 0 0 false DrawText
391 | grestore
392 | gsave
393 | /SegoeUi findfont 9 scalefont ISOEncode setfont
394 | 0.000 0.000 0.000 setrgbcolor AdjustColor
395 | 0 612 322 [
396 | [( 3.19)]
397 | ] 15 -0 0 0 false DrawText
398 | grestore
399 | gsave
400 | 598 302 moveto
401 | 663 302 lineto
402 | 0 setlinecap
403 | 1 setlinejoin
404 | 1 setlinewidth
405 | [] 0 setdash
406 | 0.000 0.000 1.000 setrgbcolor AdjustColor
407 | stroke
408 | grestore
409 | gsave
410 | /SegoeUi findfont 9 scalefont ISOEncode setfont
411 | 0.000 0.000 0.000 setrgbcolor AdjustColor
412 | 0 598 289 [
413 | [( 1003.19)]
414 | ] 15 -0 0 0 false DrawText
415 | grestore
416 | gsave
417 | 598 269 moveto
418 | 663 269 lineto
419 | 0 setlinecap
420 | 1 setlinejoin
421 | 1 setlinewidth
422 | [] 0 setdash
423 | 0.000 0.000 1.000 setrgbcolor AdjustColor
424 | stroke
425 | grestore
426 | gsave
427 | 10 226 moveto
428 | 670 226 lineto
429 | 0 setlinecap
430 | 1 setlinejoin
431 | 1 setlinewidth
432 | [] 0 setdash
433 | 0.000 0.000 1.000 setrgbcolor AdjustColor
434 | stroke
435 | grestore
436 | gsave
437 | 10 223 moveto
438 | 670 223 lineto
439 | 0 setlinecap
440 | 1 setlinejoin
441 | 1 setlinewidth
442 | [] 0 setdash
443 | 0.000 0.000 1.000 setrgbcolor AdjustColor
444 | stroke
445 | grestore
446 | gsave
447 | /SegoeUi findfont 9 scalefont ISOEncode setfont
448 | 0.000 0.000 0.000 setrgbcolor AdjustColor
449 | 0 265 210 [
450 | [( 1003.19)]
451 | ] 15 -0 0 0 false DrawText
452 | grestore
453 | gsave
454 | /SegoeUi findfont 9 scalefont ISOEncode setfont
455 | 0.000 0.000 0.000 setrgbcolor AdjustColor
456 | 0 598 210 [
457 | [( 1003.19)]
458 | ] 15 -0 0 0 false DrawText
459 | grestore
460 | restore showpage
461 |
462 | %%Trailer
463 | end
464 | %%EOF
465 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # An Accounting System
4 |
5 | A basic accounting system compliant with Generally Accepted Accounting Practice (or Principles) (GAAP). It is written in python 3.7 and SQLite3.
6 |
7 | ## Introduction
8 |
9 | There are lots of accounting information systems both proprietary and free and open source. I needed a project to exercise my python, sql and tkinter coding. The fact that it is a necessary review of my MBA curriculum doesn't hurt either after a long absence of my attention there. Finally, I think another open source offering is good and this is intened be a simple, straight forward, and transparent development offering of a accounting application.
10 |
11 | ## Principle
12 | The central core of accounting is considered to be the General Ledger. The instrument of first entry however is the General Journal. All other aspects of the system are either suecondary entry or subsidieary journals and reoprts. The well known Balance Sheet, the consolidated picture of an enterprise, is a report based on the General Ledger contents.
13 |
14 | The entry of business activities is first into the Journal, or day book. The items of the Journal are posted then to the Ledger. The double entry technique of accounting ensures that the credit accounts and the debit accounts remain in balance. If the credits always equal the the debits from the outset, and there is no other confounding entries allowed balance is retained. This is a kind of drudge task for which computer programs is eminently suited.
15 |
16 | It should be impossible to enter any accounting data except through the general journal. Accounts should be easily added but not removable unless never referenced in transactions (i.e There must never have been any entries for the account in the current fiscal cycle (year), meaning since the books were last closed out).
17 |
18 | ## Manual
19 | This readme is intended to serve as my development notes and discussion for the system. It helps me organize my thoughts and is the source document upon which (I hope. . .) helpful comments can be made.
20 |
21 | I have made a start on a user a Manual of sorts in the attaching wiki here at the [Manual Wiki](https://github.com/medmatix/Accounting-System/wiki)
22 |
23 | ## Approach
24 | Thus the Journal is where data enters the system and is the date-time record of activity. Data is then reorganized and transferred to the Ledger. The ledger is the categorized permanent record of the enterprise's functioning - taking in revenue and paying expenses to produce some value. The business operation is accountable to internal and external stakeholders. This accounting to stakeholders requires a data trail is maintained with integrity and be demonstable on demand. The audit trailas it is called must be immutable right to the reports needed to account to stakeholders.
25 |
26 | 
27 |
28 | The underlying categorization is defined by a set of accounts to which activities are attributated. This is kept in the Chart of Accounts. In modern American GAAP there are five essential accounts aways present as prinary accounts with variable kinds of subsidiary accounts providing a detailed breakdown of these five. These in the US, Canada and the UK are 1) Assets Account, 2) Liabilities Account, 3) Equity or Capital Accounts, 4) Revenue or Income Account and 5) Expense of Costs Account. There is usually some way to remove bad data or expired value from the system. This sixth account or Disposables (6) is how depreciated value, bad debts and perhaps erroneous data, can be removed from the system in a clearly demonstrable and auditable way.
29 |
30 | Often the write-offs are kept as an account in expenses as the result of their access is to expense a bad dept of similar business losses. It is more difficult to retrieve expensed write-offs in a future accounting cycle however so there are advantages to retained write-offs in their own ledger.
31 |
32 | DEBIT ACCOUNTS | NUMBERING | CREDIT ACCOUNTS | EXAMPLES
33 | ---------------|-----------|-----------------|-----------------------------
34 | Assets | 1xx | |101 Bank, 120 Receivables
35 | | | 2xx | Liabilities | 220 Payables
36 | | | 3xx | Equity | 301 Retained Earnings
37 | | | 4xx | Revenue | 420 Sales
38 | Expenses | 5xx | | 520 Mortgage
39 | | | 6xx | Disposables | 620 Write-offs (Bad Debts)
40 |
41 | To debit a Debit Account is to increase it, similarly for crediting an Credit Account. Crediting a Debit Account reduces it and vis-a-versa. Addition and subtraction of figures are implied and automatic. That is what the program must do in the database table. Thus to balance accounts all debits have a credit somewhere and all credits have and offsetting debit - double entry.
42 |
43 |
44 | ## Implementation:
45 |
46 | The Context of the development can be best represented by the list of imports. All non-standard libraries are pip installable.
47 |
48 |
49 | #### Imports
50 |
51 | - Standard library and third party imports
52 | - tkinter imports
53 |
54 | ```
55 | import tkinter as tk
56 | from tkinter import ttk
57 | from tkinter import scrolledtext
58 | from tkinter import Menu
59 | from tkinter import messagebox as mBox
60 | from tkinter import simpledialog
61 | from tkinter import Scrollbar
62 | from tkinter import Canvas
63 | from tkinter import font
64 | ```
65 |
66 | - other standard and third party imports
67 | - all 3rd party are pip installable
68 |
69 | ```
70 |
71 | import sqlite3
72 | import datetime as dt
73 | import pytz
74 | import math as mt
75 | import numpy as np
76 | import sys
77 | ```
78 |
79 | # Custom module imports
80 | from AccountDB import AccountDB
81 | from FormDialogs import insertJournalForm, insertChartForm, insertMemoForm
82 | from FormDialogs import ReportFormats
83 | from Tooltips import createToolTip, ToolTip
84 | from ReportPreps import TrialBalance
85 | Once the structure is decided on, the creation of the database, and it's tables behind the interface then the needed enabling code guided the development. The stored data must be clearly separated in development from the derived data. The latter are the reports and summaries also central to accounting, the balance sheet, revenue and expense reports and special or subsidiary journals which may play important parts in therereporting for some enterprises. The stored data which are SQLite Database and tables with keys and indexes are as follows.
86 |
87 | ### Tables of OpenAccounting.db:
88 |
89 | Ref | Accounting Reference | Table
90 | -----|----------------------|------------
91 | 1|The Chart of Accounts | chart
92 | 2|The General Journal | journal
93 | 3|The General Ledger | ledger
94 | 4|The Accounting Annotation| accountmemos
95 |
96 | Eash table structure is shown by the SQL DDL statement that created it.
97 |
98 | #### Structure of chart Table
99 |
100 | ```
101 | CREATE TABLE chart (
102 | Account INTEGER PRIMARY KEY
103 | NOT NULL,
104 | Name STRING (50) NOT NULL,
105 | ActyType STRING (6) NOT NULL,
106 | Balance REAL
107 | );
108 | ```
109 |
110 | #### Structure of journal Table
111 |
112 | ```
113 |
114 | CREATE TABLE journal (
115 | [Transaction] INT PRIMARY KEY
116 | NOT NULL,
117 | Date DATETIME NOT NULL,
118 | Time DATETIME,
119 | Description STRING (40) NOT NULL,
120 | DebitAccount INTEGER (4) NOT NULL,
121 | DebitAmount REAL NOT NULL,
122 | CreditAccount INTEGER (4) NOT NULL,
123 | CreditAmount DECIMAL NOT NULL,
124 | Posted BOOLEAN NOT NULL
125 | DEFAULT (0)
126 | );
127 |
128 | ```
129 |
130 | #### Structure of ledger Table
131 |
132 | ```
133 |
134 | CREATE TABLE ledger (
135 | Account INTEGER NOT NULL,
136 | Transact [INTEGER KEY] NOT NULL,
137 | Amount REAL NOT NULL,
138 | Balance REAL NOT NULL
139 | );
140 |
141 | ```
142 |
143 | #### Structure of accountmemos Table
144 |
145 | ```
146 |
147 | CREATE TABLE accountmemos (
148 | MemoID INTEGER PRIMARY KEY
149 | UNIQUE
150 | NOT NULL,
151 | [Transaction] INTEGER REFERENCES journal ([Transaction])
152 | NOT NULL,
153 | MemoDate DATETIME NOT NULL,
154 | Memo BLOB NOT NULL
155 | );
156 |
157 | ```
158 | In spite of the predominantly top-down approach evident, the functionality is determined by the data tables at the system's core. It is reasonable that a data heavy application be at it's heart data driven (here, bottom-up). The manipulation of the data is guided by the the needs of accounting, and the interface is key to that.
159 |
160 | Coding was M-V-C modular and this can be seen from the organization of the source. Starting with the interface, we present the screenshots that lead the bookkeeper to the accounting activities.
161 |
162 | 
163 |
164 | Discussing the 'Accounting Functions' specifically in light of the interface presented, consider the entry point to the system - the General Journal. The other accessible information is this accounting set-up reflected in the Chart of Accounts.
165 |
166 | 
167 |
168 | The Ledger accounts set up via the Chart of Account are the records of where moneys are flowing from and to. The permanent account are those of the balance sheet, - in general terms the Assets and Liabilities. When the enterprise starts operating funds provided are the owner's equity, Accounts 300 and so on. The Core assets, 100 series accounts, are the Bank holding the capital itself and the incoming cash. Moneys owed to but not yet held by the compant are Accounts recevable (120). Obligations the company aquires are it's liabilities, 200 series accounts, principal among which is the Accounts Payable (220) as bills received but not yet paid. Other 100, 200 (and less so 300) series accounts may be used BUT the ones already mentioned are immutable and present in all accounting set-ups. At the start of use, the System provides these with the database tables created.
169 |
170 | Passing mention, for now, of the General Ledger is sufficient as this is not directly accessible, ever, but populated as Transactions in the Daily Journal entries.
171 |
172 | 
173 |
174 | Later the General ledger is the source of the required and useful accounting reporting.
175 |
176 | 
177 |
178 | 
179 |
180 | The ability to annoted journal entries in more detail than the Transaction Descriptiong allows is desirable but not a canonical requirement per se in accounting systems. For our system the accounting memo interface expediteds this.
181 |
182 | 
183 |
184 | Lastly we consider the more general control required for any database systems and the consideration too of the face that accounting is a cyclical process focused on (rather artificial) fiscal periods of business activity. We need to be able to manage the system so a maintenance interface is provided.
185 |
186 | 
187 |
188 | ====
189 |
190 | Project Repository maintained by David York.
191 |
192 | Copyright Medmatix, David York 2018.
193 |
194 | License under: MIT license.
195 |
--------------------------------------------------------------------------------
/ReportPreps.py:
--------------------------------------------------------------------------------
1 | '''
2 | Created on Nov 3, 2018
3 |
4 | @author: david
5 | '''
6 | import tkinter as tk
7 | from tkinter import messagebox as mBox
8 | import math as mt
9 | import numpy as np
10 | import sqlite3
11 | from AccountDB import AccountDB
12 |
13 | class TrialBalance(object):
14 | '''
15 | Class for Trial Balance Calculations
16 | '''
17 |
18 |
19 | def __init__(self, params):
20 | '''
21 | Constructor set up the trial balance
22 | '''
23 |
24 |
25 |
26 | def getLedgerData(self):
27 | '''
28 | '''
29 | # Call database get ledger(all)
30 | # Get a current list of account numbers from chart
31 | accList = []
32 | db = sqlite3.connect('OpenAccounting.db')
33 | cursor = db.cursor()
34 | cursor.execute("SELECT Account FROM chart ORDER BY Account")
35 | for row in cursor:
36 | accList.append(row[0])
37 | db.close()
38 | balDict = {0:0.0}
39 | for account in accList:
40 | accTotal = 0
41 | ldgrAccount = AccountDB.getLedgerAccount(self, account)
42 | # sum transactions by account
43 | for row in ldgrAccount:
44 | accTotal = accTotal + row[2]
45 | #record balances and account numbers in balList
46 | balDict[account] = accTotal
47 | # display the balances in a dialog
48 | return(balDict)
49 | # mBox._show(title="Partial Trial Balance", message="Compare to Balances in Chart of Accounts \n\n"+tbal+"\n If they do not match the account is out of balance", _icon="", _type="")
50 |
51 |
52 |
53 |
54 |
55 |
56 | def trialBalance(self):
57 | '''
58 | '''
59 | # Get account transactions totals
60 | acctBalances = TrialBalance.getLedgerData(self)
61 | debitBalances = 0.0
62 | for x, y in acctBalances.items():
63 | if (x >= 100 and x<= 199):
64 | debitBalances = debitBalances + y
65 | if (x >= 500 and x<= 599):
66 | debitBalances = debitBalances + y
67 | creditBalances = 0.0
68 | for x, y in acctBalances.items():
69 | if (x >= 200 and x<= 499):
70 | creditBalances = creditBalances + y
71 | return (debitBalances, creditBalances)
72 |
73 | # Compare with Chart of Accounts balances for Chart integrity
74 |
75 | # Report Discrepancies
76 |
77 |
--------------------------------------------------------------------------------
/Tooltips.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Data Science Calculator Tool tips
4 | @acknowledgement: Adapted on Wed Sep 29, 2018 based on a template from,
5 | Python GUI Programming Solutions, by Burkhardt Meyer Packt Publishing
6 | @author: David York
7 | @copyright: David York 2018
8 | @license: MIT license
9 | """
10 |
11 | #======================
12 | # imports
13 | #======================
14 | import tkinter as tk
15 |
16 | class ToolTip(object):
17 | def __init__(self, widget):
18 | self.widget = widget
19 | self.tipwindow = None
20 | self.id = None
21 | self.col = self.row = 0 # col = x value, row = y value
22 |
23 | def showtip(self, text):
24 | "Display text in tooltip window"
25 | self.text = text
26 | if self.tipwindow or not self.text:
27 | return
28 | col, row, _ccol, crow = self.widget.bbox("insert")
29 | col = col + self.widget.winfo_rootx() + 27
30 | row = row + crow + self.widget.winfo_rooty() +27
31 | self.tipwindow = tw = tk.Toplevel(self.widget)
32 | tw.wm_overrideredirect(1)
33 | tw.wm_geometry("+%d+%d" % (col, row))
34 |
35 | label = tk.Label(tw, text=self.text, justify=tk.LEFT,
36 | background="#ffffe0", relief=tk.SOLID, borderwidth=1,
37 | font=("tahoma", "8", "normal"))
38 | label.pack(ipadx=1)
39 |
40 | def hidetip(self):
41 | tw = self.tipwindow
42 | self.tipwindow = None
43 | if tw:
44 | tw.destroy()
45 |
46 | #===================================================================
47 | def createToolTip(widget, text):
48 | toolTip = ToolTip(widget)
49 | def enter(event):
50 | toolTip.showtip(text)
51 | def leave(event):
52 | toolTip.hidetip()
53 | widget.bind('', enter)
54 | widget.bind('', leave)
55 |
--------------------------------------------------------------------------------
/__pycache__/AccountDB.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/__pycache__/AccountDB.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/FormDialogs.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/__pycache__/FormDialogs.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/ReportPreps.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/__pycache__/ReportPreps.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/Tooltips.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/__pycache__/Tooltips.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/splash.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/__pycache__/splash.cpython-37.pyc
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-architect
--------------------------------------------------------------------------------
/cruncherCr3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/cruncherCr3.gif
--------------------------------------------------------------------------------
/cruncherCr3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/cruncherCr3.jpg
--------------------------------------------------------------------------------
/cruncherCr3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/cruncherCr3.png
--------------------------------------------------------------------------------
/images/AccountingSystemOrganization.dia:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/AccountingSystemOrganization.dia
--------------------------------------------------------------------------------
/images/AccountingSystemOrganization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/AccountingSystemOrganization.png
--------------------------------------------------------------------------------
/images/ChartAccts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/ChartAccts.png
--------------------------------------------------------------------------------
/images/Journal1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal1.png
--------------------------------------------------------------------------------
/images/Journal1.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal1.xcf
--------------------------------------------------------------------------------
/images/Journal2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal2.png
--------------------------------------------------------------------------------
/images/Journal2.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal2.xcf
--------------------------------------------------------------------------------
/images/Journal3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal3.png
--------------------------------------------------------------------------------
/images/Journal3.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal3.xcf
--------------------------------------------------------------------------------
/images/Journal4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal4.png
--------------------------------------------------------------------------------
/images/Journal4.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal4.xcf
--------------------------------------------------------------------------------
/images/Journal5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal5.png
--------------------------------------------------------------------------------
/images/Journal5.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal5.xcf
--------------------------------------------------------------------------------
/images/Journal6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal6.png
--------------------------------------------------------------------------------
/images/Journal6.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal6.xcf
--------------------------------------------------------------------------------
/images/Journal7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal7.png
--------------------------------------------------------------------------------
/images/Journal7.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Journal7.xcf
--------------------------------------------------------------------------------
/images/Ldgeracct1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Ldgeracct1.png
--------------------------------------------------------------------------------
/images/Ldgeracct1.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Ldgeracct1.xcf
--------------------------------------------------------------------------------
/images/Number_cruncherCr3.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Number_cruncherCr3.ico
--------------------------------------------------------------------------------
/images/Number_cruncherCr3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/Number_cruncherCr3.png
--------------------------------------------------------------------------------
/images/README.md:
--------------------------------------------------------------------------------
1 | # Images and Graphics
2 |
3 | All images are copyright Medmatix Analytics and David York unless explicitly credited here to another source. Licensing is under the MIT License unless otherwise stated.
4 |
--------------------------------------------------------------------------------
/images/RevnExp1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/RevnExp1.png
--------------------------------------------------------------------------------
/images/ScreenChartTab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/ScreenChartTab.png
--------------------------------------------------------------------------------
/images/ScreenChartTab2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/ScreenChartTab2.png
--------------------------------------------------------------------------------
/images/ScreenJournalTab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/ScreenJournalTab.png
--------------------------------------------------------------------------------
/images/ScreenLedgerTab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/ScreenLedgerTab.png
--------------------------------------------------------------------------------
/images/ScreenMaintenanceTab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/ScreenMaintenanceTab.png
--------------------------------------------------------------------------------
/images/ScreenMemoTab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/ScreenMemoTab.png
--------------------------------------------------------------------------------
/images/ScreenReportTab1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/ScreenReportTab1.png
--------------------------------------------------------------------------------
/images/ScreenReportTab2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/ScreenReportTab2.png
--------------------------------------------------------------------------------
/images/balancesheet1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/balancesheet1.png
--------------------------------------------------------------------------------
/images/cruncherCr3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/cruncherCr3.gif
--------------------------------------------------------------------------------
/images/medmatix.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/medmatix.ico
--------------------------------------------------------------------------------
/images/medmatix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/medmatix.png
--------------------------------------------------------------------------------
/images/medmatix_tilt.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/medmatix_tilt.ico
--------------------------------------------------------------------------------
/images/medmatix_tilt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/medmatix_tilt.png
--------------------------------------------------------------------------------
/images/trialbalance1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/images/trialbalance1.png
--------------------------------------------------------------------------------
/medmatix_tilt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/medmatix/Accounting-System/2ab3dbafebe5818f55fc36f172d5938a68cf1d0c/medmatix_tilt.png
--------------------------------------------------------------------------------
/splash.py:
--------------------------------------------------------------------------------
1 | '''
2 | Created on Nov 6, 2018
3 | @summary: The module contains the code needed to build and present the splash screen at start-up
4 | @author: david york
5 | '''
6 |
7 | # #############################################
8 | # imports for the splash code functionality
9 | # #############################################
10 | import os
11 | import pathlib
12 | import tkinter as tk
13 | from tkinter import ttk
14 | from tkinter import Canvas
15 | from tkinter import font
16 | import PIL
17 | from PIL import Image, ImageTk
18 | import time
19 |
20 | class splashScreen():
21 | '''
22 | The splashScreen class
23 | '''
24 |
25 | def __init__(self):
26 | '''
27 | splashScreen constructor
28 | '''
29 |
30 | self.splash()
31 |
32 |
33 |
34 |
35 | #self.splashfrm.mainloop()
36 |
37 | def splash(self):
38 | '''
39 | The splash interface code
40 | '''
41 | self.root = tk.Tk()
42 |
43 | #root.title('Splash')
44 | #root.wm_attributes('-fullscreen','true')
45 | #eliminate the titlebar
46 | self.root.overrideredirect(1)
47 |
48 | image = Image.open("medmatix_tilt.png")
49 | f = tk.Frame(self.root, highlightthickness=0 ).grid()
50 | canvas=Canvas(f, height=500, width=500, highlightthickness=0, background='SteelBlue3')
51 | basewidth = 220
52 | wpercent = (basewidth / float(image.size[0]))
53 | hsize = int((float(image.size[1]) * float(wpercent)))
54 | image = image.resize((basewidth, hsize), PIL.Image.ANTIALIAS)
55 | photo = ImageTk.PhotoImage(image)
56 | canvas.create_image(250,250, image=photo)
57 | canvas.create_text(250,161, text='Welcome to', font=('Helvetica', '18', 'italic'))
58 | canvas.create_text(250,200, text='Open Accounting', font=('Helvetica', '32', 'bold italic' ))
59 | canvas.create_text(250,239, text='by Medmatix Analytics', font=('Helvetica', '18', 'italic'))
60 | canvas.create_text(250,470, text='(c)copyright: D A York, Medmatix 2018', font=('Times', '9', 'italic'), fill='white')
61 | canvas.grid() #.pack(side = tk.TOP, expand=True, fill=tk.BOTH)
62 | f2 = f = tk.Frame(self.root, highlightthickness=0, width=500)
63 | f2.configure(bg='SteelBlue3')
64 | f2.grid()
65 | self.btn1 = ttk.Button(f2, text="OK", command=lambda: self.on_OKkill()).grid(column=0,row=2,padx=212, pady=4)
66 | # Acknowledgement of source:
67 | # Note the functionality centering the splash window was found in a discussion on stackoverflow blog:
68 | # https://stackoverflow.com/questions/3352918/how-to-center-a-window-on-the-screen-in-tkinter
69 | self.root.eval('tk::PlaceWindow %s center' % self.root.winfo_toplevel())
70 | self.root.mainloop()
71 |
72 | def on_OKkill(self):
73 | self.root.quit() # stops mainloop
74 | self.root.destroy()
75 |
76 |
77 |
78 | if __name__ == '__main__':
79 | spl = splashScreen()
--------------------------------------------------------------------------------
/testcode.py:
--------------------------------------------------------------------------------
1 | '''
2 | Created on Nov 6, 2018
3 |
4 | @author: david
5 | '''
6 | '''
7 | Created on Sep 30, 2018
8 |
9 | @author: david
10 | '''
11 | import os
12 | import pathlib
13 | import tkinter as tk
14 | from tkinter import ttk
15 | from tkinter import Canvas
16 | from tkinter import font
17 | import PIL
18 | from PIL import Image, ImageTk
19 |
20 | class splashScreen():
21 |
22 | def __init__(self):
23 | '''
24 | Splash constructor
25 | '''
26 |
27 | self.splash()
28 |
29 |
30 |
31 |
32 | #self.splashfrm.mainloop()
33 |
34 | def splash(self):
35 | '''
36 | '''
37 | root = tk.Tk()
38 | #root.title('Splash')
39 | #root.wm_attributes('-fullscreen','true')
40 | #eliminate the titlebar
41 | root.overrideredirect(1)
42 |
43 | image = Image.open("medmatix_tilt.png")
44 | canvas=Canvas(root, height=500, width=500, background='SteelBlue3')
45 | basewidth = 220
46 | wpercent = (basewidth / float(image.size[0]))
47 | hsize = int((float(image.size[1]) * float(wpercent)))
48 | image = image.resize((basewidth, hsize), PIL.Image.ANTIALIAS)
49 | photo = ImageTk.PhotoImage(image)
50 | canvas.create_image(250,250, image=photo)
51 | canvas.create_text(250,161, text='Welcome to', font=('Helvetica', '18', 'italic'))
52 | canvas.create_text(250,200, text='Open Accounting', font=('Helvetica', '32', 'bold italic' ))
53 | canvas.create_text(250,239, text='by Medmatix Analytics', font=('Helvetica', '18', 'italic'))
54 |
55 | canvas.grid() #.pack(side = tk.TOP, expand=True, fill=tk.BOTH)
56 |
57 | root.mainloop()
58 |
59 |
60 | if __name__ == '__main__':
61 | spl = splashScreen()
62 |
63 |
64 |
65 | #===============================================================================
66 | # root=tk.Tk()
67 | # image = Image.open("medmatix_tilt.png")
68 | # canvas=Canvas(root, height=200, width=200)
69 | # basewidth = 150
70 | # wpercent = (basewidth / float(image.size[0]))
71 | # hsize = int((float(image.size[1]) * float(wpercent)))
72 | # image = image.resize((basewidth, hsize), PIL.Image.ANTIALIAS)
73 | # photo = ImageTk.PhotoImage(image)
74 | # item4 = canvas.create_image(100, 80, image=photo)
75 | #
76 | # canvas.pack(side = tk.TOP, expand=True, fill=tk.BOTH)
77 | # root.mainloop()
78 | #===============================================================================
--------------------------------------------------------------------------------