diff --git a/rattail/db/alembic/versions/5b393c108673_add_product_volatile.py b/rattail/db/alembic/versions/5b393c108673_add_product_volatile.py new file mode 100644 index 0000000000000000000000000000000000000000..1a2b0575104414bc2b8ff9cdda208b820a47ec29 --- /dev/null +++ b/rattail/db/alembic/versions/5b393c108673_add_product_volatile.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8; -*- +"""add product_volatile + +Revision ID: 5b393c108673 +Revises: 6118198dc4db +Create Date: 2019-03-08 13:14:11.645892 + +""" + +from __future__ import unicode_literals, absolute_import + +# revision identifiers, used by Alembic. +revision = '5b393c108673' +down_revision = '6118198dc4db' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa +import rattail.db.types + + + +def upgrade(): + + # product_volatile + op.create_table('product_volatile', + sa.Column('uuid', sa.String(length=32), nullable=False), + sa.Column('product_uuid', sa.String(length=32), nullable=False), + sa.Column('true_cost', sa.Numeric(precision=9, scale=5), nullable=True), + sa.Column('true_margin', sa.Numeric(precision=8, scale=5), nullable=True), + sa.ForeignKeyConstraint(['product_uuid'], ['product.uuid'], name='product_volatile_fk_product'), + sa.PrimaryKeyConstraint('uuid') + ) + + +def downgrade(): + + # product_volatile + op.drop_table('product_volatile') diff --git a/rattail/db/model/__init__.py b/rattail/db/model/__init__.py index 4837a7c07512b9ce5d5ab2d34c89532553ae43c7..14d3f02b70b9db38488e35378f75eda61683e293 100644 --- a/rattail/db/model/__init__.py +++ b/rattail/db/model/__init__.py @@ -44,7 +44,8 @@ from .shifts import ScheduledShift, WorkedShift from .vendors import Vendor, VendorPhoneNumber, VendorEmailAddress, VendorContact from .products import (Brand, Tax, Product, ProductImage, ProductCode, ProductCost, ProductFutureCost, ProductPrice, - ProductInventory, ProductStoreInfo, InventoryAdjustmentReason) + ProductInventory, ProductStoreInfo, ProductVolatile, + InventoryAdjustmentReason) from .purchase import (PurchaseBase, PurchaseItemBase, PurchaseCreditBase, Purchase, PurchaseItem, PurchaseCredit) diff --git a/rattail/db/model/products.py b/rattail/db/model/products.py index 11a22f22a8a7c6cfa51469d1534d52f60698e1f9..e7cc4c639614f399a4f5e4c3633b69f23f955daf 100644 --- a/rattail/db/model/products.py +++ b/rattail/db/model/products.py @@ -845,6 +845,53 @@ class ProductStoreInfo(Base): """) +class ProductVolatile(Base): + """ + This is the place to find "volatile" data for a given product, or at least + it should be... As of this writing there are a couple other places to look + but hopefully this table can eventually be "the" place. + + Whether any given value in a given record, applies to the "current" app + node only, or if it applies to all nodes, is up to app logic. + + Note that a custom app should (most likely) *not* bother "extending" this + table, but rather should create a separate table with similar pattern. + """ + __tablename__ = 'product_volatile' + __table_args__ = ( + sa.ForeignKeyConstraint(['product_uuid'], ['product.uuid'], name='product_volatile_fk_product'), + ) + + uuid = uuid_column() + + product_uuid = sa.Column(sa.String(length=32), nullable=False) + product = orm.relationship( + Product, + doc=""" + Product to which this "volatile" data record pertains. + """, + backref=orm.backref( + 'volatile', + uselist=False, + cascade='all, delete-orphan', + doc=""" + "Volatile" data record for the product, if any. + """)) + + true_cost = sa.Column(sa.Numeric(precision=9, scale=5), nullable=True, doc=""" + "True" unit cost for the item, if known. This might include certain + "allowances" (discounts) currently in effect etc.; really anything which + might not be reflected in "official" unit cost for the product. Usually, + this value is quite easily calculated and so this field serves as more of + a cache, for sake of SQL access to the values. + """) + + true_margin = sa.Column(sa.Numeric(precision=8, scale=5), nullable=True, doc=""" + "True" profit margin for the "regular" unit price vs. the "true" unit cost + (:attr:`true_cost`). + """) + + @six.python_2_unicode_compatible class InventoryAdjustmentReason(Base): """ diff --git a/rattail/importing/model.py b/rattail/importing/model.py index c54b996bf11d9b9fcbd8aae50d382c55ea55d1ba..d4c5cf03f27e8f34fa512dfcfe9bb7c8cf07c86b 100644 --- a/rattail/importing/model.py +++ b/rattail/importing/model.py @@ -2242,6 +2242,13 @@ class ProductStoreInfoImporter(ToRattail): model_class = model.ProductStoreInfo +class ProductVolatileImporter(ToRattail): + """ + Data importer for :class:`~rattail.db.model.products.ProductVolatile`. + """ + model_class = model.ProductVolatile + + class LabelProfileImporter(ToRattail): """ Importer for LabelProfile data diff --git a/rattail/importing/rattail.py b/rattail/importing/rattail.py index b76437db65744e36937f8326be5f50f868ff6fdf..8c201874059f9aac956f68aa3601cac6f68276e0 100644 --- a/rattail/importing/rattail.py +++ b/rattail/importing/rattail.py @@ -112,6 +112,7 @@ class FromRattailToRattailBase(object): importers['ProductCost'] = ProductCostImporter importers['ProductPrice'] = ProductPriceImporter importers['ProductStoreInfo'] = ProductStoreInfoImporter + importers['ProductVolatile'] = ProductVolatileImporter importers['ProductImage'] = ProductImageImporter importers['LabelProfile'] = LabelProfileImporter return importers @@ -364,6 +365,9 @@ class ProductPriceImporter(FromRattail, model.ProductPriceImporter): class ProductStoreInfoImporter(FromRattail, model.ProductStoreInfoImporter): pass +class ProductVolatileImporter(FromRattail, model.ProductVolatileImporter): + pass + class ProductImageImporter(FromRattail, model.ProductImageImporter): """