feat: basic CORE customer/product lookup, add CORE menu entries
This commit is contained in:
commit
ce54ca6bd6
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
*.pyc
|
||||||
|
*~
|
||||||
|
.coverage
|
||||||
|
dist/
|
||||||
|
docs/_build/
|
||||||
|
.tox/
|
6
README.md
Normal file
6
README.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
# Sideshow-COREPOS
|
||||||
|
|
||||||
|
This package adds CORE-POS integration for Sideshow.
|
||||||
|
|
||||||
|
Full docs are at https://rattailproject.org/docs/sideshow-corepos/
|
60
pyproject.toml
Normal file
60
pyproject.toml
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "Sideshow-COREPOS"
|
||||||
|
version = "0.0.0"
|
||||||
|
description = "Case/Special Order Tracker for CORE-POS"
|
||||||
|
readme = "README.md"
|
||||||
|
authors = [
|
||||||
|
{name = "Lance Edgar", email = "lance@wuttaproject.org"}
|
||||||
|
]
|
||||||
|
maintainers = [
|
||||||
|
{name = "Lance Edgar", email = "lance@wuttaproject.org"}
|
||||||
|
]
|
||||||
|
classifiers = [
|
||||||
|
"Development Status :: 3 - Alpha",
|
||||||
|
"Environment :: Web Environment",
|
||||||
|
"Framework :: Pyramid",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
|
||||||
|
"Natural Language :: English",
|
||||||
|
"Programming Language :: Python",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
]
|
||||||
|
license = {text = "GNU General Public License v3+"}
|
||||||
|
requires-python = ">= 3.8"
|
||||||
|
dependencies = [
|
||||||
|
"Sideshow",
|
||||||
|
"Wutta-COREPOS[web]",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
docs = ["Sphinx", "furo"]
|
||||||
|
tests = ["pytest-cov", "tox"]
|
||||||
|
|
||||||
|
|
||||||
|
[project.entry-points."paste.app_factory"]
|
||||||
|
"main" = "sideshow_corepos.web.app:main"
|
||||||
|
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://wuttaproject.org/"
|
||||||
|
Repository = "https://forgejo.wuttaproject.org/wutta/sideshow-corepos"
|
||||||
|
Issues = "https://forgejo.wuttaproject.org/wutta/sideshow-corepos/issues"
|
||||||
|
Changelog = "https://forgejo.wuttaproject.org/wutta/sideshow-corepos/src/branch/master/CHANGELOG.md"
|
||||||
|
|
||||||
|
|
||||||
|
[tool.commitizen]
|
||||||
|
version_provider = "pep621"
|
||||||
|
tag_format = "v$version"
|
||||||
|
update_changelog_on_bump = true
|
||||||
|
|
||||||
|
[tool.hatch.build.targets.wheel]
|
||||||
|
packages = ["src/sideshow_corepos"]
|
25
src/sideshow_corepos/__init__.py
Normal file
25
src/sideshow_corepos/__init__.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Sideshow-COREPOS -- Case/Special Order Tracker for CORE-POS
|
||||||
|
# Copyright © 2025 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Sideshow.
|
||||||
|
#
|
||||||
|
# Sideshow 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.
|
||||||
|
#
|
||||||
|
# Sideshow 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 Sideshow. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Sideshow-COREPOS - Case/Special Order Tracker for CORE-POS
|
||||||
|
"""
|
0
src/sideshow_corepos/batch/__init__.py
Normal file
0
src/sideshow_corepos/batch/__init__.py
Normal file
220
src/sideshow_corepos/batch/neworder.py
Normal file
220
src/sideshow_corepos/batch/neworder.py
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Sideshow-COREPOS -- Case/Special Order Tracker for CORE-POS
|
||||||
|
# Copyright © 2025 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Sideshow.
|
||||||
|
#
|
||||||
|
# Sideshow 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.
|
||||||
|
#
|
||||||
|
# Sideshow 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 Sideshow. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
New Order Batch Handler for CORE-POS
|
||||||
|
"""
|
||||||
|
|
||||||
|
import decimal
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import orm
|
||||||
|
|
||||||
|
from sideshow.batch import neworder as base
|
||||||
|
|
||||||
|
|
||||||
|
class NewOrderBatchHandler(base.NewOrderBatchHandler):
|
||||||
|
"""
|
||||||
|
Custom batch handler which can use CORE-POS as external data
|
||||||
|
source for customers and products.
|
||||||
|
|
||||||
|
See parent class
|
||||||
|
:class:`~sideshow:sideshow.batch.neworder.NewOrderBatchHandler`
|
||||||
|
for more info.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def autocomplete_customers_external(self, session, term, user=None):
|
||||||
|
""" """
|
||||||
|
corepos = self.app.get_corepos_handler()
|
||||||
|
op_model = corepos.get_model_office_op()
|
||||||
|
op_session = corepos.make_session_office_op()
|
||||||
|
|
||||||
|
# base query
|
||||||
|
query = op_session.query(op_model.CustomerClassic)\
|
||||||
|
.join(op_model.MemberInfo,
|
||||||
|
op_model.MemberInfo.card_number == op_model.CustomerClassic.card_number)
|
||||||
|
|
||||||
|
# filter query
|
||||||
|
criteria = []
|
||||||
|
for word in term.split():
|
||||||
|
criteria.append(sa.or_(
|
||||||
|
op_model.CustomerClassic.first_name.ilike(f'%{word}%'),
|
||||||
|
op_model.CustomerClassic.last_name.ilike(f'%{word}%')))
|
||||||
|
query = query.filter(sa.and_(*criteria))
|
||||||
|
|
||||||
|
# sort query
|
||||||
|
query = query.order_by(op_model.CustomerClassic.first_name,
|
||||||
|
op_model.CustomerClassic.last_name)
|
||||||
|
|
||||||
|
# get data
|
||||||
|
# TODO: need max_results option
|
||||||
|
customers = query.all()
|
||||||
|
|
||||||
|
# get results
|
||||||
|
def result(customer):
|
||||||
|
return {'value': str(customer.card_number),
|
||||||
|
'label': str(customer)}
|
||||||
|
results = [result(c) for c in customers]
|
||||||
|
|
||||||
|
op_session.close()
|
||||||
|
return results
|
||||||
|
|
||||||
|
def refresh_batch_from_external_customer(self, batch):
|
||||||
|
""" """
|
||||||
|
corepos = self.app.get_corepos_handler()
|
||||||
|
op_model = corepos.get_model_office_op()
|
||||||
|
op_session = corepos.make_session_office_op()
|
||||||
|
|
||||||
|
if not batch.customer_id.isdigit():
|
||||||
|
raise ValueError(f"invalid CORE-POS customer card number: {batch.customer_id}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
customer = op_session.query(op_model.CustomerClassic)\
|
||||||
|
.join(op_model.MemberInfo,
|
||||||
|
op_model.MemberInfo.card_number == op_model.CustomerClassic.card_number)\
|
||||||
|
.filter(op_model.CustomerClassic.card_number == int(batch.customer_id))\
|
||||||
|
.filter(op_model.CustomerClassic.person_number == 1)\
|
||||||
|
.options(orm.joinedload(op_model.CustomerClassic.member_info))\
|
||||||
|
.one()
|
||||||
|
except orm.exc.NoResultFound:
|
||||||
|
raise ValueError(f"CORE-POS Customer not found: {customer_id}")
|
||||||
|
|
||||||
|
batch.customer_name = str(customer)
|
||||||
|
batch.phone_number = customer.member_info.phone
|
||||||
|
batch.email_address = customer.member_info.email
|
||||||
|
|
||||||
|
op_session.close()
|
||||||
|
|
||||||
|
def autocomplete_products_external(self, session, term, user=None):
|
||||||
|
""" """
|
||||||
|
corepos = self.app.get_corepos_handler()
|
||||||
|
op_model = corepos.get_model_office_op()
|
||||||
|
op_session = corepos.make_session_office_op()
|
||||||
|
|
||||||
|
# base query
|
||||||
|
query = op_session.query(op_model.Product)
|
||||||
|
|
||||||
|
# filter query
|
||||||
|
criteria = []
|
||||||
|
for word in term.split():
|
||||||
|
criteria.append(sa.or_(
|
||||||
|
op_model.Product.brand.ilike(f'%{word}%'),
|
||||||
|
op_model.Product.description.ilike(f'%{word}%')))
|
||||||
|
query = query.filter(sa.and_(*criteria))
|
||||||
|
|
||||||
|
# sort query
|
||||||
|
query = query.order_by(op_model.Product.brand,
|
||||||
|
op_model.Product.description)
|
||||||
|
|
||||||
|
# get data
|
||||||
|
# TODO: need max_results option
|
||||||
|
products = query.all()
|
||||||
|
|
||||||
|
# get results
|
||||||
|
def result(product):
|
||||||
|
return {'value': product.upc,
|
||||||
|
'label': product.formatted_name}
|
||||||
|
results = [result(c) for c in products]
|
||||||
|
|
||||||
|
op_session.close()
|
||||||
|
return results
|
||||||
|
|
||||||
|
def get_product_info_external(self, session, product_id, user=None):
|
||||||
|
"""
|
||||||
|
Returns basic info for an :term:`external product` as pertains
|
||||||
|
to ordering.
|
||||||
|
|
||||||
|
There is no default logic here; subclass must implement.
|
||||||
|
"""
|
||||||
|
corepos = self.app.get_corepos_handler()
|
||||||
|
op_model = corepos.get_model_office_op()
|
||||||
|
op_session = corepos.make_session_office_op()
|
||||||
|
|
||||||
|
try:
|
||||||
|
product = op_session.query(op_model.Product)\
|
||||||
|
.filter(op_model.Product.upc == product_id)\
|
||||||
|
.one()
|
||||||
|
except orm.exc.NoResultFound:
|
||||||
|
raise ValueError(f"CORE-POS Product not found: {product_id}")
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'product_id': product.upc,
|
||||||
|
'scancode': product.upc,
|
||||||
|
'brand_name': product.brand,
|
||||||
|
'description': product.description,
|
||||||
|
'size': product.size,
|
||||||
|
# 'full_description': product.formatted_name,
|
||||||
|
'full_description': self.app.make_full_name(product.brand,
|
||||||
|
product.description,
|
||||||
|
product.size),
|
||||||
|
'weighed': product.scale,
|
||||||
|
'special_order': False,
|
||||||
|
'department_id': product.department_number,
|
||||||
|
'department_name': product.department.name if product.department else None,
|
||||||
|
'case_size': self.get_case_size_for_external_product(product),
|
||||||
|
'unit_price_reg': self.get_unit_price_reg_for_external_product(product),
|
||||||
|
# TODO
|
||||||
|
# 'vendor_name': product.vendor_name,
|
||||||
|
# 'vendor_item_code': product.vendor_item_code,
|
||||||
|
}
|
||||||
|
|
||||||
|
op_session.close()
|
||||||
|
return data
|
||||||
|
|
||||||
|
def refresh_row_from_external_product(self, row):
|
||||||
|
""" """
|
||||||
|
corepos = self.app.get_corepos_handler()
|
||||||
|
op_model = corepos.get_model_office_op()
|
||||||
|
op_session = corepos.make_session_office_op()
|
||||||
|
|
||||||
|
try:
|
||||||
|
product = op_session.query(op_model.Product)\
|
||||||
|
.filter(op_model.Product.upc == row.product_id)\
|
||||||
|
.one()
|
||||||
|
except orm.exc.NoResultFound:
|
||||||
|
raise ValueError(f"CORE-POS Product not found: {row.product_id}")
|
||||||
|
|
||||||
|
row.product_scancode = product.upc
|
||||||
|
row.product_brand = product.brand
|
||||||
|
row.product_description = product.description
|
||||||
|
row.product_size = product.size
|
||||||
|
row.product_weighed = product.scale
|
||||||
|
row.department_id = product.department_number
|
||||||
|
row.department_name = product.department.name if product.department else None
|
||||||
|
row.special_order = False
|
||||||
|
row.case_size = self.get_case_size_for_external_product(product)
|
||||||
|
row.unit_cost = product.cost
|
||||||
|
row.unit_price_reg = self.get_unit_price_reg_for_external_product(product)
|
||||||
|
|
||||||
|
op_session.close()
|
||||||
|
|
||||||
|
def get_case_size_for_external_product(self, product):
|
||||||
|
""" """
|
||||||
|
if product.vendor_items:
|
||||||
|
item = product.vendor_items[0]
|
||||||
|
if item.units is not None:
|
||||||
|
return decimal.Decimal(f'{item.units:0.4f}')
|
||||||
|
|
||||||
|
def get_unit_price_reg_for_external_product(self, product):
|
||||||
|
""" """
|
||||||
|
if product.normal_price is not None:
|
||||||
|
return decimal.Decimal(f'{product.normal_price:0.3f}')
|
29
src/sideshow_corepos/web/__init__.py
Normal file
29
src/sideshow_corepos/web/__init__.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Sideshow-COREPOS -- Case/Special Order Tracker for CORE-POS
|
||||||
|
# Copyright © 2025 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Sideshow.
|
||||||
|
#
|
||||||
|
# Sideshow 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.
|
||||||
|
#
|
||||||
|
# Sideshow 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 Sideshow. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Sideshow-COREPOS - Case/Special Order Tracker for CORE-POS
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
config.include('sideshow_corepos.web.views')
|
68
src/sideshow_corepos/web/app.py
Normal file
68
src/sideshow_corepos/web/app.py
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Sideshow-COREPOS -- Case/Special Order Tracker for CORE-POS
|
||||||
|
# Copyright © 2025 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Sideshow.
|
||||||
|
#
|
||||||
|
# Sideshow 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.
|
||||||
|
#
|
||||||
|
# Sideshow 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 Sideshow. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Sideshow-COREPOS web app
|
||||||
|
"""
|
||||||
|
|
||||||
|
from wuttaweb import app as base
|
||||||
|
|
||||||
|
from wutta_corepos.web.db import CoreOpSession
|
||||||
|
|
||||||
|
|
||||||
|
def main(global_config, **settings):
|
||||||
|
"""
|
||||||
|
Make and return the WSGI app (Paste entry point).
|
||||||
|
"""
|
||||||
|
# prefer Sideshow templates over wuttaweb
|
||||||
|
settings.setdefault('mako.directories', [
|
||||||
|
# 'sideshow_corepos.web:templates',
|
||||||
|
'sideshow.web:templates',
|
||||||
|
'wuttaweb:templates',
|
||||||
|
])
|
||||||
|
|
||||||
|
# make config objects
|
||||||
|
wutta_config = base.make_wutta_config(settings)
|
||||||
|
pyramid_config = base.make_pyramid_config(settings)
|
||||||
|
|
||||||
|
# configure DB sessions
|
||||||
|
CoreOpSession.configure(bind=wutta_config.core_office_op_engine)
|
||||||
|
|
||||||
|
# bring in the rest of Sideshow
|
||||||
|
pyramid_config.include('sideshow.web')
|
||||||
|
pyramid_config.include('sideshow_corepos.web')
|
||||||
|
|
||||||
|
return pyramid_config.make_wsgi_app()
|
||||||
|
|
||||||
|
|
||||||
|
def make_wsgi_app():
|
||||||
|
"""
|
||||||
|
Make and return the WSGI app (generic entry point).
|
||||||
|
"""
|
||||||
|
return base.make_wsgi_app(main)
|
||||||
|
|
||||||
|
|
||||||
|
def make_asgi_app():
|
||||||
|
"""
|
||||||
|
Make and return the ASGI app.
|
||||||
|
"""
|
||||||
|
return base.make_asgi_app(main)
|
67
src/sideshow_corepos/web/menus.py
Normal file
67
src/sideshow_corepos/web/menus.py
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Sideshow-COREPOS -- Case/Special Order Tracker for CORE-POS
|
||||||
|
# Copyright © 2025 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Sideshow.
|
||||||
|
#
|
||||||
|
# Sideshow 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.
|
||||||
|
#
|
||||||
|
# Sideshow 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 Sideshow. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Sideshow-COREPOS - custom menus
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sideshow.web import menus as base
|
||||||
|
|
||||||
|
|
||||||
|
class SideshowMenuHandler(base.SideshowMenuHandler):
|
||||||
|
"""
|
||||||
|
Custom menu handler for Sideshow, which adds CORE-POS entries.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def make_customers_menu(self, request, **kwargs):
|
||||||
|
"""
|
||||||
|
This adds the entry for CORE-POS Members..
|
||||||
|
"""
|
||||||
|
menu = super().make_customers_menu(request, **kwargs)
|
||||||
|
|
||||||
|
menu['items'].extend([
|
||||||
|
{'type': 'sep'},
|
||||||
|
{
|
||||||
|
'title': "CORE-POS Members",
|
||||||
|
'route': 'corepos_members',
|
||||||
|
'perm': 'corepos_members.list',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
return menu
|
||||||
|
|
||||||
|
def make_products_menu(self, request, **kwargs):
|
||||||
|
"""
|
||||||
|
This adds the entry for CORE-POS Products..
|
||||||
|
"""
|
||||||
|
menu = super().make_products_menu(request, **kwargs)
|
||||||
|
|
||||||
|
menu['items'].extend([
|
||||||
|
{'type': 'sep'},
|
||||||
|
{
|
||||||
|
'title': "CORE-POS Products",
|
||||||
|
'route': 'corepos_products',
|
||||||
|
'perm': 'corepos_products.list',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
return menu
|
32
src/sideshow_corepos/web/views.py
Normal file
32
src/sideshow_corepos/web/views.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Sideshow-COREPOS -- Case/Special Order Tracker for CORE-POS
|
||||||
|
# Copyright © 2025 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Sideshow.
|
||||||
|
#
|
||||||
|
# Sideshow 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.
|
||||||
|
#
|
||||||
|
# Sideshow 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 Sideshow. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Sideshow-COREPOS - custom views
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
|
||||||
|
# CORE-POS views
|
||||||
|
config.include('wutta_corepos.web.views.corepos.members')
|
||||||
|
config.include('wutta_corepos.web.views.corepos.products')
|
28
tasks.py
Normal file
28
tasks.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
"""
|
||||||
|
Tasks for Sideshow-COREPOS
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from invoke import task
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def release(c, skip_tests=False):
|
||||||
|
"""
|
||||||
|
Release a new version of Sideshow-COREPOS
|
||||||
|
"""
|
||||||
|
if not skip_tests:
|
||||||
|
c.run('pytest')
|
||||||
|
|
||||||
|
# rebuild pkg
|
||||||
|
if os.path.exists('dist'):
|
||||||
|
shutil.rmtree('dist')
|
||||||
|
if os.path.exists('Sideshow_COREPOS.egg-info'):
|
||||||
|
shutil.rmtree('Sideshow_COREPOS.egg-info')
|
||||||
|
c.run('python -m build --sdist')
|
||||||
|
|
||||||
|
# upload
|
||||||
|
c.run('twine upload dist/*')
|
17
tox.ini
Normal file
17
tox.ini
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
[tox]
|
||||||
|
envlist = py38, py39, py310, py311
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
extras = tests
|
||||||
|
commands = pytest {posargs}
|
||||||
|
|
||||||
|
[testenv:coverage]
|
||||||
|
basepython = python3.11
|
||||||
|
commands = pytest --cov=sideshow_corepos --cov-report=html --cov-fail-under=100
|
||||||
|
|
||||||
|
[testenv:docs]
|
||||||
|
basepython = python3.11
|
||||||
|
extras = docs
|
||||||
|
changedir = docs
|
||||||
|
commands = sphinx-build -b html -d {envtmpdir}/doctrees -W -T . {envtmpdir}/docs
|
Loading…
Reference in a new issue