Add update_row_quantity()
, order_row()
methods for purchase batch handler
This commit is contained in:
parent
a39c095543
commit
cf8b0282a5
|
@ -19,6 +19,8 @@
|
|||
|
||||
.. automethod:: refresh_row
|
||||
|
||||
.. automethod:: order_row
|
||||
|
||||
.. automethod:: receive_row
|
||||
|
||||
.. automethod:: receiving_update_row_attrs
|
||||
|
@ -31,6 +33,8 @@
|
|||
|
||||
.. automethod:: receiving_find_best_child_row
|
||||
|
||||
.. automethod:: update_row_quantity
|
||||
|
||||
.. automethod:: update_row_cost
|
||||
|
||||
.. automethod:: refresh
|
||||
|
|
|
@ -1553,6 +1553,111 @@ class PurchaseBatchHandler(BatchHandler):
|
|||
session.flush()
|
||||
self.refresh_row(row)
|
||||
|
||||
def update_row_quantity(self, row, **kwargs):
|
||||
"""
|
||||
Update quantity value(s) for the given row, and calculate new totals
|
||||
accordingly. This will handle updating the row as well as the batch,
|
||||
as necessary. Which kwargs this method accepts, and which values are
|
||||
updated, will depend on the batch mode.
|
||||
|
||||
*Ordering Mode*
|
||||
|
||||
Possible kwargs are:
|
||||
|
||||
* ``cases_ordered``
|
||||
* ``units_ordered``
|
||||
|
||||
Logic will figure out the "diff" between the given quantites, and the
|
||||
row's existing values at the time. It then invokes :meth:`order_row()`
|
||||
with the diff values.
|
||||
"""
|
||||
batch = row.batch
|
||||
|
||||
if batch.mode == self.enum.PURCHASE_BATCH_MODE_ORDERING:
|
||||
if 'cases_ordered' in kwargs:
|
||||
cases_diff = kwargs['cases_ordered'] - (row.cases_ordered or 0)
|
||||
if cases_diff:
|
||||
self.order_row(row, cases=cases_diff)
|
||||
if 'units_ordered' in kwargs:
|
||||
units_diff = kwargs['units_ordered'] - (row.units_ordered or 0)
|
||||
if units_diff:
|
||||
self.order_row(row, units=units_diff)
|
||||
|
||||
def order_row(self, row, cases=None, units=None, **kwargs):
|
||||
"""
|
||||
This method is conceptually similar to :meth:`receive_row()` and, while
|
||||
the latter is more "necessary" than this one is, this method tries to
|
||||
match its style just for consistency. Callers may or may not need this
|
||||
method directly, but are welcome to use it.
|
||||
|
||||
Each call to this method must include the row to be updated, as well as
|
||||
the details of the update. These details should reflect "changes"
|
||||
which are to be made, as opposed to "final values" for the row. In
|
||||
other words if a row already has ``cases_ordered == 1`` and the user
|
||||
is ordering a second case, this method should be called like so::
|
||||
|
||||
handler.order_row(row, cases=1)
|
||||
|
||||
The row will be updated such that ``cases_ordered == 2``; the main
|
||||
point here is that the caller should *not* specify ``cases=2`` because
|
||||
it is the handler's job to "apply changes" from the caller. (If the
|
||||
caller speficies ``cases=2`` then the row would end up with
|
||||
``cases_ordered == 3``.)
|
||||
|
||||
See also :meth:`update_row_quantity()` which allows the caller to
|
||||
specify the final values instead.
|
||||
|
||||
For "undo" type adjustments, caller can just send a negative amount,
|
||||
and the handler will apply the changes as expected::
|
||||
|
||||
handler.order_row(row, cases=-1)
|
||||
|
||||
Note that each call must specify *either* a (non-empty) ``cases`` or
|
||||
``units`` value, but *not* both! If you need to adjust both then you
|
||||
must make two separate calls.
|
||||
|
||||
:param ~rattail.db.model.batch.purchase.PurchaseBatchRow row: Batch row
|
||||
which is to be updated with the given order data. The row must
|
||||
exist, i.e. this method will not create a new row for you.
|
||||
|
||||
:param ~decimal.Decimal cases: Case quantity for the update, if applicable.
|
||||
|
||||
:param ~decimal.Decimal units: Unit quantity for the update, if applicable.
|
||||
"""
|
||||
# make sure we have cases *or* units
|
||||
if not (cases or units):
|
||||
raise ValueError("must provide amount for cases *or* units")
|
||||
if cases and units:
|
||||
raise ValueError("must provide amount for cases *or* units (but not both)")
|
||||
|
||||
batch = row.batch
|
||||
|
||||
# make sure we have a (non-executed) ordering batch
|
||||
if batch.mode != self.enum.PURCHASE_BATCH_MODE_ORDERING:
|
||||
raise NotImplementedError("order_row() is only for ordering batches")
|
||||
if batch.executed:
|
||||
raise NotImplementedError("order_row() is only for *non-executed* batches")
|
||||
|
||||
# add values as-is to existing case/unit amounts.
|
||||
# TODO: what if this gives us negative values?
|
||||
if cases:
|
||||
row.cases_ordered = (row.cases_ordered or 0) + cases
|
||||
if units:
|
||||
row.units_ordered = (row.units_ordered or 0) + units
|
||||
|
||||
# TODO: pretty sure this isn't needed?
|
||||
# # refresh row status etc.
|
||||
# self.refresh_row(row)
|
||||
|
||||
# update calculated PO totals
|
||||
po_amount = 0
|
||||
if cases:
|
||||
po_amount += cases * (row.case_quantity or 0) * (row.po_unit_cost or 0)
|
||||
if units:
|
||||
po_amount += units * (row.po_unit_cost or 0)
|
||||
row.po_total_calculated = (row.po_total_calculated or 0) + po_amount
|
||||
batch.po_total_calculated = (batch.po_total_calculated or 0) + po_amount
|
||||
|
||||
def populate_credit(self, credit, row):
|
||||
"""
|
||||
Populate all basic attributes for the given credit, from the given row.
|
||||
|
|
Loading…
Reference in a new issue