def _umlagermenge_helper(artnr, lager=100): """ Ermittelt wieviel Umlagerungen für einen oder alle Artikel unterwegs sind. Parmeter: - artnr - 0 oder None -> alle Artikel, die sich in der Umlagerung befinden auflisten, sonst die gesuchte Artikelnummer - lager - Das Lager, an das die Umlagerungen unterwegs sind (default 100) Rueckgabe: - Wenn eine Artikelnummer angegeben wird, dann eine Menge als int - Wenn keine Artikelnummer angegeben wird, dann alle Artikeln die sich zu dem gegebenen Zugangslager (lager) unterwegs sind. """ # This is just a private helper funcion, which should only be called by umlagermenge and # umlagermengen. The reason therefore is, that this function has different return types, depending # on the artnr you provide. umlagermenge and umlagermengen are wrappers around this function. # Das Auslieferungslager steht in AKLGN1, Das Ziellager steht in AKLGN2 # In APLGNR steht AUCH das Abgangslager tables = ['AAP00', 'AAK00'] condition = ( "AKAUFN=APAUFN" " AND AKAUFA='U'" # Umlagerungsauftrag " AND APSTAT<>'X'" # Position nicht logisch gelöscht " AND APKZVA=0" # Position nicht als 'voll ausgeliefert' markiert #" AND (APMNG-APMNGF-APMNGG) > 0" # (noch) zu liefernde menge ist positiv " AND AKSTAT<>'X'" # Auftrag nicht logisch gelöscht " AND AKKZVA=0") # Auftrag nicht als 'voll ausgeliefert' markiert fields = ['SUM(APMNG)'] grouping = [] if lager: # Zugangslager condition += " AND AKLGN2=%d" % int(lager) if artnr: # Artikelnummer condition += " AND APARTN=%s" % sql_quote(artnr) else: fields.insert(0, 'APARTN') grouping = ['APARTN'] rows = get_connection().query(tables=tables, fields=fields, querymappings={}, condition=condition, grouping=grouping) if not artnr: # Wenn kein bestimmter Artikel abgefragt wird, dann das Abfrageergebnis in ein dict umwandeln ret = {} for artnr, menge in rows: ret[artnr] = as400_2_int(menge) return ret else: if rows and rows[0] and rows[0][0]: return as400_2_int(rows[0][0]) return 0
def verfuegbare_mengen(lager=0): """Gibt die aktuell verfügbaren Mengen aller Artikel eines Lagers zurück. Siehe auch besteande(). >>> verfuegbare_mengen(34) {'10106': 6, '12551': 2854, ... '83165': 598} """ rows = get_connection().query('XLF00', grouping=['LFARTN'], querymappings={}, fields=['LFARTN', 'SUM(LFMGLP)', 'SUM(LFMGK4)', 'SUM(LFMGLP-LFMGK4)'], condition="LFLGNR=%s AND LFMGLP<>0 AND LFSTAT<>'X'" % sql_escape(lager)) return dict([(str(artnr), as400_2_int(menge) - as400_2_int(lfmgk4)) for (artnr, menge, lfmgk4, dummy) in rows])
def auftragsmengen(artnr, lager=None): """Liefert eine Liste offener Aufträge für einen Artikel OHNE UMLAGERUNGEN. >>> auftragsmengen(14865) {datetime.date(2009, 3, 2): 340, datetime.date(2009, 4, 1): 300, datetime.date(2009, 5, 4): 260, datetime.date(2009, 6, 2): 300} """ condition = ( "AKAUFN=APAUFN" " AND AKAUFA<>'U'" # kein Umlagerungsauftrag " AND APARTN=%s" # Artikelnummer " AND APSTAT<>'X'" # Position nicht logisch gelöscht " AND APKZVA=0" # Position nicht als 'voll ausgeliefert' markiert " AND (APMNG-APMNGF) > 0" # (noch) zu liefernde menge ist positiv " AND AKSTAT<>'X'" # Auftrag nicht logisch gelöscht " AND AKKZVA=0") # Auftrag nicht als 'voll ausgeliefert' markiert if lager: # Achtung, hier gibt es KEIN Lager 0 in der Tabelle. D.h. APLGNR=0 gibt nix condition = condition + (" AND APLGNR=%d" % lager) rows = get_connection().query(['AAP00', 'AAK00'], fields=['APDTLT', 'SUM(APMNG-APMNGF)'], condition=condition % (sql_quote(artnr)), ordering='APDTLT', grouping='APDTLT', querymappings={'SUM(APMNG-APMNGF)': 'menge_offen', 'APDTLT': 'liefer_date'}) return dict([(x['liefer_date'], as400_2_int(x['menge_offen'])) for x in rows if x['menge_offen'] > 0])
def bestellmengen(artnr, lager=0): """Liefert eine liste mit allen Bestellten aber noch nicht gelieferten Wareneingängen. >>> bestellmengen('14865') {datetime.date(2009, 2, 20): 1200, datetime.date(2009, 5, 5): 300} """ condition = "BPSTAT<>'X' AND BPKZAK=0 AND BPARTN=%s" % sql_quote(artnr) if lager: condition += "AND BPLGNR=%s" % sql_quote(lager) # detailierte Informationen gibts in EWZ00 rows = get_connection().query('EBP00', fields=['BPDTLT', 'SUM(BPMNGB-BPMNGL)'], ordering='BPDTLT', grouping='BPDTLT', condition=condition) return dict([(x['liefer_date'], as400_2_int(x['SUM(BPMNGB-BPMNGL)'])) for x in rows if as400_2_int(x['SUM(BPMNGB-BPMNGL)']) > 0])
def abgabepreisbasis(artnr): """Gibt eine Liste mit den durchschnittlichen Rechnungspreisen pro Monat zurück. Liefert eine Liste von 4-Tuples (datum, AVG(preis), menge, gesammtpreis) [ ... (datetime.date(2009, 2, 10), 32.95, 2, 65.90), (datetime.date(2009, 10, 19), 17.44, 2, 34.88)] """ 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 FUPNET>0" # keine Gutschriften " AND FKMJBU>'10412'" # keine legacy Daten " AND FUARTN=%s") # nur bestimmten Artikel beachten rows = get_connection().query(['AFU00', 'AFK00'], fields=['FKDTFA', 'SUM(FUMNG)', 'SUM(FUPNET)', 'COUNT(FKRGNR)'], condition=condition % (sql_quote(artnr)), ordering='FKDTFA', grouping='FKDTFA', querymappings={'SUM(FUMNG)': 'menge', 'SUM(FUPNET)': 'nettopreis', 'COUNT(FKRGNR)': 'rechnungen', 'FKDTFA': 'rechnung_date'}) ret = [] for row in rows: menge = as400_2_int(row['menge']) if menge: ret.append((row['rechnung_date'], float(row['nettopreis']) / float(row['menge']), menge, float(row['nettopreis']))) ret.sort() return ret
def verfuegbare_menge(artnr, lager=0): """Gibt die aktuell verfügbare Menge eines Artikels an einem Lager zurück oder (lager=0) für alle Lager Achtung! Die verfügbare Menge ist nicht die "freie Menge". >>> verfuegbare_menge('12345') 3456 """ rows = get_connection().query('XLF00', fields=['LFMGLP', 'LFMGK4'], condition="LFLGNR=%s AND LFARTN=%s AND LFMGLP<>0 AND LFSTAT<>'X'" % ( sql_escape(lager), sql_quote(artnr))) if rows: (menge, lfmgk4) = rows[0] return as400_2_int(menge) - as400_2_int(lfmgk4) else: return 0
def buchbestand(artnr, lager=0): """Gibt den Buchbestand eines Artikels für ein Lager zurück oder (lager=0) für alle Lager >>> buchbestand('14600') 2345 """ rows = get_connection().query('XLF00', fields=['LFMGLP'], condition="LFLGNR=%d AND LFARTN=%s AND LFMGLP<>0 AND LFSTAT<>'X'" % (int(lager), sql_quote(artnr))) if rows: return as400_2_int(rows[0][0]) return 0
def besteande(lager): """Ermittelt den Lagerbestand (Buchbestand + in diesem Lager eintreffene Güter) aller Artikel am Lager. >>> bestaende(100) {'01013': 61, '01020': 96, '01022': 2197, '01023': 1000, '01104': 110, '01104/01': 502, ... 'WK83162': 380, 'WK84020': 68} """ rows = get_connection().query('XLF00', fields=['LFARTN', 'LFMGLP'], condition="LFLGNR=%d AND LFMGLP<>0 AND LFSTAT<>'X'" % (int(lager))) bbesteande = dict([(str(row[0]), as400_2_int(row[1])) for row in rows]) # Offene Umlagerungen an dieses Lager zurechnen. uml = umlagermengen(anlager=lager) for artnr, umlagerungsmenge in uml.items(): bbesteande[str(artnr)] = bbesteande.get(artnr, 0) + as400_2_int(umlagerungsmenge) return bbesteande
def auftragsmengen_alle_artikel(lager=0, umlagerungen=False): """Liefert eine Liste offener Aufträge aller Artikel. Per default OHNE UMLAGERUNGEN. >>> auftragsmengen_alle_artikel(34) {'14550': {datetime.date(2008, 11, 30): 3450, datetime.date(2008, 12, 1): 8, datetime.date(2008, 12, 15): 5056}, '14565': {datetime.date(2009, 2, 9): 750, datetime.date(2009, 3, 23): 1008, datetime.date(2009, 4, 27): 625}, '14566': {datetime.date(2009, 2, 2): 4000, datetime.date(2009, 6, 1): 400}, '14635': {datetime.date(2008, 11, 19): 20, datetime.date(2008, 11, 24): 763, datetime.date(2008, 11, 27): 200}} """ condition = ( "AKAUFN=APAUFN" " AND APSTAT<>'X'" # Position nicht logisch gelöscht " AND APKZVA=0" # Position nicht als 'voll ausgeliefert' markiert " AND (APMNG-APMNGF) > 0" # (noch) zu liefernde menge ist positiv " AND AKSTAT<>'X'" # Auftrag nicht logisch gelöscht " AND AKKZVA=0") # Auftrag nicht als 'voll ausgeliefert' markiert if not umlagerungen: # kein Umlagerungsauftrag: condition += " AND AKAUFA<>'U'" if lager: # Achtung, hier gibt es KEIN Lager 0 in der Tabelle. D.h. APLGNR=0 gibt nix condition += " AND APLGNR=%d" % lager rows = get_connection().query(['AAP00', 'AAK00'], fields=['APARTN', 'APDTLT', 'SUM(APMNG-APMNGF)'], condition=condition, ordering='APDTLT', grouping=['APARTN', 'APDTLT'], querymappings={'SUM(APMNG-APMNGF)': 'menge_offen', 'APARTN': 'artnr', 'APDTLT': 'liefer_date'}) ret = {} for row in rows: if row['menge_offen']: ret.setdefault(str(row['artnr']), {})[row['liefer_date']] = as400_2_int(row['menge_offen']) return ret
def buchbestaende(lager=0): """Gibt den Buchbestand aller Artikel für ein Lager zurück oder (lager=0) für alle Lager >>> buchbestaende() {'01012': 1.0, '01013': 246.0, '01020': 395.0, '01022': 2554.0, '01023': 7672.0, '01104': 109.0, '01104/01': 758.0, '01105': 203.0, '01105/01': 799.0, '01106/01': 1012.0} """ rows = get_connection().query('XLF00', fields=['LFARTN', 'SUM(LFMGLP)'], grouping=['LFARTN'], condition="LFLGNR=%d AND LFMGLP<>0 AND LFSTAT<>'X'" % (int(lager))) return dict([(str(artnr), as400_2_int(quantity)) for artnr, quantity in rows])
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