Exemplo n.º 1
0
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
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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