feat: add basic readonly web views for CORE members, products

also adds canonical web app db sessions for CORE

also adds some methods to corepos handler, to get model / make session
This commit is contained in:
Lance Edgar 2025-01-12 20:04:19 -06:00
parent b134e340ff
commit 05f428586b
22 changed files with 655 additions and 2 deletions

View file

@ -21,7 +21,7 @@
#
################################################################################
"""
CORE-POS Handler
CORE-POS Integration Handler
"""
from wuttjamaican.app import GenericHandler
@ -33,6 +33,72 @@ class CoreposHandler(GenericHandler):
:term:`handler`.
"""
def get_model_office_op(self):
"""
Returns the :term:`data model` module for CORE Office 'op' DB,
i.e. :mod:`pycorepos:corepos.db.office_op.model`.
"""
from corepos.db.office_op import model
return model
def get_model_office_trans(self):
"""
Returns the :term:`data model` module for CORE Office 'trans'
DB, i.e. :mod:`pycorepos:corepos.db.office_trans.model`.
"""
from corepos.db.office_trans import model
return model
def get_model_office_arch(self):
"""
Returns the :term:`data model` module for CORE Office 'arch'
DB, i.e. :mod:`pycorepos:corepos.db.office_arch.model`.
"""
from corepos.db.office_arch import model
return model
def make_session_office_op(self, dbkey='default', **kwargs):
"""
Make a new :term:`db session` for the CORE Office 'op' DB.
:returns: Instance of
:class:`pycorepos:corepos.db.office_op.Session`.
"""
from corepos.db.office_op import Session
if 'bind' not in kwargs:
kwargs['bind'] = self.config.core_office_op_engines[dbkey]
return Session(**kwargs)
def make_session_office_trans(self, dbkey='default', **kwargs):
"""
Make a new :term:`db session` for the CORE Office 'trans' DB.
:returns: Instance of
:class:`pycorepos:corepos.db.office_trans.Session`.
"""
from corepos.db.office_trans import Session
if 'bind' not in kwargs:
kwargs['bind'] = self.config.core_office_trans_engines[dbkey]
return Session(**kwargs)
def make_session_office_arch(self, dbkey='default', **kwargs):
"""
Make a new :term:`db session` for the CORE Office 'arch' DB.
:returns: Instance of
:class:`pycorepos:corepos.db.office_arch.Session`.
"""
from corepos.db.office_arch import Session
if 'bind' not in kwargs:
kwargs['bind'] = self.config.core_office_arch_engines[dbkey]
return Session(**kwargs)
def get_office_url(self, require=False):
"""
Returns the base URL for the CORE Office web app.

View file

@ -0,0 +1,29 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Wutta-COREPOS -- Wutta Framework integration for CORE-POS
# Copyright © 2025 Lance Edgar
#
# This file is part of Wutta Framework.
#
# Wutta Framework 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.
#
# Wutta Framework 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
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Wutta-COREPOS -- wuttaweb features
"""
def includeme(config):
config.include('wutta_corepos.web.views')

View file

@ -0,0 +1,70 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Wutta-COREPOS -- Wutta Framework integration for CORE-POS
# Copyright © 2025 Lance Edgar
#
# This file is part of Wutta Framework.
#
# Wutta Framework 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.
#
# Wutta Framework 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
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Wutta-COREPOS -- wuttaweb DB sessions
See :mod:`wuttaweb:wuttaweb.db.sess` for more info on web app sessions
in general.
.. class:: CoreOpSession
Primary web app :term:`db session` for CORE Office 'op' DB.
.. class:: CoreTransSession
Primary web app :term:`db session` for CORE Office 'trans' DB.
.. class:: CoreArchSession
Primary web app :term:`db session` for CORE Office 'arch' DB.
.. class:: ExtraCoreOpSessions
Dict of secondary CORE Office 'op' DB sessions, if applicable.
.. class:: ExtraCoreTransSessions
Dict of secondary CORE Office 'trans' DB sessions, if applicable.
.. class:: ExtraCoreArchSessions
Dict of secondary CORE Office 'arch' DB sessions, if applicable.
"""
from sqlalchemy.orm import sessionmaker, scoped_session
from zope.sqlalchemy import register
CoreOpSession = scoped_session(sessionmaker())
register(CoreOpSession)
CoreTransSession = scoped_session(sessionmaker())
register(CoreTransSession)
CoreArchSession = scoped_session(sessionmaker())
register(CoreArchSession)
# nb. these start out empty but may be populated on app startup
ExtraCoreOpSessions = {}
ExtraCoreTransSessions = {}
ExtraCoreArchSessions = {}

View file

@ -0,0 +1,29 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Wutta-COREPOS -- Wutta Framework integration for CORE-POS
# Copyright © 2025 Lance Edgar
#
# This file is part of Wutta Framework.
#
# Wutta Framework 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.
#
# Wutta Framework 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
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Wutta-COREPOS -- wuttaweb views
"""
def includeme(config):
config.include('wutta_corepos.web.views.corepos')

View file

@ -0,0 +1,32 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Wutta-COREPOS -- Wutta Framework integration for CORE-POS
# Copyright © 2025 Lance Edgar
#
# This file is part of Wutta Framework.
#
# Wutta Framework 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.
#
# Wutta Framework 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
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Views for CORE-POS
"""
from .master import CoreOpMasterView
def includeme(config):
config.include('wutta_corepos.web.views.corepos.members')
config.include('wutta_corepos.web.views.corepos.products')

View file

@ -0,0 +1,40 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Wutta-COREPOS -- Wutta Framework integration for CORE-POS
# Copyright © 2025 Lance Edgar
#
# This file is part of Wutta Framework.
#
# Wutta Framework 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.
#
# Wutta Framework 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
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
CORE-POS master view base class
"""
from wuttaweb.views import MasterView
from wutta_corepos.web.db import CoreOpSession
class CoreOpMasterView(MasterView):
"""
Base class for master views which use the CORE Office 'op' DB.
"""
Session = CoreOpSession
def __init__(self, request, context=None):
super().__init__(request, context=context)
self.corepos_handler = self.app.get_corepos_handler()

View file

@ -0,0 +1,117 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Wutta-COREPOS -- Wutta Framework integration for CORE-POS
# Copyright © 2025 Lance Edgar
#
# This file is part of Wutta Framework.
#
# Wutta Framework 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.
#
# Wutta Framework 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
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Views for CORE-POS Members
"""
import sqlalchemy as sa
from sqlalchemy import orm
from corepos.db.office_op.model import MemberInfo
from wutta_corepos.web.views.corepos import CoreOpMasterView
class MemberView(CoreOpMasterView):
"""
Master view for
:class:`~pycorepos:corepos.db.office_op.model.MemberInfo`; route
prefix is ``corepos_members``.
Notable URLs provided by this class:
* ``/corepos/members/``
* ``/corepos/members/XXX``
"""
model_class = MemberInfo
model_title = "CORE-POS Member"
route_prefix = 'corepos_members'
url_prefix = '/corepos/members'
# nb. this is just for readonly lookup
creatable = False
editable = False
deletable = False
grid_columns = [
'card_number',
'first_name',
'last_name',
'street',
'city',
'state',
'zip',
'phone',
'email',
]
filter_defaults = {
'card_number': {'active': True, 'verb': 'equal'},
'first_name': {'active': True, 'verb': 'contains'},
'last_name': {'active': True, 'verb': 'contains'},
}
sort_defaults = 'card_number'
def get_query(self, session=None):
""" """
query = super().get_query(session=session)
op_model = self.corepos_handler.get_model_office_op()
query = query.outerjoin(op_model.CustomerClassic,
sa.and_(
op_model.CustomerClassic.card_number == op_model.MemberInfo.card_number,
op_model.CustomerClassic.person_number == 1,
))\
.options(orm.joinedload(op_model.MemberInfo.customers))
return query
def configure_grid(self, g):
""" """
super().configure_grid(g)
op_model = self.corepos_handler.get_model_office_op()
# first_name
g.set_renderer('first_name', self.render_customer_attr)
g.set_sorter('first_name', op_model.CustomerClassic.first_name)
# last_name
g.set_renderer('last_name', self.render_customer_attr)
g.set_sorter('last_name', op_model.CustomerClassic.last_name)
def render_customer_attr(self, member, key, value):
""" """
customer = member.customers[0]
return getattr(customer, key)
def defaults(config, **kwargs):
base = globals()
MemberView = kwargs.get('MemberView', base['MemberView'])
MemberView.defaults(config)
def includeme(config):
defaults(config)

View file

@ -0,0 +1,97 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Wutta-COREPOS -- Wutta Framework integration for CORE-POS
# Copyright © 2025 Lance Edgar
#
# This file is part of Wutta Framework.
#
# Wutta Framework 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.
#
# Wutta Framework 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
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Views for CORE-POS Products
"""
from corepos.db.office_op.model import Product
from wutta_corepos.web.views.corepos import CoreOpMasterView
class ProductView(CoreOpMasterView):
"""
Master view for
:class:`~pycorepos:corepos.db.office_op.model.Product`; route
prefix is ``corepos_products``.
Notable URLs provided by this class:
* ``/corepos/products/``
* ``/corepos/products/XXX``
"""
model_class = Product
model_title = "CORE-POS Product"
route_prefix = 'corepos_products'
url_prefix = '/corepos/products'
# nb. this is just for readonly lookup
creatable = False
editable = False
deletable = False
labels = {
'upc': "UPC",
}
grid_columns = [
'upc',
'brand',
'description',
'size',
'department',
'vendor',
'normal_price',
]
filter_defaults = {
'upc': {'active': True, 'verb': 'contains'},
'brand': {'active': True, 'verb': 'contains'},
'description': {'active': True, 'verb': 'contains'},
}
sort_defaults = 'upc'
def configure_grid(self, g):
""" """
super().configure_grid(g)
# normal_price
g.set_renderer('normal_price', 'currency')
# links
g.set_link('upc')
g.set_link('brand')
g.set_link('description')
g.set_link('size')
def defaults(config, **kwargs):
base = globals()
ProductView = kwargs.get('ProductView', base['ProductView'])
ProductView.defaults(config)
def includeme(config):
defaults(config)