#!/usr/bin/env python
# encoding: utf-8
"""Uebernimmt alle offenen Kommissionierbelege aus der Soft-Schnittstelle ISA00,
und sendet je eine Kommiauftrag Nachricht.
Der Status des Satzes in ISA00 wird dann auf "X" gesetzt.

Siehe
https://cybernetics.hudora.biz/intern/trac/browser/projects/cs/trunk/doc/messaging_ic-wms.rst
zum Nachrichtenformat.

Created by Lars Ronge, Maximillian Dornseif on 2007-12-07, 2007-12-19.
Rewritten by Maximillian Dornseif 2008-12, 2010-01.
Copyright (c) 2007-2010 HUDORA GmbH.
"""

import cs.messaging as messaging
import cs.zwitscher
import datetime
import husoftm.kunden
import husoftm.lieferscheine
import husoftm.versandart
import huTools.NetStringIO as NetStringIO
import optparse
import simplejson as json
import sys
import time


rowcounter = 0


def display(msg):
    """Display messages based on command line options."""
    if options.debug or (not options.quiet):
        print (msg)
        sys.stdout.flush()


def write_journal(doc):
    """Write journal entrys of incoming messages."""
    logdata = json.dumps(doc, sort_keys=True, separators=(',', ':'))
    nstring = NetStringIO.NetStringIO(open(options.log, 'a'))
    nstring.write(logdata)
    nstring.file.close()


def transfer_kommis(lager):
    "Handles the transfer of data SoftM/ISA00 -> Kommiauftrag messages."
    global rowcounter

    outqueuename = u"%s#%s" % (options.out_queue, lager)
    messaging.setup_queue(outqueuename, durable=True)

    lsnrs = husoftm.lieferscheine.get_lieferscheinnrs_for_lager(lager)
    lsnrs.sort()
    lsnrs.reverse()

    for lsnr in lsnrs[:5]:
        ls = husoftm.lieferscheine.Lieferschein(lsnr)
        komminr, auftragsnr, satznr, lagernr = [ls.kommissionierbelegnr, ls.auftragsnr, ls.satznr, ls.lager]
        display("%r" % ([komminr, auftragsnr, satznr, lagernr]))

        if int(lagernr) != lager:
            if options.debug:
                print "wrong lager"
            continue

        softmschein = husoftm.lieferscheine.Kommibeleg(komminr)

        if not softmschein.liefer_date:
            # Leider kann man in SoftM Aufträuge ohne Liefertermin erfassen ...
            betreuer = husoftm.kunden.get_kundenbetreuer(softmschein.warenempfaenger)
            msg = u'@%s: %s ohne Aniefertermin erfasst #error' % (betreuer, softmschein.auftragsnr)
            cs.zwitscher.zwitscher(msg, username='mypl')
            softmschein.liefer_date = datetime.date.today()
            softmschein.anlieferdatum = datetime.date.today()

        # Datensatz ist gelockt, wir koennen damit arbeiten
        doc = messaging.empty_message('ic2wms_xovr.kommiauftrag',
                                      guid="%s-%s-%s-%s" % (komminr, auftragsnr, satznr, lagernr),
                                      audit_trail='ic2wms_xovr.kommiauftrag',
                                      audit_info='Auftrag aus SoftM')
        doc.update(dict(kommiauftragsnr=komminr,
                        anliefertermin=softmschein.anlieferdatum.strftime("%Y-%m-%d"),
                        prioritaet=7, # Wird noch überschrieben, s.u.
                        # anliefertermin_ab
                        # versandtermin
                        # versandtermin_ab
                        # fixtermin:    Wenn True: Zuspätlieferung kann erhebliche Kosten nach sich ziehen.
                        # gewicht:      Netto gewicht der Ware in Gramm
                        # volumen:      Netto Volumen der Ware in Liter
                        kundennr=softmschein.warenempfaenger,
                        info_kunde=softmschein.auftragsnr_kunde,
                        auftragsnr=softmschein.auftragsnr,
                        kundenname=(' '.join([softmschein.name1, softmschein.name2,
                                              softmschein.name3])).strip(),
                        # addressprotocol
                        name1=softmschein.name1,
                        strasse=softmschein.strasse,
                        land=softmschein.land,
                        plz=softmschein.plz,
                        ort=softmschein.ort,
                    ))
        if softmschein.name2:
            doc['name2'] = softmschein.name2
        if softmschein.name2:
            doc['name3'] = softmschein.name3

        # Add kommibelegpositionen to doc
        doc['positionen'] = []
        for position in softmschein.positionen:
            doc['positionen'].append(dict(menge=int(position.menge_komissionierbeleg),
                                          artnr=position.artnr,
                                          posnr=position.auftrags_position,
                                          # text
                                          # EAN
                                          setartikel=(position.setartikel == 1),
                                          kommissionierbeleg_position=position.kommissionierbeleg_position,
                                          kommissionierbelegnr=position.kommissionierbelegnr,
                                          satznummer=position.satznr))

        if softmschein.fixtermin or softmschein.art == 'WA':
            doc['fixtermin'] = True

        # Priorität:
        # 100000 - Normal;
        # 100010 - Fixtermin;
        # 100100 - Werbeauftrag;
        # 100110 - Fixtermin + Werbeauftrag
        doc['prioritaet'] = 100000 + 10 * int(bool(softmschein.fixtermin)) + 100 * int(bool(softmschein.art == 'WA'))

        if softmschein.versandart: # FIXME gibt es wahrscheinlich immer, also ist die if-clause unnütz
            # Beschreibung der Versandart aus SoftM
            # In SoftM werden teilweise auch versandvorschriften in die Versandart gepackt, bspw. Hebebühne.
            # Dh. die Versandart wird von einem späteren Filter nochmals überprüft/verändert.
            # Hier schonmal die Daten aus dem SoftM eintragen
            versandart = husoftm.versandart.versandart(softmschein.versandart)[1]
            doc['versandartschluessel'] = softmschein.versandart
            doc['versandart'] = versandart

        if options.debug:
            display(doc)

        if not options.dry_run:
            # log file for replaying in case of errors
            write_journal(doc)
            messaging.publish(doc, outqueuename)
            messaging.publish(doc, 'log.%s' % outqueuename)


def main():
    """main function - option parsing and calling of transfer_kommis()."""
    global options
    
    parser = optparse.OptionParser()
    parser.description = ('Uebernimmt Kommibelege aus der SoftM-Schnittstelle ISA00 und '
                         + 'erzeugt Kommiauftragsmeldungen')
    parser.set_usage('usage: %prog [options]')
    parser.add_option('--lager', type="int", action='append', help='Lager, das bearbeitet werden soll')
    parser.add_option('--out', dest='out_queue', help='Queue to send messages to.')
    parser.add_option('--log', default='/var/log/ic2wms_xovr.kommiauftrag.log',
                      help='Wo sollen die Nachrichten protokolliert werden? [%default]')
    parser.add_option('--continuous', action='store_true',
                      help='Run continuously forever')
    parser.add_option('--sleep', type="int", default=53,
                      help='Pause zwischen Durchlaeufen, wenn --continuous verwendet wird [%default s]')
    parser.add_option('--quiet', action='store_true', help='Uebliche Ausgaben unterdruecken')
    parser.add_option('--debug', action='store_true', help='Debugging Informationen ausgeben')
    parser.add_option('--dry-run', action='store_true', help='Keine Nachrichten absenden und loeschen')
    parser.add_option('--maxnum', type='int',
                      help='Maximale Anzahl der zu transferierenden Datensaetze [default: unlimited]')

    options, args = parser.parse_args()
    if args:
        parser.error("incorrect number of arguments")
    if not options.lager:
        parser.error("'--lager' nicht gesetzt")
    if not options.out_queue:
        parser.error("'--out' nicht gesetzt")

    while True:
        for lager in options.lager:
            transfer_kommis(lager)
        if not options.continuous:
            break
        time.sleep(options.sleep)

    return 0


if __name__ == "__main__":
    sys.exit(main())
