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>
-
-<%def name="render_xref_helper()">
-
-%def>
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>
-
-<%def name="render_import_helper()">
- % if master.has_perm('import_from_harvest'):
-
- % endif
-%def>
-
-<%def name="modify_this_page_vars()">
- ${parent.modify_this_page_vars()}
- % if master.has_perm('import_from_harvest'):
-
- % endif
-%def>
-
-
-${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()}
-%def>
-
-
-${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))