def komponentenaufloesung(mengenliste): """Löst Artikel in ihre Komponenten auf. >>> komponentenaufloesung([(5, '00049'), (4, '00537')]) [(5, u'A42438'), (5, u'A42439'), (5, u'A42440'), (10, u'A42441'), (4, u'42050/A'), (12, u'42051/A'), (4, u'42052/A')] >>> komponentenaufloesung([(2, '00001')]) [(2, '00001')] Achtung: Diese Funktion implementiert mehrere Tage caching """ ret = [] for menge, artnr in mengenliste: # check if we have a cached result memc = caching.get_cache() rows = memc.get('husoftm.komponentencache.%r' % (artnr)) if rows == None: # empty lists are cached too, so check against None here rows = get_connection().query(['ASK00'], fields=['SKLFNR', 'SKKART', 'SKMENG'], condition="SKARTN='%s'" % artnr) memc.set('husoftm.komponentencache.%r' % (artnr), rows, 60 * 60 * 72) # 4 d if not rows: # kein Setartikel ret.append((menge, artnr)) else: for row in rows: ret.append((menge * row['menge_im_set'], row['komponenten_artnr'])) return ret
def get_umschlag(artnr): """Gibt aufgeschlüsselt nach Datum zurück, wie viel Einheiten fakturiert wurden. >>> get_umschlag('14600') [(datetime.date(2005, 1, 25), 104), (datetime.date(2005, 1, 27), 8), ... (datetime.date(2008, 5, 29), 2), (datetime.date(2009, 2, 10), 2)] Achtung: Diese Funktion implementiert mehrere Tage caching. """ # check if we have a cached result memc = caching.get_cache() cacheddata = memc.get('husoftm.umschlag.%r' % (artnr)) if cacheddata: return cacheddata condition = ( "FKRGNR=FURGNR" # JOIN " AND FKAUFA<>'U'" # Keine Umlagerung " AND FKSTAT<>'X'" # nicht gelöscht " AND FKDTFA > 0" # Druckdatum nicht leer " AND FUKZRV=2" # ? " AND FURGNI<>0" # ? " AND FKFORM=' '" # ? " AND FURGNR<>0" # es gibt eine Rechnungsnummer " AND FKMJBU>'10412'" # keine legacy Daten " AND FUARTN=%s") # nur bestimmten Artikel beachten rows = get_connection().query(['AFU00', 'AFK00'], fields=['FKDTFA', 'SUM(FUMNG)'], condition=condition % (sql_quote(artnr)), ordering='FKDTFA', grouping='FKDTFA', querymappings={'SUM(FUMNG)': 'menge', 'FKDTFA': 'rechnung_date'}) ret = [(x['rechnung_date'], as400_2_int(x['menge'])) for x in rows if x['menge'] > 0] memc.set('husoftm.umschlag.%r' % (artnr), ret, 60 * 60 * 24 * 6) # 6 d return ret
def bestandsentwicklung(artnr, dateformat="%Y-%m-%d", lager=0): """Liefert ein Dictionary, dass alle zukünftigen, bzw. noch nicht ausgeführten Bewegungen für einen Artikel beinhaltet. Ist kein Bestand für den Artikel vorhanden, wird None zurückgegeben. dateformat bestimmt dabei die Keys des Dictionaries und steuert die Granularität. "%Y-%W" sorgt z.B. für eine wochenweise Auflösung. >>> bestandsentwicklung('14865') {'2009-02-20': 1200, '2009-03-02': 860, '2009-04-01': 560, '2009-05-04': 300} Achtung: Diese Funktion implementiert bis zu 120 Sekunden caching. """ # check if we have a cached result. memc = caching.get_cache() memc_key = 'husoftm.bestandsentwicklung.%r.%r.%r' % (artnr, dateformat, lager) cache = memc.get(memc_key) if cache: return cache # Auflösung von Set-Artikeln in ihre Unterartikel. # Die Bestandsentwicklung des Sets der Bestandsentwicklung der Unterartikel dividiert durch # die jeweilige Anzahl der Unterartikel pro Set entsprechen. components = husoftm.artikel.komponentenaufloesung([(1, artnr)]) bestentw_all = [] for mng_set, artnr_set in components: bestentwicklung = dict(((datum, mng / mng_set) for (datum, mng) in _sum_bewegungen(_bewegungen(artnr_set, dateformat, lager)).items())) bestentw_all.append(bestentwicklung) # Die kleinste Menge eines Sub-Artikels ist die an diesem Datum verfügbare Menge # !Es gibt Setartikel, deren Unterartikel sich überschneiden. # !Darum die get Methode, mit einem Defaultwert von 99999999 commonkeys = [dct.keys() for dct in bestentw_all] commonkeys = set(itertools.chain(*commonkeys)) bestentwicklung = {} for key in commonkeys: bestentwicklung[key] = min(dct.get(key, 99999999) for dct in bestentw_all) # Bei Setartikeln werden die Auftragsmengen (evtl. auch die Bestellmengen) mal für den Set, # und mal für die Subartikel behandelt. # Darum hier noch die Bewegungen des Setartikels überlagern if artnr_set != artnr: # Das darf nur auf Setartikel angewendet werden! bewegungen_set = _bewegungen(artnr, dateformat, lager) # Bewegungsmengen aus der gerade ermittelten Bestandsendwicklung der Unterartikel erzeugen bestentwicklung = sorted(bestentwicklung.items()) date, mng = bestentwicklung[0] bewegungen_sub = [(date, mng)] for date, x in bestentwicklung[1:]: bewegungen_sub.append((date, x - mng)) mng = x # Bewegungen mit denen des Setartikels kombinieren und erneut eine Bestandsentwicklung # daraus berechnen bewegungen = bewegungen_sub + bewegungen_set bewegungen.sort() bestentwicklung = _sum_bewegungen(bewegungen) if not bestentwicklung: # kein Bestand - diese Information 6 Stunden cachen memc.set(memc_key, bestentwicklung, 60 * 60 * 6) else: # Bestand - die menge fuer 2 Minuten cachen memc.set(memc_key, bestentwicklung, 60 * 2) return bestentwicklung