Features: Combined all the list forms

Feautres: New Forms, Tax, Product
TODO: Initial Sale Window testing  with flow layout
This commit is contained in:
Amritanshu 2014-07-29 13:22:10 +05:30
parent d44daf921b
commit 196e556550
26 changed files with 1282 additions and 159 deletions

6
README.txt Normal file
View File

@ -0,0 +1,6 @@
TODO: Authorization and Authentication
TODO: User View == Proper has_permission handling
TODO: Settings / Config module
INFO: product now has a 'has_happy_hour' check box, if it is there, then show twice in list once as happy hour
and one normal. in the sale also do the same. this will also make sure that the price is synced and if happy hour
is being properly given

View File

@ -0,0 +1,103 @@
from PyQt5.QtCore import QPoint, QRect, QSize, Qt
from PyQt5.QtWidgets import QLayout, QSizePolicy, QStyle
__author__ = 'tanshu'
class FlowLayout(QLayout):
def __init__(self, parent=None, margin=0, spacing=-1):
super(FlowLayout, self).__init__(parent)
if parent is not None:
self.setContentsMargins(margin, margin, margin, margin)
self.setSpacing(spacing)
self.itemList = []
def __del__(self):
item = self.takeAt(0)
while item:
item = self.takeAt(0)
def addItem(self, item):
self.itemList.append(item)
def count(self):
return len(self.itemList)
def itemAt(self, index):
if index >= 0 and index < len(self.itemList):
return self.itemList[index]
return None
def takeAt(self, index):
if index >= 0 and index < len(self.itemList):
return self.itemList.pop(index)
return None
def expandingDirections(self):
return Qt.Orientations(Qt.Orientation(0))
def hasHeightForWidth(self):
return True
def heightForWidth(self, width):
height = self.doLayout(QRect(0, 0, width, 0), True)
return height
def setGeometry(self, rect):
super(FlowLayout, self).setGeometry(rect)
self.doLayout(rect, False)
def sizeHint(self):
return self.minimumSize()
def minimumSize(self):
size = QSize()
for item in self.itemList:
size = size.expandedTo(item.minimumSize())
margin, _, _, _ = self.getContentsMargins()
size += QSize(2 * margin, 2 * margin)
return size
def horizontalSpacing(self):
return self.smartSpacing(QStyle.PM_LayoutHorizontalSpacing)
def verticalSpacing(self):
return self.smartSpacing(QStyle.PM_LayoutVerticalSpacing)
def doLayout(self, rect, testOnly):
left, top, right, bottom = self.getContentsMargins()
effectiveRect = rect.adjusted(+left, +top, -right, -bottom)
x = effectiveRect.x()
y = effectiveRect.y()
lineHeight = 0
for item in self.itemList:
wid = item.widget()
if wid.isHidden():
continue
spaceX = self.spacing() + wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton,
Qt.Horizontal)
spaceY = self.spacing() + wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton,
Qt.Vertical)
nextX = x + item.sizeHint().width() + spaceX
if nextX - spaceX > rect.right() and lineHeight > 0:
x = rect.x()
y = y + lineHeight + spaceY
nextX = x + item.sizeHint().width() + spaceX
lineHeight = 0
if not testOnly:
item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
x = nextX
lineHeight = max(lineHeight, item.sizeHint().height())
return y + lineHeight - rect.y()

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RoleList</class>
<widget class="QMainWindow" name="RoleList">
<class>ListForm</class>
<widget class="QMainWindow" name="ListForm">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
@ -14,17 +14,17 @@
</rect>
</property>
<property name="windowTitle">
<string>Roles</string>
<string>List Form</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QTableView" name="tblRoles"/>
<widget class="QTableView" name="tblItems"/>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="btnAddNew">
<property name="text">
<string>Add Role</string>
<string>Add Item</string>
</property>
</widget>
</item>

View File

@ -251,8 +251,8 @@
<widget class="QPushButton" name="btnExit">
<property name="geometry">
<rect>
<x>650</x>
<y>340</y>
<x>10</x>
<y>450</y>
<width>150</width>
<height>100</height>
</rect>
@ -274,6 +274,19 @@
<string>Management</string>
</property>
</widget>
<widget class="QPushButton" name="btnTaxes">
<property name="geometry">
<rect>
<x>650</x>
<y>340</y>
<width>150</width>
<height>100</height>
</rect>
</property>
<property name="text">
<string>Taxes</string>
</property>
</widget>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
@ -297,6 +310,7 @@
<tabstop>btnDiscountReport</tabstop>
<tabstop>btnChangePassword</tabstop>
<tabstop>btnManagement</tabstop>
<tabstop>btnTaxes</tabstop>
<tabstop>btnExit</tabstop>
</tabstops>
<resources/>

View File

@ -0,0 +1,188 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ProductDetails</class>
<widget class="QDialog" name="ProductDetails">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>397</width>
<height>417</height>
</rect>
</property>
<property name="windowTitle">
<string>Product 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="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Units</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="txtUnits"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Group</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="cmbProductGroup"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Price</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="dsbPrice"/>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="chkHasHappyHour">
<property name="text">
<string>Has Happy Hour?</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Service Charge</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QDoubleSpinBox" name="dsbServiceCharge"/>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="chkScTaxable">
<property name="text">
<string>Is Service Charge Taxable?</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Service Tax</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QComboBox" name="cmbServiceTax"/>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>VAT</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QComboBox" name="cmbVat"/>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Sort Order</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QSpinBox" name="sbSortOrder"/>
</item>
<item row="11" column="1">
<widget class="QCheckBox" name="chkIsActive">
<property name="text">
<string>Is Active?</string>
</property>
</widget>
</item>
<item row="15" 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>txtUnits</tabstop>
<tabstop>cmbProductGroup</tabstop>
<tabstop>dsbPrice</tabstop>
<tabstop>chkHasHappyHour</tabstop>
<tabstop>dsbServiceCharge</tabstop>
<tabstop>chkScTaxable</tabstop>
<tabstop>cmbServiceTax</tabstop>
<tabstop>cmbVat</tabstop>
<tabstop>sbSortOrder</tabstop>
<tabstop>chkIsActive</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ProductDetails</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>ProductDetails</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

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ProductGroupList</class>
<widget class="QMainWindow" name="ProductGroupList">
<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>Product Groups</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QTableView" name="tblProductGroups"/>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="btnAddNew">
<property name="text">
<string>Add Product Group</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,68 @@
from PyQt5 import QtCore, QtWidgets
from summer.QtDesignerFiles.FlowLayout import FlowLayout
class SaleWindowQt(object):
def setupUi(self, SaleWindow):
SaleWindow.setObjectName("SaleWindow")
SaleWindow.resize(1024, 768)
self.centralwidget = QtWidgets.QWidget(SaleWindow)
self.centralwidget.setObjectName("centralwidget")
self.tableView = QtWidgets.QTableView(self.centralwidget)
self.tableView.setGeometry(QtCore.QRect(10, 10, 400, 550))
self.tableView.setObjectName("tableView")
self.abWidget = QtWidgets.QWidget(self.centralwidget)
self.abWidget.setGeometry(QtCore.QRect(10, 620, 1004, 140))
self.abWidget.setObjectName("abWidget")
self.flActions = FlowLayout(self.abWidget)
self.flActions.setContentsMargins(0, 0, 0, 0)
self.flActions.setObjectName("flActions")
self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(909, 10, 101, 641))
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.vlGroups = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.vlGroups.setContentsMargins(0, 0, 0, 0)
self.vlGroups.setObjectName("vlGroups")
self.pushButton_9 = QtWidgets.QPushButton(self.verticalLayoutWidget)
self.pushButton_9.setObjectName("pushButton_9")
self.vlGroups.addWidget(self.pushButton_9)
self.pushButton_8 = QtWidgets.QPushButton(self.verticalLayoutWidget)
self.pushButton_8.setObjectName("pushButton_8")
self.vlGroups.addWidget(self.pushButton_8)
self.mbWidget = QtWidgets.QWidget(self.centralwidget)
self.mbWidget.setGeometry(QtCore.QRect(420, 10, 510, 550))
self.mbWidget.setObjectName("mbWidget")
self.flMainButtons = FlowLayout(self.mbWidget)
self.flMainButtons.setContentsMargins(0, 0, 0, 0)
self.flMainButtons.setObjectName("flMainButtons")
SaleWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(SaleWindow)
self.statusbar.setObjectName("statusbar")
SaleWindow.setStatusBar(self.statusbar)
self.retranslateUi(SaleWindow)
QtCore.QMetaObject.connectSlotsByName(SaleWindow)
def retranslateUi(self, SaleWindow):
_translate = QtCore.QCoreApplication.translate
SaleWindow.setWindowTitle(_translate("SaleWindow", "MainWindow"))
self.pushButton_9.setText(_translate("SaleWindow", "PushButton"))
self.pushButton_8.setText(_translate("SaleWindow", "PushButton"))
def add_action(self, button, title, action):
act = QtWidgets.QPushButton(self.horizontalLayoutWidget)
act.setObjectName(button)
act.clicked.connect(action)
act.setText(title)
self.flActions.addWidget(act)
self.actions[button] = act
def remove_action(self, button):
if button in self.actions:
del self.actions[button]

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaxDetails</class>
<widget class="QDialog" name="TaxDetails">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>397</width>
<height>231</height>
</rect>
</property>
<property name="windowTitle">
<string>Tax 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="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Rate %</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="dsbRate"/>
</item>
<item row="5" 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>dsbRate</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>TaxDetails</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>TaxDetails</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

@ -1,37 +0,0 @@
<?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>

View File

@ -7,8 +7,8 @@ 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
from summer.models.guidtype import GUID
from summer.models import Base
def encrypt(val):

View File

@ -1,10 +1,12 @@
__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
from summer.models import Base
from summer.models.guidtype import GUID
class Product(Base):
@ -30,15 +32,14 @@ class Product(Base):
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,
def __init__(self, name=None, units=None, product_group_id=None, price=None, has_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.has_happy_hour = has_happy_hour
self.service_tax_id = service_tax_id
self.vat_id = vat_id
self.service_charge = service_charge
@ -52,8 +53,8 @@ class Product(Base):
return "{0} ({1})".format(self.name, self.units)
@classmethod
def list(cls, name, active, *, DBSession=None):
query = DBSession.query(cls)
def list(cls, name, active, *, session=None):
query = session.query(cls)
if active is not None:
query = query.filter(cls.is_active != active)
for item in name.split():
@ -61,28 +62,28 @@ class Product(Base):
return query.order_by(cls.name)
@classmethod
def by_name(cls, name, *, DBSession=None):
return DBSession.query(cls).filter(cls.name == name).first()
def by_name(cls, name, *, session=None):
return session.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()
def by_full_name(cls, full_name, *, session=None):
return session.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()
def by_id(cls, id, *, session=None):
return session.query(cls).filter(cls.id == id).first()
@classmethod
def query(cls, *, DBSession=None):
return DBSession.query(cls)
def query(cls, *, session=None):
return session.query(cls)
def create(self, *, DBSession=None):
code = DBSession.query(func.max(Product.code)).one()[0]
def create(self, *, session=None):
code = session.query(func.max(Product.code)).one()[0]
if code is None:
self.code = 1
else:
self.code = code + 1
DBSession.add(self)
session.add(self)
return self
def can_delete(self, advanced_delete):
@ -126,7 +127,7 @@ class ProductGroup(Base):
self.is_fixture = is_fixture
@classmethod
def by_id(cls, id, * , session=None):
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).first()
@ -134,8 +135,8 @@ class ProductGroup(Base):
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'
# if len(self.inventories) > 0 and not advanced_delete:
# return False, 'Product has entries'
return True, ''
@ -156,23 +157,23 @@ class Tax(Base):
self.is_fixture = is_fixture
@classmethod
def by_id(cls, id):
def by_id(cls, id, *, session=None):
if not isinstance(id, uuid.UUID):
id = uuid.UUID(id)
return DBSession.query(cls).filter(cls.id == id).first()
return session.query(cls).filter(cls.id == id).first()
@classmethod
def by_name(cls, name):
return DBSession.query(cls).filter(cls.name == name).first()
def by_name(cls, name, *, session=None):
return session.query(cls).filter(cls.name == name).first()
@classmethod
def list(cls):
return DBSession.query(cls).order_by(cls.name).all()
def list(cls, *, session=None):
return session.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:
# if len(self.inventories) > 0 and not advanced_delete:
# return False, 'Product has entries'
return True, ''
@ -243,7 +244,7 @@ class FoodTable(Base):
return DBSession.query(cls).order_by(cls.name).all()
def can_delete(self, advanced_delete):
#if len(self.inventories) > 0 and not advanced_delete:
# if len(self.inventories) > 0 and not advanced_delete:
# return False, 'Product has entries'
return True, ''
@ -306,7 +307,7 @@ class Modifier(Base):
return DBSession.query(cls).order_by(cls.name).all()
def can_delete(self, advanced_delete):
#if len(self.inventories) > 0 and not advanced_delete:
# if len(self.inventories) > 0 and not advanced_delete:
# return False, 'Product has entries'
return True, ''

View File

@ -1,16 +1,11 @@
import json
__author__ = 'tanshu'
from sqlalchemy.exc import OperationalError, IntegrityError
class ValidationError(Exception):
def __init__(self, header, message, Errors=None):
self.header = header
def __init__(self, message, Errors=None):
self.message = message
# Call the base class constructor with the parameters it needs
Exception.__init__(self, (header, message))
Exception.__init__(self, message)
# Now for your custom code...
self.Errors = Errors
@ -19,22 +14,4 @@ class ValidationError(Exception):
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
return self.message

View File

@ -6,9 +6,9 @@ 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
from summer.models.master import Tax
from summer.models.guidtype import GUID
from summer.models import Base
class VoucherType:

View File

@ -7,15 +7,17 @@ from PyQt5 import uic
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.btnSales.clicked.connect(router.show_sales)
self.btnRoles.clicked.connect(router.show_roles)
self.btnProductGroups.clicked.connect(router.show_product_groups)
self.btnTaxes.clicked.connect(router.show_taxes)
self.btnProducts.clicked.connect(router.show_products)
def handle_exit(self):
self.close()

View File

@ -0,0 +1,108 @@
__author__ = 'tanshu'
from PyQt5 import uic, QtCore
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/ProductDetail.ui'
base, form = uic.loadUiType(file)
class ProductDetail(base, form):
def __init__(self, router, product, product_groups, taxes, parent=None):
super(ProductDetail, self).__init__()
self.setupUi(self)
self.router = router
self.product = product
self.txtName.setText(product['Name'])
self.txtUnits.setText(product['Units'])
self.product_group_model = ProductGroupModel(product_groups)
self.cmbProductGroup.setModel(self.product_group_model)
pg_index = [i for (i, d) in enumerate(product_groups) if
d['ProductGroupID'] == product['ProductGroup']['ProductGroupID']]
if len(pg_index) != 0:
self.cmbProductGroup.setCurrentIndex(pg_index[0])
self.dsbPrice.setMinimum(0)
self.dsbPrice.setValue(product['Price'])
self.chkHasHappyHour.setCheckState(QtCore.Qt.Checked if product['HasHappyHour'] else QtCore.Qt.Unchecked)
self.service_tax_model = TaxModel(taxes)
self.cmbServiceTax.setModel(self.service_tax_model)
st_index = [i for (i, d) in enumerate(taxes) if d['TaxID'] == product['ServiceTax']['TaxID']]
if len(st_index) != 0:
self.cmbServiceTax.setCurrentIndex(st_index[0])
self.vat_model = TaxModel(taxes)
self.cmbVat.setModel(self.vat_model)
vat_index = [i for (i, d) in enumerate(taxes) if d['TaxID'] == product['Vat']['TaxID']]
if len(vat_index) != 0:
self.cmbVat.setCurrentIndex(vat_index[0])
self.dsbServiceCharge.setMinimum(0)
self.dsbServiceCharge.setValue(product['ServiceCharge'])
self.chkScTaxable.setCheckState(QtCore.Qt.Checked if product['ScTaxable'] else QtCore.Qt.Unchecked)
self.chkIsActive.setCheckState(QtCore.Qt.Checked if product['IsActive'] else QtCore.Qt.Unchecked)
self.sbSortOrder.setMinimum(0)
self.sbSortOrder.setValue(product['SortOrder'])
self.accepted.connect(self.save_product)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
def save_product(self):
self.product['Name'] = self.txtName.text()
self.product['Units'] = self.txtUnits.text()
self.product['ProductGroup'] = self.cmbProductGroup.currentData()
self.product['Price'] = self.dsbPrice.value()
self.product['HasHappyHour'] = self.chkHasHappyHour.isChecked()
self.product['ServiceTax'] = self.cmbServiceTax.currentData()
self.product['Vat'] = self.cmbVat.currentData()
self.product['ServiceCharge'] = self.dsbServiceCharge.value() / 100
self.product['ScTaxable'] = self.chkScTaxable.isChecked()
self.product['IsActive'] = self.chkIsActive.isChecked()
self.product['SortOrder'] = self.sbSortOrder.value()
self.router.save_product(self.product)
class ProductGroupModel(QtCore.QAbstractListModel):
def __init__(self, product_groups=None, parent=None):
QtCore.QAbstractListModel.__init__(self, parent)
self.product_groups = product_groups if product_groups is not None else []
def rowCount(self, parent):
return len(self.product_groups)
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
item = self.product_groups[index.row()]
return item['Name']
if role == QtCore.Qt.UserRole:
return self.product_groups[index.row()]
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return 'Product Groups'
else:
return section + 1
class TaxModel(QtCore.QAbstractListModel):
def __init__(self, taxes=None, parent=None):
QtCore.QAbstractListModel.__init__(self, parent)
self.taxes = taxes if taxes is not None else []
def rowCount(self, parent):
return len(self.taxes)
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
item = self.taxes[index.row()]
return item['Name'] + ' ' + '({0:,.2f}%)'.format(item['Rate'] * 100)
if role == QtCore.Qt.UserRole:
return self.taxes[index.row()]
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return 'Taxes'
else:
return section + 1

View File

@ -2,7 +2,7 @@ __author__ = 'tanshu'
from PyQt5 import uic, QtCore, QtWidgets
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/ProductGroupList.ui'
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/ListForm.ui'
base, form = uic.loadUiType(file)
@ -10,19 +10,26 @@ class ProductGroupList(base, form):
def __init__(self, router, product_groups, parent=None):
super(ProductGroupList, self).__init__()
self.setupUi(self)
self.translateUi()
self.router = router
self.product_groups = product_groups
self.model = ProductGroupsTableModel(product_groups)
self.tblProductGroups.setModel(self.model)
self.tblProductGroups.doubleClicked.connect(self.show_product_group)
self.tblItems.setModel(self.model)
self.tblItems.doubleClicked.connect(self.show_product_group)
self.btnAddNew.clicked.connect(self.add_new_product_group)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
self.tblProductGroups.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.tblItems.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
def translateUi(self):
self.setObjectName("ProductGroupList")
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("ListForm", "Product Groups"))
self.btnAddNew.setText(_translate("ListForm", "Add Product Group"))
def update_data(self, data):
self.product_groups = data
self.model = ProductGroupsTableModel(self.product_groups)
self.tblProductGroups.setModel(self.model)
self.tblItems.setModel(self.model)
def show_product_group(self, index):
product_group = self.model.product_groups[index.row()]

View File

@ -0,0 +1,110 @@
__author__ = 'tanshu'
from PyQt5 import uic, QtCore, QtWidgets
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/ListForm.ui'
base, form = uic.loadUiType(file)
class ProductList(base, form):
def __init__(self, router, products, parent=None):
super(ProductList, self).__init__()
self.setupUi(self)
self.translateUi()
self.router = router
self.products = products
self.model = ProductsTableModel(products)
self.tblItems.setModel(self.model)
self.tblItems.doubleClicked.connect(self.show_product)
self.btnAddNew.clicked.connect(self.add_new_product)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
self.tblItems.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
def translateUi(self):
self.setObjectName("ProductList")
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("ListForm", "Products"))
self.btnAddNew.setText(_translate("ListForm", "Add Product"))
def update_data(self, data):
self.products = data
self.model = ProductsTableModel(self.products)
self.tblItems.setModel(self.model)
def show_product(self, index):
product = self.model.products[index.row()]
self.router.show_product(product['ProductID'])
def add_new_product(self):
self.router.show_product(None)
class ProductsTableModel(QtCore.QAbstractTableModel):
def __init__(self, products=None, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.products = products if products is not None else []
def rowCount(self, parent):
return len(self.products)
def columnCount(self, parent):
return 12
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
item = self.products[index.row()]
column = index.column()
if column == 0:
return item['Name']
elif column == 1:
return item['Units']
elif column == 2:
return item['ProductGroup']['Name']
elif column == 3:
return '{0:,.2f}'.format(item['Price'])
elif column == 4:
return item['HasHappyHour']
elif column == 5:
return item['ServiceTax']['Name'] + ' ' + '({0:,.2f}%)'.format(item['ServiceTax']['Rate'] * 100)
elif column == 6:
return item['Vat']['Name'] + ' ' + '({0:,.2f}%)'.format(item['Vat']['Rate'] * 100)
elif column == 7:
return '{0:,.2f}%'.format(item['ServiceCharge'] * 100)
elif column == 8:
return item['ScTaxable']
elif column == 9:
return item['IsActive']
elif column == 10:
return item['IsFixture']
elif column == 11:
return item['SortOrder']
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 'Units'
elif section == 2:
return 'Product Group'
elif section == 3:
return 'Price'
elif section == 4:
return 'Has Happy Hour'
elif section == 5:
return 'Service Tax'
elif section == 6:
return 'Vat'
elif section == 7:
return 'Service Charge'
elif section == 8:
return 'Is Sc Taxable?'
elif section == 9:
return 'Is Active?'
elif section == 10:
return 'Is Fixture?'
elif section == 11:
return 'Sort Order'
else:
return section + 1

View File

@ -2,7 +2,7 @@ __author__ = 'tanshu'
from PyQt5 import uic, QtCore, QtWidgets
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/RoleList.ui'
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/ListForm.ui'
base, form = uic.loadUiType(file)
@ -10,19 +10,26 @@ class RoleList(base, form):
def __init__(self, router, roles, parent=None):
super(RoleList, self).__init__()
self.setupUi(self)
self.translateUi()
self.router = router
self.roles = roles
self.model = RolesTableModel(roles)
self.tblRoles.setModel(self.model)
self.tblRoles.doubleClicked.connect(self.show_role)
self.tblItems.setModel(self.model)
self.tblItems.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)
self.tblItems.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
def translateUi(self):
self.setObjectName("RoleList")
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("ListForm", "Roles"))
self.btnAddNew.setText(_translate("ListForm", "Add Role"))
def update_data(self, data):
self.roles = data
self.model = RolesTableModel(self.roles)
self.tblRoles.setModel(self.model)
self.tblItems.setModel(self.model)
def show_role(self, index):
role = self.model.roles[index.row()]

View File

@ -0,0 +1,83 @@
from PyQt5 import QtCore, QtWidgets
from summer.QtDesignerFiles.SaleWindow import SaleWindowQt
__author__ = 'tanshu'
class SaleWindow(SaleWindowQt, QtWidgets.QMainWindow):
def __init__(self, router, parent=None):
super(SaleWindow, self).__init__()
self.setupUi(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
self.actionButtons = []
self.mainButtons = []
self.fillActionBar()
self.fillMainButtons()
def addButton(self, widget, layout, name, text, connect=None):
button = QtWidgets.QPushButton(widget)
button.setObjectName(name)
button.setText(text)
button.setMinimumSize(75, 75)
button.setMaximumSize(75, 75)
layout.addWidget(button)
if connect is not None:
button.clicked.connect(connect(button))
return button
def addActionButton(self, name, text, connect=None):
button = self.addButton(self.abWidget, self.flActions, name, text, connect)
self.actionButtons.append(button)
def fillActionBar(self):
buttons = [
('quantity', 'Quantity'),
('delete', 'Delete'),
('discount', 'Discount - F3'),
('modifier', 'Modifier'),
('waiter', 'Waiter - F5'),
('print_kot', 'Print KOT - F12'),
('print_bill', 'Print Bill - F11'),
('clear', 'Clear - Esc'),
('settle_bill', 'Settle Bill'),
('rate', 'Rate'),
('move_table', 'Move Table'),
('void_bill', 'Void Bill'),
('move_kot', 'Move KOT'),
('split_bill', 'Split Bill')
]
for name, text in buttons:
self.addActionButton(name, text, self.hide_button)
def addMainButton(self, name, text, connect=None):
button = self.addButton(self.mbWidget, self.flMainButtons, name, text, connect)
self.mainButtons.append(button)
def hide_button(self, button):
def inner():
button.hide()
return inner
def fillMainButtons(self):
buttons = [
('quantity', 'Quantity'),
('delete', 'Delete'),
('discount', 'Discount - F3'),
('modifier', 'Modifier'),
('waiter', 'Waiter - F5'),
('print_kot', 'Print KOT - F12'),
('print_bill', 'Print Bill - F11'),
('clear', 'Clear - Esc'),
('settle_bill', 'Settle Bill'),
('rate', 'Rate'),
('move_table', 'Move Table'),
('void_bill', 'Void Bill'),
('move_kot', 'Move KOT'),
('split_bill', 'Split Bill')
]
for name, text in buttons:
self.addMainButton(name, text, self.hide_button)

View File

@ -0,0 +1,25 @@
__author__ = 'tanshu'
from PyQt5 import uic, QtCore
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/TaxDetail.ui'
base, form = uic.loadUiType(file)
class TaxDetail(base, form):
def __init__(self, router, tax, parent=None):
super(TaxDetail, self).__init__()
self.setupUi(self)
self.router = router
self.tax = tax
self.txtName.setText(tax['Name'])
self.dsbRate.setMinimum(0)
self.dsbRate.setValue(tax['Rate'] * 100)
self.accepted.connect(self.save_tax)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
def save_tax(self):
self.tax['Name'] = self.txtName.text()
self.tax['Rate'] = self.dsbRate.value() / 100
self.router.save_tax(self.tax)

View File

@ -0,0 +1,74 @@
__author__ = 'tanshu'
from PyQt5 import uic, QtCore, QtWidgets
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/ListForm.ui'
base, form = uic.loadUiType(file)
class TaxList(base, form):
def __init__(self, router, taxes, parent=None):
super(TaxList, self).__init__()
self.setupUi(self)
self.translateUi()
self.router = router
self.taxes = taxes
self.model = TaxsTableModel(taxes)
self.tblItems.setModel(self.model)
self.tblItems.doubleClicked.connect(self.show_tax)
self.btnAddNew.clicked.connect(self.add_new_tax)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
self.tblItems.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
def translateUi(self):
self.setObjectName("TaxList")
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("ListForm", "Taxes"))
self.btnAddNew.setText(_translate("ListForm", "Add Tax"))
def update_data(self, data):
self.taxes = data
self.model = TaxsTableModel(self.taxes)
self.tblItems.setModel(self.model)
def show_tax(self, index):
tax = self.model.taxes[index.row()]
self.router.show_tax(tax['TaxID'])
def add_new_tax(self):
self.router.show_tax(None)
class TaxsTableModel(QtCore.QAbstractTableModel):
def __init__(self, taxes=None, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.taxes = taxes if taxes is not None else []
def rowCount(self, parent):
return len(self.taxes)
def columnCount(self, parent):
return 3
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
item = self.taxes[index.row()]
column = index.column()
if column == 0:
return item['Name']
elif column == 1:
return '{0:,.2f}%'.format(item['Rate'] * 100)
elif column == 2:
return item['IsFixture']
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 'Rate'
elif section == 2:
return 'Is Fixture?'
else:
return section + 1

View File

@ -2,7 +2,7 @@ __author__ = 'tanshu'
from PyQt5 import uic, QtCore, QtWidgets
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/UserList.ui'
file = '/home/tanshu/Programming/summer/summer/QtDesignerFiles/ListForm.ui'
base, form = uic.loadUiType(file)
@ -10,19 +10,26 @@ class UserList(base, form):
def __init__(self, router, users, parent=None):
super(UserList, self).__init__()
self.setupUi(self)
self.translateUi()
self.router = router
self.users = users
self.model = UsersTableModel(users)
self.tblUsers.setModel(self.model)
self.tblUsers.doubleClicked.connect(self.show_user)
self.tblItems.setModel(self.model)
self.tblItems.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)
self.tblItems.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
def translateUi(self):
self.setObjectName("UserList")
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("ListForm", "Users"))
self.btnAddNew.setText(_translate("ListForm", "Add User"))
def update_data(self, data):
self.users = data
self.model = UsersTableModel(self.users)
self.tblUsers.setModel(self.model)
self.tblItems.setModel(self.model)
def show_user(self, index):
user = self.model.users[index.row()]

View File

@ -5,3 +5,7 @@ from summer.templates.UserDetail import UserDetail
from summer.templates.UserList import UserList
from summer.templates.ProductGroupList import ProductGroupList
from summer.templates.ProductGroupDetail import ProductGroupDetail
from summer.templates.TaxList import TaxList
from summer.templates.TaxDetail import TaxDetail
from summer.templates.ProductList import ProductList
from summer.templates.ProductDetail import ProductDetail

View File

@ -1,8 +1,12 @@
from summer.templates import RoleDetail, RoleList, UserDetail, UserList, ProductGroupList, ProductGroupDetail
from summer.templates import RoleDetail, RoleList, UserDetail, UserList, ProductGroupList, ProductGroupDetail, TaxList, \
TaxDetail, ProductList, ProductDetail
from summer.templates.SaleWindow import SaleWindow
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
from summer.views.product_group import show_list as product_group_list, product_group_info, save_product_group, \
update_product_group
from summer.views.tax import show_list as tax_list, tax_info, save_tax, update_tax
from summer.views.product import show_list as product_list, product_info, save_product, update_product
__author__ = 'tanshu'
@ -15,6 +19,11 @@ class Router():
self.role_detail_form = None
self.product_group_list_form = None
self.product_group_detail_form = None
self.tax_list_form = None
self.tax_detail_form = None
self.product_list_form = None
self.product_detail_form = None
self.sales_form = None
def show_users(self):
users = user_list()
@ -101,3 +110,73 @@ class Router():
save_product_group(product_group)
else:
update_product_group(product_group)
def show_taxes(self):
taxes = tax_list()
if self.tax_list_form is None:
self.tax_list_form = TaxList(self, taxes)
self.tax_list_form.destroyed.connect(self.tax_list_form_destroyed)
self.tax_list_form.show()
def tax_list_form_destroyed(self):
self.tax_list_form = None
def show_tax(self, id=None):
tax = tax_info(id)
if self.tax_detail_form is None:
self.tax_detail_form = TaxDetail(self, tax)
self.tax_detail_form.destroyed.connect(self.tax_detail_form_destroyed)
self.tax_detail_form.show()
def tax_detail_form_destroyed(self):
self.tax_detail_form = None
if self.tax_list_form is not None:
self.tax_list_form.update_data(tax_list())
def save_tax(self, tax):
if 'TaxID' not in tax:
save_tax(tax)
else:
update_tax(tax)
def show_products(self):
products = product_list()
if self.product_list_form is None:
self.product_list_form = ProductList(self, products)
self.product_list_form.destroyed.connect(self.product_list_form_destroyed)
self.product_list_form.show()
def product_list_form_destroyed(self):
self.product_list_form = None
def show_product(self, id=None):
pass
product = product_info(id)
product_group = product_group_list()
taxes = tax_list()
if self.product_detail_form is None:
self.product_detail_form = ProductDetail(self, product, product_group, taxes)
self.product_detail_form.destroyed.connect(self.product_detail_form_destroyed)
self.product_detail_form.show()
def product_detail_form_destroyed(self):
self.product_detail_form = None
if self.product_list_form is not None:
self.product_list_form.update_data(product_list())
def save_product(self, product):
if 'ProductID' not in product:
save_product(product)
else:
update_product(product)
def show_sales(self):
if self.sales_form is None:
self.sales_form = SaleWindow(self)
self.sales_form.destroyed.connect(self.sales_form_destroyed)
self.sales_form.show()
def sales_form_destroyed(self):
self.sales_form = None

177
summer/views/product.py Normal file
View File

@ -0,0 +1,177 @@
__author__ = 'tanshu'
from decimal import Decimal, InvalidOperation
from summer.models import session_scope
from summer.models.validation_exception import ValidationError
from summer.models.master import Product
def save_product(json):
name = json['Name'].strip()
if name == '':
raise ValidationError('Name cannot be blank')
units = json['Units'].strip()
product_group = json['ProductGroup']
if product_group is None:
raise ValidationError('Please choose a product group')
product_group_id = product_group['ProductGroupID']
try:
price = Decimal(json['Price'])
if price < 0:
raise ValidationError("Price must be a decimal >= 0")
except (ValueError, InvalidOperation):
raise ValidationError("Price must be a decimal >= 0")
has_happy_hour = json['HasHappyHour']
service_tax = json['ServiceTax']
if service_tax is None:
raise ValidationError('Please choose a service tax')
service_tax_id = service_tax['TaxID']
vat = json['Vat']
if vat is None:
raise ValidationError('Please choose vat')
vat_id = vat['TaxID']
try:
service_charge = Decimal(json['ServiceCharge'])
if service_charge < 0:
raise ValidationError("Service Charge must be a decimal >= 0")
except (ValueError, InvalidOperation):
raise ValidationError("Service Charge must be a decimal >= 0")
sc_taxable = json['ScTaxable']
is_active = json['IsActive']
try:
sort_order = Decimal(json['SortOrder'])
if sort_order < 0:
raise ValidationError("Sort Order must be a decimal >= 0")
except (ValueError, InvalidOperation):
raise ValidationError("Sort Order must be a decimal >= 0")
item = Product(name, units, product_group_id, price, has_happy_hour, service_tax_id, vat_id, service_charge,
sc_taxable, is_active, sort_order)
with session_scope() as DBSession:
DBSession.add(item)
return product_info(item.id)
def update_product(json):
with session_scope() as DBSession:
item = Product.by_id(json['ProductID'], session=DBSession)
if item.is_fixture:
raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.full_name))
item.name = json['Name'].strip()
item.units = json['Units'].strip()
item.product_group_id = json['ProductGroup']['ProductGroupID']
try:
item.price = Decimal(json['Price'])
if item.price < 0:
raise ValidationError("Price must be a decimal >= 0")
except (ValueError, InvalidOperation):
raise ValidationError("Price must be a decimal >= 0")
item.has_happy_hour = json['HasHappyHour']
item.service_tax_id = json['ServiceTax']['TaxID']
item.vat_id = json['Vat']['TaxID']
try:
item.service_charge = Decimal(json['ServiceCharge'])
if item.service_charge <= 0:
raise ValidationError("Service Charge must be a decimal > 0")
except (ValueError, InvalidOperation):
raise ValidationError("Service Charge must be a decimal > 0")
item.sc_taxable = json['ScTaxable']
item.is_active = json['IsActive']
try:
item.sort_order = Decimal(json['SortOrder'])
if item.sort_order < 0:
raise ValidationError("Sort Order must be a decimal >= 0")
except (ValueError, InvalidOperation):
raise ValidationError("Sort Order must be a decimal >= 0")
return product_info(item.id)
def delete_product(id):
with session_scope() as DBSession:
item = Product.by_id(id, session=DBSession)
# TODO: Proper advanced delete checking
# 'Advanced Delete'
advance_delete = True
can_delete, reason = item.can_delete(advance_delete)
if can_delete:
delete_with_data(item, DBSession)
return product_info(None)
else:
raise ValidationError("Cannot delete product because {0}".format(reason))
def show_list():
with session_scope() as DBSession:
list = DBSession.query(Product).order_by(Product.sort_order).order_by(Product.name).all()
products = []
for item in list:
products.append({'Name': item.name, 'Units': item.units, 'ProductGroup': {'Name': item.product_group.name},
'Price': item.price, 'HasHappyHour': item.has_happy_hour,
'ServiceTax': {'Name': item.service_tax.name, 'Rate': item.service_tax.rate},
'Vat': {'Name': item.vat.name, 'Rate': item.vat.rate},
'ServiceCharge': item.service_charge, 'ScTaxable': item.sc_taxable,
'IsActive': item.is_active, 'IsFixture': item.is_fixture, 'SortOrder': item.sort_order})
return products
def product_info(id):
with session_scope() as DBSession:
if id is None:
item = {'Name': '', 'Units': '', 'ProductGroup': {'ProductGroupID': None}, 'Price': 0,
'HasHappyHour': False, 'ServiceTax': {'TaxID': None}, 'Vat': {'TaxID': None}, 'ServiceCharge': 0,
'ScTaxable': True, 'IsActive': True, 'IsFixture': False, 'SortOrder': 0}
else:
product = Product.by_id(id, session=DBSession)
item = {'ProductID': product.id, 'Name': product.name, 'Units': product.units,
'ProductGroup': {'ProductGroupID': product.product_group.id, 'Name': product.product_group.name},
'Price': product.price, 'HasHappyHour': product.has_happy_hour,
'ServiceTax': {'TaxID': product.service_tax.id, 'Name': product.service_tax.name,
'Rate': product.service_tax.rate},
'Vat': {'TaxID': product.vat.id, 'Name': product.vat.name, 'Rate': product.vat.rate},
'ServiceCharge': product.service_charge, 'ScTaxable': product.sc_taxable,
'IsActive': product.is_active, 'IsFixture': product.is_fixture, 'SortOrder': product.sort_order}
return item
def delete_with_data(product, *, session=None):
pass
# suspense_product = Product.by_id(Product.suspense(), session=session)
# query = Voucher.query().options(joinedload_all(Voucher.inventories, Inventory.product, innerjoin=True)) \
# .filter(Voucher.inventories.any(Inventory.product_id == product.id)) \
# .all()
#
# for voucher in query:
# others, sus_inv, prod_inv = False, None, None
# for inventory in voucher.inventories:
# if inventory.product_id == product.id:
# prod_inv = inventory
# elif inventory.product_id == Product.suspense():
# sus_inv = inventory
# else:
# others = True
# if not others and voucher.type == VoucherType.by_id('Issue'):
# DBSession.delete(voucher)
# else:
# if sus_inv is None:
# prod_inv.product = suspense_product
# prod_inv.quantity = prod_inv.amount
# prod_inv.rate = 1
# prod_inv.tax = 0
# prod_inv.discount = 0
# prod_inv.batch = suspense_batch
# voucher.narration += '\nSuspense \u20B9{0:,.2f} is {1}'.format(prod_inv.amount, product.name)
# else:
# sus_inv.quantity += prod_inv.amount
# DBSession.delete(prod_inv)
# voucher.narration += '\nDeleted \u20B9{0:,.2f} of {1}'.format(prod_inv.amount, product.name)
# for batch in product.batches:
# DBSession.delete(batch)
# DBSession.delete(product)

59
summer/views/tax.py Normal file
View File

@ -0,0 +1,59 @@
from decimal import Decimal, InvalidOperation
from summer.models import session_scope
from summer.models.validation_exception import ValidationError
__author__ = 'tanshu'
from summer.models.master import Tax
def save_tax(json):
name = json['Name'].strip()
try:
rate = Decimal(json['Rate'])
if rate < 0:
raise ValidationError("Rate must be a decimal >= 0")
except (ValueError, InvalidOperation):
raise ValidationError("Rate must be a decimal >= 0")
item = Tax(name, rate)
with session_scope() as DBSession:
DBSession.add(item)
return tax_info(item.id)
def update_tax(json):
with session_scope() as DBSession:
item = Tax.by_id(json['TaxID'], session=DBSession)
if item.is_fixture:
raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.name))
item.name = json['Name'].strip()
try:
rate = Decimal(json['Rate'])
if rate < 0:
raise ValidationError("Rate must be a decimal >= 0")
except (ValueError, InvalidOperation):
raise ValidationError("Rate must be a decimal >= 0")
item.rate = rate
return tax_info(item.id)
def show_list():
with session_scope() as DBSession:
list = DBSession.query(Tax).order_by(Tax.name)
taxes = []
for item in list:
taxes.append({'TaxID': item.id, 'Name': item.name, 'Rate': item.rate, 'IsFixture': item.is_fixture})
return taxes
def tax_info(id):
with session_scope() as DBSession:
if id is None:
item = {'Name': '', 'Rate': 0, 'IsFixture': False}
else:
tax = Tax.by_id(id, session=DBSession)
return {'TaxID': tax.id, 'Name': tax.name, 'Rate': tax.rate, 'IsFixture': tax.is_fixture}
return item