Beispiel #1
0
def get_rechnung(rechnungsnr):
    """Findet eine Rechnung anhand ihrer Rechnungsnr"""

    conditions = ["FKSTAT <> 'X'",
                  "FKRGNR = %d" % remove_prefix(rechnungsnr, 'RG')]
    rows = query(tables=['AFK00'], condition=' AND '.join(conditions), limit=1, ua='husoftm2.rechnungen')
    if not rows:
        return
    rechnung = rows[0]

    # Rechnungspositionen
    conditions = ["FURGNR <> 'X'"]
    rows = query(tables=['AFU00'], condition='FURGNR = %d' % remove_prefix(rechnungsnr, 'RG'),
                 ua='husoftm2.rechnungen')

    rechnung['positionen'] = rows

    # Evtl. in Funktion auslagern wie in husoftm2.kunden:
    rechnung['rechnungsnr'] = add_prefix(rechnung['rechnungsnr'], 'RG')
    rechnung['auftragsnr'] = add_prefix(rechnung['auftragsnr'], 'SO')
    rechnung['kundennr_rechnungsempfaenger'] = add_prefix(rechnung['kundennr_rechnungsempfaenger'], 'SC')
    rechnung['kundennr_warenempfaenger'] = add_prefix(rechnung['kundennr_warenempfaenger'], 'SC')
    if rechnung['verbandsnr']:
        rechnung['verbandsnr'] = add_prefix(rechnung['verbandsnr'], 'SC')

    return rechnung
Beispiel #2
0
def _get_umsatz(kundennr, jahr, kundenfeld):
    """Ermittle den Umsatz im gegebenen Jahr"""

    if isinstance(jahr, datetime.date):
        jahr = jahr.year
    elif isinstance(jahr, basestring):
        jahr = int(jahr)

    # Das ist deutlich schneller als ein IN-Operator in der eigentlichen Abfrage
    kunde = husoftm2.kunden.get_kunde(kundennr)
    if kunde['land'] == 'DE':
        ktonr = 85100
    elif huTools.world.in_european_union(kunde['land']):
        ktonr = 82100
    else:
        ktonr = 81100

    conditions = ['BUJJBU=%d' % (jahr - 2000),  # Keinen Kommentar zu SoftM!
                  'BUGKTO=%s' % pad('BUGKTO', ktonr),
                  'BUPKTO=%s' % pad('BUPKTO', remove_prefix(kundennr, 'SC')),
                 ]

    rows = query(tables=['BBU00'], fields=['BUSOHA', 'SUM(BUNEBT)'], grouping=['BUSOHA'],
                 querymappings={'BUSOHA': 'art', 'SUM(BUNEBT)': 'umsatz'},
                 condition=' AND '.join(conditions), ua='husoftm2.umsatz.get_umsatz', cachingtime=86400)

    umsatz = decimal.Decimal()
    for row in rows:
        if row['art'] == 'H':
            umsatz -= decimal.Decimal(row['umsatz'])
        elif row['art'] == 'S':
            umsatz += decimal.Decimal(row['umsatz'])
    return umsatz
Beispiel #3
0
def mark_processed(lieferscheinnr):
    """Markiert einen Lieferschein, so dass er von get_new() nicht mehr zurücuk gegeben wird."""
    conditions = ["LKLFSN=%s" % sql_quote(remove_prefix(lieferscheinnr, 'SL')),
                  "LKSTAT<>'X'",
                  "LKKZ02=0",
                  ]
    return x_en('ALK00', condition=' AND '.join(conditions), ua='husoftm2.lieferscheine')
Beispiel #4
0
def kundenpreise(kundennr, gueltig_von=None, gueltig_bis=None):
    """Alle kundenspezifischen Preis für einen Kunden"""

    kundennr = remove_prefix(kundennr, 'SC')

    conditions = ["PNSANR=PRSANR",
                  "PRANW='A'",
                  "PRSTAT=' '",
                  "PNSTAT=' '",
                  "PRKDNR=%s" % pad('PRKDNR', kundennr)
                  ]

    if gueltig_von:
        conditions.append("PRDTVO>=%s" % sql_quote(date2softm(gueltig_von)))
    if gueltig_bis:
        conditions.append("PRDTBI>=%s" % sql_quote(date2softm(gueltig_bis)))

    rows = query(tables=['XPN00', 'XPR00'],
                 fields=['PRARTN', 'PNPRB', 'PRDTVO', 'PRDTBI', 'PRSANR'],
                 condition=' AND '.join(conditions),
                 ordering='PRDTVO'
                 )

    preise = {}
    for row in rows:
        preise[row['artnr']] = dict(preis=int(row['preis'] * 100),
                                    gueltig_von=row.get('gueltig_ab_date'),
                                    gueltig_bis=row.get('gueltig_bis_date'),
                                    satznr=str(row['satznr_xpr00']))
    return preise
def get_kommibeleg(komminr, header_only=False):
    """Gibt einen Kommissionierbeleg zurück"""

    prefix = 'KA'
    if komminr.startswith('KB'):
        prefix = 'KB'
    komminr = remove_prefix(komminr, prefix)

    # In der Tabelle ALK00 stehen Kommissionierbelege und Lieferscheine.
    # Die Kommissionierbelege haben '0' als Lieferscheinnr.
    # Zusätzlich werden die (logisch) gelöschten Lieferscheine rausgefiltert.
    conditions = ["LKLFSN = 0", "LKKBNR = %s" % sql_quote(komminr), "LKSTAT<>'X'"]
    try:
        belege = get_ls_kb_data(conditions, header_only=header_only,
                                is_lieferschein=False)
    except RuntimeError:
        return {}

    if belege:
        beleg = belege[0]
        # Falls es bereits einen Lieferschein gibt, die Lieferscheinnr in das dict schreiben.
        # Ansonsten die Eintrag 'lieferscheinnr' entfernen (wäre sonst SL0)
        rows = query(['ALK00'], condition="LKLFSN <> 0 AND LKKBNR = %s" % sql_quote(komminr))
        if rows:
            beleg['lieferscheinnr'] = rows[0]['lieferscheinnr']
        else:
            beleg.pop('lieferscheinnr', None)
        return beleg
    return {}
Beispiel #6
0
def auftragstextdaten(auftragsnr):
    """Auftrags- und Positionstexte und -daten für einen Auftrag zurückliefern."""
    auftragsnr = "SO%s" % remove_prefix(auftragsnr, 'SO')
    postexte, kopftexte, posdaten, kopfdaten = txt_auslesen([auftragsnr])
    return (postexte.get(auftragsnr, {}),
            kopftexte.get(auftragsnr, []),
            posdaten.get(auftragsnr, {}),
            kopfdaten.get(auftragsnr, {}))
Beispiel #7
0
def get_auftraege_by_auftragsnrs(auftragsnrs, header_only=False, canceled=False):
    """Aufträge mit bestimmten Auftragsnummern zurückgeben.

    Wenn `canceled == False` werden keine stornierten Aufträge und Positionen zurückgegeben."""

    auftragsnrs = [sql_escape(remove_prefix(x, 'SO')) for x in auftragsnrs]
    auftraege = _auftraege(["AKAUFN IN (%s)" % ','.join(auftragsnrs)],
                           header_only=header_only, canceled=canceled)
    return auftraege
Beispiel #8
0
def durchschnittlicher_abgabepreis(artnr, kundennr=None, startdatum=None):
    """Gibt eine Liste mit den durchschnittlichen Rechnungspreisen pro Monat zurück.

    Liefert eine Liste von 4-Tuples (datum, AVG(preis), menge, umsatz)

    Wenn eine Kundennummer mitgeliefert wird, werden nur Rechungen für diesen Kunden betrachtet.
    Wenn ein startdatum angegebenw wird, werden nur vorgänge nach diesem Datum betrachtet.

    [ ...
    (datetime.date(2009, 2, 1), 3295, 2, 6590),
    (datetime.date(2009, 10, 1), 1744, 2, 3488)]

    Die Funktion ist ausgesprochen langsam - bis zu 8 Sekunden.
    """

    conditions = [
        "FUARTN=%s" % (sql_quote(artnr)),  # nur bestimmten Artikel beachten
        "FKRGNR=FURGNR",   # JOIN
        "FKAUFA<>'U'",     # Keine Umlagerung
        "FKSTAT<>'X'",     # nicht gelöscht
        "FKDTFA>0",        # Druckdatum nicht leer
        "FUKZRV=2",        # ?
        "FURGNI<>0",       # ?
        "FKFORM=' '",      # ?
        "FURGNR<>0",       # es gibt eine Rechnungsnummer
        "FUPNET>0",        # keine Gutschriften
        ]

    if kundennr:
        kundennr = remove_prefix(kundennr, 'SC')
        conditions = ["(FKKDNR=%s OR FKKDRG=%s)" % (sql_quote('%8s' % kundennr),
                                                    sql_quote('%8s' % kundennr))] + conditions
    if not startdatum:
        conditions = ["FKDTFA>'10501'"] + conditions  # keine legacy Daten
    else:
        conditions = ["FKDTFA>%s" % sql_quote(date2softm(startdatum))[:5]] + conditions

    rows = query(['AFU00', 'AFK00'], fields=["FKDTFA", 'SUM(FUMNG)', 'SUM(FUPNET)', 'COUNT(FKRGNR)'],
                 condition=' AND '.join(conditions),
                 grouping='FKDTFA', cachingtime=60 * 60 * 24 * 3,
                 querymappings={'SUM(FUMNG)': 'menge', 'SUM(FUPNET)': 'nettopreis',
                                'COUNT(FKRGNR)': 'rechnungen', 'FKDTFA': 'rechnung_date'})
    mengen = {}
    umsatz = {}
    for row in rows:
        menge = int(float(row['menge']))
        nettopreis = float(row['nettopreis']) * 100
        if menge:
            datum = datetime.date(row['rechnung_date'].year, row['rechnung_date'].month, 1)
            if datum not in mengen:
                mengen[datum] = umsatz[datum] = 0
            mengen[datum] += int(menge)
            umsatz[datum] += int(nettopreis)
    ret = []
    for datum in sorted(mengen.keys()):
        ret.append((datum, int(umsatz[datum] / mengen[datum]), mengen[datum], umsatz[datum]))
    return ret
Beispiel #9
0
def offene_auftraege_kunde(kundennr, limit=None, header_only=False, canceled=False):
    """Alle nicht abgeschlossene Aufträge für eine Kundennummer ermitteln.

    Gibt eine Liste von dict()s zurück.
    Wenn `canceled == False` werden keine stornierten Aufträge und Positionen zurückgegeben."""
    kundennr = remove_prefix(kundennr, 'SC')
    auftraege = _auftraege(["AKKDNR=%s" % pad('AKKDNR', kundennr), "AKKZVA=0"],
                           limit=limit, header_only=header_only, canceled=canceled)
    return auftraege
Beispiel #10
0
def lieferschein_for_kommiauftrag(komminr, header_only=False):
    """Gibt den zu dem Kommiauftrag passenden Lieferschein zurück

    Falls der Lieferschein (noch) nicht existiert, wird None zurückgegeben
    """
    komminr = remove_prefix(komminr, 'KA')
    lieferscheine = _lieferscheine(["LKKBNR = %s" % sql_quote(komminr)], limit=1, header_only=header_only)
    if lieferscheine:
        return lieferscheine[0]
Beispiel #11
0
def get_auftragsarten_by_auftragsnrs(auftragsnrs):
    """Ermittelt die Auftragsart (Freitext) der Aufträge der gegebenen Auftragsnummern.

    auftragsnrs: liste von Auftragsnummern
    return: Dictionary Auftragnr -> Auftragsart
    """
    condition = "AKAUFN in (%s)" % ','.join(sql_quote(remove_prefix(nr, 'SO')) for nr in auftragsnrs)
    rows = query(['AAK00'], fields=['AKAUFN', 'AKAUFA'], condition=condition)
    return dict(("SO%s" % row['auftragsnr'], AUFTRAGSARTEN[row['art']]) for row in rows)
Beispiel #12
0
def get_guid(auftragsnr):
    """Gibt den GUID zu einer Auftragsnr zurück, sofern vorhanden."""
    auftragsnr = remove_prefix(auftragsnr, 'SO')
    condition = "ATTX60 LIKE %s AND ATAUFN = %s AND ATAUPO = 0 AND ATTART = 8" % (sql_quote("#:guid:%%"),
                                                                                  sql_quote(auftragsnr))
    rows = query('AAT00', fields=['ATTX60'], condition=condition)
    if rows:
        return rows[0][0].replace('#:guid:', '')
    return ''
Beispiel #13
0
def abgabepreis_kunde(artnr, kundennr, auftragsdatum=None):
    """
    Verkaufspreis für einen Artikel in Abhängigkeit von kundennr und Auftragsdatum ermitteln.

    Höchste Priorität hat der für einen Kunden hinterlegt Preis.
    Zweithöchste Priorität hat der für die Preisliste (Kundengruppe) hinterlegte Preis
    Niedrigste Priorität hat der Listenpreis aus den Artikelstammdaten.

    Rückgabe ist tuple mit Preis und Herkunft des Preises.

    >>> abgabepreis_kunde('04711', 99954)
    (1500, 'Preisliste 95')

    >>> abgabepreis_kunde('04711', 98000)
    (1400, 'Listenpreis')

    >>> abgabepreis_kunde('04711', 94763)
    (1300, 'Kundenpreis')

    """

    if not auftragsdatum:
        auftragsdatum = datetime.date.today()

    # Kundennr als Zeichenkette
    kundennr = remove_prefix(kundennr, 'SC')
    date_str = sql_quote(date2softm(auftragsdatum))

    # 1. Preis für Kunde hinterlegt?
    conditions = ["PNSANR=PRSANR",
                  "PRANW='A'",
                  "PRSTAT=' '",
                  "PNSTAT=' '",
                  "PRARTN=%s" % sql_quote(artnr),
                  "PRDTBI>=%s" % date_str,
                  "PRDTVO<=%s" % date_str,
                  ]
    condition_kunde = conditions + ["PRKDNR=%s" % pad('PRKDNR', kundennr)]
    rows = query(['XPN00', 'XPR00'], fields=['PNPRB'], condition=' AND '.join(condition_kunde),
                 ordering='PRDTVO', limit=1)
    if rows:
        return (int(rows[0][0] * 100), 'Kundenpreis')

    # 2. Preis aus Preislistennr. des Kunden ermitteln
    condition_gruppe = conditions + [
                            # "PRPRLK = %s" % sql_quote(kunde['kunden_gruppe']),
                            "KDKDNR=%s" % pad('KDKDNR', kundennr),
                            "PRPRLK=KDKGRP"
                       ]
    rows = query(['XPN00', 'XPR00', 'XKD00'], fields=['PNPRB', 'PRPRLK'],
                 ordering='PRDTVO', condition=' AND '.join(condition_gruppe), limit=1)
    if rows:
        return (int(rows[0]['preis'] * 100), 'Preisliste %s' % rows[0]['preisliste_kunde'])

    # 3. Listenpreis aus Artikelstammdaten
    return (listenpreis(artnr), 'Listenpreis')
Beispiel #14
0
def get_auftrag_by_auftragsnr(auftragsnr, header_only=False):
    """Auftrag mit Auftragsnummer auftragsnr zurueckgeben"""

    auftragsnr = remove_prefix(auftragsnr, 'SO')
    auftraege = _auftraege(["AKAUFN=%s" % sql_escape(auftragsnr)], header_only=header_only)
    if len(auftraege) > 1:
        raise RuntimeError("Mehr als ein Auftrag mit auftragsnr %s vorhanden" % auftragsnr)
    if not auftraege:
        return None
    return auftraege[0]
Beispiel #15
0
def fertige_auftraege_kunde(kundennr, limit=None, header_only=False, canceled=False):
    """Alle abgeschlossene Aufträge für eine Kundennummer ermitteln.

    Gibt eine Liste von dict()s zurück.
    Wenn `canceled == False` werden keine stornierten Aufträge und Positionen zurückgegeben."""
    kundennr = remove_prefix(kundennr, 'SC')
    # dies mag stornierte Aufträge übersehen - hab ich bisher nicht überprüft
    auftraege = _auftraege(["AKKDNR=%s" % pad('AKKDNR', kundennr),
                            "(AKKZVA=1 OR AKSTAT='X')"], limit=limit,
                            header_only=header_only, canceled=canceled)
    return auftraege
Beispiel #16
0
def get_auftrag_by_auftragsnr(auftragsnr, header_only=False, canceled=False):
    """Auftrag mit Auftragsnummer auftragsnr zurueckgeben.

    Wenn `canceled == False` werden keine stornierten Aufträge und Positionen zurückgegeben."""

    auftragsnr = remove_prefix(auftragsnr, 'SO')
    auftraege = _auftraege(["AKAUFN=%s" % sql_escape(auftragsnr)], header_only=header_only, canceled=canceled)
    if len(auftraege) > 1:
        raise RuntimeError("Mehr als ein Auftrag mit auftragsnr %s vorhanden" % auftragsnr)
    if not auftraege:
        return None
    return auftraege[0]
Beispiel #17
0
def get_rahmenauftraege(kundennr, artnr):
    """Gib die Auftragsnummern aller offenen Rahmenaufträge für den Kunden und den Artikel als Liste zurück.

    >>> get_rahmenauftraege('SC66663', '14600')
    ['SO1205711']
    """
    kundennr = remove_prefix(kundennr, 'SC')
    conditions = ["AKAUFN=APAUFN", "AKKZVA=0", "APKZVA=0", "AKSTAT<>'X'", "APSTAT<>'X'", "AKAUFN>0",
                  "AKAUFA='R'", "AKKDNR=%s" % pad('AKKDNR', kundennr), "APARTN=%s" % sql_quote(artnr)]
    rows = query(['AAK00', 'AAP00'], condition=' AND '.join(conditions), fields=['AKAUFN'],
                 ua='husoftm2.auftraege.get_rahmenauftraege')
    return [add_prefix(row[0], 'SO') for row in rows]
Beispiel #18
0
def auftraege_kunde(kundennr, limit=None, header_only=False, canceled=False):
    """Alle Aufträge für eine Kundennummer ermitteln.

    Gibt eine Liste von dict()s zurück.
    Wenn `canceled == False` werden keine stornierten Aufträge und Positionen zurückgegeben."""

    conditions = []
    if '.' in kundennr:
        kundennr, adressindex = kundennr.split('.')
        conditions.append("AKVANR=%d" % int(adressindex))
    kundennr = remove_prefix(kundennr, 'SC')
    conditions.append("AKKDNR=%s" % pad('AKKDNR', kundennr))
    auftraege = _auftraege(conditions, limit=limit, header_only=header_only, canceled=canceled)
    return auftraege
Beispiel #19
0
def get_address(lieferantennr):
    """Liefert die Adresse zu einer Lieferantennummer."""
    # Präfix für Lieferanten (SP) entfernen. Für Präfix siehe
    # https://sites.google.com/a/hudora.de/intern/it-administration/nummern/nummernkreise
    lieferantennr = remove_prefix(lieferantennr, 'SP')
    # LISTAT kann 'X' (gelöscht) oder 'I' (inaktiv) sein. Wir wollen nur gültige Adressen, also LISTAT = ' '
    rows = query(tables=['XLI00'],
                 condition="LISTAT=' ' AND LIKZLI=1 AND LILINR=%s" % pad('LILINR', lieferantennr),
                 limit=1, ua='husoftm2.lieferanten')
    if rows:
        row = rows[0]
        row['lieferantennr'] = add_prefix(row['lieferantennr'], 'SP')
        row['land'] = land2iso(row.pop('laenderkennzeichen'))
        return row
    return None
Beispiel #20
0
def get_lieferschein(lieferscheinnr, header_only=False):
    """Gibt ein Lieferscheindict für eine Lieferscheinnummer zurück"""
    lieferscheinnr = remove_prefix(lieferscheinnr, 'SL')
    lscheine = _lieferscheine(["LKLFSN = %s" % sql_quote(lieferscheinnr)], limit=1, header_only=header_only)
    if lscheine:
        if len(lscheine) > 1:
            raise RuntimeError('Suche nach %s hat mehr als einen Lieferschein ergeben: %r'
                               % (lieferscheinnr, lscheine))
        lschein = lscheine[0]
        infotext = lschein.get('infotext_kunde')
        if infotext and isinstance(infotext, list):
            lschein['infotext_kunde'] = ', '.join(infotext)
        if not lschein.get('datum'):
            raise RuntimeError('LS %s hat kein Datum: %r' % (lieferscheinnr, lschein))
        return lschein
    return {}
Beispiel #21
0
def txt_auslesen(auftragsnrs, postexte=None, kopftexte=None, kopfdaten=None, posdaten=None):
    """Gibt Positions und Kopftexte für eine Liste von Auftragsnummern zurück."""

    # Die Clients können dicts mit vorbelegten Daten mitgeben. Das ist vor allem da nützlich, wo
    # Jobs relativ viele Auftruage in Batches abarbeiten.
    postexte = postexte or {}
    posdaten = posdaten or {}
    kopftexte = kopftexte or {}
    kopfdaten = kopfdaten or {}
    # Wir arbeiten auf einer Kopie der Auftragsnummern, da wir von der Liste batches abschneiden.
    allauftrnr = auftragsnrs[:]
    while allauftrnr:
        # In 50er Schritten Texte lesen, 'SO'-Kürzel entfernen.
        # Wir erwarten auf jeden Fall String-Parameter.
        batch = [remove_prefix(x, 'SO') for x in allauftrnr[:50]]
        allauftrnr = allauftrnr[50:]
        # Texte aus SoftM einlesen
        condition = 'ATAUFN IN (%s)' % ','.join((str(x) for x in batch))
        for row in query(['AAT00'], ordering=['ATTART', 'ATLFNR'], condition=condition, ua='husoftm2.texte'):
            # Jeden der eingelesenen Texte nach Textart klassifizieren.
            row['textart'] = int(row['textart'])
            auftragsnr = "SO%s" % remove_prefix(row['auftragsnr'], 'SO')
            # Textzeilen die leer sind oder nur Trennzeichen enthalten, ignorieren wir.
            if not row['text'].strip('=*_- '):
                continue

            # Wir behandeln hier nur Texte, die auf Auftragsbestätigungen, Lieferscheinen oder Rechnungen
            # auftauchen sollen. Allerdings drucken wir diese dann auch auf beiden Belegarten auf - keine
            # weiteren Unterscheidungen.
            if row['andruck_re'] or row['andruck_ls'] or row['andruck_ab']:
                if row['andruck_re'] > 1 or row['andruck_ls'] > 3:
                    raise NotImplementedError(row)

                # Wir haben gelegentlich Texte mit `andruck_ab == 2` die offensichtlich nicht als
                # Kundenbelege sollen. Der Wert 2 in diesem Feld ist gänzlich undokumentiert,
                # wir ignorieren bis auf weiteres einfach diese Zeilen.
                if row['andruck_ab'] > 1:
                    continue

                # Texte wo andruck_ls=2 steht soll man laut SoftM "nur auf KB drucken".
                # Die Inhalte sind manchmal grenzwertig ... an dieser stelle kann man die aussortieren,
                # machen wir aber zur zeit nicht.
                if row['andruck_ls'] == 1 and (not row['andruck_re']) and (not row['andruck_ab']):
                    pass

                # Die Statistische Warennummer wird als Positionstext mit der Nummer 5 transportiert
                # In Produktivdaten haben wir die aber bisher noch nicht gesehen.
                if row['textart'] == 5:
                    postexte.setdefault(auftragsnr, {}
                           ).setdefault(row['auftragsposition'], []
                           ).append("Statistische Warennummer: %s" % row['text'].strip())
                # Die Textarten 2, 7 und 8 sind verschiedenen Positionstexte:
                # * 2 Abweichende Artikelbezeichnung
                # * 7 Auftragstexte vor Position
                # * 8 Auftragstexte nach Position
                # Wir fassen alle drei Textarten in einem einzigen Feld zusammen
                elif row['auftragsposition'] > 0 and row['textart'] in (2, 7, 8):
                    postexte.setdefault(auftragsnr, {}
                           ).setdefault(row['auftragsposition'], []
                           ).append(row['text'].strip())
                # Textart 7 bei Position 0 ist eine Faxnummer. Warum auch immer. Wir ignorieren das.
                # Das Feld ist **sehr oft** gefüllt.
                elif row['auftragsposition'] == 0 and row['textart'] == 7:
                    pass
                # Bei Position 0 sind Textart 8 und 9 Fuß- und Kopftexte für den gesammten Auftrag.
                # Wir fassen die in einem einzigen Feld zusammen.
                elif row['auftragsposition'] == 0 and row['textart'] in (8, 9):
                    kopftexte.setdefault(auftragsnr, []).append(row['text'])
                else:
                    # Andere Textarten sind uns bisher nicht untergekommen.
                    print row
                    raise NotImplementedError
            # Wenn der Text eigentlich nirgends angedruckt werden soll, dann ist es entweder ein Warntext
            # bei der Auftragserfassung, oder ein Verschlüsseltes Datenfeld.
            else:
                if int(row['auftragsposition'] == 0):
                    # Erfassungstexte sind Texte, die bei der Auftragserfassung angeziegt werden, aber auf
                    # keinem Beleg erscheinen (kein druckkennzeichen) - die ignorieren wir hier.
                    # Die gesonderten Datenfelder, die mit #:VARNAME: beginnen, verwenden wir aber weiter
                    _erfassungstexte, daten = texte_trennen([row['text']])
                    if daten:
                        kopfdaten.setdefault(auftragsnr, {}).update(daten)
                else:  # row['auftragsposition'] > 0:
                    erfassungstexte, daten = texte_trennen([row['text']])
                    if daten:
                        posdaten.setdefault(auftragsnr, {}
                                            ).setdefault(row['auftragsposition'], {}
                                            ).update(daten)
    return postexte, kopftexte, posdaten, kopfdaten
Beispiel #22
0
def auftraege_kunde(kundennr, limit=None, header_only=False):
    """Alle Aufträge für eine Kundennummer ermitteln.
    Gibt eine Liste von dict()s zurück."""
    kundennr = remove_prefix(kundennr, 'SC')
    auftraege = _auftraege(["AKKDNR=%s" % pad('AKKDNR', kundennr)], limit=limit, header_only=header_only)
    return auftraege
Beispiel #23
0
def _auftraege(additional_conditions=None, addtables=None, mindate=None, maxdate=None, limit=None,
               header_only=False):
    """
    Alle Aufträge ermitteln
    `additional_conditions` kann eine Liste von SQL-Bedingungen enthalten, die die Auftragssuche
    einschränken.
    `mindate` & `maxdate` können den Anliefertermin einschränken.
    `limit` kann die Zahl der zurückgelieferten Aufträge einschraenken. Dabei werden groessere
    Auftragsnummern zuerst zurueck gegeben.

    Rückgabewert sind dicts nach dem Lieferungprotokoll.
    Wenn header_only == True, werden nur Auftragsköpfe zurück gegeben, was deutlich schneller ist.
    """

    conditions = ["AKSTAT<>'X'"]
    if mindate and maxdate:
        conditions.append("AKDTER BETWEEN %s AND %s" % (date2softm(mindate), date2softm(maxdate)))
    elif mindate:
        conditions.append("AKDTER > %s" % date2softm(mindate))
    elif maxdate:
        conditions.append("AKDTER < %s" % date2softm(maxdate))
    if additional_conditions:
        conditions.extend(additional_conditions)

    condition = " AND ".join(conditions)
    koepfe = {}
    kopftexte = {}

    if addtables is None:
        addtables = []

    # Köpfe und Adressen einlesen
    for kopf in query(['AAK00'] + addtables, ordering=['AKAUFN DESC'], condition=condition,
                      joins=[('XKD00', 'AKKDNR', 'KDKDNR')],
                             limit=limit, ua='husoftm2.auftraege'):
        d = dict(kundennr="SC%s" % kopf['kundennr_warenempf'],
                 auftragsnr="SO%s" % kopf['auftragsnr'],
                 auftragsnr_kunde=kopf['auftragsnr_kunde'],
                 erfassung=kopf['AAK_erfassung_date'],
                 aenderung=kopf['AAK_aenderung_date'],
                 sachbearbeiter=husoftm2.sachbearbeiter.resolve(kopf['sachbearbeiter']),
                 anliefertermin=kopf['liefer_date'],
                 teillieferung_erlaubt=(kopf['teillieferung_erlaubt'] == 1),
                 erledigt=(kopf['voll_ausgeliefert'] == 1),
                 positionen=[],
                 # * *auftragsnr_kunde* - id of the order submitted by the customer
                 # * *info_kunde* - Freitext der für den Empfänger relevanz hat
                 )
        koepfe[kopf['auftragsnr']] = d

    if header_only:
        return koepfe.values()

    allauftrnr = koepfe.keys()
    # Texte auslesen
    # Die dritte und vierte Position des Werts von txt_auslesen sind posdaten und kopfdaten.
    # Es handelt sich dabei wohl um Texte, die nicht angedruckt werden sollen.
    # Bis auf weiteres werden diese hier ignoriert.
    postexte, kopftexte, _, _ = txt_auslesen(allauftrnr)
    while allauftrnr:
        # In 50er Schritten Auftragspositionen lesen und den 50 Aufträgen zuordnen
        batch = allauftrnr[:50]
        allauftrnr = allauftrnr[50:]

        # Abweichende Lieferadressen
        for row in query(['XAD00'], ua='husoftm2.lieferscheine',
                         condition="ADAART=1 AND ADRGNR IN (%s)" % ','.join([str(x) for x in batch])):
            koepfe[row['nr']]['lieferadresse'] = dict(name1=kopf['name1'],
                                    name2=kopf['name2'],
                                    name3=kopf['name3'],
                                    strasse=row['strasse'],
                                    land=husoftm2.tools.land2iso(row['laenderkennzeichen']),
                                    plz=row['plz'],
                                    ort=row['ort'])

        # Positionen einlesen
        for row in query(['AAP00'], condition="APSTAT<>'X' AND APAUFN IN (%s)" % ','.join([str(x)
                                                                                           for x in batch]),
                         ua='husoftm2.auftraege'):
            d = dict(menge=int(row['bestellmenge']),
                     artnr=row['artnr'],
                     liefer_date=row['liefer_date'],
                     menge_offen=int(row['menge_offen']),
                     fakturierte_menge=int(row['fakturierte_menge']),
                     erledigt=(row['voll_ausgeliefert'] == 1),
                     # 'position': 2,
                     # 'teilzuteilungsverbot': u'0',
                     )
            texte = postexte.get(row['auftragsnr'], {}).get(row['position'], [])
            texte, attrs = texte_trennen(texte)
            d['infotext_kunde'] = texte
            if 'guid' in attrs:
                d['guid'] = attrs['guid']
            koepfe[row['auftragsnr']]['positionen'].append(d)

        # Kopftexte zuordnen
        for auftragsnr, texte in kopftexte.items():
            texte, attrs = texte_trennen(texte)
            koepfe[remove_prefix(auftragsnr, 'SO')]['infotext_kunde'] = texte
            if 'guid' in attrs:
                koepfe[remove_prefix(auftragsnr, 'SO')]['guid'] = attrs['guid']

    return koepfe.values()
Beispiel #24
0
def get_ls_kb_data(conditions, additional_conditions=None, limit=None, header_only=False,
                   is_lieferschein=True):
    """Lieferscheindaten oder Kommsissionierbelegdaten entsprechend dem Lieferungsprotokoll.

    Wenn is_lieferschein = False, dann werden Kommiauftragsdaten zurückgebeben (Kommimengen)

    """

    cachingtime = 60 * 60 * 12

    if additional_conditions:
        conditions.extend(additional_conditions)
    condition = " AND ".join(conditions)
    koepfe = {}
    auftragsnr2satznr = {}
    satznr2auftragsnr = {}

    # Lieferscheinkopf JOIN Kundenadresse um die Anzahl der Queries zu minimieren
    # JOIN Lieferadresse geht nicht, weil wir "ADAART=1" mit DB2/400 nicht klappt
    for row in query(['ALK00'], ordering=['LKSANK DESC'], condition=condition, limit=limit,
                      joins=[('XKD00', 'LKKDNR', 'KDKDNR'), ('AAK00', 'LKAUFS', 'AKAUFN')],
                      cachingtime=cachingtime, ua='husoftm2.lieferscheine'):
        kopf = dict(positionen=[],
                    auftragsnr="SO%s" % row['auftragsnr'],
                    auftragsnr_kunde=row['auftragsnr_kunde'],
                    erfassung=row['ALK_erfassung'],
                    aenderung=row.get('ALK_aenderung'),
                    anliefer_date=row['anliefer_date'],
                    kundennr="SC%s" % row['rechnungsempfaenger'],
                    lieferadresse=dict(kundennr="SC%s" % row['warenempfaenger']),
                    anlieferdatum=row['anliefer_date'],
                    lager="LG%03d" % int(row['lager']),
                    kommiauftragnr="KA%s" % row['kommibelegnr'],
                    kommiauftrag_datum=row['kommibeleg_date'],
                    lieferscheinnr="SL%s" % row['lieferscheinnr'],
                    name1=row.get('name1', ''),
                    name2=row.get('name2', ''),
                    name3=row.get('name3', ''),
                    strasse=row.get('strasse', ''),
                    land=husoftm2.tools.land2iso(row['laenderkennzeichen']),
                    plz=row.get('plz', ''),
                    ort=row.get('ort', ''),
                    tel=row.get('tel', ''),
                    fax=row.get('fax', ''),
                    art=row.get('art', ''),
                    softm_created_at=row.get('ALK_lieferschein'),
                    )
        # Wir hatten erhebliche Probleme, weil datumsfelder mal befüllt waren
        # und mal nicht (race condition) - wir gehen deswegen recht großzügig
        # bei der suceh nach einem geeigenten feld vor.
        for fieldname in ['ALK_lieferschein', 'ALK_aenderung']:
            if row.get(fieldname):
                kopf['datum'] = row.get(fieldname)
                break
        if not kopf.get('datum'):
            raise RuntimeError("Konnte kein Datum ermitteln %r", row)

        pos_key = remove_prefix((row['satznr']), 'SO')
        if row.get('bezogener_kopf'):
            pos_key = remove_prefix(row['bezogener_kopf'], 'SO')
        auftragsnr2satznr[remove_prefix(row['auftragsnr'], 'SO')] = pos_key
        satznr2auftragsnr[pos_key] = remove_prefix(row['auftragsnr'], 'SO')
        if row['ALK00_dfsl']:
            # Basis dieses Codes:
            # [LH #721] LS mit 0-mengen vermeiden
            # Wir sehen im Produktiv-Betrieb immer wieder Lieferscheine mit der Menge "0"
            # erzeugt werden. Wir vermuten hier eine race Condition, bei der die
            # ALK00 schon mit der Lieferscheinnummer geupdated ist, die ALN00 aber noch
            # nicht mit der Lieferscheinmenge.
            # Eine weitere Vermutung ist, dass wenn in der ALN00 die Menge noch cniht eingetragen
            # ist, dort auch noch die Lieferscheinnummer fehlt. Das versuchen wir hier abzufangen.
            # Lieber ein Crash, als ein Lieferschein mit (unbegründerter) 0-menge.
            raise RuntimeError("Dateiführungsschlüssel in ALK00: %r" % kopf)
        koepfe[pos_key] = kopf

    if header_only:
        return koepfe.values()

    satznr = koepfe.keys()
    allauftrnr = koepfe.keys()
    # Alle texte einlesen
    postexte, kopftexte, posdaten, kopfdaten = txt_auslesen([satznr2auftragsnr[x] for x in allauftrnr])
    while satznr:
        # In 50er Schritten Auftragspositionen & Texte lesen und den 50 Aufträgen zuordnen
        batch = satznr[:50]
        satznr = satznr[50:]

        # Abweichende Lieferadressen
        condition = "ADAART=1 AND ADRGNR IN (%s) AND ADRGNR=AKAUFN" % ','.join([str(satznr2auftragsnr[x])
                                                                                for x in batch])
        for row in query(['XAD00', 'AAK00'], cachingtime=cachingtime, ua='husoftm2.lieferscheine',
                         condition=condition):
            aktsatznr = auftragsnr2satznr[row['nr']]
            koepfe[aktsatznr]['lieferadresse'].update(dict(name1=row['name1'],
                            name2=row['name2'],
                            name3=row['name3'],
                            strasse=row['strasse'],
                            land=husoftm2.tools.land2iso(row['laenderkennzeichen']),
                            plz=row['plz'],
                            ort=row['ort']))
            versandadressnr = row['versandadressnr']
            warenempfaenger = koepfe[aktsatznr]['lieferadresse']['kundennr']
            if versandadressnr:
                warenempfaenger = "%s.%03d" % (warenempfaenger, versandadressnr)
            koepfe[aktsatznr]['lieferadresse']['warenempfaenger'] = warenempfaenger

        # Positionen & Positionstexte zuordnen
        for row in query(['ALN00'], condition="LNSTAT<>'X' AND LNSANK IN (%s)" % ','.join([str(x)
                                                                                           for x in batch]),
                         cachingtime=cachingtime, ua='husoftm2.lieferscheine'):
            if is_lieferschein == True:
                lsmenge = int(row['menge'])
                if row['ALN00_dfsl']:
                    # Basis dieses Codes:
                    # [LH #721] LS mit 0-mengen vermeiden
                    # Wir sehen im Produktiv-Betrieb immer wieder Lieferscheine mit der Menge "0"
                    # erzeugt werden. Wir vermuten hier eine race Condition, bei der die
                    # ALK00 schon mit der Lieferscheinnummer geupdated ist, die ALN00 aber noch
                    # nicht mit der Lieferscheinmenge.
                    # Eine weitere Vermutung ist, dass wenn in der ALN00 die Menge noch cniht eingetragen
                    # ist, dort auch noch die Lieferscheinnummer fehlt. Das versuchen wir hier abzufangen.
                    # Lieber ein Crash, als ein Lieferschein mit (unbegründerter) 0-menge.
                    raise RuntimeError("Dateiführungsschlüssel in ALN00: %r" % row)
            else:
                lsmenge = int(row['menge_komissionierbeleg'])
            pos = dict(artnr=row['artnr'],
                       guid='%s-%03d-%03d' % (row['kommibelegnr'], row['auftrags_position'],
                                              row['kommibeleg_position']),
                       menge=lsmenge)
            texte = postexte.get(remove_prefix(row['auftragsnr'], 'SO'),
                                               {}).get(row['auftrags_position'], [])
            pos['infotext_kunde'] = texte
            if 'guid' in posdaten.get(remove_prefix(row['auftragsnr'], 'SO'), {}):
                pos['auftragpos_guid'] = posdaten.get(remove_prefix(row['auftragsnr'], 'SO'), {}).get('guid')
            else:
                pos['auftragpos_guid'] = "%s-%03d" % (row['auftragsnr'], row['auftrags_position'])

            lieferung = koepfe[remove_prefix(row['satznr_kopf'], 'SO')]
            lieferung['positionen'].append(pos)
            # *Sachbearbeiter* ist der, der den Vorgang tatsächlich bearbeitet hat. *Betreuer* ist
            # die (oder der), die für den Kunden zusändig ist.
            lieferung['sachbearbeiter'] = husoftm2.sachbearbeiter.resolve(row['sachbearbeiter_bearbeitung'])

        # Kopftexte zuordnen
        for auftragsnr, texte in kopftexte.items():
            pos_key = auftragsnr2satznr[remove_prefix(auftragsnr, 'SO')]
            koepfe[pos_key]['infotext_kunde'] = texte
        for auftragsnr, werte in kopfdaten.items():
            if 'guid' in werte:
                pos_key = auftragsnr2satznr[remove_prefix(auftragsnr, 'SO')]
                koepfe[pos_key]['guid_auftrag'] = werte['guid']

        for aktsatznr in koepfe.keys():
            # Entfernt Konstrukte wie das:
            #     "kundennr": "SC19971",
            #      "lieferadresse": {
            #       "kundennr": "SC19971"
            #      }
            if len(koepfe[aktsatznr]['lieferadresse']) == 1:
                if koepfe[aktsatznr]['lieferadresse']['kundennr'] == koepfe[aktsatznr]['kundennr']:
                    del(koepfe[aktsatznr]['lieferadresse'])

    return koepfe.values()
Beispiel #25
0
def abgabepreise_kunde(artnrs, kundennr, auftragsdatum=None):
    """
    Verkaufspreis für einen oder mehrere Artikel in Abhängigkeit von kundennr und Auftragsdatum ermitteln.

    Der Rückgabewert ist ein dict mit den ArtNr. als  Schlüssel.
    Die Werte sind Preisinformationen als Tupel (Preis, Herkunft)
    oder None, falls zu der ArtNr. kein Preis ermittelt werden konnte.

    Die Logik funktioniert genau wie bei abgabepreis_kunde:
    Es werden zuerst kundenspezifische Preise, dann kundengruppen-spezifische Preise und als
    letztes Listenpreise ermittelt.
    """
    warnings.warn("use `cs.salesforce.preise` instead!", DeprecationWarning, stacklevel=2)
    if not auftragsdatum:
        auftragsdatum = datetime.date.today()

    artnrs = set(artnrs)
    kundennr = remove_prefix(kundennr, 'SC')
    date_str = sql_quote(date2softm(auftragsdatum))

    abgabepreise = {}

    # 1. Preise für Kunden hinterlegt?
    conditions = ["PNSANR=PRSANR",
                  "PRANW='A'",
                  "PRPRLK<>''"
                  "PRSTAT=' '",
                  "PNSTAT=' '",
                  "PRDTBI>=%s" % date_str,
                  "PRDTVO<=%s" % date_str,
                  ]
    condition_kunde = conditions + ["PRKDNR=%s" % sql_quote("%8s" % kundennr),
                                    "PRARTN IN (%s)" % ",".join([sql_quote(artnr) for artnr in artnrs])]
    rows = query(tables=['XPN00', 'XPR00'],
                 fields=['PRARTN', 'PNPRB'],
                 condition=' AND '.join(condition_kunde),
                 ordering='PRDTVO')
    for row in rows:
        if row['artnr'] in artnrs:
            artnrs.remove(row['artnr'])
        abgabepreise[row['artnr']] = (int(row['preis'] * 100), u'Kundenpreis')

    if not artnrs:
        return abgabepreise

    # 2. Preise aus Preislistennr. des Kunden ermitteln
    condition_gruppe = conditions + [
                            # "PRPRLK = %s" % sql_quote(kunde['kunden_gruppe']),
                            "PRARTN IN (%s)" % ",".join([sql_quote(artnr) for artnr in artnrs]),
                            "KZKDNR=%s" % pad('KZKDNR', kundennr),
                            "PRPRLK=KZPREL"
                       ]
    rows = query(tables=['XPN00', 'XPR00', 'AKZ00'],
                 fields=['PRARTN', 'PNPRB', 'PRPRLK'],
                 condition=' AND '.join(condition_gruppe),
                 ordering='PRDTVO')

    for row in rows:
        if row['artnr'] in artnrs:
            artnrs.remove(row['artnr'])
        abgabepreise[row['artnr']] = (int(row['preis'] * 100), u'Preisliste %s' % row['preisliste_kunde'])

    if not artnrs:
        return abgabepreise

    # 3. Listenpreis aus Artikelstammdaten
    for artnr, preis in listenpreise(artnrs).iteritems():
        if artnr in artnrs:
            artnrs.remove(artnr)
        abgabepreise[artnr] = (preis, u'Listenpreis')

    for artnr in artnrs:
        abgabepreise[artnr] = None

    return abgabepreise
Beispiel #26
0
def _auftraege(additional_conditions=None, addtables=None, mindate=None, maxdate=None, limit=None,
               header_only=False, canceled=False):
    """
    Alle Aufträge ermitteln
    `additional_conditions` kann eine Liste von SQL-Bedingungen enthalten, die die Auftragssuche
    einschränken.
    `mindate` & `maxdate` können den Anliefertermin einschränken.
    `limit` kann die Zahl der zurückgelieferten Aufträge einschraenken. Dabei werden groessere
    Auftragsnummern zuerst zurueck gegeben.
    `header_only` ruft nur Auftragsköpfe ab und ist bedeutend schneller
    `canceled` wenn True, werden auch stornierte Aufträge zurück gegeben.

    Rückgabewert sind dicts nach dem Lieferungprotokoll.
    Wenn header_only == True, werden nur Auftragsköpfe zurück gegeben, was deutlich schneller ist.
    """

    # Solange der Client das nciht gesondert verlangt, werden stornierte Aufträge ignoriert.
    if not canceled:
        conditions = ["AKSTAT<>'X'"]
    else:
        conditions = []
    # Anliefertermin ist ein Range
    if mindate and maxdate:
        conditions.append("AKDTER BETWEEN %s AND %s" % (date2softm(mindate), date2softm(maxdate)))
    # Anliefertermin ist nach unten begrenzt
    elif mindate:
        conditions.append("AKDTER > %s" % date2softm(mindate))
    # Anliefertermin ist nach oben begrenzt
    elif maxdate:
        conditions.append("AKDTER < %s" % date2softm(maxdate))
    # vom Aufrufer direkt angegebenen, weitere SQL Bedingungen zufügen. Diese werden mit `AND` verkettet.
    if additional_conditions:
        conditions.extend(additional_conditions)

    condition = " AND ".join(conditions)
    koepfe = {}
    kopftexte = {}

    auftragsnr_to_lieferadresse_kdnr = {}

    if addtables is None:
        addtables = []

    # Köpfe und Adressen einlesen
    for kopf in query(['AAK00'] + addtables, ordering=['AKAUFN DESC'], condition=condition,
                      joins=[('XKD00', 'AKKDNR', 'KDKDNR')],
                             limit=limit, ua='husoftm2.auftraege'):
        d = dict(kundennr="SC%s" % kopf['kundennr_warenempf'],
                 kundennr_rechnung="SC%s" % kopf['kundennr_rechnungsempf'],
                 name1=kopf['name1'],
                 name2=kopf['name2'],
                 name3=kopf['name3'],
                 strasse=kopf['strasse'],
                 land=husoftm2.tools.land2iso(kopf['laenderkennzeichen']),
                 plz=kopf['plz'],
                 ort=kopf['ort'],
                 auftragsnr="SO%s" % kopf['auftragsnr'],
                 auftragsnr_kunde=kopf['auftragsnr_kunde'],
                 erfassung=kopf.get('AAK_erfassung'),
                 aenderung=kopf.get('AAK_aenderung', None),
                 sachbearbeiter=husoftm2.sachbearbeiter.resolve(kopf['sachbearbeiter']),
                 anliefertermin=kopf['liefer_date'],
                 teillieferung_erlaubt=(kopf['teillieferung_erlaubt'] == 1),
                 # TODO: md: ich denke, "erledigt" ist ein Auftrag auch, wenn er storneirt wurde,
                 # oder wenn alle Positionen auf voll_ausgeliefert stehen.
                 erledigt=(kopf['voll_ausgeliefert'] == 1),
                 positionen=[],
                 art=kopf['art'],
                 storniert=(kopf['AAK_status'] == 'X'))
        koepfe[kopf['auftragsnr']] = d

        # Auftrag geht an die 'normale' Lieferadresse: Kein .\d\d\d-Suffix an die `lieferadresse.kundennr`
        if kopf['versandadressnr'] == 0:
            auftragsnr_to_lieferadresse_kdnr[kopf['auftragsnr']] = add_prefix(kopf['kundennr_warenempf'],
                                                                              'SC')
        # Auftrag geht an eine abweichende Lieferadresse: .00?-Suffix an die `lieferadresse.kundennr` hängen.
        else:
            lieferadresse_kdnr = add_prefix("%s.%03d" % (kopf['kundennr_warenempf'], kopf['versandadressnr']),
                                            "SC")
            auftragsnr_to_lieferadresse_kdnr[kopf['auftragsnr']] = lieferadresse_kdnr

    if header_only:
        return koepfe.values()

    allauftrnr = koepfe.keys()
    # Texte auslesen
    # Die dritte und vierte Position des Werts von txt_auslesen sind posdaten und kopfdaten.
    # Es handelt sich dabei wohl um Texte, die nicht angedruckt werden sollen.
    # Bis auf weiteres werden diese hier ignoriert.
    postexte, kopftexte, _, _ = txt_auslesen(allauftrnr)
    while allauftrnr:
        # In 50er Schritten Auftragspositionen lesen und den 50 Aufträgen zuordnen
        batch = allauftrnr[:50]
        allauftrnr = allauftrnr[50:]

        # Abweichende Lieferadressen
        for row in query(['XAD00'], ua='husoftm2.auftraege',
                         condition="ADAART=1 AND ADRGNR IN (%s)" % ','.join([str(x) for x in batch])):
            koepfe[row['nr']]['lieferadresse'] = dict(name1=row['name1'],
                                                      name2=row['name2'],
                                                      name3=row['name3'],
                                                      strasse=row['strasse'],
                                                      land=husoftm2.tools.land2iso(row['laenderkennzeichen']),
                                                      plz=row['plz'],
                                                      kundennr=auftragsnr_to_lieferadresse_kdnr[row['nr']],
                                                      ort=row['ort'])
        # Positionen einlesen
        if not canceled:
            poscondition = "APSTAT<>'X' AND APAUFN IN (%s)" % ','.join([str(x) for x in batch])
        else:
            poscondition = "APAUFN IN (%s)" % ','.join([str(x) for x in batch])
        for row in query(['AAP00'], condition=poscondition,
                         ua='husoftm2.auftraege'):
            d = dict(menge=int(row['bestellmenge']),
                     lager="LG%s" % row['lager'],
                     artnr=row['artnr'],
                     liefer_date=row['liefer_date'],
                     menge_offen=int(row['menge_offen']),
                     fakturierte_menge=int(row['fakturierte_menge']),
                     erledigt=(row['voll_ausgeliefert'] == 1),
                     storniert=(row['AAP_status'] == 'X'),
                     posnr=int(row['position']),
                     _aenderung=row.get('AAP_aenderung'),
                     _erfassung=row.get('AAP_erfassung'),
                     _zuteilung=row.get('AAP_zuteilung'),
                     # 'position': 2,
                     # 'teilzuteilungsverbot': u'0',
                     )

            # Preis einfügen
            if row.get('verkaufspreis'):
                d['preis'] = row['verkaufspreis']

            texte = postexte.get(row['auftragsnr'], {}).get(row['position'], [])
            texte, attrs = texte_trennen(texte)
            d['infotext_kunde'] = texte
            if 'guid' in attrs:
                d['guid'] = attrs['guid']
            koepfe[row['auftragsnr']]['positionen'].append(d)

        # Kopftexte zuordnen
        for auftragsnr, texte in kopftexte.items():
            texte, attrs = texte_trennen(texte)
            koepfe[remove_prefix(auftragsnr, 'SO')]['infotext_kunde'] = texte
            if 'guid' in attrs:
                koepfe[remove_prefix(auftragsnr, 'SO')]['guid'] = attrs['guid']

    return koepfe.values()
Beispiel #27
0
def lieferscheine_auftrag(auftragsnr, header_only=False):
    """Gibt eine Liste mit Lieferscheindicts für einen Auftrag zurück"""
    auftragsnr = remove_prefix(auftragsnr, 'SO')
    return _lieferscheine(["LKAUFS = %s" % sql_quote(auftragsnr)], header_only=header_only)