Initial Commit: Still Trying things out

There is Router in the view.__init__ to handle routing.
Trying out Qt Still. Looks good.
This commit is contained in:
Amritanshu
2014-07-01 12:15:00 +05:30
commit d88db662f6
23 changed files with 2110 additions and 0 deletions

56
.gitignore vendored Normal file
View File

@ -0,0 +1,56 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# PyCharm
.idea/

2
MANIFEST.in Normal file
View File

@ -0,0 +1,2 @@
include *.txt *.ini *.cfg *.rst
recursive-include brewman *.ico *.png *.css *.gif *.jpg *.txt *.js *.html *.map *.eot *.svg *.ttf *.ui

31
setup.py Normal file
View File

@ -0,0 +1,31 @@
import os
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
README = open(os.path.join(here, 'README.txt')).read()
CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()
requires = [
'SQLAlchemy', 'PyQt5',
]
setup(name='summer',
version='3.4',
description='summer',
long_description=README + '\n\n' + CHANGES,
classifiers=[
"Programming Language :: Python",
],
author='Tanshu',
author_email='summer@tanshu.com',
url='http://tanshu.com',
keywords='',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
install_requires=requires,
tests_require=requires,
test_suite="summer",
)

View File

@ -0,0 +1,304 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>810</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Point of Sale</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="btnLogin">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Login</string>
</property>
</widget>
<widget class="QPushButton" name="btnSwipeLogin">
<property name="geometry">
<rect>
<x>170</x>
<y>10</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Swipe Login</string>
</property>
</widget>
<widget class="QPushButton" name="btnSales">
<property name="geometry">
<rect>
<x>330</x>
<y>10</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Sales</string>
</property>
</widget>
<widget class="QPushButton" name="btnCustomers">
<property name="geometry">
<rect>
<x>490</x>
<y>10</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Customers</string>
</property>
</widget>
<widget class="QPushButton" name="btnProducts">
<property name="geometry">
<rect>
<x>650</x>
<y>10</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Products</string>
</property>
</widget>
<widget class="QPushButton" name="btnUsers">
<property name="geometry">
<rect>
<x>650</x>
<y>120</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Users</string>
</property>
</widget>
<widget class="QPushButton" name="btnProductGroups">
<property name="geometry">
<rect>
<x>10</x>
<y>120</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Product Groups</string>
</property>
</widget>
<widget class="QPushButton" name="btnAdjustAdvance">
<property name="geometry">
<rect>
<x>490</x>
<y>120</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Adjust Advance</string>
</property>
</widget>
<widget class="QPushButton" name="btnReceiveAdvance">
<property name="geometry">
<rect>
<x>330</x>
<y>120</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Receive Advance</string>
</property>
</widget>
<widget class="QPushButton" name="btnOpenBill">
<property name="geometry">
<rect>
<x>170</x>
<y>120</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Open Bill</string>
</property>
</widget>
<widget class="QPushButton" name="btnSalesDetail">
<property name="geometry">
<rect>
<x>490</x>
<y>230</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Sales Detail</string>
</property>
</widget>
<widget class="QPushButton" name="btnDiscountReport">
<property name="geometry">
<rect>
<x>170</x>
<y>340</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Discount Report</string>
</property>
</widget>
<widget class="QPushButton" name="btnRoles">
<property name="geometry">
<rect>
<x>10</x>
<y>230</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Roles</string>
</property>
</widget>
<widget class="QPushButton" name="btnSalesAnalysis">
<property name="geometry">
<rect>
<x>330</x>
<y>230</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Sales Analysis</string>
</property>
</widget>
<widget class="QPushButton" name="btnCashierCheckout">
<property name="geometry">
<rect>
<x>170</x>
<y>230</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Cashier Checkout</string>
</property>
</widget>
<widget class="QPushButton" name="btnChangePassword">
<property name="geometry">
<rect>
<x>330</x>
<y>340</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Change Password</string>
</property>
</widget>
<widget class="QPushButton" name="btnVoids">
<property name="geometry">
<rect>
<x>10</x>
<y>340</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Voids / Reprints</string>
</property>
</widget>
<widget class="QPushButton" name="btnBillDetails">
<property name="geometry">
<rect>
<x>650</x>
<y>230</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Bill Details</string>
</property>
</widget>
<widget class="QPushButton" name="btnExit">
<property name="geometry">
<rect>
<x>650</x>
<y>340</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Exit</string>
</property>
</widget>
<widget class="QPushButton" name="btnManagement">
<property name="geometry">
<rect>
<x>490</x>
<y>340</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Management</string>
</property>
</widget>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<tabstops>
<tabstop>btnLogin</tabstop>
<tabstop>btnSwipeLogin</tabstop>
<tabstop>btnSales</tabstop>
<tabstop>btnCustomers</tabstop>
<tabstop>btnProducts</tabstop>
<tabstop>btnProductGroups</tabstop>
<tabstop>btnOpenBill</tabstop>
<tabstop>btnReceiveAdvance</tabstop>
<tabstop>btnAdjustAdvance</tabstop>
<tabstop>btnUsers</tabstop>
<tabstop>btnRoles</tabstop>
<tabstop>btnCashierCheckout</tabstop>
<tabstop>btnSalesAnalysis</tabstop>
<tabstop>btnSalesDetail</tabstop>
<tabstop>btnBillDetails</tabstop>
<tabstop>btnVoids</tabstop>
<tabstop>btnDiscountReport</tabstop>
<tabstop>btnChangePassword</tabstop>
<tabstop>btnManagement</tabstop>
<tabstop>btnExit</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UserDetails</class>
<widget class="QDialog" name="UserDetails">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>397</width>
<height>310</height>
</rect>
</property>
<property name="windowTitle">
<string>User Details</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtName"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Permissions</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QListView" name="lvwPermissions"/>
</item>
<item row="6" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>txtName</tabstop>
<tabstop>lvwPermissions</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>UserDetails</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>227</x>
<y>331</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>UserDetails</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>295</x>
<y>337</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RoleList</class>
<widget class="QMainWindow" name="RoleList">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Roles</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QTableView" name="tblRoles"/>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="btnAddNew">
<property name="text">
<string>Add Role</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UserDetails</class>
<widget class="QDialog" name="UserDetails">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>397</width>
<height>353</height>
</rect>
</property>
<property name="windowTitle">
<string>User Details</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtName"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Password</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="txtPassword">
<property name="inputMask">
<string notr="true"/>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="chkLockedOut">
<property name="text">
<string>Locked Out</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="btnSwipe">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="text">
<string>Swipe Login</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QListView" name="lvwRoles"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Roles</string>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>txtName</tabstop>
<tabstop>txtPassword</tabstop>
<tabstop>chkLockedOut</tabstop>
<tabstop>lvwRoles</tabstop>
<tabstop>btnSwipe</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>UserDetails</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>227</x>
<y>331</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>UserDetails</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>295</x>
<y>337</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UserList</class>
<widget class="QMainWindow" name="UserList">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Users</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QTableView" name="tblUsers"/>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="btnAddNew">
<property name="text">
<string>Add User</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

19
summer/__init__.py Normal file
View File

@ -0,0 +1,19 @@
from PyQt5 import QtWidgets
from sqlalchemy import create_engine
from summer.models import initialize_sql
from summer.templates.MainWindow import MainWindow
from summer.views import Router
if __name__ == '__main__':
import sys
engine = create_engine('postgresql://postgres:123456@localhost:5432/summer')
initialize_sql(engine)
app = QtWidgets.QApplication(sys.argv)
router = Router()
window = MainWindow(router)
window.show()
sys.exit(app.exec_())

80
summer/models/__init__.py Normal file
View File

@ -0,0 +1,80 @@
__author__ = 'tanshu'
from contextlib import contextmanager
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(expire_on_commit=False)
Base = declarative_base()
@contextmanager
def session_scope():
"""Provide a transactional scope around a series of operations."""
session = Session()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()
def initialize_sql(engine):
Session.configure(bind=engine)
Base.metadata.bind = engine
if not schema_exists(engine):
fixtures(engine)
def schema_exists(engine):
from models.master import DbSetting
with engine.connect() as connection:
return engine.dialect.has_table(connection, DbSetting.__tablename__)
def fixtures(engine):
import uuid
from .auth import Permission, Role, User, role_group, user_role
from .master import Tax, Modifier, ProductGroup, FoodTable, DbSetting
from .voucher import RunningTable
Base.metadata.create_all(engine)
with session_scope() as DBSession:
user = User('Admin', '123456', False, id=uuid.UUID('8de98592-76d9-c74d-bb3f-d6184d388b5a'))
DBSession.add(user)
permissions = [Permission('Users', uuid.UUID('c5b7d9d7-f178-0e45-8ea4-bf4e08ec901b')),
Permission('Taxes', uuid.UUID('c830872a-ba1b-4593-800e-dd0573eea930')),
Permission('Product Groups', uuid.UUID('08413a22-cf88-fd43-b2b7-365d2951d99f')),
Permission('Products', uuid.UUID('74fa6d21-eebb-e14c-8153-bebc57190ab4')),
Permission('Food Tables', uuid.UUID('f31a8e97-9ee0-4dbb-9016-637c03fbb646')),
Permission('Modifiers', uuid.UUID('0e88b9f8-3ed6-4304-b3cf-5a66c96ac650'))]
owner = Role('Owner', uuid.UUID('52e08c0c-048a-784f-be10-6e129ad4b5d4'))
DBSession.add(owner)
for permission in permissions:
DBSession.add(permission)
owner.permissions.append(permission)
user.roles.append(owner)
tax = Tax('Tax Free', 0, '08c3101d-cdab-449f-9574-a025c8ae5556', True)
modifiers = [Modifier('Spicy', True, uuid.UUID('d1b76d14-ab02-45c8-8a37-3197113e7bd5')),
Modifier('Mild', True, uuid.UUID('c49ed960-6635-4347-8b30-41258f372894')),
Modifier('Less Oily', True, uuid.UUID('972593ee-2196-4978-a4b2-e91e9e5cac5d'))]
for modifier in modifiers:
DBSession.add(modifier)
pgrs = [ProductGroup('Beer', 1, 'Beer', 0, True),
ProductGroup('Whisky', 1, 'Alcohol', 0, True),
ProductGroup('Wine', 1, 'Alcohol', 0, True),
ProductGroup('Main Course', 1, 'Food', 0, True),
ProductGroup('Appetizers', 1, 'Food', 0, True)]
for pgr in pgrs:
DBSession.add(pgr)
for i in range(1, 20):
DBSession.add(FoodTable('Table No ' + str(i), 'Test Location'))
DBSession.add(tax)

137
summer/models/auth.py Normal file
View File

@ -0,0 +1,137 @@
__author__ = 'tanshu'
import uuid
from hashlib import md5
from sqlalchemy.schema import ForeignKey, Table
from sqlalchemy import Column, Boolean, Unicode
from sqlalchemy.orm import synonym, relationship
from models.guidtype import GUID
from models import Base
def encrypt(val):
return md5(val.encode('utf-8') + "Salt".encode('utf-8')).hexdigest()
user_role = Table(
'auth_user_roles', Base.metadata,
Column('user_role_id', GUID(), primary_key=True, default=uuid.uuid4),
Column('user_id', GUID(), ForeignKey('auth_users.user_id')),
Column('role_id', GUID(), ForeignKey('auth_roles.role_id'))
)
role_group = Table(
'auth_permission_roles', Base.metadata,
Column('permission_role_id', GUID(), primary_key=True, default=uuid.uuid4),
Column('permission_id', GUID(), ForeignKey('auth_permissions.permission_id')),
Column('role_id', GUID(), ForeignKey('auth_roles.role_id'))
)
class User(Base):
__tablename__ = 'auth_users'
id = Column('user_id', GUID(), primary_key=True, default=uuid.uuid4)
name = Column('name', Unicode(255), unique=True)
_password = Column('password', Unicode(60))
locked_out = Column('locked_out', Boolean)
roles = relationship('Role', secondary=user_role)
def _get_password(self):
return self._password
def _set_password(self, password):
self._password = encrypt(password)
password = property(_get_password, _set_password)
password = synonym('_password', descriptor=password)
@property
def __name__(self):
return self.name
def __init__(self, name=None, password=None, locked_out=None, id=None):
self.name = name
self.password = password
self.locked_out = locked_out
self.id = id
@classmethod
def by_name(cls, name, *, session=None):
return session.query(cls).filter(cls.name.ilike(name)).first()
@classmethod
def by_id(cls, id, *, session=None):
if not isinstance(id, uuid.UUID):
id = uuid.UUID(id)
return session.query(cls).filter(cls.id == id).one()
@classmethod
def auth(cls, name, password):
user = cls.by_name(name)
if not user:
return False, None
if user.password != encrypt(password) or user.locked_out:
return False, None
else:
return True, user
@classmethod
def list(cls, *, session=None):
return session.query(cls).order_by(cls.name).all()
@classmethod
def query(cls, *, session=None):
return session.query(cls)
@classmethod
def filtered_list(cls, name, *, session=None):
query = session.query(cls)
for item in name.split():
query = query.filter(cls.name.ilike('%' + item + '%'))
return query.order_by(cls.name)
class Role(Base):
__tablename__ = 'auth_roles'
id = Column('role_id', GUID(), primary_key=True, default=uuid.uuid4)
name = Column('name', Unicode(255), unique=True)
def __init__(self, name=None, id=None):
self.name = name
self.id = id
@classmethod
def by_id(cls, id, *, session=None):
return session.query(cls).filter(cls.id == id).one()
@classmethod
def list(cls, *, session=None):
return session.query(cls).order_by(cls.name).all()
class Permission(Base):
__tablename__ = 'auth_permissions'
id = Column('permission_id', GUID(), primary_key=True, default=uuid.uuid4)
name = Column('name', Unicode(255), unique=True)
groups = relationship('Role', secondary=role_group, backref='permissions')
def __init__(self, name=None, id=None):
self.name = name
self.id = id
@classmethod
def list(cls, *, session=None):
return session.query(cls).order_by(cls.name).all()
@classmethod
def by_id(cls, id, *, session=None):
return session.query(cls).filter(cls.id == id).one()

60
summer/models/guidtype.py Normal file
View File

@ -0,0 +1,60 @@
__author__ = 'tanshu'
import uuid
from sqlalchemy.types import TypeDecorator, CHAR, Binary
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.dialects.sqlite import BLOB
class GUID(TypeDecorator):
"""Platform-independent GUID type.
Uses Postgresql's UUID type, otherwise uses
CHAR(32), storing as stringified hex values.
"""
impl = Binary
# if dialect.value == 'postgresql':
# impl = CHAR
# elif dialect.value == 'mysql':
# impl = MSBinary
# elif dialect.valie == 'sqlite':
# impl = Binary
# else:
# impl = Binary
def load_dialect_impl(self, dialect):
if dialect.name == 'postgresql':
return dialect.type_descriptor(UUID())
elif dialect.name == 'sqlite':
return dialect.type_descriptor(BLOB())
else:
return dialect.type_descriptor(CHAR(32))
def process_bind_param(self, value, dialect):
if value is None:
return None
elif dialect.name == 'postgresql':
return str(value)
elif not isinstance(value, uuid.UUID):
raise ValueError('value %s is not a valid uuid.UUID' % value)
else:
return value.bytes
# if not isinstance(value, uuid.UUID):
# return "%.32x" % uuid.UUID(value)
# else:
# # hexstring
# return "%.32x" % value
def process_result_value(self, value, dialect=None):
if value is None:
return None
elif isinstance(value, bytes):
return uuid.UUID(bytes=value)
else:
return uuid.UUID(value)
def is_mutable(self):
return False

331
summer/models/master.py Normal file
View File

@ -0,0 +1,331 @@
__author__ = 'tanshu'
import uuid
from sqlalchemy import UniqueConstraint, Column, Integer, Unicode, Numeric, Boolean, ForeignKey, func, PickleType
from sqlalchemy.orm import relationship
from models import Base
from models.guidtype import GUID
class Product(Base):
__tablename__ = 'products'
__tableagrs__ = (UniqueConstraint('name', 'units'))
id = Column('product_id', GUID(), primary_key=True, default=uuid.uuid4)
code = Column('code', Integer, unique=True, nullable=False)
name = Column('name', Unicode(255), nullable=False)
units = Column('units', Unicode(255), nullable=False)
product_group_id = Column('product_group_id', GUID(), ForeignKey('product_groups.product_group_id'), nullable=False)
price = Column('price', Numeric, nullable=False)
happy_hour = Column('happy_hour', Boolean, nullable=False)
service_tax_id = Column('service_tax_id', GUID(), ForeignKey('taxes.tax_id'), nullable=False)
vat_id = Column('vat_id', GUID(), ForeignKey('taxes.tax_id'), nullable=False)
service_charge = Column('service_charge', Numeric, nullable=False)
sc_taxable = Column('sc_taxable', Boolean, nullable=False)
is_active = Column('is_active', Boolean, nullable=False)
is_fixture = Column('is_fixture', Boolean, nullable=False)
sort_order = Column('sort_order', Integer, nullable=False)
service_tax = relationship('Tax', foreign_keys=service_tax_id, backref='products_service_tax')
vat = relationship('Tax', foreign_keys=vat_id, backref='products_vat')
def __init__(self, code=None, name=None, units=None, product_group_id=None, price=None, happy_hour=None,
service_tax_id=None, vat_id=None, service_charge=None, sc_taxable=None, is_active=None,
sort_order=None, is_fixture=False):
self.code = code
self.name = name
self.units = units
self.product_group_id = product_group_id
self.price = price
self.happy_hour = happy_hour
self.service_tax_id = service_tax_id
self.vat_id = vat_id
self.service_charge = service_charge
self.sc_taxable = sc_taxable
self.is_active = is_active
self.sort_order = sort_order
self.is_fixture = is_fixture
@property
def full_name(self):
return "{0} ({1})".format(self.name, self.units)
@classmethod
def list(cls, name, active, *, DBSession=None):
query = DBSession.query(cls)
if active is not None:
query = query.filter(cls.is_active != active)
for item in name.split():
query = query.filter(cls.name.ilike('%' + item + '%'))
return query.order_by(cls.name)
@classmethod
def by_name(cls, name, *, DBSession=None):
return DBSession.query(cls).filter(cls.name == name).first()
@classmethod
def by_full_name(cls, full_name, *, DBSession=None):
return DBSession.query(cls).filter(cls.name + ' (' + cls.units + ')' == full_name).first()
@classmethod
def by_id(cls, id, *, DBSession=None):
return DBSession.query(cls).filter(cls.id == id).first()
@classmethod
def query(cls, *, DBSession=None):
return DBSession.query(cls)
def create(self, *, DBSession=None):
code = DBSession.query(func.max(Product.code)).one()[0]
if code is None:
self.code = 1
else:
self.code = code + 1
DBSession.add(self)
return self
def can_delete(self, advanced_delete):
if self.is_fixture:
return False, ('Fixture', "{0} cannot be edited or deleted.".format(self.name))
if self.is_active:
return False, ('Active', 'Product is active')
if len(self.inventories) > 0 and not advanced_delete:
return False, ('In Use', 'Product has entries')
return True, ''
@classmethod
def suspense(cls):
return uuid.UUID('aa79a643-9ddc-4790-ac7f-a41f9efb4c15')
class ProductGroup(Base):
__tablename__ = 'product_groups'
id = Column('product_group_id', GUID(), primary_key=True, default=uuid.uuid4)
name = Column('name', Unicode(255), unique=True, nullable=False)
max_discount = Column('max_discount', Numeric, nullable=False)
header = Column('header', Unicode(255), nullable=False)
is_active = Column('is_active', Boolean, nullable=False)
is_fixture = Column('is_fixture', Boolean, nullable=False)
sort_order = Column('sort_order', Integer, nullable=False)
products = relationship('Product', backref='product_group')
def __init__(self, name=None, max_discount=1, header=None, sort_order=None, is_active=True, id=None,
is_fixture=False):
self.name = name
self.max_discount = max_discount
self.header = header
self.sort_order = sort_order
self.is_active = is_active
if id is not None and not isinstance(id, uuid.UUID):
id = uuid.UUID(id)
self.id = id
self.is_fixture = is_fixture
@classmethod
def list(cls):
return DBSession.query(cls).order_by(cls.name)
@classmethod
def by_id(cls, id):
if not isinstance(id, uuid.UUID):
id = uuid.UUID(id)
return DBSession.query(cls).filter(cls.id == id).first()
def can_delete(self, advanced_delete):
if self.is_fixture:
return False, ('Fixture', "{0} cannot be edited or deleted.".format(self.name))
#if len(self.inventories) > 0 and not advanced_delete:
# return False, 'Product has entries'
return True, ''
class Tax(Base):
__tablename__ = 'taxes'
id = Column('tax_id', GUID(), primary_key=True, default=uuid.uuid4)
name = Column('name', Unicode(255), unique=True, nullable=False)
rate = Column('rate', Numeric, nullable=False)
is_fixture = Column('is_fixture', Boolean, nullable=False)
def __init__(self, name=None, rate=None, id=None, is_fixture=False):
if id is not None and not isinstance(id, uuid.UUID):
id = uuid.UUID(id)
self.id = id
self.name = name
self.rate = rate
self.is_fixture = is_fixture
@classmethod
def by_id(cls, id):
if not isinstance(id, uuid.UUID):
id = uuid.UUID(id)
return DBSession.query(cls).filter(cls.id == id).first()
@classmethod
def by_name(cls, name):
return DBSession.query(cls).filter(cls.name == name).first()
@classmethod
def list(cls):
return DBSession.query(cls).order_by(cls.name).all()
def can_delete(self, advanced_delete):
if self.is_fixture:
return False, ('Fixture', "{0} cannot be edited or deleted.".format(self.name))
#if len(self.inventories) > 0 and not advanced_delete:
# return False, 'Product has entries'
return True, ''
@classmethod
def tax_free_id(cls):
return uuid.UUID('08c3101d-cdab-449f-9574-a025c8ae5556')
@classmethod
def tax_free(cls):
return {'TaxID': uuid.UUID('08c3101d-cdab-449f-9574-a025c8ae5556')}
class DbSetting(Base):
__tablename__ = 'auth_settings'
id = Column('setting_id', GUID(), primary_key=True, default=uuid.uuid4)
name = Column('name', Unicode(255), unique=True, nullable=False)
data = Column('data', PickleType)
def __init__(self, id=None, name=None, data=None):
self.id = id
self.name = name
self.data = data
@classmethod
def by_id(cls, id):
if not isinstance(id, uuid.UUID):
id = uuid.UUID(id)
return DBSession.query(cls).filter(cls.id == id).first()
@classmethod
def by_name(cls, name):
return DBSession.query(cls).filter(cls.name == name).first()
@classmethod
def list(cls):
return DBSession.query(cls).order_by(cls.name).all()
class FoodTable(Base):
__tablename__ = 'food_tables'
id = Column('food_table_id', GUID(), primary_key=True, default=uuid.uuid4)
name = Column('name', Unicode(255), unique=True, nullable=False)
location = Column('location', Unicode(255), nullable=False)
def __init__(self, name=None, location=None, id=None):
self.id = id
self.name = name
self.location = location
@classmethod
def by_id(cls, id):
if not isinstance(id, uuid.UUID):
id = uuid.UUID(id)
return DBSession.query(cls).filter(cls.id == id).first()
@classmethod
def by_name(cls, name):
return DBSession.query(cls).filter(cls.name == name).first()
@classmethod
def by_normalized_name(cls, name):
return DBSession.query(cls).filter(cls.name == name.replace('-', ' ')).first()
@classmethod
def list(cls):
return DBSession.query(cls).order_by(cls.name).all()
def can_delete(self, advanced_delete):
#if len(self.inventories) > 0 and not advanced_delete:
# return False, 'Product has entries'
return True, ''
class TableStatus:
def __init__(self, id, status):
self.id = id
self.status = status
@classmethod
def list(cls):
list = []
list.append(TableStatus(1, 'Locked'))
list.append(TableStatus(2, 'Running'))
list.append(TableStatus(3, 'Billed'))
return list
@classmethod
def by_name(cls, name):
list = cls.list()
for item in list:
if item.name == name:
return item
@classmethod
def by_id(cls, id):
list = cls.list()
for item in list:
if item.id == id:
return item
class Modifier(Base):
__tablename__ = 'modifiers'
id = Column('modifier_id', GUID(), primary_key=True, default=uuid.uuid4)
name = Column('name', Unicode(255), unique=True, nullable=False)
is_active = Column('is_active', Boolean, nullable=False)
groups = relationship('ModifierProductGroup', backref='modifier')
def __init__(self, name=None, is_active=None, id=None):
self.id = id
self.name = name
self.is_active = is_active
@classmethod
def by_id(cls, id):
if not isinstance(id, uuid.UUID):
id = uuid.UUID(id)
return DBSession.query(cls).filter(cls.id == id).first()
@classmethod
def by_name(cls, name):
return DBSession.query(cls).filter(cls.name == name).first()
@classmethod
def list(cls):
return DBSession.query(cls).order_by(cls.name).all()
def can_delete(self, advanced_delete):
#if len(self.inventories) > 0 and not advanced_delete:
# return False, 'Product has entries'
return True, ''
class ModifierProductGroup(Base):
__tablename__ = 'modifier_product_groups'
id = Column('modifier_product_groups_id', GUID(), primary_key=True, default=uuid.uuid4)
modifier_id = Column('modifier_id', GUID(), ForeignKey('modifiers.modifier_id'), nullable=False)
product_group_id = Column('product_group_id', GUID(), ForeignKey('product_groups.product_group_id'), nullable=True)
group = relationship('ProductGroup', backref='modifiers')
def __init__(self, modifier_id=None, product_group_id=None, id=None):
self.id = id
self.modifier_id = modifier_id
self.product_group_id = product_group_id

View File

@ -0,0 +1,40 @@
import json
__author__ = 'tanshu'
from sqlalchemy.exc import OperationalError, IntegrityError
class ValidationError(Exception):
def __init__(self, header, message, Errors=None):
self.header = header
self.message = message
# Call the base class constructor with the parameters it needs
Exception.__init__(self, (header, message))
# Now for your custom code...
self.Errors = Errors
def __str__(self):
return self.message
def json(self):
return (self.header, self.message)
#
#
# def TryCatchFunction(f):
# def _decorator(self, *args, **kwargs):
# try:
# return f(self, *args, **kwargs)
# except ValidationError as ex:
# transaction.abort()
# response = Response(json.dumps(ex.json()))
# response.status_int = 500
# return response
# except (ValueError, KeyError, AttributeError, TypeError, OperationalError, IntegrityError) as ex:
# transaction.abort()
# response = Response(json.dumps(('Failed validation', str(ex))))
# response.status_int = 500
# return response
#
# return _decorator

262
summer/models/voucher.py Normal file
View File

@ -0,0 +1,262 @@
__author__ = 'tanshu'
import uuid
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy import Column, Integer, DateTime, Numeric, ForeignKey, Boolean, UniqueConstraint
from sqlalchemy.orm import relationship, synonym, backref
from models.master import Tax
from models.guidtype import GUID
from models import Base
class VoucherType:
def __init__(self, id, name, show_in_choices, group):
self.id = id
self.name = name
self.show_in_choices = show_in_choices
self.group = group
@classmethod
def list(cls):
list = []
list.append(VoucherType(1, 'Regular Bill', True, 2))
list.append(VoucherType(2, 'No Charge', True, 3))
list.append(VoucherType(3, 'Take Away', True, 2))
list.append(VoucherType(4, 'Staff Bill', True, 4))
return list
@classmethod
def by_name(cls, name):
list = cls.list()
for item in list:
if item.name == name:
return item
@classmethod
def by_id(cls, id):
list = cls.list()
for item in list:
if item.id == id:
return item
class Voucher(Base):
__tablename__ = 'vouchers'
__tableagrs__ = (UniqueConstraint('voucher_type', 'bill_id'))
id = Column('voucher_id', GUID(), primary_key=True, default=uuid.uuid4)
date = Column('date', DateTime(timezone=True), nullable=False)
creation_date = Column('creation_date', DateTime(timezone=True), nullable=False)
last_edit_date = Column('last_edit_date', DateTime(timezone=True), nullable=False)
_type = Column('voucher_type', Integer, nullable=False)
kot_id = Column('kot_id', Integer, unique=True, nullable=False)
bill_id = Column('bill_id', Integer, nullable=True)
pax = Column('pax', Integer, nullable=False)
per_chair = Column('per_chair', Boolean, nullable=False)
user_id = Column('user_id', GUID(), ForeignKey('auth_users.user_id'), nullable=False)
food_table_id = Column('table_id', GUID(), ForeignKey('food_tables.food_table_id'), nullable=False)
user = relationship('User', primaryjoin="User.id==Voucher.user_id", cascade=None)
food_table = relationship('FoodTable', primaryjoin="FoodTable.id==Voucher.food_table_id", cascade=None)
kots = relationship('Kot', backref='voucher', cascade="delete, delete-orphan", cascade_backrefs=False)
def _get_type(self):
return self._type
# for item in VoucherType.list():
# if self._type == item.id:
# return item
def _set_type(self, value):
if type(value) == int:
self._type = value
else:
self._type = value.id
type = property(_get_type, _set_type)
type = synonym('_type', descriptor=type)
@property
def __name__(self):
return self.name
def __init__(self, date=None, creation_date=None, last_edit_date=None, type=None, kot_id=None, bill_id=None,
user_id=None, food_table_id=None, pax=None, per_seat=None, id=None):
self.id = id
self.date = date
self.creation_date = creation_date
self.last_edit_date = last_edit_date
self.type = type
self.kot_id = kot_id
self.bill_id = bill_id
self.user_id = user_id
self.food_table_id = food_table_id
self.pax = pax
self.per_seat = per_seat
@classmethod
def by_id(cls, id, *, DBSession=None):
return DBSession.query(cls).filter(cls.id == id).first()
@classmethod
def list(cls, *, DBSession=None):
return DBSession.query(cls).all()
@classmethod
def query(cls, *, DBSession=None):
return DBSession.query(cls)
class Kot(Base):
__tablename__ = 'kots'
id = Column('kot_id', GUID(), primary_key=True, default=uuid.uuid4)
voucher_id = Column('voucher_id', GUID(), ForeignKey('vouchers.voucher_id'), nullable=False)
code = Column('code', Integer, unique=True, nullable=False)
food_table_id = Column('table_id', GUID(), ForeignKey('food_tables.food_table_id'), nullable=False)
date = Column('date', DateTime, nullable=False)
user_id = Column('user_id', GUID(), ForeignKey('auth_users.user_id'), nullable=False)
food_table = relationship('FoodTable', primaryjoin="FoodTable.id==Kot.food_table_id", cascade=None)
@hybrid_property
def signed_amount(self):
return self.debit * self.amount
@property
def __name__(self):
return self.name
def __init__(self, code=None, food_table_id=None, date=None, user_id=None, voucher_id=None, id=None):
self.id = id
self.voucher_id = voucher_id
self.code = code
self.food_table_id = food_table_id
self.date = date
self.user_id = user_id
@classmethod
def by_id(cls, id):
return DBSession.query(cls).filter(cls.id == id).first()
@classmethod
def list(cls, voucher_id):
return DBSession.query(cls).filter(cls.voucher_id == voucher_id).all()
@classmethod
def query(cls):
return DBSession.query(cls)
class Inventory(Base):
__tablename__ = 'inventories'
# __tableagrs__ = (UniqueConstraint('VoucherID', 'ProductID'))
id = Column('inventory_id', GUID(), primary_key=True, default=uuid.uuid4)
kot_id = Column('kot_id', GUID(), ForeignKey('kots.kot_id'), nullable=False)
chair = Column('chair', Integer, nullable=False)
product_id = Column('product_id', GUID(), ForeignKey('products.product_id'), nullable=False)
quantity = Column('quantity', Numeric, nullable=False)
price = Column('rate', Numeric, nullable=False)
discount = Column('discount', Numeric, nullable=False)
is_happy_hour = Column('is_happy_hour', Boolean, nullable=False)
_service_tax_rate = Column('service_tax_rate', Numeric, nullable=False)
service_tax_id = Column('service_tax_id', GUID(), ForeignKey('taxes.tax_id'), nullable=False)
_vat_rate = Column('vat_rate', Numeric, nullable=False)
vat_id = Column('vat_id', GUID(), ForeignKey('taxes.tax_id'), nullable=False)
service_charge = Column('service_charge', Numeric, nullable=False)
sc_taxable = Column('sc_taxable', Boolean, nullable=False)
service_tax = relationship('Tax', foreign_keys=service_tax_id)
vat = relationship('Tax', foreign_keys=vat_id)
def __init__(self, chair=0, product_id=None, quantity=None, price=None, discount=None, is_happy_hour=None,
service_tax_id=None, service_tax_rate=None, vat_id=None, vat_rate=None, service_charge=None,
sc_taxable=None, kot_id=None, id=None):
self.id = id
self.kot_id = kot_id
self.chair = chair
self.product_id = product_id
self.quantity = quantity
self.price = price
self.discount = discount
self.is_happy_hour = is_happy_hour
self.service_tax_id = service_tax_id
self.service_tax_rate = service_tax_rate
self.vat_id = vat_id
self.vat_rate = vat_rate
self.service_charge = service_charge
self.sc_taxable = sc_taxable
def _get_service_tax_rate(self):
if self._service_tax_rate is not None:
return self._service_tax_rate
if self.service_tax is not None:
return self.service_tax.rate
if self.service_tax_id is not None:
return Tax.by_id(self.service_tax_id).rate
return None
def _set_service_tax_rate(self, value):
self._service_tax_rate = value
service_tax_rate = property(_get_service_tax_rate, _set_service_tax_rate)
service_tax_rate = synonym('_service_tax_rate', descriptor=service_tax_rate)
def _get_vat_rate(self):
if self._vat_rate is not None:
return self._vat_rate
if self.vat is not None:
return self.vat.rate
if self.vat_id is not None:
return Tax.by_id(self.vat_id).rate
return None
def _set_vat_rate(self, value):
self._vat_rate = value
vat_rate = property(_get_vat_rate, _set_vat_rate)
vat_rate = synonym('_vat_rate', descriptor=vat_rate)
@hybrid_property
def amount(self):
if self.is_happy_hour:
return 0
base = self.quantity * self.rate * (1 - self.discount)
if self.sc_taxable:
return base * (1 + self.service_charge) * (1 + self.service_tax_rate + self.vat_rate)
return base * (1 + self.service_charge + self.service_tax_rate + self.vat_rate)
class RunningTable(Base):
__tablename__ = 'running_tables'
id = Column('running_table_id', GUID(), primary_key=True, default=uuid.uuid4)
voucher_id = Column('voucher_id', GUID(), ForeignKey('vouchers.voucher_id'), nullable=False, unique=True)
food_table_id = Column('food_table_id', GUID(), ForeignKey('food_tables.food_table_id'), nullable=False,
unique=True)
_status = Column('table_status', Integer, nullable=False)
food_table = relationship('FoodTable', backref=backref('info', uselist=False))
def _get_status(self):
for item in RunningTable.list():
if self._status == item.id:
return item
def _set_status(self, value):
if type(value) == int:
self._status = value
else:
self._status = value.id
status = property(_get_status, _set_status)
status = synonym('_status', descriptor=status)
def __init__(self, id=None, voucher_id=None, food_table_id=None, status=None):
self.id = id
self.voucher_id = voucher_id
self.food_table_id = food_table_id
self.status = status

View File

@ -0,0 +1,21 @@
__author__ = 'tanshu'
from PyQt5 import uic
# package, resource = 'summer:QtDesignerFiles/MainWindow.ui'.split(':', 1)
# file = pkg_resources.resource_stream(package, resource)
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/MainWindow.ui'
base, form = uic.loadUiType(file)
class MainWindow(base, form):
def __init__(self, router, parent=None):
super(MainWindow, self).__init__()
self.setupUi(self)
self.btnExit.clicked.connect(self.handle_exit)
self.btnUsers.clicked.connect(router.show_users)
self.btnRoles.clicked.connect(router.show_roles)
def handle_exit(self):
self.close()

View File

@ -0,0 +1,56 @@
__author__ = 'tanshu'
from PyQt5 import uic, QtCore
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/RoleDetail.ui'
base, form = uic.loadUiType(file)
class RoleDetail(base, form):
def __init__(self, router, role, parent=None):
super(RoleDetail, self).__init__()
self.setupUi(self)
self.router = router
self.role = role
self.txtName.setText(role['Name'])
self.accepted.connect(self.save_role)
self.lvwPermissions.setModel(RolesListModel(self.role['Permissions']))
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
def save_role(self):
self.role['Name'] = self.txtName.text()
self.router.save_role(self.role)
class RolesListModel(QtCore.QAbstractListModel):
def __init__(self, permissions=None, parent=None):
QtCore.QAbstractListModel.__init__(self, parent)
self.permissions = permissions if permissions is not None else []
def rowCount(self, parent):
return len(self.permissions)
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
item = self.permissions[index.row()]
return item['Name']
elif role == QtCore.Qt.CheckStateRole:
item = self.permissions[index.row()]
return QtCore.Qt.Checked if item['Enabled'] else QtCore.Qt.Unchecked
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return 'Permissions'
else:
return section + 1
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.CheckStateRole:
item = self.permissions[index.row()]
item['Enabled'] = False if value == 0 else True
return True
def flags(self, index):
return QtCore.QAbstractListModel.flags(self, index) | QtCore.Qt.ItemIsUserCheckable

View File

@ -0,0 +1,63 @@
__author__ = 'tanshu'
from PyQt5 import uic, QtCore, QtWidgets
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/RoleList.ui'
base, form = uic.loadUiType(file)
class RoleList(base, form):
def __init__(self, router, roles, parent=None):
super(RoleList, self).__init__()
self.setupUi(self)
self.router = router
self.roles = roles
self.model = RolesTableModel(roles)
self.tblRoles.setModel(self.model)
self.tblRoles.doubleClicked.connect(self.show_role)
self.btnAddNew.clicked.connect(self.add_new_role)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
self.tblRoles.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
def update_data(self, data):
self.roles = data
self.model = RolesTableModel(self.roles)
self.tblRoles.setModel(self.model)
def show_role(self, index):
role = self.model.roles[index.row()]
self.router.show_role(role['RoleID'])
def add_new_role(self):
self.router.show_role(None)
class RolesTableModel(QtCore.QAbstractTableModel):
def __init__(self, roles=None, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.roles = roles if roles is not None else []
def rowCount(self, parent):
return len(self.roles)
def columnCount(self, parent):
return 2
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
item = self.roles[index.row()]
column = index.column()
if column == 0:
return item['Name']
elif column == 1:
return ", ".join(item['Permissions'])
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
if section == 0:
return 'Name'
elif section == 1:
return 'Permissions'
else:
return section + 1

View File

@ -0,0 +1,60 @@
__author__ = 'tanshu'
from PyQt5 import uic, QtCore
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/UserDetail.ui'
base, form = uic.loadUiType(file)
class UserDetail(base, form):
def __init__(self, router, user, parent=None):
super(UserDetail, self).__init__()
self.setupUi(self)
self.router = router
self.user = user
self.txtName.setText(user['Name'])
self.txtPassword.setText('')
self.chkLockedOut.setCheckState(QtCore.Qt.Checked if user['LockedOut'] else QtCore.Qt.Unchecked)
self.accepted.connect(self.save_user)
self.lvwRoles.setModel(RolesListModel(self.user['Roles']))
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
def save_user(self):
self.user['Name'] = self.txtName.text()
self.user['Password'] = self.txtPassword.text()
self.user['LockedOut'] = self.chkLockedOut.isChecked()
self.router.save_user(self.user)
class RolesListModel(QtCore.QAbstractListModel):
def __init__(self, roles=None, parent=None):
QtCore.QAbstractListModel.__init__(self, parent)
self.roles = roles if roles is not None else []
def rowCount(self, parent):
return len(self.roles)
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
item = self.roles[index.row()]
return item['Name']
elif role == QtCore.Qt.CheckStateRole:
item = self.roles[index.row()]
return QtCore.Qt.Checked if item['Enabled'] else QtCore.Qt.Unchecked
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return 'Roles'
else:
return section + 1
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.CheckStateRole:
item = self.roles[index.row()]
item['Enabled'] = False if value == 0 else True
return True
def flags(self, index):
return QtCore.QAbstractListModel.flags(self, index) | QtCore.Qt.ItemIsUserCheckable

View File

@ -0,0 +1,67 @@
__author__ = 'tanshu'
from PyQt5 import uic, QtCore, QtWidgets
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/UserList.ui'
base, form = uic.loadUiType(file)
class UserList(base, form):
def __init__(self, router, users, parent=None):
super(UserList, self).__init__()
self.setupUi(self)
self.router = router
self.users = users
self.model = UsersTableModel(users)
self.tblUsers.setModel(self.model)
self.tblUsers.doubleClicked.connect(self.show_user)
self.btnAddNew.clicked.connect(self.add_new_user)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
self.tblUsers.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
def update_data(self, data):
self.users = data
self.model = UsersTableModel(self.users)
self.tblUsers.setModel(self.model)
def show_user(self, index):
user = self.model.users[index.row()]
self.router.show_user(user['UserID'])
def add_new_user(self):
self.router.show_user(None)
class UsersTableModel(QtCore.QAbstractTableModel):
def __init__(self, users=None, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.users = users if users is not None else []
def rowCount(self, parent):
return len(self.users)
def columnCount(self, parent):
return 3
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
user = self.users[index.row()]
column = index.column()
if column == 0:
return user['Name']
elif column == 1:
return user['LockedOut']
elif column == 2:
return ", ".join(user['Roles'])
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
if section == 0:
return 'Name'
elif section == 1:
return 'Locked Out'
elif section == 2:
return 'Roles'
else:
return section + 1

73
summer/views/__init__.py Normal file
View File

@ -0,0 +1,73 @@
from summer.templates.RoleDetail import RoleDetail
from summer.templates.RoleList import RoleList
from summer.templates.UserDetail import UserDetail
from summer.templates.UserList import UserList
from summer.views.user import show_list as user_list, user_info, save_user, update_user
from summer.views.role import show_list as role_list, role_info, save_role, update_role
__author__ = 'tanshu'
class Router():
def __init__(self):
self.user_list_form = None
self.user_detail_form = None
self.role_list_form = None
self.role_detail_form = None
def show_users(self):
users = user_list()
if self.user_list_form is None:
self.user_list_form = UserList(self, users)
self.user_list_form.destroyed.connect(self.user_list_form_destroyed)
self.user_list_form.show()
def user_list_form_destroyed(self):
self.user_list_form = None
def show_user(self, id=None):
user = user_info(id)
if self.user_detail_form is None:
self.user_detail_form = UserDetail(self, user)
self.user_detail_form.destroyed.connect(self.user_detail_form_destroyed)
self.user_detail_form.show()
def user_detail_form_destroyed(self):
self.user_detail_form = None
if self.user_list_form is not None:
self.user_list_form.update_data(user_list())
def save_user(self, user):
if 'UserID' not in user:
save_user(user)
else:
update_user(user)
def show_roles(self):
roles = role_list()
if self.role_list_form is None:
self.role_list_form = RoleList(self, roles)
self.role_list_form.destroyed.connect(self.role_list_form_destroyed)
self.role_list_form.show()
def role_list_form_destroyed(self):
self.role_list_form = None
def show_role(self, id=None):
role = role_info(id)
if self.role_detail_form is None:
self.role_detail_form = RoleDetail(self, role)
self.role_detail_form.destroyed.connect(self.role_detail_form_destroyed)
self.role_detail_form.show()
def role_detail_form_destroyed(self):
self.role_detail_form = None
if self.role_list_form is not None:
self.role_list_form.update_data(role_list())
def save_role(self, role):
if 'RoleID' not in role:
save_role(role)
else:
update_role(role)

61
summer/views/role.py Normal file
View File

@ -0,0 +1,61 @@
from summer.models import session_scope
__author__ = 'tanshu'
from summer.models.auth import Role, Permission
def save_role(json):
role = Role(json['Name'])
with session_scope() as DBSession:
DBSession.add(role)
add_permissions(role, json['Permissions'], DBSession)
return role_info(role.id)
def update_role(json):
with session_scope() as DBSession:
role = Role.by_id(json['RoleID'], session=DBSession)
role.name = json['Name']
add_permissions(role, json['Permissions'], session=DBSession)
return role_info(role.id)
def add_permissions(role, permissions, *, session=None):
for permission in permissions:
id = permission['PermissionID']
gp = [p for p in role.permissions if p.id == id]
gp = None if len(gp) == 0 else gp[0]
if permission['Enabled'] and gp is None:
role.permissions.append(Permission.by_id(id, session=session))
elif not permission['Enabled'] and gp:
role.permissions.remove(gp)
def show_list():
with session_scope() as DBSession:
list = Role.list(session=DBSession)
roles = []
for item in list:
role = {'RoleID': item.id, 'Name': item.name, 'Permissions': []}
for permission in item.permissions:
role['Permissions'].append(permission.name)
roles.append(role)
return roles
def role_info(id):
with session_scope() as DBSession:
if id is None:
role = {'Name': '', 'Permissions': []}
for item in Permission.list(session=DBSession):
role['Permissions'].append({'PermissionID': item.id, 'Name': item.name, 'Enabled': False})
else:
role_object = Role.by_id(id, session=DBSession)
role = {'RoleID': role_object.id, 'Name': role_object.name, 'Permissions': []}
for item in Permission.list(session=DBSession):
enabled = True if item in role_object.permissions else False
role['Permissions'].append({'PermissionID': item.id, 'Name': item.name, 'Enabled': enabled})
return role

74
summer/views/user.py Normal file
View File

@ -0,0 +1,74 @@
from summer.models import session_scope
from summer.models.auth import User, Role
from summer.models.validation_exception import ValidationError
def save_user(json):
user = User(json['Name'], json['Password'], json['LockedOut'])
with session_scope() as DBSession:
DBSession.add(user)
add_roles(user, json['Roles'], session=DBSession)
return user_info(user.id)
def update_user(json):
with session_scope() as DBSession:
user = User.by_id(json['UserID'], session=DBSession)
if user is None:
raise ValidationError('User name / id not found')
has_permission = True
if has_permission:
user.name = json['Name']
user.locked_out = json['LockedOut']
add_roles(user, json['Roles'], session=DBSession)
if json['Password'] != '' and json['Password'] != user.password:
user.password = json['Password']
return user_info(user.id)
def show_list():
with session_scope() as DBSession:
list = User.list(session=DBSession)
users = []
for item in list:
user = {'UserID': item.id, 'Name': item.name, 'LockedOut': item.locked_out, 'Roles': []}
for role in item.roles:
user['Roles'].append(role.name)
users.append(user)
return users
def user_info(id):
with session_scope() as DBSession:
if id is None:
account = {'Name': '', 'LockedOut': False, 'Roles': []}
for item in Role.list(session=DBSession):
account['Roles'].append({'RoleID': item.id, 'Name': item.name, 'Enabled': False})
return account
user = User.by_id(id, session=DBSession)
has_permission = True
if has_permission:
account = {'UserID': user.id, 'Name': user.name, 'Password': '', 'LockedOut': user.locked_out, 'Roles': []}
for item in Role.list(session=DBSession):
account['Roles'].append(
{'RoleID': item.id, 'Name': item.name, 'Enabled': True if item in user.roles else False})
# elif self.user.id == user.id:
elif 1 == 1:
account = {'UserID': user.id, 'Name': user.name, 'Password': '', 'LockedOut': user.locked_out, 'Roles': []}
else:
raise ValidationError("User can only update his/her password")
return account
def add_roles(user, roles, *, session=None):
for role in roles:
id = role['RoleID']
ur = [r for r in user.roles if r.id == id]
ur = None if len(ur) == 0 else ur[0]
if role['Enabled'] and ur is None:
user.roles.append(Role.by_id(id, session=session))
elif not role['Enabled'] and ur:
user.roles.remove(ur)