Add generic "products" batch type, can convert to labels or pricing batch
This commit is contained in:
parent
8fa7c6e732
commit
437230b958
|
@ -193,8 +193,7 @@ class HandheldBatchHandler(BatchHandler):
|
|||
default='rattail.batch.inventory:InventoryBatchHandler')
|
||||
session = orm.object_session(handheld_batches[0])
|
||||
batch = handler.make_batch(session, created_by=user, handheld_batches=handheld_batches)
|
||||
handler.populate(batch, progress=progress)
|
||||
batch.rowcount = len(batch.active_rows())
|
||||
handler.do_populate(batch, user, progress=progress)
|
||||
return batch
|
||||
|
||||
def make_label_batch(self, handheld_batches, user, progress=None):
|
||||
|
@ -202,6 +201,5 @@ class HandheldBatchHandler(BatchHandler):
|
|||
default='rattail.batch.labels:LabelBatchHandler')
|
||||
session = orm.object_session(handheld_batches[0])
|
||||
batch = handler.make_batch(session, created_by=user, handheld_batches=handheld_batches)
|
||||
handler.populate(batch, progress=progress)
|
||||
batch.rowcount = len(batch.active_rows())
|
||||
handler.do_populate(batch, user, progress=progress)
|
||||
return batch
|
||||
|
|
|
@ -87,35 +87,42 @@ class LabelBatchHandler(BatchHandler):
|
|||
"""
|
||||
Pre-fill batch with row data from handheld batch, etc.
|
||||
"""
|
||||
assert batch.handheld_batch or batch.filename or batch.products
|
||||
session = orm.object_session(batch)
|
||||
if batch.label_profile:
|
||||
self.label_profile = batch.label_profile
|
||||
else:
|
||||
self.label_profile = self.get_label_profile(session)
|
||||
self.setup_populate(batch, progress=progress)
|
||||
|
||||
if hasattr(batch, 'product_batch') and batch.product_batch:
|
||||
self.populate_from_product_batch(batch, progress=progress)
|
||||
return
|
||||
|
||||
assert batch.handheld_batch or batch.filename or batch.products
|
||||
label_code = self.label_profile.code if self.label_profile else None
|
||||
|
||||
def append(item, i):
|
||||
row = model.LabelBatchRow()
|
||||
row.label_code = self.label_profile.code if self.label_profile else None
|
||||
row.label_code = label_code
|
||||
row.label_profile = self.label_profile
|
||||
with session.no_autoflush:
|
||||
if isinstance(item, model.Product):
|
||||
row.product = item
|
||||
row.upc = row.product.upc
|
||||
row.label_quantity = 1
|
||||
if batch.static_prices and hasattr(item, '_batch_price'):
|
||||
row.regular_price = item._batch_price
|
||||
else: # item is handheld batch row
|
||||
row.upc = item.upc
|
||||
row.product = item.product
|
||||
row.label_quantity = item.units or 1
|
||||
# copy these in case product is null
|
||||
row.item_entry = item.item_entry
|
||||
row.item_id = item.item_id
|
||||
row.upc = item.upc
|
||||
row.brand_name = item.brand_name
|
||||
row.description = item.description
|
||||
row.size = item.size
|
||||
batch.add_row(row)
|
||||
self.refresh_row(row)
|
||||
self.add_row(batch, row)
|
||||
if i % 200 == 0:
|
||||
session.flush()
|
||||
|
||||
if batch.handheld_batch:
|
||||
data = batch.handheld_batch.active_rows()
|
||||
|
@ -131,6 +138,28 @@ class LabelBatchHandler(BatchHandler):
|
|||
self.progress_loop(append, data, progress,
|
||||
message="Adding initial rows to batch")
|
||||
|
||||
def populate_from_product_batch(self, batch, progress=None):
|
||||
"""
|
||||
Populate label batch from product batch.
|
||||
"""
|
||||
session = orm.object_session(batch)
|
||||
product_batch = batch.product_batch
|
||||
label_code = self.label_profile.code if self.label_profile else None
|
||||
|
||||
def add(prow, i):
|
||||
row = model.LabelBatchRow()
|
||||
row.label_code = label_code
|
||||
row.label_profile = self.label_profile
|
||||
row.label_quantity = 1
|
||||
with session.no_autoflush:
|
||||
row.product = prow.product
|
||||
self.add_row(batch, row)
|
||||
if i % 200 == 0:
|
||||
session.flush()
|
||||
|
||||
self.progress_loop(add, product_batch.active_rows(), progress,
|
||||
message="Adding initial rows to batch")
|
||||
|
||||
def set_options_from_file(self, batch):
|
||||
"""
|
||||
Set various batch options, if any are present within the data file.
|
||||
|
@ -211,14 +240,19 @@ class LabelBatchHandler(BatchHandler):
|
|||
Inspect a row from the source data and populate additional attributes
|
||||
for it, according to what we find in the database.
|
||||
"""
|
||||
if not row.product and row.upc:
|
||||
if not row.product:
|
||||
session = orm.object_session(row)
|
||||
if row.item_entry:
|
||||
row.product = self.locate_product_for_entry(session, row.item_entry)
|
||||
if not row.product and row.upc:
|
||||
row.product = api.get_product_by_upc(session, row.upc)
|
||||
if not row.product:
|
||||
row.status_code = row.STATUS_PRODUCT_NOT_FOUND
|
||||
return
|
||||
|
||||
product = row.product
|
||||
row.item_id = product.item_id
|
||||
row.upc = product.upc
|
||||
row.brand_name = six.text_type(product.brand or '')
|
||||
row.description = product.description
|
||||
row.size = product.size
|
||||
|
|
|
@ -60,6 +60,10 @@ class PricingBatchHandler(BatchHandler):
|
|||
if batch.input_filename:
|
||||
return self.populate_from_file(batch, progress=progress)
|
||||
|
||||
if hasattr(batch, 'product_batch') and batch.product_batch:
|
||||
self.populate_from_product_batch(batch, progress=progress)
|
||||
return
|
||||
|
||||
assert batch.products
|
||||
session = orm.object_session(batch)
|
||||
|
||||
|
@ -97,6 +101,25 @@ class PricingBatchHandler(BatchHandler):
|
|||
self.progress_loop(append, excel_rows, progress,
|
||||
message="Adding initial rows to batch")
|
||||
|
||||
def populate_from_product_batch(self, batch, progress=None):
|
||||
"""
|
||||
Populate pricing batch from product batch.
|
||||
"""
|
||||
session = orm.object_session(batch)
|
||||
product_batch = batch.product_batch
|
||||
|
||||
def add(prow, i):
|
||||
row = model.PricingBatchRow()
|
||||
row.item_entry = prow.item_entry
|
||||
with session.no_autoflush:
|
||||
row.product = prow.product
|
||||
self.add_row(batch, row)
|
||||
if i % 200 == 0:
|
||||
session.flush()
|
||||
|
||||
self.progress_loop(add, product_batch.active_rows(), progress,
|
||||
message="Adding initial rows to batch")
|
||||
|
||||
def refresh_row(self, row):
|
||||
"""
|
||||
Inspect a row from the source data and populate additional attributes
|
||||
|
|
134
rattail/batch/product.py
Normal file
134
rattail/batch/product.py
Normal file
|
@ -0,0 +1,134 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2019 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/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Handler for generic product batches
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from sqlalchemy import orm
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.batch import BatchHandler, get_batch_handler
|
||||
|
||||
|
||||
class ProductBatchHandler(BatchHandler):
|
||||
"""
|
||||
Handler for generic product batches.
|
||||
"""
|
||||
batch_model_class = model.ProductBatch
|
||||
|
||||
def should_populate(self, batch):
|
||||
if batch.input_filename:
|
||||
return True
|
||||
return False
|
||||
|
||||
def populate(self, batch, progress=None):
|
||||
if batch.input_filename:
|
||||
return self.populate_from_file(batch, progress=progress)
|
||||
|
||||
def populate_from_file(self, batch, progress=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def refresh_row(self, row):
|
||||
if not row.product:
|
||||
if not row.item_entry:
|
||||
row.status_code = row.STATUS_MISSING_KEY
|
||||
return
|
||||
|
||||
session = orm.object_session(row)
|
||||
row.product = self.locate_product_for_entry(session, row.item_entry)
|
||||
if not row.product:
|
||||
row.status_code = row.STATUS_PRODUCT_NOT_FOUND
|
||||
return
|
||||
|
||||
product = row.product
|
||||
row.upc = product.upc
|
||||
row.item_id = product.item_id
|
||||
row.brand_name = product.brand.name if product.brand else None
|
||||
row.description = product.description
|
||||
row.size = product.size
|
||||
|
||||
dept = product.department
|
||||
row.department = dept
|
||||
row.department_number = dept.number if dept else None
|
||||
row.department_name = dept.name if dept else None
|
||||
|
||||
subdept = product.subdepartment
|
||||
row.subdepartment = subdept
|
||||
row.subdepartment_number = subdept.number if subdept else None
|
||||
row.subdepartment_name = subdept.name if subdept else None
|
||||
|
||||
cost = product.cost
|
||||
row.vendor = cost.vendor if cost else None
|
||||
row.vendor_item_code = cost.code if cost else None
|
||||
row.regular_cost = cost.unit_cost if cost else None
|
||||
row.current_cost = cost.discount_cost if cost else None
|
||||
row.current_cost_starts = cost.discount_starts if row.current_cost else None
|
||||
row.current_cost_ends = cost.discount_ends if row.current_cost else None
|
||||
|
||||
regprice = product.regular_price
|
||||
curprice = product.current_price
|
||||
sugprice = product.suggested_price
|
||||
row.regular_price = regprice.price if regprice else None
|
||||
row.current_price = curprice.price if curprice else None
|
||||
row.current_price_starts = curprice.starts if curprice else None
|
||||
row.current_price_ends = curprice.ends if curprice else None
|
||||
row.suggested_price = sugprice.price if sugprice else None
|
||||
|
||||
row.status_code = row.STATUS_OK
|
||||
|
||||
def execute(self, batch, user=None, action='make_label_batch', progress=None, **kwargs):
|
||||
|
||||
if action == 'make_label_batch':
|
||||
result = self.make_label_batch(batch, user, progress=progress)
|
||||
|
||||
elif action == 'make_pricing_batch':
|
||||
result = self.make_pricing_batch(batch, user, progress=progress)
|
||||
|
||||
else:
|
||||
raise RuntimeError("Batch execution action is not supported: {}".format(action))
|
||||
|
||||
return result
|
||||
|
||||
def make_label_batch(self, product_batch, user, progress=None):
|
||||
handler = get_batch_handler(self.config, 'labels',
|
||||
default='rattail.batch.labels:LabelBatchHandler')
|
||||
session = orm.object_session(product_batch)
|
||||
label_batch = handler.make_batch(session, created_by=user,
|
||||
description=product_batch.description,
|
||||
notes=product_batch.notes)
|
||||
label_batch.product_batch = product_batch
|
||||
handler.do_populate(label_batch, user, progress=progress)
|
||||
return label_batch
|
||||
|
||||
def make_pricing_batch(self, product_batch, user, progress=None):
|
||||
handler = get_batch_handler(self.config, 'pricing',
|
||||
default='rattail.batch.pricing:PricingBatchHandler')
|
||||
session = orm.object_session(product_batch)
|
||||
pricing_batch = handler.make_batch(session, created_by=user,
|
||||
description=product_batch.description,
|
||||
notes=product_batch.notes)
|
||||
pricing_batch.product_batch = product_batch
|
||||
handler.do_populate(pricing_batch, user, progress=progress)
|
||||
return pricing_batch
|
|
@ -0,0 +1,97 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
"""add product batches
|
||||
|
||||
Revision ID: e1685bf9f1ad
|
||||
Revises: 5dee2f796f25
|
||||
Create Date: 2019-04-18 19:17:58.520577
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'e1685bf9f1ad'
|
||||
down_revision = '5dee2f796f25'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import rattail.db.types
|
||||
|
||||
|
||||
|
||||
def upgrade():
|
||||
|
||||
# batch_product
|
||||
op.create_table('batch_product',
|
||||
sa.Column('uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column('created', sa.DateTime(), nullable=False),
|
||||
sa.Column('created_by_uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('cognized', sa.DateTime(), nullable=True),
|
||||
sa.Column('cognized_by_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('rowcount', sa.Integer(), nullable=True),
|
||||
sa.Column('complete', sa.Boolean(), nullable=False),
|
||||
sa.Column('executed', sa.DateTime(), nullable=True),
|
||||
sa.Column('executed_by_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('purge', sa.Date(), nullable=True),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('extra_data', sa.Text(), nullable=True),
|
||||
sa.Column('status_code', sa.Integer(), nullable=True),
|
||||
sa.Column('status_text', sa.String(length=255), nullable=True),
|
||||
sa.Column('input_filename', sa.String(length=255), nullable=True),
|
||||
sa.ForeignKeyConstraint(['cognized_by_uuid'], ['user.uuid'], name='batch_product_fk_cognized_by'),
|
||||
sa.ForeignKeyConstraint(['created_by_uuid'], ['user.uuid'], name='batch_product_fk_created_by'),
|
||||
sa.ForeignKeyConstraint(['executed_by_uuid'], ['user.uuid'], name='batch_product_fk_executed_by'),
|
||||
sa.PrimaryKeyConstraint('uuid')
|
||||
)
|
||||
|
||||
# batch_product_row
|
||||
op.create_table('batch_product_row',
|
||||
sa.Column('uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('batch_uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('sequence', sa.Integer(), nullable=False),
|
||||
sa.Column('status_code', sa.Integer(), nullable=True),
|
||||
sa.Column('status_text', sa.String(length=255), nullable=True),
|
||||
sa.Column('modified', sa.DateTime(), nullable=True),
|
||||
sa.Column('removed', sa.Boolean(), nullable=False),
|
||||
sa.Column('item_entry', sa.String(length=20), nullable=True),
|
||||
sa.Column('upc', rattail.db.types.GPCType(), nullable=True),
|
||||
sa.Column('item_id', sa.String(length=20), nullable=True),
|
||||
sa.Column('product_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('brand_name', sa.String(length=100), nullable=True),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column('size', sa.String(length=255), nullable=True),
|
||||
sa.Column('department_number', sa.Integer(), nullable=True),
|
||||
sa.Column('department_name', sa.String(length=30), nullable=True),
|
||||
sa.Column('subdepartment_number', sa.Integer(), nullable=True),
|
||||
sa.Column('subdepartment_name', sa.String(length=30), nullable=True),
|
||||
sa.Column('department_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('subdepartment_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('vendor_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('vendor_item_code', sa.String(length=20), nullable=True),
|
||||
sa.Column('regular_cost', sa.Numeric(precision=9, scale=5), nullable=True),
|
||||
sa.Column('current_cost', sa.Numeric(precision=9, scale=5), nullable=True),
|
||||
sa.Column('current_cost_starts', sa.DateTime(), nullable=True),
|
||||
sa.Column('current_cost_ends', sa.DateTime(), nullable=True),
|
||||
sa.Column('regular_price', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('current_price', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('current_price_starts', sa.DateTime(), nullable=True),
|
||||
sa.Column('current_price_ends', sa.DateTime(), nullable=True),
|
||||
sa.Column('suggested_price', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.ForeignKeyConstraint(['batch_uuid'], ['batch_product.uuid'], name='batch_product_row_fk_batch'),
|
||||
sa.ForeignKeyConstraint(['product_uuid'], ['product.uuid'], name='batch_product_row_fk_product'),
|
||||
sa.ForeignKeyConstraint(['department_uuid'], ['department.uuid'], name='batch_product_row_fk_department'),
|
||||
sa.ForeignKeyConstraint(['subdepartment_uuid'], ['subdepartment.uuid'], name='batch_product_row_fk_subdepartment'),
|
||||
sa.ForeignKeyConstraint(['vendor_uuid'], ['vendor.uuid'], name='batch_product_row_fk_vendor'),
|
||||
sa.PrimaryKeyConstraint('uuid')
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
|
||||
# batch_product*
|
||||
op.drop_table('batch_product_row')
|
||||
op.drop_table('batch_product')
|
|
@ -2,7 +2,7 @@
|
|||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
# Copyright © 2010-2019 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -68,6 +68,7 @@ from .batch.inventory import InventoryBatch, InventoryBatchRow
|
|||
from .batch.labels import LabelBatch, LabelBatchRow
|
||||
from .batch.newproduct import NewProductBatch, NewProductBatchRow
|
||||
from .batch.pricing import PricingBatch, PricingBatchRow
|
||||
from .batch.product import ProductBatch, ProductBatchRow
|
||||
from .batch.purchase import PurchaseBatch, PurchaseBatchRow, PurchaseBatchRowClaim, PurchaseBatchCredit
|
||||
from .batch.vendorcatalog import VendorCatalog, VendorCatalogRow
|
||||
from .batch.vendorinvoice import VendorInvoice, VendorInvoiceRow
|
||||
|
|
134
rattail/db/model/batch/product.py
Normal file
134
rattail/db/model/batch/product.py
Normal file
|
@ -0,0 +1,134 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2019 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/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Data model for generic "product" batches
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy.ext.declarative import declared_attr
|
||||
|
||||
from rattail.db.model import (Base, BatchMixin, ProductBatchRowMixin,
|
||||
Vendor, Department, Subdepartment)
|
||||
from rattail.db.core import filename_column
|
||||
|
||||
|
||||
class ProductBatch(BatchMixin, Base):
|
||||
"""
|
||||
Primary data model for product batches.
|
||||
"""
|
||||
__tablename__ = 'batch_product'
|
||||
__batchrow_class__ = 'ProductBatchRow'
|
||||
batch_key = 'product'
|
||||
model_title = "Product Batch"
|
||||
model_title_plural = "Product Batches"
|
||||
|
||||
input_filename = filename_column(nullable=True, doc="""
|
||||
Base name of the input data file, if applicable.
|
||||
""")
|
||||
|
||||
|
||||
class ProductBatchRow(ProductBatchRowMixin, Base):
|
||||
"""
|
||||
Row of data within a product batch.
|
||||
"""
|
||||
__tablename__ = 'batch_product_row'
|
||||
__batch_class__ = ProductBatch
|
||||
|
||||
@declared_attr
|
||||
def __table_args__(cls):
|
||||
return cls.__default_table_args__() + (
|
||||
sa.ForeignKeyConstraint(['department_uuid'], ['department.uuid'],
|
||||
name='batch_product_row_fk_department'),
|
||||
sa.ForeignKeyConstraint(['subdepartment_uuid'], ['subdepartment.uuid'],
|
||||
name='batch_product_row_fk_subdepartment'),
|
||||
sa.ForeignKeyConstraint(['vendor_uuid'], ['vendor.uuid'],
|
||||
name='batch_product_row_fk_vendor'),
|
||||
)
|
||||
|
||||
STATUS_OK = 1
|
||||
STATUS_MISSING_KEY = 2
|
||||
STATUS_PRODUCT_NOT_FOUND = 3
|
||||
|
||||
STATUS = {
|
||||
STATUS_OK : "ok",
|
||||
STATUS_MISSING_KEY : "missing product key",
|
||||
STATUS_PRODUCT_NOT_FOUND : "product not found",
|
||||
}
|
||||
|
||||
department_uuid = sa.Column(sa.String(length=32), nullable=True)
|
||||
department = orm.relationship(Department, doc="""
|
||||
Reference to the department to which the product belongs.
|
||||
""")
|
||||
|
||||
subdepartment_uuid = sa.Column(sa.String(length=32), nullable=True)
|
||||
subdepartment = orm.relationship(Subdepartment, doc="""
|
||||
Reference to the subdepartment to which the product belongs.
|
||||
""")
|
||||
|
||||
vendor_uuid = sa.Column(sa.String(length=32), nullable=True)
|
||||
vendor = orm.relationship(Vendor, doc="""
|
||||
Reference to the "preferred" vendor from which product may be purchased.
|
||||
""")
|
||||
|
||||
vendor_item_code = sa.Column(sa.String(length=20), nullable=True, doc="""
|
||||
Vendor-specific item code (SKU) for the product.
|
||||
""")
|
||||
|
||||
regular_cost = sa.Column(sa.Numeric(precision=9, scale=5), nullable=True, doc="""
|
||||
The "base" unit cost for the item, i.e. with no discounts applied.
|
||||
""")
|
||||
|
||||
current_cost = sa.Column(sa.Numeric(precision=9, scale=5), nullable=True, doc="""
|
||||
The "true" unit cost for the item, i.e. with discounts applied.
|
||||
""")
|
||||
|
||||
current_cost_starts = sa.Column(sa.DateTime(), nullable=True, doc="""
|
||||
Date/time when the current cost starts, if applicable.
|
||||
""")
|
||||
|
||||
current_cost_ends = sa.Column(sa.DateTime(), nullable=True, doc="""
|
||||
Date/time when the current cost ends, if applicable.
|
||||
""")
|
||||
|
||||
regular_price = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
||||
The "regular" unit price for the item.
|
||||
""")
|
||||
|
||||
current_price = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
||||
The "current" unit price for the item.
|
||||
""")
|
||||
|
||||
current_price_starts = sa.Column(sa.DateTime(), nullable=True, doc="""
|
||||
Date/time when the current price starts, if applicable.
|
||||
""")
|
||||
|
||||
current_price_ends = sa.Column(sa.DateTime(), nullable=True, doc="""
|
||||
Date/time when the current price ends, if applicable.
|
||||
""")
|
||||
|
||||
suggested_price = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
||||
The "suggested" retail price for the item.
|
||||
""")
|
Loading…
Reference in a new issue