Shadow task fixes, asset link ids, backup verdict
This commit is contained in:
@@ -185,6 +185,76 @@ def analyse(points, rise=REPLACEMENT_RISE, currentlevel=None):
|
||||
return result
|
||||
|
||||
|
||||
# Urgency bands. The report groups by these and the order list is drawn from
|
||||
# the first two, so they are defined once here rather than in the view - a
|
||||
# heading that disagrees with what got added to the list is worse than either.
|
||||
SOON_DAYS = 14
|
||||
MONTH_DAYS = 30
|
||||
|
||||
# What goes on the order list. Two weeks is the horizon that survives a
|
||||
# delivery: ordering only what is already empty means running empty.
|
||||
ORDER_HORIZON_DAYS = SOON_DAYS
|
||||
|
||||
BANDS = ('empty', 'soon', 'month', 'later')
|
||||
|
||||
|
||||
def band(daysleft):
|
||||
"""Which urgency band a cartridge belongs in, or None with no estimate."""
|
||||
if daysleft is None:
|
||||
return None
|
||||
if daysleft <= 0:
|
||||
return 'empty'
|
||||
if daysleft <= SOON_DAYS:
|
||||
return 'soon'
|
||||
if daysleft <= MONTH_DAYS:
|
||||
return 'month'
|
||||
return 'later'
|
||||
|
||||
|
||||
def orderlist(cartridges, horizon=ORDER_HORIZON_DAYS):
|
||||
"""What to buy, grouped by part number: [{partnumber, quantity, ...}].
|
||||
|
||||
The report's whole purpose reduced to a list someone can hand to
|
||||
purchasing. Two cartridges of the same part in different printers is a
|
||||
quantity of two, which is the number an order needs and the one a
|
||||
per-printer table makes you count by hand.
|
||||
|
||||
A cartridge with no part mapped is still listed, under its printer's model
|
||||
and colour. Dropping it would quietly shorten the order.
|
||||
"""
|
||||
groups = {}
|
||||
for cartridge in cartridges:
|
||||
if cartridge.get('daysleft') is None or cartridge['daysleft'] > horizon:
|
||||
continue
|
||||
parts = cartridge.get('partnumbers') or []
|
||||
# Several capacity tiers can match; the first is the standard one and
|
||||
# is what the low-supplies report shows first too.
|
||||
partnumber = parts[0]['partnumber'] if parts else None
|
||||
key = (partnumber, cartridge.get('color'), cartridge.get('model'))
|
||||
group = groups.setdefault(key, {
|
||||
'partnumber': partnumber,
|
||||
'color': cartridge.get('color'),
|
||||
'supplytype': cartridge.get('supplytype'),
|
||||
'model': cartridge.get('model'),
|
||||
'marketingname': parts[0].get('marketingname') if parts else None,
|
||||
'alternates': [p['partnumber'] for p in parts[1:]],
|
||||
'quantity': 0,
|
||||
'printers': [],
|
||||
})
|
||||
group['quantity'] += 1
|
||||
group['printers'].append({
|
||||
'printerid': cartridge.get('printerid'),
|
||||
'printername': cartridge.get('printername'),
|
||||
'daysleft': cartridge.get('daysleft'),
|
||||
})
|
||||
|
||||
# Unmapped parts last: they need a decision before they can be ordered.
|
||||
return sorted(groups.values(),
|
||||
key=lambda g: (g['partnumber'] is None,
|
||||
-g['quantity'],
|
||||
g['partnumber'] or ''))
|
||||
|
||||
|
||||
def soonest(supplies):
|
||||
"""Days-left of the supply that runs out first, or None if none estimate.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user