# -*- coding: utf-8; -*- ################################################################################ # # pyCOREPOS -- Python Interface to CORE POS # Copyright © 2018 Lance Edgar # # This file is part of pyCOREPOS. # # pyCOREPOS is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) # any later version. # # pyCOREPOS is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # pyCOREPOS. If not, see . # ################################################################################ """ CORE POS Data Model """ from __future__ import unicode_literals, absolute_import import six import sqlalchemy as sa from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship from sqlalchemy.ext.associationproxy import association_proxy Base = declarative_base() @six.python_2_unicode_compatible class Department(Base): """ Represents a department within the organization. """ __tablename__ = 'departments' dept_no = sa.Column(sa.SmallInteger(), primary_key=True, autoincrement=False, nullable=False) dept_name = sa.Column(sa.String(length=30), nullable=True) dept_tax = sa.Column(sa.Boolean(), nullable=True) dept_fs = sa.Column(sa.Boolean(), nullable=True) dept_limit = sa.Column(sa.Float(), nullable=True) dept_minimum = sa.Column(sa.Float(), nullable=True) dept_discount = sa.Column(sa.Boolean(), nullable=True) dept_see_id = sa.Column(sa.Boolean(), nullable=True) modified = sa.Column(sa.DateTime(), nullable=True) modifiedby = sa.Column(sa.Integer(), nullable=True) margin = sa.Column(sa.Float(), nullable=False, default=0) salesCode = sa.Column(sa.Integer(), nullable=False, default=0) memberOnly = sa.Column(sa.SmallInteger(), nullable=False, default=0) def __str__(self): return self.dept_name or '' @six.python_2_unicode_compatible class Subdepartment(Base): """ Represents a subdepartment within the organization. """ __tablename__ = 'subdepts' __table_args__ = ( sa.ForeignKeyConstraint(['dept_ID'], ['departments.dept_no']), ) subdept_no = sa.Column(sa.SmallInteger(), primary_key=True, autoincrement=False, nullable=False) subdept_name = sa.Column(sa.String(length=30), nullable=True) dept_ID = sa.Column(sa.SmallInteger(), nullable=True) department = relationship( Department, doc=""" Reference to the parent :class:`Department` for this subdepartment. """) def __str__(self): return self.subdept_name or '' @six.python_2_unicode_compatible class Vendor(Base): """ Represents a vendor from which product may be purchased. """ __tablename__ = 'vendors' vendorID = sa.Column(sa.Integer(), primary_key=True, autoincrement=False, nullable=False) vendorName = sa.Column(sa.String(length=50), nullable=True) vendorAbbreviation = sa.Column(sa.String(length=10), nullable=True) discountRate = sa.Column(sa.Float(), nullable=True) contact = relationship( 'VendorContact', uselist=False, doc=""" Reference to the :class:`VendorContact` instance for this vendor. """) phone = association_proxy( 'contact', 'phone', creator=lambda p: VendorContact(phone=p)) fax = association_proxy( 'contact', 'fax', creator=lambda f: VendorContact(fax=f)) email = association_proxy( 'contact', 'email', creator=lambda e: VendorContact(email=e)) website = association_proxy( 'contact', 'website', creator=lambda w: VendorContact(website=w)) notes = association_proxy( 'contact', 'notes', creator=lambda n: VendorContact(notes=n)) def __str__(self): return self.vendorName or '' class VendorContact(Base): """ A general contact record for a vendor. """ __tablename__ = 'vendorContact' vendorID = sa.Column(sa.Integer(), sa.ForeignKey('vendors.vendorID'), primary_key=True, autoincrement=False, nullable=False) phone = sa.Column(sa.String(length=15), nullable=True) fax = sa.Column(sa.String(length=15), nullable=True) email = sa.Column(sa.String(length=50), nullable=True) website = sa.Column(sa.String(length=100), nullable=True) notes = sa.Column(sa.Text(), nullable=True) @six.python_2_unicode_compatible class Product(Base): """ Represents a product, purchased and/or sold by the organization. """ __tablename__ = 'products' __table_args__ = ( sa.ForeignKeyConstraint(['department'], ['departments.dept_no']), ) id = sa.Column(sa.Integer(), primary_key=True, autoincrement=True, nullable=False) upc = sa.Column(sa.String(length=13), nullable=True) description = sa.Column(sa.String(length=30), nullable=True) brand = sa.Column(sa.String(length=30), nullable=True) formatted_name = sa.Column(sa.String(length=30), nullable=True) normal_price = sa.Column(sa.Float(), nullable=True) pricemethod = sa.Column(sa.SmallInteger(), nullable=True) groupprice = sa.Column(sa.Float(), nullable=True) quantity = sa.Column(sa.SmallInteger(), nullable=True) special_price = sa.Column(sa.Float(), nullable=True) specialpricemethod = sa.Column(sa.SmallInteger(), nullable=True) specialgroupprice = sa.Column(sa.Float(), nullable=True) specialquantity = sa.Column(sa.SmallInteger(), nullable=True) start_date = sa.Column(sa.DateTime(), nullable=True) end_date = sa.Column(sa.DateTime(), nullable=True) dept_no = sa.Column('department', sa.SmallInteger(), nullable=True) size = sa.Column(sa.String(length=9), nullable=True) tax = sa.Column(sa.SmallInteger(), nullable=True) foodstamp = sa.Column(sa.Boolean(), nullable=True) scale = sa.Column(sa.Boolean(), nullable=True) scaleprice = sa.Column(sa.Boolean(), nullable=True, default=False) mixmatchcode = sa.Column(sa.String(length=13), nullable=True) modified = sa.Column(sa.DateTime(), nullable=True) # advertised = sa.Column(sa.Boolean(), nullable=True) tareweight = sa.Column(sa.Float(), nullable=True) discount = sa.Column(sa.SmallInteger(), nullable=True) discounttype = sa.Column(sa.SmallInteger(), nullable=True) line_item_discountable = sa.Column(sa.Boolean(), nullable=True) unitofmeasure = sa.Column(sa.String(length=15), nullable=True) wicable = sa.Column(sa.SmallInteger(), nullable=True) qttyEnforced = sa.Column(sa.Boolean(), nullable=True) idEnforced = sa.Column(sa.Boolean(), nullable=True) cost = sa.Column(sa.Float(), nullable=True, default=0) inUse = sa.Column(sa.Boolean(), nullable=True) numflag = sa.Column(sa.Integer(), nullable=True, default=0) subdept = sa.Column(sa.SmallInteger(), nullable=True) deposit = sa.Column(sa.Float(), nullable=True) local = sa.Column(sa.Integer(), nullable=True, default=0) store_id = sa.Column(sa.SmallInteger(), nullable=True, default=0) default_vendor_id = sa.Column(sa.Integer(), nullable=True, default=0) current_origin_id = sa.Column(sa.Integer(), nullable=True, default=0) department = relationship( Department, primaryjoin=Department.dept_no == dept_no, foreign_keys=[dept_no], doc=""" Reference to the :class:`Department` to which the product belongs. """) vendor = relationship( Vendor, primaryjoin=Vendor.vendorID == default_vendor_id, foreign_keys=[default_vendor_id], doc=""" Reference to the default :class:`Vendor` from which the product is obtained. """) @property def full_description(self): fields = ['brand', 'description', 'size'] fields = [getattr(self, f) or '' for f in fields] fields = filter(bool, fields) return ' '.join(fields) def __str__(self): return self.description or '' class Employee(Base): """ Represents an employee within the organization. """ __tablename__ = 'employees' emp_no = sa.Column(sa.SmallInteger(), primary_key=True, autoincrement=False, nullable=False) CashierPassword = sa.Column(sa.String(length=50), nullable=True) AdminPassword = sa.Column(sa.String(length=50), nullable=True) FirstName = sa.Column(sa.String(length=255), nullable=True) LastName = sa.Column(sa.String(length=255), nullable=True) JobTitle = sa.Column(sa.String(length=255), nullable=True) EmpActive = sa.Column(sa.Boolean(), nullable=True) frontendsecurity = sa.Column(sa.SmallInteger(), nullable=True) backendsecurity = sa.Column(sa.SmallInteger(), nullable=True) birthdate = sa.Column(sa.DateTime(), nullable=True) @six.python_2_unicode_compatible class MemberType(Base): """ Represents a type of membership within the organization. """ __tablename__ = 'memtype' memtype = sa.Column(sa.SmallInteger(), primary_key=True, nullable=False, default=0) memDesc = sa.Column(sa.String(length=20), nullable=True) custdataType = sa.Column(sa.String(length=10), nullable=True) discount = sa.Column(sa.SmallInteger(), nullable=True) staff = sa.Column(sa.Boolean(), nullable=True) ssi = sa.Column(sa.Boolean(), nullable=True) salesCode = sa.Column(sa.Integer(), nullable=True) def __str__(self): return self.memDesc or "" class Customer(Base): """ Represents a customer of the organization. """ __tablename__ = 'custdata' id = sa.Column(sa.Integer(), primary_key=True, autoincrement=True, nullable=False) CardNo = sa.Column(sa.Integer(), nullable=True) personNum = sa.Column(sa.SmallInteger(), nullable=False, default=1) FirstName = sa.Column(sa.String(length=30), nullable=True) LastName = sa.Column(sa.String(length=30), nullable=True) CashBack = sa.Column(sa.Float(), nullable=False, default=60) Balance = sa.Column(sa.Float(), nullable=False, default=0) Discount = sa.Column(sa.SmallInteger(), nullable=True) MemDiscountLimit = sa.Column(sa.Float(), nullable=False, default=0) ChargeLimit = sa.Column(sa.Float(), nullable=False, default=0) ChargeOk = sa.Column(sa.Boolean(), nullable=False, default=False) WriteChecks = sa.Column(sa.Boolean(), nullable=False, default=True) StoreCoupons = sa.Column(sa.Boolean(), nullable=False, default=True) Type = sa.Column(sa.String(length=10), nullable=False, default='pc') memType = sa.Column(sa.SmallInteger(), nullable=True) staff = sa.Column(sa.Boolean(), nullable=False, default=False) SSI = sa.Column(sa.Boolean(), nullable=False, default=False) Purchases = sa.Column(sa.Float(), nullable=False, default=0) NumberOfChecks = sa.Column(sa.SmallInteger(), nullable=False, default=0) memCoupons = sa.Column(sa.Integer(), nullable=False, default=1) blueLine = sa.Column(sa.String(length=50), nullable=True) Shown = sa.Column(sa.Boolean(), nullable=False, default=True) LastChange = sa.Column(sa.DateTime(), nullable=False) member_type = relationship( MemberType, primaryjoin=MemberType.memtype == memType, foreign_keys=[memType], doc=""" Reference to the :class:`MemberType` to which this member belongs. """) member_info = relationship( 'MemberInfo', primaryjoin='MemberInfo.card_no == Customer.CardNo', foreign_keys=[CardNo], uselist=False, back_populates='customers', doc=""" Reference to the :class:`MemberInfo` instance for this customer. """) class MemberInfo(Base): """ Contact info regarding a member of the organization. """ __tablename__ = 'meminfo' card_no = sa.Column(sa.Integer(), primary_key=True, autoincrement=False, nullable=False) last_name = sa.Column(sa.String(length=30), nullable=True) first_name = sa.Column(sa.String(length=30), nullable=True) othlast_name = sa.Column(sa.String(length=30), nullable=True) othfirst_name = sa.Column(sa.String(length=30), nullable=True) street = sa.Column(sa.String(length=255), nullable=True) city = sa.Column(sa.String(length=20), nullable=True) state = sa.Column(sa.String(length=2), nullable=True) zip = sa.Column(sa.String(length=10), nullable=True) phone = sa.Column(sa.String(length=30), nullable=True) email_1 = sa.Column(sa.String(length=50), nullable=True) email_2 = sa.Column(sa.String(length=50), nullable=True) ads_OK = sa.Column(sa.Boolean(), nullable=True, default=True) customers = relationship( Customer, primaryjoin=Customer.CardNo == card_no, foreign_keys=[Customer.CardNo], back_populates='member_info', remote_side=Customer.CardNo, doc=""" List of :class:`Customer` instances which are associated with this member info. """) @property def full_name(self): return '{0} {1}'.format(self.first_name or '', self.last_name or '').strip() def __unicode__(self): return self.full_name