From cf90ca57043034900fe90b58a5075e47d62fcb8c Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 7 Oct 2023 16:28:12 -0500 Subject: [PATCH] Add importer for tax rates from CORE --- .../versions/673ff7088d35_add_corepos_tax.py | 51 +++++++++++++++++++ rattail_corepos/db/model/__init__.py | 2 +- rattail_corepos/db/model/stores.py | 35 +++++++++++++ rattail_corepos/importing/corepos/db.py | 26 ++++++++++ rattail_corepos/importing/model.py | 9 ++++ 5 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 rattail_corepos/db/alembic/versions/673ff7088d35_add_corepos_tax.py diff --git a/rattail_corepos/db/alembic/versions/673ff7088d35_add_corepos_tax.py b/rattail_corepos/db/alembic/versions/673ff7088d35_add_corepos_tax.py new file mode 100644 index 0000000..ec087de --- /dev/null +++ b/rattail_corepos/db/alembic/versions/673ff7088d35_add_corepos_tax.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8; -*- +"""add corepos_tax + +Revision ID: 673ff7088d35 +Revises: 1f2e2f57c90b +Create Date: 2023-10-06 21:01:01.105790 + +""" + +# revision identifiers, used by Alembic. +revision = '673ff7088d35' +down_revision = '1f2e2f57c90b' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa +import rattail.db.types + + + +def upgrade(): + + # corepos_tax + op.create_table('corepos_tax', + sa.Column('uuid', sa.String(length=32), nullable=False), + sa.Column('corepos_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['uuid'], ['tax.uuid'], name='corepos_tax_fk_tax'), + sa.PrimaryKeyConstraint('uuid') + ) + op.create_table('corepos_tax_version', + sa.Column('uuid', sa.String(length=32), autoincrement=False, nullable=False), + sa.Column('corepos_id', sa.Integer(), 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_corepos_tax_version_end_transaction_id'), 'corepos_tax_version', ['end_transaction_id'], unique=False) + op.create_index(op.f('ix_corepos_tax_version_operation_type'), 'corepos_tax_version', ['operation_type'], unique=False) + op.create_index(op.f('ix_corepos_tax_version_transaction_id'), 'corepos_tax_version', ['transaction_id'], unique=False) + + +def downgrade(): + + # corepos_tax + op.drop_index(op.f('ix_corepos_tax_version_transaction_id'), table_name='corepos_tax_version') + op.drop_index(op.f('ix_corepos_tax_version_operation_type'), table_name='corepos_tax_version') + op.drop_index(op.f('ix_corepos_tax_version_end_transaction_id'), table_name='corepos_tax_version') + op.drop_table('corepos_tax_version') + op.drop_table('corepos_tax') diff --git a/rattail_corepos/db/model/__init__.py b/rattail_corepos/db/model/__init__.py index 72a241c..5a8a4e4 100644 --- a/rattail_corepos/db/model/__init__.py +++ b/rattail_corepos/db/model/__init__.py @@ -24,7 +24,7 @@ Database schema extensions for CORE-POS integration """ -from .stores import CoreStore, CoreTender +from .stores import CoreStore, CoreTax, CoreTender from .people import (CorePerson, CoreEmployee, CoreCustomer, CoreCustomerShopper, CoreMember, CoreMemberEquityPayment) diff --git a/rattail_corepos/db/model/stores.py b/rattail_corepos/db/model/stores.py index 3ad90f9..f16a96d 100644 --- a/rattail_corepos/db/model/stores.py +++ b/rattail_corepos/db/model/stores.py @@ -65,6 +65,41 @@ class CoreStore(model.Base): CoreStore.make_proxy(model.Store, '_corepos', 'corepos_id') +class CoreTax(model.Base): + """ + CORE-specific extensions to :class:`rattail:rattail.db.model.Tax`. + """ + __tablename__ = 'corepos_tax' + __table_args__ = ( + sa.ForeignKeyConstraint(['uuid'], ['tax.uuid'], + name='corepos_tax_fk_tax'), + ) + __versioned__ = {} + + uuid = model.uuid_column(default=None) + tax = orm.relationship( + model.Tax, + doc=""" + Reference to the actual tax record, which this one extends. + """, + backref=orm.backref( + '_corepos', + uselist=False, + cascade='all, delete-orphan', + doc=""" + Reference to the CORE-POS extension record for this tax. + """)) + + corepos_id = sa.Column(sa.Integer(), nullable=False, doc=""" + ``taxrates.id`` value for this tax, within CORE-POS. + """) + + def __str__(self): + return str(self.tax) + +CoreTax.make_proxy(model.Tax, '_corepos', 'corepos_id') + + class CoreTender(model.Base): """ CORE-specific extensions to :class:`rattail:rattail.db.model.Tender`. diff --git a/rattail_corepos/importing/corepos/db.py b/rattail_corepos/importing/corepos/db.py index 847daf9..62fc6c5 100644 --- a/rattail_corepos/importing/corepos/db.py +++ b/rattail_corepos/importing/corepos/db.py @@ -67,6 +67,7 @@ class FromCOREPOSToRattail(importing.FromSQLAlchemyHandler, importing.ToRattailH def get_importers(self): importers = OrderedDict() importers['Employee'] = EmployeeImporter + importers['Tax'] = TaxImporter importers['Tender'] = TenderImporter importers['Vendor'] = VendorImporter importers['Department'] = DepartmentImporter @@ -114,6 +115,28 @@ class EmployeeImporter(FromCOREPOS, corepos_importing.model.EmployeeImporter): } +class TaxImporter(FromCOREPOS, corepos_importing.model.TaxImporter): + """ + Importer for tax data from CORE POS. + """ + host_model_class = corepos.TaxRate + key = 'corepos_id' + supported_fields = [ + 'corepos_id', + 'code', + 'description', + 'rate', + ] + + def normalize_host_object(self, tax): + return { + 'corepos_id': tax.id, + 'code': str(tax.id), + 'description': tax.description, + 'rate': decimal.Decimal(str(tax.rate * 100)), + } + + class TenderImporter(FromCOREPOS, corepos_importing.model.TenderImporter): """ Importer for tender data from CORE POS. @@ -253,6 +276,7 @@ class ProductImporter(FromCOREPOS, corepos_importing.model.ProductImporter): 'regular_price_type', 'food_stampable', # 'tax1', + 'tax_code', ] def normalize_host_object(self, product): @@ -286,6 +310,8 @@ class ProductImporter(FromCOREPOS, corepos_importing.model.ProductImporter): 'regular_price_price': price, 'regular_price_multiple': 1 if price is not None else None, 'regular_price_type': self.enum.PRICE_TYPE_REGULAR if price is not None else None, + + 'tax_code': str(product.tax_rate.id) if product.tax_rate_id else None, } if self.fields_active(self.size_fields): diff --git a/rattail_corepos/importing/model.py b/rattail_corepos/importing/model.py index f39775e..5f42827 100644 --- a/rattail_corepos/importing/model.py +++ b/rattail_corepos/importing/model.py @@ -131,6 +131,15 @@ class SubdepartmentImporter(importing.model.SubdepartmentImporter): } +class TaxImporter(importing.model.TaxImporter): + + extensions = { + '_corepos': [ + 'corepos_id', + ], + } + + class TenderImporter(importing.model.TenderImporter): extensions = {