diff --git a/.gitignore b/.gitignore
index 5d6335c..7893476 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
+*~
+*.pyc
+dist/
tailbone_woocommerce.egg-info/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 220b0d8..fa1effb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to tailbone-woocommerce will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## v0.2.0 (2024-06-11)
+
+### Feat
+
+- switch from setup.cfg to pyproject.toml + hatchling
+
## [0.1.0] - 2021-01-21
### Changed
- Initial release.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..873af83
--- /dev/null
+++ b/README.md
@@ -0,0 +1,11 @@
+
+# tailbone-woocommerce
+
+Rattail is a retail software framework, released under the GNU General
+Public License.
+
+This package contains software interfaces for the
+[WooCommerce](https://woocommerce.com/) system.
+
+Please see the [Rattail Project](https://rattailproject.org/) for more
+information.
diff --git a/README.rst b/README.rst
deleted file mode 100644
index d768e06..0000000
--- a/README.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-
-tailbone-woocommerce
-====================
-
-Rattail is a retail software framework, released under the GNU General Public
-License.
-
-This package contains software interfaces for the `WooCommerce`_ system.
-
-.. _WooCommerce: https://woocommerce.com/
-
-Please see the `Rattail Project`_ for more information.
-
-.. _`Rattail Project`: https://rattailproject.org/
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..100dd71
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,42 @@
+
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+
+[project]
+name = "tailbone-woocommerce"
+version = "0.2.0"
+description = "Tailbone integration for WooCommerce"
+readme = "README.md"
+authors = [{name = "Lance Edgar", email = "lance@edbob.org"}]
+license = {text = "GNU GPL v3+"}
+classifiers = [
+ "Development Status :: 4 - Beta",
+ "Environment :: Web Environment",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
+ "Natural Language :: English",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ "Topic :: Office/Business",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+]
+dependencies = [
+ "rattail",
+ "rattail-woocommerce",
+ "Tailbone",
+]
+
+
+[project.urls]
+Homepage = "https://rattailproject.org"
+Repository = "https://kallithea.rattailproject.org/rattail-project/tailbone-woocommerce"
+Changelog = "https://kallithea.rattailproject.org/rattail-project/tailbone-woocommerce/files/master/CHANGELOG.md"
+
+
+[tool.commitizen]
+version_provider = "pep621"
+tag_format = "v$version"
+update_changelog_on_bump = true
diff --git a/setup.py b/setup.py
deleted file mode 100644
index ffea671..0000000
--- a/setup.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# -*- coding: utf-8; -*-
-################################################################################
-#
-# Rattail -- Retail Software Framework
-# Copyright © 2010-2021 Lance Edgar
-#
-# This file is part of Rattail.
-#
-# Rattail 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.
-#
-# Rattail 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
-# Rattail. If not, see .
-#
-################################################################################
-
-import os
-from setuptools import setup, find_packages
-
-
-here = os.path.abspath(os.path.dirname(__file__))
-exec(open(os.path.join(here, 'tailbone_woocommerce', '_version.py')).read())
-README = open(os.path.join(here, 'README.rst')).read()
-
-
-requires = [
- #
- # Version numbers within comments below have specific meanings.
- # Basically the 'low' value is a "soft low," and 'high' a "soft high."
- # In other words:
- #
- # If either a 'low' or 'high' value exists, the primary point to be
- # made about the value is that it represents the most current (stable)
- # version available for the package (assuming typical public access
- # methods) whenever this project was started and/or documented.
- # Therefore:
- #
- # If a 'low' version is present, you should know that attempts to use
- # versions of the package significantly older than the 'low' version
- # may not yield happy results. (A "hard" high limit may or may not be
- # indicated by a true version requirement.)
- #
- # Similarly, if a 'high' version is present, and especially if this
- # project has laid dormant for a while, you may need to refactor a bit
- # when attempting to support a more recent version of the package. (A
- # "hard" low limit should be indicated by a true version requirement
- # when a 'high' version is present.)
- #
- # In any case, developers and other users are encouraged to play
- # outside the lines with regard to these soft limits. If bugs are
- # encountered then they should be filed as such.
- #
- # package # low high
-
- 'rattail', # 0.9.138
- 'rattail-woocommerce', # 0.1.0
- 'Tailbone', # 0.8.103
-]
-
-
-setup(
- name = "tailbone-woocommerce",
- version = __version__,
- author = "Lance Edgar",
- author_email = "lance@edbob.org",
- url = "https://rattailproject.org/",
- license = "GNU GPL v3",
- description = "Tailbone integration for WooCommerce",
- long_description = README,
-
- classifiers = [
- 'Development Status :: 4 - Beta',
- 'Environment :: Web Environment',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
- 'Natural Language :: English',
- 'Operating System :: OS Independent',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 3',
- 'Topic :: Office/Business',
- 'Topic :: Software Development :: Libraries :: Python Modules',
- ],
-
- install_requires = requires,
- packages = find_packages(),
- include_package_data = True,
- zip_safe = False,
-)
diff --git a/tailbone_woocommerce/_version.py b/tailbone_woocommerce/_version.py
index e41b669..5c5048a 100644
--- a/tailbone_woocommerce/_version.py
+++ b/tailbone_woocommerce/_version.py
@@ -1,3 +1,6 @@
# -*- coding: utf-8; -*-
-__version__ = '0.1.0'
+from importlib.metadata import version
+
+
+__version__ = version('tailbone-woocommerce')
diff --git a/tailbone_woocommerce/templates/products/view.mako b/tailbone_woocommerce/templates/products/view.mako
deleted file mode 100644
index 29c92d4..0000000
--- a/tailbone_woocommerce/templates/products/view.mako
+++ /dev/null
@@ -1,52 +0,0 @@
-## -*- coding: utf-8; -*-
-<%inherit file="tailbone:templates/products/view.mako" />
-
-<%def name="object_helpers()">
- ${parent.object_helpers()}
- ${self.render_xref_helper()}
-%def>
-
-<%def name="render_xref_store_button()">
-
- View in WooCommerce Store
-
-%def>
-
-<%def name="render_xref_admin_button()">
-
- View in WooCommerce Admin
-
-%def>
-
-<%def name="render_xref_helper()">
-
-
Cross-Reference
-
- ${self.render_xref_store_button()}
- ${self.render_xref_admin_button()}
-
-
-%def>
-
-<%def name="extra_main_fields(form)">
- ${parent.extra_main_fields(form)}
- ${self.extra_main_fields_woocommerce(form)}
-%def>
-
-<%def name="extra_main_fields_woocommerce(form)">
- ${form.render_field_readonly('woocommerce_id')}
-%def>
-
-${parent.body()}
diff --git a/tailbone_woocommerce/views/__init__.py b/tailbone_woocommerce/views/__init__.py
index e69de29..6be242f 100644
--- a/tailbone_woocommerce/views/__init__.py
+++ b/tailbone_woocommerce/views/__init__.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8; -*-
+################################################################################
+#
+# Rattail -- Retail Software Framework
+# Copyright © 2010-2022 Lance Edgar
+#
+# This file is part of Rattail.
+#
+# Rattail 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.
+#
+# Rattail 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
+# Rattail. If not, see .
+#
+################################################################################
+"""
+Views w/ WooCommerce integration
+"""
+
+
+def includeme(config):
+ config.include('tailbone_woocommerce.views.products')
diff --git a/tailbone_woocommerce/views/products.py b/tailbone_woocommerce/views/products.py
index 545d22f..f38525e 100644
--- a/tailbone_woocommerce/views/products.py
+++ b/tailbone_woocommerce/views/products.py
@@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
-# Copyright © 2010-2021 Lance Edgar
+# Copyright © 2010-2022 Lance Edgar
#
# This file is part of Rattail.
#
@@ -28,72 +28,68 @@ from sqlalchemy import orm
from rattail_woocommerce.config import woocommerce_admin_product_url
-from tailbone.views import products as base
+from webhelpers2.html import tags
+
+from tailbone.views import ViewSupplement
-class ProductView(base.ProductsView):
+class ProductViewSupplement(ViewSupplement):
"""
- Master view for the Product class.
+ Product view supplement for WooCommerce integration
"""
+ route_prefix = 'products'
+
labels = {
'woocommerce_id': "WooCommerce ID",
}
- @property
- def form_fields(self):
- fields = super(ProductView, self).form_fields
- return self.woocommerce_add_form_fields(fields)
-
- def woocommerce_add_form_fields(self, fields):
- fields.extend([
- 'woocommerce_id',
- ])
- return fields
-
- def query(self, session):
- query = super(ProductView, self).query(session)
- return self.woocommerce_modify_query(query)
-
- def woocommerce_modify_query(self, query):
+ def get_grid_query(self, query):
model = self.model
return query.outerjoin(model.WooProductExtension)
def configure_grid(self, g):
- super(ProductView, self).configure_grid(g)
- self.woocommerce_configure_grid(g)
-
- def woocommerce_configure_grid(self, g):
model = self.model
g.set_filter('woocommerce_id', model.WooProductExtension.woocommerce_id)
def configure_form(self, f):
- super(ProductView, self).configure_form(f)
- self.woocommerce_configure_form(f)
-
- def woocommerce_configure_form(self, f):
- f.set_required('woocommerce_id', False)
- if self.creating:
- f.remove('woocommerce_id')
+ if not self.master.creating:
+ f.append('woocommerce_id')
def get_version_child_classes(self):
- classes = super(ProductView, self).get_version_child_classes()
- return self.woocommerce_add_version_classes(classes)
-
- def woocommerce_add_version_classes(self, classes):
model = self.model
- classes.extend([
- model.WooProductExtension,
- ])
- return classes
+ return [model.WooProductExtension]
- def template_kwargs_view(self, **kwargs):
- kwargs = super(ProductView, self).template_kwargs_view(**kwargs)
- return self.woocommerce_template_kwargs_view(**kwargs)
+ def get_panel_fields_main(self, product):
+ return ['woocommerce_id']
+
+ def get_xref_buttons(self, product):
+ buttons = []
+
+ woo_cached = self.get_woo_cached_product(product)
+ if woo_cached:
+ buttons.append({'url': woo_cached.permalink,
+ 'text': "View in WooCommerce Store"})
+
+ woo_id = woo_cached.id if woo_cached else product.woocommerce_id
+ if woo_id:
+ url = woocommerce_admin_product_url(self.rattail_config, woo_id)
+ if url:
+ buttons.append({'url': url,
+ 'text': "View in WooCommerce Admin"})
+
+ return buttons
+
+ def get_xref_links(self, product):
+ if product.woocommerce_cache_product:
+ url = self.request.route_url('woocommerce.products.view',
+ uuid=product.woocommerce_cache_product.uuid)
+ return [tags.link_to("View WooCommerce Product", url)]
def get_woo_cached_product(self, product):
"""
Tries to identify the WooCacheProduct for the given Rattail Product.
"""
+ model = self.model
woo_cached = None
if product.woocommerce_cache_product:
@@ -102,7 +98,6 @@ class ProductView(base.ProductsView):
elif product.item_id:
# try to find matching woo product, even though not linked
- model = self.rattail_config.get_model()
try:
woo_cached = self.Session.query(model.WooCacheProduct)\
.filter(model.WooCacheProduct.sku == product.item_id)\
@@ -112,45 +107,6 @@ class ProductView(base.ProductsView):
return woo_cached
- def woocommerce_template_kwargs_view(self, **kwargs):
- product = kwargs['instance']
- woo_cached = self.get_woo_cached_product(product)
-
- # WooCommerce Store URL
- store_url = why_not = None
- if woo_cached:
- store_url = woo_cached.permalink
- else:
- why_not = "WooCommerce cache product not found"
- kwargs['woocommerce_store_url'] = store_url
- kwargs['woocommerce_store_why_no_url'] = why_not
-
- # WooCommerce Admin URL
- admin_url = why_not = None
- woo_id = woo_cached.id if woo_cached else product.woocommerce_id
- if woo_id:
- admin_url = woocommerce_admin_product_url(self.rattail_config,
- woo_id)
- if not admin_url:
- why_not = "WooCommerce Admin URL is not configured"
- else:
- why_not = "Product is not known to exist in WooCommerce"
- kwargs['woocommerce_admin_url'] = admin_url
- kwargs['woocommerce_admin_why_no_url'] = why_not
-
- return kwargs
-
def includeme(config):
-
- # TODO: getting pretty tired of copy/pasting this extra config...
- config.add_route('products.autocomplete', '/products/autocomplete')
- config.add_view(base.ProductsAutocomplete, route_name='products.autocomplete',
- renderer='json', permission='products.list')
-
- # TODO: getting pretty tired of copy/pasting this extra config...
- config.add_route('products.print_labels', '/products/labels')
- config.add_view(base.print_labels, route_name='products.print_labels',
- renderer='json', permission='products.print_labels')
-
- ProductView.defaults(config)
+ ProductViewSupplement.defaults(config)
diff --git a/tasks.py b/tasks.py
index 469b737..a376936 100644
--- a/tasks.py
+++ b/tasks.py
@@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
-# Copyright © 2010-2021 Lance Edgar
+# Copyright © 2010-2024 Lance Edgar
#
# This file is part of Rattail.
#
@@ -30,15 +30,14 @@ import shutil
from invoke import task
-here = os.path.abspath(os.path.dirname(__file__))
-exec(open(os.path.join(here, 'tailbone_woocommerce', '_version.py')).read())
-
-
@task
-def release(ctx):
+def release(c):
"""
Release a new version of 'tailbone-woocommerce'.
"""
- shutil.rmtree('tailbone_woocommerce.egg-info')
- ctx.run('python setup.py sdist --formats=gztar')
- ctx.run('twine upload dist/tailbone-woocommerce-{}.tar.gz'.format(__version__))
+ if os.path.exists('dist'):
+ shutil.rmtree('dist')
+ if os.path.exists('tailbone_woocommerce.egg-info'):
+ shutil.rmtree('tailbone_woocommerce.egg-info')
+ c.run('python -m build --sdist')
+ c.run('twine upload dist/*')