diff --git a/.gitignore b/.gitignore index 40ca5bc..6ee5074 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ -*~ -*.pyc -dist/ tailbone_harvest.egg-info/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 0728aeb..cbaaf9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,23 +5,6 @@ All notable changes to tailbone-harvest 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.3.1 (2024-07-01) - -### Fix - -- remove incorrect entry points - -## v0.3.0 (2024-06-10) - -### Feat - -- switch from setup.cfg to pyproject.toml + hatchling - -## [0.2.0] - 2024-06-06 -Catch-up release. -### Changed -- lots of things... - ## [0.1.0] - 2022-01-29 ### Added - Initial version. diff --git a/README.md b/README.md deleted file mode 100644 index ec86877..0000000 --- a/README.md +++ /dev/null @@ -1,11 +0,0 @@ - -# tailbone-harvest - -Rattail is a retail software framework, released under the GNU General -Public License. - -This package contains software interfaces for -[Harvest](https://www.getharvest.com/). - -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..4866f29 --- /dev/null +++ b/README.rst @@ -0,0 +1,14 @@ + +tailbone-harvest +================ + +Rattail is a retail software framework, released under the GNU General +Public License. + +This package contains software interfaces for `Harvest`_. + +.. _`Harvest`: https://www.getharvest.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 e9ffcd3..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,42 +0,0 @@ - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - - -[project] -name = "tailbone-harvest" -version = "0.3.1" -description = "Tailbone integration package for Harvest" -readme = "README.md" -authors = [{name = "Lance Edgar", email = "lance@edbob.org"}] -license = {text = "GNU GPL v3+"} -classifiers = [ - "Development Status :: 3 - Alpha", - "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 = [ - "invoke", - "rattail-harvest", - "Tailbone", -] - - -[project.urls] -Homepage = "https://rattailproject.org" -Repository = "https://forgejo.wuttaproject.org/rattail/tailbone-harvest" -Changelog = "https://forgejo.wuttaproject.org/rattail/tailbone-harvest/src/branch/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..d333d3f --- /dev/null +++ b/setup.py @@ -0,0 +1,96 @@ +# -*- 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 . +# +################################################################################ +""" +tailbone-harvest setup script +""" + +import os +from setuptools import setup, find_packages + + +here = os.path.abspath(os.path.dirname(__file__)) +exec(open(os.path.join(here, 'tailbone_harvest', '_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 + + 'invoke', # 1.5.0 + 'rattail-harvest', # 0.1.0 + 'Tailbone', # 0.8.199 +] + + +setup( + name = "tailbone-harvest", + version = __version__, + author = "Lance Edgar", + author_email = "lance@edbob.org", + url = "https://rattailproject.org/", + description = "Tailbone integration package for Harvest", + long_description = README, + + classifiers = [ + 'Development Status :: 3 - Alpha', + '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, +) diff --git a/tailbone_harvest/_version.py b/tailbone_harvest/_version.py index 0e7a01b..e41b669 100644 --- a/tailbone_harvest/_version.py +++ b/tailbone_harvest/_version.py @@ -1,6 +1,3 @@ # -*- coding: utf-8; -*- -from importlib.metadata import version - - -__version__ = version('tailbone-harvest') +__version__ = '0.1.0' diff --git a/tailbone_harvest/templates/.keepme b/tailbone_harvest/templates/.keepme new file mode 100644 index 0000000..e69de29 diff --git a/tailbone_harvest/templates/harvest-util.mako b/tailbone_harvest/templates/harvest-util.mako deleted file mode 100644 index 907cc96..0000000 --- a/tailbone_harvest/templates/harvest-util.mako +++ /dev/null @@ -1,23 +0,0 @@ -## -*- coding: utf-8; -*- - -<%def name="render_xref_buttons()"> - - View in Harvest - - - -<%def name="render_xref_helper()"> - - diff --git a/tailbone_harvest/templates/harvest/time-entries/view.mako b/tailbone_harvest/templates/harvest/time-entries/view.mako deleted file mode 100644 index 3b36ff5..0000000 --- a/tailbone_harvest/templates/harvest/time-entries/view.mako +++ /dev/null @@ -1,45 +0,0 @@ -## -*- coding: utf-8; -*- -<%inherit file="/master/view.mako" /> - -<%def name="object_helpers()"> - ${parent.object_helpers()} - ${self.render_import_helper()} - - -<%def name="render_import_helper()"> - % if master.has_perm('import_from_harvest'): - - % endif - - -<%def name="modify_this_page_vars()"> - ${parent.modify_this_page_vars()} - % if master.has_perm('import_from_harvest'): - - % endif - - - -${parent.body()} diff --git a/tailbone_harvest/templates/harvest/users/view.mako b/tailbone_harvest/templates/harvest/users/view.mako deleted file mode 100644 index 245deff..0000000 --- a/tailbone_harvest/templates/harvest/users/view.mako +++ /dev/null @@ -1,16 +0,0 @@ -## -*- coding: utf-8; -*- -<%inherit file="/master/view.mako" /> - -<%def name="page_content()"> - - % if instance.avatar_url: -
- -
- % endif - - ${parent.page_content()} - - - -${parent.body()} diff --git a/tailbone_harvest/views/harvest/clients.py b/tailbone_harvest/views/harvest/clients.py index d80751d..1f7be2b 100644 --- a/tailbone_harvest/views/harvest/clients.py +++ b/tailbone_harvest/views/harvest/clients.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2023 Lance Edgar +# Copyright © 2010-2022 Lance Edgar # # This file is part of Rattail. # @@ -24,19 +24,18 @@ Harvest Client views """ -from rattail_harvest.db.model import HarvestCacheClient -from rattail_harvest.harvest.config import get_harvest_url +from rattail_harvest.db.model import HarvestClient from webhelpers2.html import HTML, tags from .master import HarvestMasterView -class HarvestCacheClientView(HarvestMasterView): +class HarvestClientView(HarvestMasterView): """ Master view for Harvest Clients """ - model_class = HarvestCacheClient + model_class = HarvestClient url_prefix = '/harvest/clients' route_prefix = 'harvest.clients' @@ -47,25 +46,18 @@ class HarvestCacheClientView(HarvestMasterView): ] def configure_grid(self, g): - super().configure_grid(g) + super(HarvestClientView, self).configure_grid(g) g.filters['name'].default_active = True g.filters['name'].default_verb = 'contains' - g.filters['is_active'].default_active = True - g.filters['is_active'].default_verb = 'is_true' - g.set_sort_defaults('name') g.set_link('id') g.set_link('name') - def grid_extra_class(self, client, i): - if not client.is_active: - return 'warning' - def configure_form(self, f): - super().configure_form(f) + super(HarvestClientView, self).configure_form(f) # projects f.set_renderer('projects', self.render_projects) @@ -85,26 +77,6 @@ class HarvestCacheClientView(HarvestMasterView): items.append(HTML.tag('li', c=[tags.link_to(text, url)])) return HTML.tag('ul', c=items) - def get_xref_buttons(self, client): - buttons = super().get_xref_buttons(client) - model = self.model - - # harvest proper - url = get_harvest_url(self.rattail_config) - if url: - url = '{}/clients'.format(url) - buttons.append(self.make_xref_button(url=url, - text="View in Harvest")) - - return buttons - - -def defaults(config, **kwargs): - base = globals() - - HarvestCacheClientView = kwargs.get('HarvestCacheClientView', base['HarvestCacheClientView']) - HarvestCacheClientView.defaults(config) - def includeme(config): - defaults(config) + HarvestClientView.defaults(config) diff --git a/tailbone_harvest/views/harvest/master.py b/tailbone_harvest/views/harvest/master.py index 5230987..5d206ac 100644 --- a/tailbone_harvest/views/harvest/master.py +++ b/tailbone_harvest/views/harvest/master.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2023 Lance Edgar +# Copyright © 2010-2022 Lance Edgar # # This file is part of Rattail. # @@ -24,10 +24,6 @@ Harvest master view """ -from rattail_harvest.db.model import HarvestCacheTimeEntry - -from webhelpers2.html import tags - from tailbone.views import MasterView @@ -36,58 +32,10 @@ class HarvestMasterView(MasterView): Base class for Harvest master views """ creatable = False - touchable = True + editable = False + deletable = False has_versions = True - model_row_class = HarvestCacheTimeEntry labels = { 'id': "ID", - 'user_id': "User ID", - 'client_id': "Client ID", - 'project_id': "Project ID", - 'task_id': "Task ID", - 'invoice_id': "Invoice ID", } - - row_labels = { - 'id': "ID", - } - - def configure_form(self, f): - super(HarvestMasterView, self).configure_form(f) - f.remove('time_entries') - - def render_harvest_user(self, obj, field): - user = getattr(obj, field) - if user: - text = str(user) - url = self.request.route_url('harvest.users.view', uuid=user.uuid) - return tags.link_to(text, url) - - def render_harvest_client(self, obj, field): - client = getattr(obj, field) - if client: - text = str(client) - url = self.request.route_url('harvest.clients.view', uuid=client.uuid) - return tags.link_to(text, url) - - def render_harvest_project(self, obj, field): - project = getattr(obj, field) - if project: - text = str(project) - url = self.request.route_url('harvest.projects.view', uuid=project.uuid) - return tags.link_to(text, url) - - def render_harvest_task(self, obj, field): - task = getattr(obj, field) - if task: - text = str(task) - url = self.request.route_url('harvest.tasks.view', uuid=task.uuid) - return tags.link_to(text, url) - - def configure_row_grid(self, g): - super(HarvestMasterView, self).configure_row_grid(g) - g.set_sort_defaults('spent_date', 'desc') - - def row_view_action_url(self, entry, i): - return self.request.route_url('harvest.time_entries.view', uuid=entry.uuid) diff --git a/tailbone_harvest/views/harvest/projects.py b/tailbone_harvest/views/harvest/projects.py index 55bf236..30b8a9d 100644 --- a/tailbone_harvest/views/harvest/projects.py +++ b/tailbone_harvest/views/harvest/projects.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2023 Lance Edgar +# Copyright © 2010-2022 Lance Edgar # # This file is part of Rattail. # @@ -24,22 +24,19 @@ Harvest Project views """ -from rattail_harvest.db.model import HarvestCacheProject -from rattail_harvest.harvest.config import get_harvest_url +from rattail_harvest.db.model import HarvestProject from .master import HarvestMasterView -class HarvestCacheProjectView(HarvestMasterView): +class HarvestProjectView(HarvestMasterView): """ Master view for Harvest Projects """ - model_class = HarvestCacheProject + model_class = HarvestProject url_prefix = '/harvest/projects' route_prefix = 'harvest.projects' - has_rows = True - grid_columns = [ 'id', 'client', @@ -52,89 +49,26 @@ class HarvestCacheProjectView(HarvestMasterView): 'fee', ] - row_grid_columns = [ - 'id', - 'spent_date', - 'user', - 'client', - 'task', - 'hours', - ] - def configure_grid(self, g): - super().configure_grid(g) + super(HarvestProjectView, self).configure_grid(g) model = self.model - g.set_joiner('client', lambda q: q.outerjoin(model.HarvestCacheClient)) - g.set_sorter('client', model.HarvestCacheClient.name) - g.set_filter('client', model.HarvestCacheClient.name, label="Client Name") + g.set_joiner('client', lambda q: q.outerjoin(model.HarvestClient)) + g.set_sorter('client', model.HarvestClient.name) + g.set_filter('client', model.HarvestClient.name, label="Client Name") g.filters['client'].default_active = True g.filters['client'].default_verb = 'contains' - g.filters['is_active'].default_active = True - g.filters['is_active'].default_verb = 'is_true' - g.set_type('hourly_rate', 'currency') g.set_type('fee', 'currency') g.set_sort_defaults('client') - g.set_filters_sequence([ - 'id', - 'name', - 'client', - ]) - g.set_link('id') g.set_link('client') g.set_link('name') g.set_link('code') - def grid_extra_class(self, project, i): - if not project.is_active: - return 'warning' - - def configure_form(self, f): - super().configure_form(f) - - f.set_type('hourly_rate', 'currency') - - if self.editing: - f.remove('client') - f.set_type('over_budget_notification_date', 'date_jquery') - f.set_type('starts_on', 'date_jquery') - f.set_type('ends_on', 'date_jquery') - f.set_readonly('created_at') - f.set_readonly('updated_at') - - def get_xref_buttons(self, project): - buttons = super().get_xref_buttons(project) - model = self.model - - # harvest - url = get_harvest_url(self.rattail_config) - if url: - url = '{}/projects/{}'.format(url, project.id) - buttons.append(self.make_xref_button(url=url, - text="View in Harvest")) - - return buttons - - def get_row_data(self, project): - model = self.model - return self.Session.query(model.HarvestCacheTimeEntry)\ - .filter(model.HarvestCacheTimeEntry.project == project) - - def get_parent(self, entry): - return entry.project - - -def defaults(config, **kwargs): - base = globals() - - HarvestCacheProjectView = kwargs.get('HarvestCacheProjectView', base['HarvestCacheProjectView']) - HarvestCacheProjectView.defaults(config) - def includeme(config): - defaults(config) + HarvestProjectView.defaults(config) diff --git a/tailbone_harvest/views/harvest/tasks.py b/tailbone_harvest/views/harvest/tasks.py index 2cf52df..a3b61b4 100644 --- a/tailbone_harvest/views/harvest/tasks.py +++ b/tailbone_harvest/views/harvest/tasks.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2023 Lance Edgar +# Copyright © 2010-2022 Lance Edgar # # This file is part of Rattail. # @@ -24,17 +24,16 @@ Harvest Task views """ -from rattail_harvest.db.model import HarvestCacheTask -from rattail_harvest.harvest.config import get_harvest_url +from rattail_harvest.db.model import HarvestTask from .master import HarvestMasterView -class HarvestCacheTaskView(HarvestMasterView): +class HarvestTaskView(HarvestMasterView): """ Master view for Harvest Tasks """ - model_class = HarvestCacheTask + model_class = HarvestTask url_prefix = '/harvest/tasks' route_prefix = 'harvest.tasks' @@ -48,7 +47,7 @@ class HarvestCacheTaskView(HarvestMasterView): ] def configure_grid(self, g): - super().configure_grid(g) + super(HarvestTaskView, self).configure_grid(g) g.set_sort_defaults('name') @@ -56,31 +55,11 @@ class HarvestCacheTaskView(HarvestMasterView): g.set_link('name') def configure_form(self, f): - super().configure_form(f) + super(HarvestTaskView, self).configure_form(f) # time_entries f.remove_field('time_entries') - def get_xref_buttons(self, task): - buttons = super().get_xref_buttons(task) - model = self.model - - # harvest - url = get_harvest_url(self.rattail_config) - if url: - url = '{}/tasks'.format(url) - buttons.append(self.make_xref_button(url=url, - text="View in Harvest")) - - return buttons - - -def defaults(config, **kwargs): - base = globals() - - HarvestCacheTaskView = kwargs.get('HarvestCacheTaskView', base['HarvestCacheTaskView']) - HarvestCacheTaskView.defaults(config) - def includeme(config): - defaults(config) + HarvestTaskView.defaults(config) diff --git a/tailbone_harvest/views/harvest/time_entries.py b/tailbone_harvest/views/harvest/time_entries.py index fc04bf8..3ddfdab 100644 --- a/tailbone_harvest/views/harvest/time_entries.py +++ b/tailbone_harvest/views/harvest/time_entries.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2023 Lance Edgar +# Copyright © 2010-2022 Lance Edgar # # This file is part of Rattail. # @@ -24,20 +24,27 @@ Harvest Time Entry views """ -from rattail_harvest.db.model import HarvestCacheTimeEntry -from rattail_harvest.harvest.config import get_harvest_url +from rattail_harvest.db.model import HarvestTimeEntry from .master import HarvestMasterView -class HarvestCacheTimeEntryView(HarvestMasterView): +class HarvestTimeEntryView(HarvestMasterView): """ Master view for Harvest Time Entries """ - model_class = HarvestCacheTimeEntry + model_class = HarvestTimeEntry url_prefix = '/harvest/time-entries' route_prefix = 'harvest.time_entries' + labels = { + 'user_id': "User ID", + 'client_id': "Client ID", + 'project_id': "Project ID", + 'task_id': "Task ID", + 'invoice_id': "Invoice ID", + } + grid_columns = [ 'id', 'spent_date', @@ -50,7 +57,7 @@ class HarvestCacheTimeEntryView(HarvestMasterView): ] def configure_grid(self, g): - super().configure_grid(g) + super(HarvestTimeEntryView, self).configure_grid(g) g.set_type('hours', 'duration_hours') @@ -61,103 +68,6 @@ class HarvestCacheTimeEntryView(HarvestMasterView): g.set_link('client') g.set_link('notes') - def configure_form(self, f): - super().configure_form(f) - - # make sure id is first field - f.remove('id') - f.insert(0, 'id') - - # user - f.remove('user_id') - f.set_renderer('user', self.render_harvest_user) - - # client - f.remove('client_id') - f.set_renderer('client', self.render_harvest_client) - - # project - f.remove('project_id') - f.set_renderer('project', self.render_harvest_project) - - # task - f.remove('task_id') - f.set_renderer('task', self.render_harvest_task) - - # hours - f.set_renderer('hours', self.render_hours) - - f.set_type('notes', 'text') - - f.set_type('billable_rate', 'currency') - f.set_type('cost_rate', 'currency') - - def render_hours(self, entry, field): - hours = getattr(entry, field) - app = self.get_rattail_app() - duration = app.render_duration(hours=hours) - return f"{hours} ({duration})" - - def get_xref_buttons(self, entry): - buttons = super().get_xref_buttons(entry) - model = self.model - - # harvest - url = get_harvest_url(self.rattail_config) - if url: - url = '{}/time/day/{}/{}'.format( - url, - entry.spent_date.strftime('%Y/%m/%d'), - entry.user_id) - buttons.append(self.make_xref_button(url=url, - text="View in Harvest")) - - return buttons - - def import_from_harvest(self): - app = self.get_rattail_app() - handler = app.get_import_handler('to_rattail.from_harvest.import', require=True) - importer = handler.get_importer('HarvestCacheTimeEntry') - importer.session = self.Session() - importer.setup() - - cache_entry = self.get_instance() - if self.oneoff_import(importer, local_object=cache_entry): - self.request.session.flash(f"{self.get_model_title()} has been " - f"(re-)imported from Harvest: {cache_entry}") - else: - self.request.session.flash("Import failed!", 'error') - - return self.redirect(self.get_action_url('view', cache_entry)) - - @classmethod - def defaults(cls, config): - route_prefix = cls.get_route_prefix() - instance_url_prefix = cls.get_instance_url_prefix() - permission_prefix = cls.get_permission_prefix() - model_title = cls.get_model_title() - - # normal defaults - cls._defaults(config) - - # import from harvest - config.add_tailbone_permission(permission_prefix, - f'{permission_prefix}.import_from_harvest', - f"Re-Import {model_title} from Harvest") - config.add_route(f'{route_prefix}.import_from_harvest', - f'{instance_url_prefix}/import-from-harvest', - request_method='POST') - config.add_view(cls, attr='import_from_harvest', - route_name=f'{route_prefix}.import_from_harvest', - permission=f'{permission_prefix}.import_from_harvest') - - -def defaults(config, **kwargs): - base = globals() - - HarvestCacheTimeEntryView = kwargs.get('HarvestCacheTimeEntryView', base['HarvestCacheTimeEntryView']) - HarvestCacheTimeEntryView.defaults(config) - def includeme(config): - defaults(config) + HarvestTimeEntryView.defaults(config) diff --git a/tailbone_harvest/views/harvest/users.py b/tailbone_harvest/views/harvest/users.py index d360b83..8f87fb0 100644 --- a/tailbone_harvest/views/harvest/users.py +++ b/tailbone_harvest/views/harvest/users.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2023 Lance Edgar +# Copyright © 2010-2022 Lance Edgar # # This file is part of Rattail. # @@ -24,27 +24,19 @@ Harvest User views """ -from rattail_harvest.db.model import HarvestCacheUser -from rattail_harvest.harvest.config import get_harvest_url +from rattail_harvest.db.model import HarvestUser -import colander - -from tailbone import forms from .master import HarvestMasterView -class HarvestCacheUserView(HarvestMasterView): +class HarvestUserView(HarvestMasterView): """ Master view for Harvest Users """ - model_class = HarvestCacheUser + model_class = HarvestUser url_prefix = '/harvest/users' route_prefix = 'harvest.users' - labels = { - 'avatar_url': "Avatar URL", - } - grid_columns = [ 'id', 'first_name', @@ -56,11 +48,7 @@ class HarvestCacheUserView(HarvestMasterView): ] def configure_grid(self, g): - super().configure_grid(g) - model = self.model - - g.set_joiner('person_name', lambda q: q.outerjoin(model.Person)) - g.set_filter('person_name', model.Person.display_name) + super(HarvestUserView, self).configure_grid(g) g.set_sort_defaults('first_name') @@ -70,75 +58,11 @@ class HarvestCacheUserView(HarvestMasterView): g.set_link('email') def configure_form(self, f): - super().configure_form(f) - model = self.model - user = f.model_instance + super(HarvestUserView, self).configure_form(f) - # person - f.set_renderer('person', self.render_person) - if self.creating or self.editing: - if 'person' in f.fields: - f.remove('person_uuid') - f.replace('person', 'person_uuid') - person_display = "" - if self.request.method == 'POST': - if self.request.POST.get('person_uuid'): - person = self.Session.get(model.Person, - self.request.POST['person_uuid']) - if person: - person_display = str(person) - elif self.editing: - person_display = str(user.person or '') - people_url = self.request.route_url('people.autocomplete') - f.set_widget('person_uuid', forms.widgets.JQueryAutocompleteWidget( - field_display=person_display, service_url=people_url)) - f.set_validator('person_uuid', self.valid_person) - f.set_label('person_uuid', "Person") - else: - f.remove('person_uuid') - - f.set_type('weekly_capacity', 'duration') - - f.set_type('default_hourly_rate', 'currency') - f.set_type('cost_rate', 'currency') - - f.set_renderer('avatar_url', self.render_url) - - # timestamps - if self.creating or self.editing: - f.remove('created_at') - f.remove('updated_at') - - # time_entries # TODO: should add this as child rows/grid instead f.remove('time_entries') - def valid_person(self, node, value): - model = self.model - if value: - person = self.Session.get(model.Person, value) - if not person: - raise colander.Invalid(node, "Person not found (you must *select* a record)") - - def get_xref_buttons(self, user): - buttons = super().get_xref_buttons(user) - model = self.model - - # harvest proper - url = get_harvest_url(self.rattail_config) - if url: - url = '{}/team'.format(url) - buttons.append(self.make_xref_button(url=url, text="View in Harvest")) - - return buttons - - -def defaults(config, **kwargs): - base = globals() - - HarvestCacheUserView = kwargs.get('HarvestCacheUserView', base['HarvestCacheUserView']) - HarvestCacheUserView.defaults(config) - def includeme(config): - defaults(config) + HarvestUserView.defaults(config) diff --git a/tasks.py b/tasks.py index c4ed484..88b264a 100644 --- a/tasks.py +++ b/tasks.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2024 Lance Edgar +# Copyright © 2010-2022 Lance Edgar # # This file is part of Rattail. # @@ -25,36 +25,24 @@ Tasks for tailbone-harvest """ import os -import re import shutil from invoke import task here = os.path.abspath(os.path.dirname(__file__)) -__version__ = None -pattern = re.compile(r'^version = "(\d+\.\d+\.\d+)"$') -with open(os.path.join(here, 'pyproject.toml'), 'rt') as f: - for line in f: - line = line.rstrip('\n') - match = pattern.match(line) - if match: - __version__ = match.group(1) - break -if not __version__: - raise RuntimeError("could not parse version!") +exec(open(os.path.join(here, 'tailbone_harvest', '_version.py')).read()) @task -def release(c): +def release(ctx): """ Release a new version of tailbone-harvest """ # rebuild local tar.gz file for distribution - if os.path.exists('tailbone_harvest.egg-info'): - shutil.rmtree('tailbone_harvest.egg-info') - c.run('python -m build --sdist') + shutil.rmtree('tailbone_harvest.egg-info') + ctx.run('python setup.py sdist --formats=gztar') # upload to public PyPI - filename = f'tailbone_harvest-{__version__}.tar.gz' - c.run(f'twine upload dist/{filename}') + filename = 'tailbone-harvest-{}.tar.gz'.format(__version__) + ctx.run('twine upload dist/{}'.format(filename))