diff --git a/.gitignore b/.gitignore index 7893476..5d6335c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ -*~ -*.pyc -dist/ tailbone_woocommerce.egg-info/ diff --git a/CHANGELOG.md b/CHANGELOG.md index fa1effb..220b0d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,6 @@ 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 deleted file mode 100644 index 873af83..0000000 --- a/README.md +++ /dev/null @@ -1,11 +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](https://woocommerce.com/) system. - -Please see the [Rattail Project](https://rattailproject.org/) for more -information. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..d768e06 --- /dev/null +++ b/README.rst @@ -0,0 +1,14 @@ + +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 deleted file mode 100644 index 100dd71..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,42 +0,0 @@ - -[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 new file mode 100644 index 0000000..ffea671 --- /dev/null +++ b/setup.py @@ -0,0 +1,95 @@ +# -*- 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 5c5048a..e41b669 100644 --- a/tailbone_woocommerce/_version.py +++ b/tailbone_woocommerce/_version.py @@ -1,6 +1,3 @@ # -*- coding: utf-8; -*- -from importlib.metadata import version - - -__version__ = version('tailbone-woocommerce') +__version__ = '0.1.0' diff --git a/tailbone_woocommerce/templates/products/view.mako b/tailbone_woocommerce/templates/products/view.mako new file mode 100644 index 0000000..29c92d4 --- /dev/null +++ b/tailbone_woocommerce/templates/products/view.mako @@ -0,0 +1,52 @@ +## -*- coding: utf-8; -*- +<%inherit file="tailbone:templates/products/view.mako" /> + +<%def name="object_helpers()"> + ${parent.object_helpers()} + ${self.render_xref_helper()} + + +<%def name="render_xref_store_button()"> + + View in WooCommerce Store + + + +<%def name="render_xref_admin_button()"> + + View in WooCommerce Admin + + + +<%def name="render_xref_helper()"> +
+

Cross-Reference

+
+ ${self.render_xref_store_button()} + ${self.render_xref_admin_button()} +
+
+ + +<%def name="extra_main_fields(form)"> + ${parent.extra_main_fields(form)} + ${self.extra_main_fields_woocommerce(form)} + + +<%def name="extra_main_fields_woocommerce(form)"> + ${form.render_field_readonly('woocommerce_id')} + + +${parent.body()} diff --git a/tailbone_woocommerce/views/__init__.py b/tailbone_woocommerce/views/__init__.py index 6be242f..e69de29 100644 --- a/tailbone_woocommerce/views/__init__.py +++ b/tailbone_woocommerce/views/__init__.py @@ -1,29 +0,0 @@ -# -*- 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 f38525e..545d22f 100644 --- a/tailbone_woocommerce/views/products.py +++ b/tailbone_woocommerce/views/products.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2022 Lance Edgar +# Copyright © 2010-2021 Lance Edgar # # This file is part of Rattail. # @@ -28,68 +28,72 @@ from sqlalchemy import orm from rattail_woocommerce.config import woocommerce_admin_product_url -from webhelpers2.html import tags - -from tailbone.views import ViewSupplement +from tailbone.views import products as base -class ProductViewSupplement(ViewSupplement): +class ProductView(base.ProductsView): """ - Product view supplement for WooCommerce integration + Master view for the Product class. """ - route_prefix = 'products' - labels = { 'woocommerce_id': "WooCommerce ID", } - def get_grid_query(self, query): + @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): 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): - if not self.master.creating: - f.append('woocommerce_id') + 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') 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 - return [model.WooProductExtension] + classes.extend([ + model.WooProductExtension, + ]) + return classes - 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 template_kwargs_view(self, **kwargs): + kwargs = super(ProductView, self).template_kwargs_view(**kwargs) + return self.woocommerce_template_kwargs_view(**kwargs) 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: @@ -98,6 +102,7 @@ class ProductViewSupplement(ViewSupplement): 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)\ @@ -107,6 +112,45 @@ class ProductViewSupplement(ViewSupplement): 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): - ProductViewSupplement.defaults(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) diff --git a/tasks.py b/tasks.py index a376936..469b737 100644 --- a/tasks.py +++ b/tasks.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2024 Lance Edgar +# Copyright © 2010-2021 Lance Edgar # # This file is part of Rattail. # @@ -30,14 +30,15 @@ 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(c): +def release(ctx): """ Release a new version of 'tailbone-woocommerce'. """ - 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/*') + 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__))