source: rattail/rattail/db/model/batch/purchase.py @ 3fdd880

Last change on this file since 3fdd880 was 3fdd880, checked in by Lance Edgar <lance@…>, 2 years ago

Tweak schema for receiving batch, to allow for truck dump scenario

probably not quite done with required changes yet, but this much seems ready

  • Property mode set to 100644
File size: 6.1 KB
Line 
1# -*- coding: utf-8; -*-
2################################################################################
3#
4#  Rattail -- Retail Software Framework
5#  Copyright © 2010-2018 Lance Edgar
6#
7#  This file is part of Rattail.
8#
9#  Rattail is free software: you can redistribute it and/or modify it under the
10#  terms of the GNU General Public License as published by the Free Software
11#  Foundation, either version 3 of the License, or (at your option) any later
12#  version.
13#
14#  Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
15#  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16#  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17#  details.
18#
19#  You should have received a copy of the GNU General Public License along with
20#  Rattail.  If not, see <http://www.gnu.org/licenses/>.
21#
22################################################################################
23"""
24Models for purchase order batches
25"""
26
27from __future__ import unicode_literals, absolute_import
28
29import six
30import sqlalchemy as sa
31from sqlalchemy import orm
32from sqlalchemy.ext.declarative import declared_attr
33
34from rattail.db.model import (Base, uuid_column, BatchMixin, BatchRowMixin,
35                              PurchaseBase, PurchaseItemBase, PurchaseCreditBase,
36                              Purchase, PurchaseItem)
37from rattail.util import pretty_quantity
38
39
40class PurchaseBatch(BatchMixin, PurchaseBase, Base):
41    """
42    Hopefully generic batch used for entering new purchases into the system, etc.?
43    """
44    batch_key = 'purchase'
45    __tablename__ = 'purchase_batch'
46    __batchrow_class__ = 'PurchaseBatchRow'
47    model_title = "Purchasing Batch"
48    model_title_plural = "Purchasing Batches"
49
50    @declared_attr
51    def __table_args__(cls):
52        return cls.__batch_table_args__() + cls.__purchase_table_args__() + (
53            sa.ForeignKeyConstraint(['purchase_uuid'], ['purchase.uuid'], name='purchase_batch_fk_purchase'),
54        )
55
56    STATUS_OK                   = 1
57    STATUS_UNKNOWN_PRODUCT      = 2
58
59    STATUS = {
60        STATUS_OK:              "ok",
61        STATUS_UNKNOWN_PRODUCT: "has unknown product(s)",
62    }
63
64    purchase_uuid = sa.Column(sa.String(length=32), nullable=True)
65
66    purchase = orm.relationship(
67        Purchase,
68        doc="""
69        Reference to the purchase with which the batch is associated.  May be
70        null, e.g. in the case of a "new purchase" batch.
71        """,
72        backref=orm.backref(
73            'batches',
74            order_by='PurchaseBatch.id',
75            doc="""
76            List of batches associated with the purchase.
77            """))
78
79    mode = sa.Column(sa.Integer(), nullable=False, doc="""
80    Numeric "mode" for the purchase batch, to indicate new/receiving etc.
81    """)
82
83    truck_dump = sa.Column(sa.Boolean(), nullable=True, doc="""
84    Flag indicating whether a "receiving" batch is of the "truck dump"
85    persuasion, i.e.  it does not correspond to a single purchase order but
86    rather is assumed to represent multiple orders.
87    """)
88
89
90class PurchaseBatchRow(BatchRowMixin, PurchaseItemBase, Base):
91    """
92    Row of data within a purchase batch.
93    """
94    __tablename__ = 'purchase_batch_row'
95    __batch_class__ = PurchaseBatch
96
97    @declared_attr
98    def __table_args__(cls):
99        return cls.__batchrow_table_args__() + cls.__purchaseitem_table_args__() + (
100            sa.ForeignKeyConstraint(['item_uuid'], ['purchase_item.uuid'], name='purchase_batch_row_fk_item'),
101        )
102
103    STATUS_OK                           = 1
104    STATUS_PRODUCT_NOT_FOUND            = 2
105    STATUS_COST_NOT_FOUND               = 3
106    STATUS_CASE_QUANTITY_UNKNOWN        = 4
107    STATUS_INCOMPLETE                   = 5
108    STATUS_ORDERED_RECEIVED_DIFFER      = 6
109
110    STATUS = {
111        STATUS_OK                       : "ok",
112        STATUS_PRODUCT_NOT_FOUND        : "product not found",
113        STATUS_COST_NOT_FOUND           : "product found but not cost",
114        STATUS_CASE_QUANTITY_UNKNOWN    : "case quantity not known",
115        STATUS_INCOMPLETE               : "incomplete",
116        STATUS_ORDERED_RECEIVED_DIFFER  : "ordered / received differ",
117    }
118
119    item_uuid = sa.Column(sa.String(length=32), nullable=True)
120
121    item = orm.relationship(
122        PurchaseItem,
123        doc="""
124        Reference to the purchase item with which the batch row is associated.
125        May be null, e.g. in the case of a "new purchase" batch.
126        """)
127
128
129@six.python_2_unicode_compatible
130class PurchaseBatchCredit(PurchaseCreditBase, Base):
131    """
132    Represents a working copy of purchase credit tied to a batch row.
133    """
134    __tablename__ = 'purchase_batch_credit'
135
136    @declared_attr
137    def __table_args__(cls):
138        return cls.__purchasecredit_table_args__() + (
139            sa.ForeignKeyConstraint(['row_uuid'], ['purchase_batch_row.uuid'], name='purchase_batch_credit_fk_row'),
140        )
141
142    uuid = uuid_column()
143
144    row_uuid = sa.Column(sa.String(length=32), nullable=True)
145
146    row = orm.relationship(
147        PurchaseBatchRow,
148        doc="""
149        Reference to the batch row with which the credit is associated.
150        """,
151        backref=orm.backref(
152            'credits',
153            doc="""
154            List of :class:`PurchaseBatchCredit` instances for the row.
155            """))
156
157    def __str__(self):
158        if self.cases_shorted is not None and self.units_shorted is not None:
159            qty = "{} cases, {} units".format(
160                pretty_quantity(self.cases_shorted),
161                pretty_quantity(self.units_shorted))
162        elif self.cases_shorted is not None:
163            qty = "{} cases".format(pretty_quantity(self.cases_shorted))
164        elif self.units_shorted is not None:
165            qty = "{} units".format(pretty_quantity(self.units_shorted))
166        else:
167            qty = "??"
168        qty += " {}".format(self.credit_type)
169        if self.credit_type == 'expired' and self.expiration_date:
170            qty += " ({})".format(self.expiration_date)
171        if self.credit_type == 'mispick' and self.mispick_product:
172            qty += " ({})".format(self.mispick_product)
173        if self.invoice_total:
174            return "{} = ${:0.2f}".format(qty, self.invoice_total)
175        return qty
Note: See TracBrowser for help on using the repository browser.