Initial commit; w/ views for cache tables

This commit is contained in:
Lance Edgar 2022-01-29 14:51:59 -06:00
commit 455027c5d0
19 changed files with 744 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
tailbone_harvest.egg-info/

10
CHANGELOG.md Normal file
View file

@ -0,0 +1,10 @@
# Changelog
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).
## [0.1.0] - ??
### Added
- Initial version.

3
MANIFEST.in Normal file
View file

@ -0,0 +1,3 @@
include *.md
include *.rst
recursive-include tailbone_harvest/templates *.mako

14
README.rst Normal file
View file

@ -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/

96
setup.py Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
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,
)

View file

@ -0,0 +1,27 @@
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
tailbone-harvest package root
"""
from ._version import __version__

View file

@ -0,0 +1,3 @@
# -*- coding: utf-8; -*-
__version__ = '0.1.0'

74
tailbone_harvest/menus.py Normal file
View file

@ -0,0 +1,74 @@
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Common menus for Harvest
"""
def make_harvest_menu(request):
url = request.route_url
harvest_menu = {
'title': "Harvest",
'type': 'menu',
'items': [
{
'title': "Users",
'url': url('harvest.users'),
'perm': 'harvest.users.list',
},
{
'title': "Clients",
'url': url('harvest.clients'),
'perm': 'harvest.clients.list',
},
{
'title': "Projects",
'url': url('harvest.projects'),
'perm': 'harvest.projects.list',
},
{
'title': "Tasks",
'url': url('harvest.tasks'),
'perm': 'harvest.tasks.list',
},
{
'title': "Time Entries",
'url': url('harvest.time_entries'),
'perm': 'harvest.time_entries.list',
},
],
}
harvest_url = request.rattail_config.get('harvest', 'url')
if harvest_url:
harvest_menu['items'].insert(
0, {
'title': "Go to Harvest",
'url': harvest_url,
'target': '_blank',
})
harvest_menu['items'].insert(
1, {'type': 'sep'})
return harvest_menu

View file

@ -0,0 +1,30 @@
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Static assets for tailbone-harvest
"""
def includeme(config):
config.add_static_view('tailbone_harvest', 'tailbone_harvest:static',
cache_max_age=3600)

View file

View file

View file

@ -0,0 +1,35 @@
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Harvest Views
"""
from .master import HarvestMasterView
def includeme(config):
config.include('tailbone_harvest.views.harvest.users')
config.include('tailbone_harvest.views.harvest.clients')
config.include('tailbone_harvest.views.harvest.projects')
config.include('tailbone_harvest.views.harvest.tasks')
config.include('tailbone_harvest.views.harvest.time_entries')

View file

@ -0,0 +1,82 @@
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Harvest Client views
"""
from rattail_harvest.db.model import HarvestClient
from webhelpers2.html import HTML, tags
from .master import HarvestMasterView
class HarvestClientView(HarvestMasterView):
"""
Master view for Harvest Clients
"""
model_class = HarvestClient
url_prefix = '/harvest/clients'
route_prefix = 'harvest.clients'
grid_columns = [
'id',
'name',
'currency',
]
def configure_grid(self, g):
super(HarvestClientView, self).configure_grid(g)
g.filters['name'].default_active = True
g.filters['name'].default_verb = 'contains'
g.set_sort_defaults('name')
g.set_link('id')
g.set_link('name')
def configure_form(self, f):
super(HarvestClientView, self).configure_form(f)
# projects
f.set_renderer('projects', self.render_projects)
# time_entries
f.remove_field('time_entries')
def render_projects(self, client, field):
projects = client.projects
if not projects:
return
items = []
for project in projects:
text = "({}) {}".format(project.code, project.name)
url = self.request.route_url('harvest.projects.view', uuid=project.uuid)
items.append(HTML.tag('li', c=[tags.link_to(text, url)]))
return HTML.tag('ul', c=items)
def includeme(config):
HarvestClientView.defaults(config)

View file

@ -0,0 +1,41 @@
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Harvest master view
"""
from tailbone.views import MasterView
class HarvestMasterView(MasterView):
"""
Base class for Harvest master views
"""
creatable = False
editable = False
deletable = False
has_versions = True
labels = {
'id': "ID",
}

View file

@ -0,0 +1,74 @@
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Harvest Project views
"""
from rattail_harvest.db.model import HarvestProject
from .master import HarvestMasterView
class HarvestProjectView(HarvestMasterView):
"""
Master view for Harvest Projects
"""
model_class = HarvestProject
url_prefix = '/harvest/projects'
route_prefix = 'harvest.projects'
grid_columns = [
'id',
'client',
'name',
'code',
'is_active',
'is_billable',
'bill_by',
'hourly_rate',
'fee',
]
def configure_grid(self, g):
super(HarvestProjectView, self).configure_grid(g)
model = self.model
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.set_type('hourly_rate', 'currency')
g.set_type('fee', 'currency')
g.set_sort_defaults('client')
g.set_link('id')
g.set_link('client')
g.set_link('name')
g.set_link('code')
def includeme(config):
HarvestProjectView.defaults(config)

View file

@ -0,0 +1,65 @@
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Harvest Task views
"""
from rattail_harvest.db.model import HarvestTask
from .master import HarvestMasterView
class HarvestTaskView(HarvestMasterView):
"""
Master view for Harvest Tasks
"""
model_class = HarvestTask
url_prefix = '/harvest/tasks'
route_prefix = 'harvest.tasks'
grid_columns = [
'id',
'name',
'billable_by_default',
'default_hourly_rate',
'is_default',
'is_active',
]
def configure_grid(self, g):
super(HarvestTaskView, self).configure_grid(g)
g.set_sort_defaults('name')
g.set_link('id')
g.set_link('name')
def configure_form(self, f):
super(HarvestTaskView, self).configure_form(f)
# time_entries
f.remove_field('time_entries')
def includeme(config):
HarvestTaskView.defaults(config)

View file

@ -0,0 +1,73 @@
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Harvest Time Entry views
"""
from rattail_harvest.db.model import HarvestTimeEntry
from .master import HarvestMasterView
class HarvestTimeEntryView(HarvestMasterView):
"""
Master view for Harvest Time Entries
"""
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',
'user',
'client',
'project',
'task',
'hours',
'notes',
]
def configure_grid(self, g):
super(HarvestTimeEntryView, self).configure_grid(g)
g.set_type('hours', 'duration_hours')
g.set_sort_defaults('spent_date', 'desc')
g.set_link('id')
g.set_link('user')
g.set_link('client')
g.set_link('notes')
def includeme(config):
HarvestTimeEntryView.defaults(config)

View file

@ -0,0 +1,68 @@
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Harvest User views
"""
from rattail_harvest.db.model import HarvestUser
from .master import HarvestMasterView
class HarvestUserView(HarvestMasterView):
"""
Master view for Harvest Users
"""
model_class = HarvestUser
url_prefix = '/harvest/users'
route_prefix = 'harvest.users'
grid_columns = [
'id',
'first_name',
'last_name',
'email',
'telephone',
'timezone',
'is_admin',
]
def configure_grid(self, g):
super(HarvestUserView, self).configure_grid(g)
g.set_sort_defaults('first_name')
g.set_link('id')
g.set_link('first_name')
g.set_link('last_name')
g.set_link('email')
def configure_form(self, f):
super(HarvestUserView, self).configure_form(f)
# TODO: should add this as child rows/grid instead
f.remove('time_entries')
def includeme(config):
HarvestUserView.defaults(config)

48
tasks.py Normal file
View file

@ -0,0 +1,48 @@
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Tasks for tailbone-harvest
"""
import os
import shutil
from invoke import task
here = os.path.abspath(os.path.dirname(__file__))
exec(open(os.path.join(here, 'tailbone_harvest', '_version.py')).read())
@task
def release(ctx):
"""
Release a new version of tailbone-harvest
"""
# rebuild local tar.gz file for distribution
shutil.rmtree('tailbone_harvest.egg-info')
ctx.run('python setup.py sdist --formats=gztar')
# upload to public PyPI
filename = 'tailbone-harvest-{}.tar.gz'.format(__version__)
ctx.run('twine upload dist/{}'.format(filename))