Initial tables and importer stubs, mostly for invoice exports to QB

This commit is contained in:
Lance Edgar 2022-12-20 19:20:11 -06:00
commit 9394171ba5
18 changed files with 1087 additions and 0 deletions

1
.gitignore vendored Normal file
View file

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

10
CHANGELOG.md Normal file
View file

@ -0,0 +1,10 @@
# Changelog
All notable changes to rattail-quickbooks 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 rattail_quickbooks/db/alembic *.mako

14
README.rst Normal file
View file

@ -0,0 +1,14 @@
rattail-quickbooks
==================
Rattail is a retail software framework, released under the GNU General
Public License.
This package contains software interfaces for `Quickbooks`_.
.. _`Quickbooks`: https://quickbooks.intuit.com/
Please see the `Rattail Project`_ for more information.
.. _`Rattail Project`: https://rattailproject.org/

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/>.
#
################################################################################
"""
rattail-quickbooks package root
"""
from ._version import __version__

View file

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

View file

View file

@ -0,0 +1,209 @@
# -*- coding: utf-8; -*-
"""initial integration tables
Revision ID: 72134a69c576
Revises: dc28b97c33ff
Create Date: 2022-12-08 15:19:54.448794
"""
from __future__ import unicode_literals, absolute_import
# revision identifiers, used by Alembic.
revision = '72134a69c576'
down_revision = None
branch_labels = ('rattail_quickbooks',)
depends_on = None
from alembic import op
import sqlalchemy as sa
import rattail.db.types
def upgrade():
# quickbooks_store
op.create_table('quickbooks_store',
sa.Column('uuid', sa.String(length=32), nullable=False),
sa.Column('quickbooks_location', sa.String(length=100), nullable=True),
sa.ForeignKeyConstraint(['uuid'], ['store.uuid'], name='quickbooks_store_fk_store'),
sa.PrimaryKeyConstraint('uuid')
)
op.create_table('quickbooks_store_version',
sa.Column('uuid', sa.String(length=32), autoincrement=False, nullable=False),
sa.Column('quickbooks_location', sa.String(length=100), autoincrement=False, nullable=True),
sa.Column('transaction_id', sa.BigInteger(), autoincrement=False, nullable=False),
sa.Column('end_transaction_id', sa.BigInteger(), nullable=True),
sa.Column('operation_type', sa.SmallInteger(), nullable=False),
sa.PrimaryKeyConstraint('uuid', 'transaction_id')
)
op.create_index(op.f('ix_quickbooks_store_version_end_transaction_id'), 'quickbooks_store_version', ['end_transaction_id'], unique=False)
op.create_index(op.f('ix_quickbooks_store_version_operation_type'), 'quickbooks_store_version', ['operation_type'], unique=False)
op.create_index(op.f('ix_quickbooks_store_version_transaction_id'), 'quickbooks_store_version', ['transaction_id'], unique=False)
# quickbooks_department
op.create_table('quickbooks_department',
sa.Column('uuid', sa.String(length=32), nullable=False),
sa.Column('quickbooks_expense_account', sa.String(length=100), nullable=True),
sa.Column('quickbooks_expense_class', sa.String(length=100), nullable=True),
sa.ForeignKeyConstraint(['uuid'], ['department.uuid'], name='quickbooks_department_fk_department'),
sa.PrimaryKeyConstraint('uuid')
)
op.create_table('quickbooks_department_version',
sa.Column('uuid', sa.String(length=32), autoincrement=False, nullable=False),
sa.Column('quickbooks_expense_account', sa.String(length=100), autoincrement=False, nullable=True),
sa.Column('quickbooks_expense_class', sa.String(length=100), autoincrement=False, nullable=True),
sa.Column('transaction_id', sa.BigInteger(), autoincrement=False, nullable=False),
sa.Column('end_transaction_id', sa.BigInteger(), nullable=True),
sa.Column('operation_type', sa.SmallInteger(), nullable=False),
sa.PrimaryKeyConstraint('uuid', 'transaction_id')
)
op.create_index(op.f('ix_quickbooks_department_version_end_transaction_id'), 'quickbooks_department_version', ['end_transaction_id'], unique=False)
op.create_index(op.f('ix_quickbooks_department_version_operation_type'), 'quickbooks_department_version', ['operation_type'], unique=False)
op.create_index(op.f('ix_quickbooks_department_version_transaction_id'), 'quickbooks_department_version', ['transaction_id'], unique=False)
# quickbooks_vendor
op.create_table('quickbooks_vendor',
sa.Column('uuid', sa.String(length=32), nullable=False),
sa.Column('quickbooks_name', sa.String(length=100), nullable=True),
sa.Column('quickbooks_bank_account', sa.String(length=100), nullable=True),
sa.Column('quickbooks_terms', sa.String(length=100), nullable=True),
sa.ForeignKeyConstraint(['uuid'], ['vendor.uuid'], name='quickbooks_vendor_fk_vendor'),
sa.PrimaryKeyConstraint('uuid')
)
op.create_table('quickbooks_vendor_version',
sa.Column('uuid', sa.String(length=32), autoincrement=False, nullable=False),
sa.Column('quickbooks_name', sa.String(length=100), autoincrement=False, nullable=True),
sa.Column('quickbooks_bank_account', sa.String(length=100), autoincrement=False, nullable=True),
sa.Column('quickbooks_terms', sa.String(length=100), autoincrement=False, nullable=True),
sa.Column('transaction_id', sa.BigInteger(), autoincrement=False, nullable=False),
sa.Column('end_transaction_id', sa.BigInteger(), nullable=True),
sa.Column('operation_type', sa.SmallInteger(), nullable=False),
sa.PrimaryKeyConstraint('uuid', 'transaction_id')
)
op.create_index(op.f('ix_quickbooks_vendor_version_end_transaction_id'), 'quickbooks_vendor_version', ['end_transaction_id'], unique=False)
op.create_index(op.f('ix_quickbooks_vendor_version_operation_type'), 'quickbooks_vendor_version', ['operation_type'], unique=False)
op.create_index(op.f('ix_quickbooks_vendor_version_transaction_id'), 'quickbooks_vendor_version', ['transaction_id'], unique=False)
# quickbooks_exportable_invoice
op.create_table('quickbooks_exportable_invoice',
sa.Column('uuid', sa.String(length=32), nullable=False),
sa.Column('store_id', sa.String(length=4), nullable=True),
sa.Column('vendor_id', sa.String(length=14), nullable=True),
sa.Column('txn_id', sa.String(length=20), nullable=True),
sa.Column('invoice_number', sa.String(length=20), nullable=True),
sa.Column('invoice_date', sa.Date(), nullable=True),
sa.Column('invoice_total', sa.Numeric(precision=8, scale=2), nullable=False),
sa.Column('store_uuid', sa.String(length=32), nullable=True),
sa.Column('vendor_uuid', sa.String(length=32), nullable=True),
sa.Column('quickbooks_vendor_name', sa.String(length=100), nullable=True),
sa.Column('quickbooks_vendor_terms', sa.String(length=100), nullable=True),
sa.Column('quickbooks_bank_account', sa.String(length=100), nullable=True),
sa.Column('quickbooks_export_template', sa.String(length=100), nullable=True),
sa.Column('status_code', sa.Integer(), nullable=False),
sa.Column('status_text', sa.String(length=255), nullable=True),
sa.Column('deleted', sa.DateTime(), nullable=True),
sa.Column('deleted_by_uuid', sa.String(length=32), nullable=True),
sa.Column('exported', sa.DateTime(), nullable=True),
sa.Column('exported_by_uuid', sa.String(length=32), nullable=True),
sa.ForeignKeyConstraint(['deleted_by_uuid'], ['user.uuid'], name='quickbooks_exportable_invoice_fk_deleted_by'),
sa.ForeignKeyConstraint(['exported_by_uuid'], ['user.uuid'], name='quickbooks_exportable_invoice_fk_exported_by'),
sa.ForeignKeyConstraint(['store_uuid'], ['store.uuid'], name='quickbooks_exportable_invoice_fk_store'),
sa.ForeignKeyConstraint(['vendor_uuid'], ['vendor.uuid'], name='quickbooks_exportable_invoice_fk_vendor'),
sa.PrimaryKeyConstraint('uuid')
)
op.create_table('quickbooks_exportable_invoice_version',
sa.Column('uuid', sa.String(length=32), autoincrement=False, nullable=False),
sa.Column('store_id', sa.String(length=4), autoincrement=False, nullable=True),
sa.Column('vendor_id', sa.String(length=14), autoincrement=False, nullable=True),
sa.Column('txn_id', sa.String(length=20), autoincrement=False, nullable=True),
sa.Column('invoice_number', sa.String(length=20), autoincrement=False, nullable=True),
sa.Column('invoice_date', sa.Date(), autoincrement=False, nullable=True),
sa.Column('invoice_total', sa.Numeric(precision=8, scale=2), autoincrement=False, nullable=True),
sa.Column('store_uuid', sa.String(length=32), autoincrement=False, nullable=True),
sa.Column('vendor_uuid', sa.String(length=32), autoincrement=False, nullable=True),
sa.Column('quickbooks_vendor_name', sa.String(length=100), autoincrement=False, nullable=True),
sa.Column('quickbooks_vendor_terms', sa.String(length=100), autoincrement=False, nullable=True),
sa.Column('quickbooks_bank_account', sa.String(length=100), autoincrement=False, nullable=True),
sa.Column('quickbooks_export_template', sa.String(length=100), autoincrement=False, nullable=True),
sa.Column('status_code', sa.Integer(), autoincrement=False, nullable=True),
sa.Column('status_text', sa.String(length=255), autoincrement=False, nullable=True),
sa.Column('deleted', sa.DateTime(), autoincrement=False, nullable=True),
sa.Column('deleted_by_uuid', sa.String(length=32), autoincrement=False, nullable=True),
sa.Column('exported', sa.DateTime(), autoincrement=False, nullable=True),
sa.Column('exported_by_uuid', sa.String(length=32), autoincrement=False, nullable=True),
sa.Column('transaction_id', sa.BigInteger(), autoincrement=False, nullable=False),
sa.Column('end_transaction_id', sa.BigInteger(), nullable=True),
sa.Column('operation_type', sa.SmallInteger(), nullable=False),
sa.PrimaryKeyConstraint('uuid', 'transaction_id')
)
op.create_index(op.f('ix_quickbooks_exportable_invoice_version_end_transaction_id'), 'quickbooks_exportable_invoice_version', ['end_transaction_id'], unique=False)
op.create_index(op.f('ix_quickbooks_exportable_invoice_version_operation_type'), 'quickbooks_exportable_invoice_version', ['operation_type'], unique=False)
op.create_index(op.f('ix_quickbooks_exportable_invoice_version_transaction_id'), 'quickbooks_exportable_invoice_version', ['transaction_id'], unique=False)
# quickbooks_exportable_invoice_dist
op.create_table('quickbooks_exportable_invoice_dist',
sa.Column('uuid', sa.String(length=32), nullable=False),
sa.Column('invoice_uuid', sa.String(length=32), nullable=False),
sa.Column('department_id', sa.Integer(), nullable=False),
sa.Column('source_amount', sa.Numeric(precision=8, scale=2), nullable=False),
sa.Column('department_uuid', sa.String(length=32), nullable=True),
sa.Column('quickbooks_expense_account', sa.String(length=100), nullable=True),
sa.Column('quickbooks_expense_class', sa.String(length=100), nullable=True),
sa.Column('calculated_percent', sa.Numeric(precision=8, scale=3), nullable=True),
sa.Column('calculated_amount', sa.Numeric(precision=8, scale=2), nullable=True),
sa.Column('status_code', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['department_uuid'], ['department.uuid'], name='quickbooks_exportable_invoice_dist_fk_department'),
sa.ForeignKeyConstraint(['invoice_uuid'], ['quickbooks_exportable_invoice.uuid'], name='quickbooks_exportable_invoice_dist_fk_invoice'),
sa.PrimaryKeyConstraint('uuid')
)
# quickbooks_invoice_export
op.create_table('quickbooks_invoice_export',
sa.Column('uuid', sa.String(length=32), nullable=False),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('created', sa.DateTime(), nullable=False),
sa.Column('created_by_uuid', sa.String(length=32), nullable=False),
sa.Column('record_count', sa.Integer(), nullable=True),
sa.Column('filename', sa.String(length=255), nullable=True),
sa.ForeignKeyConstraint(['created_by_uuid'], ['user.uuid'], name='quickbooks_invoice_export_fk_created_by'),
sa.PrimaryKeyConstraint('uuid')
)
def downgrade():
# quickbooks_invoice_export
op.drop_table('quickbooks_invoice_export')
# quickbooks_exportable_invoice_dist
op.drop_table('quickbooks_exportable_invoice_dist')
# quickbooks_exportable_invoice_dist
op.drop_index(op.f('ix_quickbooks_exportable_invoice_version_transaction_id'), table_name='quickbooks_exportable_invoice_version')
op.drop_index(op.f('ix_quickbooks_exportable_invoice_version_operation_type'), table_name='quickbooks_exportable_invoice_version')
op.drop_index(op.f('ix_quickbooks_exportable_invoice_version_end_transaction_id'), table_name='quickbooks_exportable_invoice_version')
op.drop_table('quickbooks_exportable_invoice_version')
op.drop_table('quickbooks_exportable_invoice')
# quickbooks_vendor
op.drop_index(op.f('ix_quickbooks_vendor_version_transaction_id'), table_name='quickbooks_vendor_version')
op.drop_index(op.f('ix_quickbooks_vendor_version_operation_type'), table_name='quickbooks_vendor_version')
op.drop_index(op.f('ix_quickbooks_vendor_version_end_transaction_id'), table_name='quickbooks_vendor_version')
op.drop_table('quickbooks_vendor_version')
op.drop_table('quickbooks_vendor')
# quickbooks_department
op.drop_index(op.f('ix_quickbooks_department_version_transaction_id'), table_name='quickbooks_department_version')
op.drop_index(op.f('ix_quickbooks_department_version_operation_type'), table_name='quickbooks_department_version')
op.drop_index(op.f('ix_quickbooks_department_version_end_transaction_id'), table_name='quickbooks_department_version')
op.drop_table('quickbooks_department_version')
op.drop_table('quickbooks_department')
# quickbooks_store
op.drop_index(op.f('ix_quickbooks_store_version_transaction_id'), table_name='quickbooks_store_version')
op.drop_index(op.f('ix_quickbooks_store_version_operation_type'), table_name='quickbooks_store_version')
op.drop_index(op.f('ix_quickbooks_store_version_end_transaction_id'), table_name='quickbooks_store_version')
op.drop_table('quickbooks_store_version')
op.drop_table('quickbooks_store')

View file

@ -0,0 +1,32 @@
# -*- 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/>.
#
################################################################################
"""
Quickbooks integration data models
"""
from .stores import QuickbooksStore
from .org import QuickbooksDepartment
from .vendors import QuickbooksVendor
from .invoices import (QuickbooksExportableInvoice,
QuickbooksExportableInvoiceDistribution,
QuickbooksInvoiceExport)

View file

@ -0,0 +1,302 @@
# -*- 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/>.
#
################################################################################
"""
Invoice data models
"""
import sqlalchemy as sa
from sqlalchemy import orm
from rattail.db import model
from rattail.db.core import filename_column
from rattail.util import OrderedDict
class QuickbooksExportableInvoice(model.Base):
"""
Represents a vendor invoice capable of being exported to Quickbooks.
"""
__tablename__ = 'quickbooks_exportable_invoice'
__table_args__ = (
sa.ForeignKeyConstraint(['store_uuid'], ['store.uuid'],
name='quickbooks_exportable_invoice_fk_store'),
sa.ForeignKeyConstraint(['vendor_uuid'], ['vendor.uuid'],
name='quickbooks_exportable_invoice_fk_vendor'),
sa.ForeignKeyConstraint(['deleted_by_uuid'], ['user.uuid'],
name='quickbooks_exportable_invoice_fk_deleted_by'),
sa.ForeignKeyConstraint(['exported_by_uuid'], ['user.uuid'],
name='quickbooks_exportable_invoice_fk_exported_by'),
)
__versioned__ = {}
STATUS_NOT_YET_REFRESHED = 1
STATUS_EXPORTABLE = 2
STATUS_STORE_NOT_FOUND = 3
STATUS_VENDOR_NOT_FOUND = 4
STATUS_VENDOR_BAD_INFO = 5
STATUS_PO_NOT_FOUND = 6
STATUS_PO_BAD_INFO = 7
STATUS_DIST_PROBLEMS = 8
STATUS_DEPTS_IGNORED = 9
STATUS_EXPORTED = 10
STATUS_DELETED = 11
STATUS = OrderedDict([
(STATUS_NOT_YET_REFRESHED, "data not yet refreshed"),
(STATUS_EXPORTABLE, "exportable"),
(STATUS_STORE_NOT_FOUND, "store not found"),
(STATUS_VENDOR_NOT_FOUND, "vendor not found"),
(STATUS_VENDOR_BAD_INFO, "vendor info is invalid"),
(STATUS_PO_NOT_FOUND, "PO not found"),
(STATUS_PO_BAD_INFO, "PO info is invalid"),
(STATUS_DIST_PROBLEMS, "see distribution problem(s)"),
(STATUS_DEPTS_IGNORED, "all departments ignored"),
(STATUS_EXPORTED, "exported"),
(STATUS_DELETED, "deleted"),
])
uuid = model.uuid_column()
##################################################
# columns whose values come from source data
##################################################
store_id = sa.Column(sa.String(length=4), nullable=True, doc="""
ID string for the store which must pay the invoice.
""")
vendor_id = sa.Column(sa.String(length=14), nullable=True, doc="""
ID string for the vendor which sent the invoice.
""")
txn_id = sa.Column(sa.String(length=20), nullable=True, doc="""
ID string for the transaction represented by the invoice, if
applicable.
""")
invoice_number = sa.Column(sa.String(length=20), nullable=True, doc="""
Invoice number, per source data.
""")
invoice_date = sa.Column(sa.Date(), nullable=True, doc="""
Date of the invoice, per source data.
""")
invoice_total = sa.Column(sa.Numeric(precision=8, scale=2), nullable=False, doc="""
Total amount for the invoice, per source data.
""")
##################################################
# columns whose values come from data refresh
##################################################
store_uuid = sa.Column(sa.String(length=32), nullable=True)
store = orm.relationship(
model.Store,
doc="""
Reference to the :class:`rattail:~rattail.db.model.Store`
instance associated with the invoice, or ``None``.
""")
vendor_uuid = sa.Column(sa.String(length=32), nullable=True)
vendor = orm.relationship(
model.Vendor,
doc="""
Reference to the vendor associated with the invoice, or
``None``.
""",
backref=orm.backref(
'dtail_qbo_invoices',
cascade='all'))
quickbooks_vendor_name = sa.Column(sa.String(length=100), nullable=True, doc="""
Quickbooks name for the invoice vendor.
""")
quickbooks_vendor_terms = sa.Column(sa.String(length=100), nullable=True, doc="""
Quickbooks terms for the invoice vendor.
""")
quickbooks_bank_account = sa.Column(sa.String(length=100), nullable=True, doc="""
Quickbooks bank account for the invoice vendor.
""")
quickbooks_export_template = sa.Column(sa.String(length=100), nullable=True, doc="""
Name of the Quickbooks export template to use for this invoice.
""")
status_code = sa.Column(sa.Integer(), nullable=False, doc="""
Status code for the invoice; indicates whether it's exportable etc.
""")
status_text = sa.Column(sa.String(length=255), nullable=True, doc="""
Extra text relating to the invoice status, if applicable.
""")
##################################################
# other columns
##################################################
deleted = sa.Column(sa.DateTime(), nullable=True, doc="""
Timestamp when the invoice was marked as deleted, or ``None``.
""")
deleted_by_uuid = sa.Column(sa.String(length=32), nullable=True)
deleted_by = orm.relationship(
model.User,
primaryjoin='User.uuid == QuickbooksExportableInvoice.deleted_by_uuid',
doc="""
Reference to the :class:`rattail:~rattail.db.model.User`
instance who marked the invoice as deleted, or ``None``.
""")
exported = sa.Column(sa.DateTime(), nullable=True, doc="""
Timestamp when the invoice was exported, or ``None``.
""")
exported_by_uuid = sa.Column(sa.String(length=32), nullable=True)
exported_by = orm.relationship(
model.User,
primaryjoin='User.uuid == QuickbooksExportableInvoice.exported_by_uuid',
doc="""
Reference to the :class:`rattail:~rattail.db.model.User`
instance who exported the invoice, or ``None``.
""")
def __str__(self):
return "{}, {}, {} (trans. {})".format(self.store_id,
self.vendor_id,
self.invoice_number,
self.txn_id)
def add_distribution(self, **kwargs):
dist = QuickbooksExportableInvoiceDistribution(**kwargs)
if not dist.status_code:
dist.status_code = dist.STATUS_NOT_YET_REFRESHED
self.distributions.append(dist)
class QuickbooksExportableInvoiceDistribution(model.Base):
"""
Represents a "distribution" for a department, within the context
of a vendor invoice which is to be exported to Quickbooks.
"""
__tablename__ = 'quickbooks_exportable_invoice_dist'
__table_args__ = (
sa.ForeignKeyConstraint(['invoice_uuid'], ['quickbooks_exportable_invoice.uuid'],
name='quickbooks_exportable_invoice_dist_fk_invoice'),
sa.ForeignKeyConstraint(['department_uuid'], ['department.uuid'],
name='quickbooks_exportable_invoice_dist_fk_department'),
)
STATUS_NOT_YET_REFRESHED = 1
STATUS_EXPORTABLE = 2
STATUS_DEPT_NOT_FOUND = 3
STATUS_DEPT_IGNORED = 4
STATUS_DEPT_BAD_INFO = 5
STATUS_EXPORTED = 6
STATUS = OrderedDict([
(STATUS_NOT_YET_REFRESHED, "data not yet refreshed"),
(STATUS_EXPORTABLE, "exportable"),
(STATUS_DEPT_NOT_FOUND, "department not found"),
(STATUS_DEPT_IGNORED, "department ignored"),
(STATUS_DEPT_BAD_INFO, "department info is invalid"),
(STATUS_EXPORTED, "exported"),
])
uuid = model.uuid_column()
invoice_uuid = sa.Column(sa.String(length=32), nullable=False)
invoice = orm.relationship(
QuickbooksExportableInvoice,
doc="""
Reference to the parent invoice.
""",
backref=orm.backref(
'distributions',
cascade='all',
doc="""
Sequence of
:class:`QuickbooksExportableInvoiceDistribution` instances
which belong to the invoice.
"""))
##################################################
# columns whose values come from source data
##################################################
department_id = sa.Column(sa.Integer(), nullable=False, doc="""
Department ID for the distribution, per source data.
""")
source_amount = sa.Column(sa.Numeric(precision=8, scale=2), nullable=False, doc="""
Dollar amount for the distribution, per source data.
""")
##################################################
# columns whose values come from data refresh
##################################################
department_uuid = sa.Column(sa.String(length=32), nullable=True)
department = orm.relationship(
model.Department,
doc="""
Reference to the :class:`rattail:~rattail.db.model.Department`
instance associated with the distribution, or ``None``.
""")
quickbooks_expense_account = sa.Column(sa.String(length=100), nullable=True, doc="""
Quickbooks expense account for the department.
""")
quickbooks_expense_class = sa.Column(sa.String(length=100), nullable=True, doc="""
Quickbooks expense class for the department.
""")
calculated_percent = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
Percentage of the invoice total which should be considered
attributable to the current distribution (department). This is
calculated after taking "ignored" departments into consideration,
etc.
""")
calculated_amount = sa.Column(sa.Numeric(precision=8, scale=2), nullable=True, doc="""
Dollar amount for the distribution, per business logic.
""")
status_code = sa.Column(sa.Integer(), nullable=False, doc="""
Status code for the distribution; indicates whether it's
exportable etc.
""")
class QuickbooksInvoiceExport(model.ExportMixin, model.Base):
"""
Invoice export file, for *consumption* by Quickbooks.
"""
__tablename__ = 'quickbooks_invoice_export'
filename = filename_column(nullable=True, doc="""
Filename for the export.
""")

View file

@ -0,0 +1,69 @@
# -*- 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/>.
#
################################################################################
"""
Organizational data model extensions
"""
import sqlalchemy as sa
from sqlalchemy import orm
from rattail.db import model
class QuickbooksDepartment(model.Base):
"""
Quickbooks extensions to core Department model
"""
__tablename__ = 'quickbooks_department'
__table_args__ = (
sa.ForeignKeyConstraint(['uuid'], ['department.uuid'],
name='quickbooks_department_fk_department'),
)
__versioned__ = {}
uuid = model.uuid_column(default=None)
department = orm.relationship(
model.Department,
doc="""
Department to which this extension record pertains.
""",
backref=orm.backref(
'_quickbooks',
uselist=False,
cascade='all, delete-orphan',
doc="""
Quickbooks extension record for the department.
"""))
quickbooks_expense_account = sa.Column(sa.String(length=100), nullable=True, doc="""
Quickbooks "expense account" for the department.
""")
quickbooks_expense_class = sa.Column(sa.String(length=100), nullable=True, doc="""
Quickbooks "expense class" for the department.
""")
QuickbooksDepartment.make_proxy(model.Department, '_quickbooks', 'quickbooks_expense_account')
QuickbooksDepartment.make_proxy(model.Department, '_quickbooks', 'quickbooks_expense_class')

View file

@ -0,0 +1,64 @@
# -*- 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/>.
#
################################################################################
"""
Store data model extensions
"""
import sqlalchemy as sa
from sqlalchemy import orm
from rattail.db import model
class QuickbooksStore(model.Base):
"""
Quickbooks extensions to core Store model
"""
__tablename__ = 'quickbooks_store'
__table_args__ = (
sa.ForeignKeyConstraint(['uuid'], ['store.uuid'],
name='quickbooks_store_fk_store'),
)
__versioned__ = {}
uuid = model.uuid_column(default=None)
store = orm.relationship(
model.Store,
doc="""
Store to which this extension record pertains.
""",
backref=orm.backref(
'_quickbooks',
uselist=False,
cascade='all, delete-orphan',
doc="""
Quickbooks extension record for the store.
"""))
quickbooks_location = sa.Column(sa.String(length=100), nullable=True, doc="""
Quickbooks "location" for the store.
""")
QuickbooksStore.make_proxy(model.Store, '_quickbooks', 'quickbooks_location')

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/>.
#
################################################################################
"""
Vendor data model extensions
"""
import sqlalchemy as sa
from sqlalchemy import orm
from rattail.db import model
class QuickbooksVendor(model.Base):
"""
Quickbooks extensions to core Vendor model
"""
__tablename__ = 'quickbooks_vendor'
__table_args__ = (
sa.ForeignKeyConstraint(['uuid'], ['vendor.uuid'],
name='quickbooks_vendor_fk_vendor'),
)
__versioned__ = {}
uuid = model.uuid_column(default=None)
vendor = orm.relationship(
model.Vendor,
doc="""
Vendor to which this extension record pertains.
""",
backref=orm.backref(
'_quickbooks',
uselist=False,
cascade='all, delete-orphan',
doc="""
Quickbooks extension record for the vendor.
"""))
quickbooks_name = sa.Column(sa.String(length=100), nullable=True, doc="""
Quickbooks "name" for the vendor.
""")
quickbooks_bank_account = sa.Column(sa.String(length=100), nullable=True, doc="""
Quickbooks "bank account" for the vendor.
""")
quickbooks_terms = sa.Column(sa.String(length=100), nullable=True, doc="""
Quickbooks "terms" for the vendor.
""")
QuickbooksVendor.make_proxy(model.Vendor, '_quickbooks', 'quickbooks_name')
QuickbooksVendor.make_proxy(model.Vendor, '_quickbooks', 'quickbooks_bank_account')
QuickbooksVendor.make_proxy(model.Vendor, '_quickbooks', 'quickbooks_terms')

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/>.
#
################################################################################
"""
rattail-quickbooks importing
"""
from . import model

View file

@ -0,0 +1,70 @@
# -*- 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/>.
#
################################################################################
"""
rattail-quickbooks model importers
"""
from rattail import importing
##############################
# core importer overrides
##############################
class DepartmentImporter(importing.model.DepartmentImporter):
extension_attr = '_quickbooks'
extension_fields = [
'quickbooks_expense_account',
'quickbooks_expense_class',
]
class VendorImporter(importing.model.VendorImporter):
extension_attr = '_quickbooks'
extension_fields = [
'quickbooks_name',
'quickbooks_bank_account',
'quickbooks_terms',
]
##############################
# custom models
##############################
class QuickbooksExportableInvoiceImporter(importing.model.ToRattail):
def get_model_class(self):
return self.model.QuickbooksExportableInvoice
def cache_query(self):
query = super(QuickbooksExportableInvoiceImporter, self).cache_query()
model = self.model
# TODO: possibly should filter this way only if config says so?
if self.start_date:
query = query.filter(model.QuickbooksExportableInvoice.invoice_date >= self.start_date)
if self.end_date:
query = query.filter(model.QuickbooksExportableInvoice.invoice_date <= self.end_date)
return query

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/>.
#
################################################################################
"""
Rattail -> Rattail "versions" import w/ Quickbooks schema
"""
from rattail.importing import versions as base
class QuickbooksVersionMixin(object):
def add_quickbooks_importers(self, importers):
importers['QuickbooksExportableInvoiceImporter'] = QuickbooksExportableInvoiceImporter
return importers
class QuickbooksExportableInvoiceImporter(base.VersionImporter):
@property
def host_model_class(self):
return self.model.QuickbooksExportableInvoice

95
setup.py Normal file
View file

@ -0,0 +1,95 @@
# -*- 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/>.
#
################################################################################
"""
rattail-quickbooks setup script
"""
import os
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
exec(open(os.path.join(here, 'rattail_quickbooks', '_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.246
]
setup(
name = "rattail-quickbooks",
version = __version__,
author = "Lance Edgar",
author_email = "lance@edbob.org",
url = "https://rattailproject.org/",
description = "Rattail integration package for Quickbooks",
long_description = README,
classifiers = [
'Development Status :: 3 - Alpha',
'Environment :: Console',
'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,
)

46
tasks.py Normal file
View file

@ -0,0 +1,46 @@
# -*- 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 rattail-quickbooks
"""
import os
from invoke import task
here = os.path.abspath(os.path.dirname(__file__))
exec(open(os.path.join(here, 'rattail_quickbooks', '_version.py')).read())
@task
def release(c):
"""
Release a new version of rattail-quickbooks
"""
# rebuild local tar.gz file for distribution
c.run('rm -rf rattail_quickbooks.egg-info')
c.run('python setup.py sdist --formats=gztar')
filename = 'rattail-quickbooks-{}.tar.gz'.format(__version__)
c.run('twine upload dist/{}'.format(filename))