Modul "MyOdoo Versandsteuerung"

Funktionsumfang

Dieser Artikel befasst sich mit dem Modul "Eq Shipping & Eq Instances". In der jetzigen Version wird das Format von "DPD DeliSprint 6" unterstützt. Dieses Modul generiert automatisch  nach durchgeführter Lieferung die passende CSV-Datei für den KEP-Dienstleister. Die generierte CSV-Datei kann in das Programm von DPD namens DeliSprint (z.B. auf Windows) automatisch importiert werden und  die Versandetiketten drucken, um die Pakete zu bekleben.

Module "Eq Shipping" & "Eq Instances"

Installation im Backend

Einstellungen > Lokale Apps > eq_shipping und eq_instances suchen und installieren (installieren Sie zuerst Shipping, dann wird Instances mit installiert)


Das Modul erweitert nun die Maske der Auslieferungsmethoden unter Lager > Konfiguration > Auslieferungsmethoden in einer Auslieferungsmethode um den Bereich DPD DeliSprint.


Einstellungsmöglichkeiten

Exportdatei erzeugen: ja / nein  - Möchte ich die Exportdaten für diese Auslieferungsmethode ermöglichen?
Export-Instanz: für jede Exportaufgabe eine Instanz anlegen (z.B. der Export an DPD DeliSprint und eine Kundenliste per CSV exportieren) Instanzen können sein DPD, DHL, UPS, etc.
(Im Skript wird auf den Instanznamen referenziert.)

Bei der Anlage einer Instanz geben Sie ein Zeitintervall (in Sekunden) an, in dem dieser Abgleich stattfindet.

Produkt: legen Sie ein Produkt / einen Tarif Ihres Dienstleisters fest (DPD Classic, Express, etc.)  

Zur Auswahl steht eine statische Produktliste von DPD, die vorgegebene interne Codes von DPD verwendet:


NP = DPD CLASSIC

MAIL = DPD Mail

E18 = DPD 18:00 / GUA

E12 = DPD 12:00

E10 = DPD 10:00

E830 = DPD 8:30

B2CR = B2C Retoure

MAX = DPD MAX

IE2 = DPD EXPRESS

SD = DPD Same Day

PL = DPD PARCEL Letter

SP = DPD CLASSIC Small

EECN = Express Eco

EECS = Express Eco Small



Datei nach dem Export löschen:  ja / nein → soll diese Datei archiviert werden? Thema Speicherplatz

Anzahl Pakete aus Anzahl Zielverpackungen ermitteln: aktiv - wir übergeben die Anzahl, wenn ein Kunde in den Lagereinstellungen die Option aktiv und im Liefervorgang Zielverpackungen definiert hat, dann können wir anhand der Anzahl eindeutiger Zielverpackungen innerhalb des Auslieferungsauftrags auch die Anzahl der Pakete ermitteln / nicht aktiv - muss es von Hand angegeben werden.

Einstellungen > Lager > unter Lieferverfolgung > Benutze Verpackungen: Paletten, Boxen... → wenn diese Option aktiv ist, werden nach erfolgreicher Lieferung, so  Packstücke aus einer Lieferung gebildet. 


Die Anzahl der Pakete steht standardmäßig unter Lager auf Alle Vorgänge in Ihrem Warenausgangslager > Auslieferungsaufträge > im Auftrag > zusätzliche Informationen

Konnte die Durchführung der Lieferung erfolgreich ausgeführt werden und ist in der im Auslieferungsauftrag hinterlegten Auslieferungsmethode die Eigenschaft „Exportdatei erzeugen“ aktiv, so wird die Generierung der CSV Datei für den Auftrag ausgeführt. Die generierte Datei wird in einem Exportauftrag gespeichert. 




Sie können die gelaufenen Exporte unter Lager > Versand Export CSV einsehen. Sie haben hier auch die Möglichkeit die CSV-Datei noch einmal herunterzuladen.

Struktur der CSV-Datei

Die exportierte Datei hat folgende Struktur:

Firma;Name;Straße;Adresszusatz;PLZ;Ort;Land;Telefon;E-Mail;KundenNr;Referenz;Inhalt;Gewicht;Nachnahmebetrag


Beispiel fertig eingerichtete DPD Auslieferungsmethode

Für die Erstellung der CSV-Datei sind folgende Punkte zu beachten:

  • Das Auslieferungsprodukt muss eine Position des Auftrags sein
  • Die Produktart des Verkaufsmaterials darf nicht "Dienstleistung" sein.


Instanzen

Die Funktionalität der Instanzen wurde als separates Modul eq_instances ausgelagert. Damit können Sie ein Python Skript aus dem Odoo-System heraus fernsteuern.

1 Instanz = 1 Export Job.


Skript für Instanzen

Installieren Sie Python unter Windows:

Gehen Sie hierzu auf folgenden Link : https://www.python.org/downloads/ Version  2.7.13 und installieren Sie Python wie folgt:

Öffnen Sie danach eine Shell/Terminal mit dem cmd.exe und geben dort den Befehl: "pip install odoorpc" ein.

Jetzt richten wir das Skript ein:

In der Klasse odoo_rpc_connector sind zwei Beispiele für die Verbindungsparameter zu einem Odoosystem zu finden. Neben den Zugangsdaten des Nutzers und des Datenbanknamens ist die Angabe der Adresse des Odoosystems, des Ports und des Protokolls erforderlich. Für eine http-Verbindung muss der Protokollparameter auf jsonrpc und für eine https-Verbindung auf jsonrpc+ssl gesetzt werden. Beginnt die Adresse des Odoosystems mit https, dann wird dieser Protokollparameter automatisch gesetzt.

eq_deli_csv_files_copy.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
##############################################################################
# Dieses Skript gehört zum Modul eq_instances 
# https://equitania.atlassian.net/wiki/x/XQ9aAw
# Es dient zum Transfer der CSV vom Server zum Druckclient
# Version 1.0.10
# Date 01.02.2017
##############################################################################
#
#    Python Script for Odoo, Open Source Management Solution
#    Copyright (C) 2014-now Equitania Software GmbH(<http://www.equitania.de>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import odoorpc
import time
import base64
import os.path
import sys

import logging
_logger = logging.getLogger(__name__)


instance_id = 1
default_sleep_time = 60


class odoo_rpc_connector():
    """
    TODO: Connection settings
    """
    # Unter http
    #odoo_address = 'localhost'
    #odoo_port = 8069
    #user = 'admin'
    #db = ''
    #pw = ''
    #protocol = 'jsonrpc'

    # Unter https
    # odoo_address = 'test.myodoo.de' ohne Präfix http/https etc.
    odoo_address = ''
    odoo_port = 443
    # Benutzername in Odoo
    user = 'admin'
    # Datenbankname in Odoo
    db = ''
    # Passwort des Benutzers
    pw = ''
    # Protokoll für ht
    protocol = 'jsonrpc+ssl'

    def odoo_connect(self):
        """
        Prepare the connection to the server
        :return:
        """

        if self.odoo_address.startswith('https'):
            ssl = True
            self.odoo_address = self.odoo_address.replace('https:', '')
            protocol = 'jsonrpc+ssl'
            if self.odoo_port <= 0:
                self.odoo_port = 443
        elif self.odoo_address.startswith('http:'):
            self.odoo_address = self.odoo_address.replace('http:', '')

        while self.odoo_address and self.odoo_address.startswith('/'):
            self.odoo_address = self.odoo_address[1:]

        while self.odoo_address and self.odoo_address.endswith('/'):
            self.odoo_address = self.odoo_address[:-1]

        while self.odoo_address and self.odoo_address.endswith('\\'):
            self.odoo_address = location[:-1]

        odoo_con = odoorpc.ODOO(self.odoo_address, port=self.odoo_port, protocol=self.protocol)
        odoo_con.login(self.db, self.user, self.pw)

        odoo_con.config['auto_commit'] = True  # No need for manual commits
        odoo_con.env.context['active_test'] = False  # Show inactive articles
        return odoo_con

connector = odoo_rpc_connector()
odoo = connector.odoo_connect()

EXPORT_JOB_DATA = odoo.env['eq.export.data.job']
EXPORT_DATA_ENTITY = odoo.env['eq.export.data.entity']
CONFIG_PARAMS = odoo.env['ir.config_parameter']
LOGGING = odoo.env['ir.logging']


class deli_file_copier():
    use_log = False
    module_info = 'eq_instances/scripts/eq_deli_csv_files_copy'

    def _init__(self):
        self.use_log = False
        # self.module_info = 'eq_instances/scripts/eq_deli_csv_files_copy'


    def get_instance_settings(self, instance_id):
        """
        Get the settings for the export instance
        :param instance_id:
        :return:
        """
        path = ''
        interval = default_sleep_time
        if instance_id > 0:
            instance = EXPORT_DATA_ENTITY.browse(instance_id)
            if instance and instance.eq_export_data_active:
                interval = instance.eq_export_data_intervall
                if interval < 1:
                    interval = 1
                path = instance.eq_root_directory
        return interval, path


    def check_for_files(self, path):
        """
        Checks for new files to be copied to the given directory
        :param path: root directory
        :return:
        """

        new_files_ids = EXPORT_JOB_DATA.search([('eq_data_state', '=', 'new'), ('eq_data_entity_id', '=', instance_id)])

        if new_files_ids:
            new_files = EXPORT_JOB_DATA.browse(new_files_ids)
            for cur_file in new_files:
                try:
                    file_data = cur_file.eq_data_binary
                    file_name = cur_file.eq_data_filename
                    file_target = ""
                    update_data = {
                        'eq_data_state': 'done',
                    }

                    file_name = "".join([x if x.isalnum() or x in [' ', '-', '+', '.'] else "_" for x in file_name])

                    file_data_dec = base64.decodestring(file_data)
                    file_target = os.path.join(path, file_name)
                    print "Writing " + file_target 
                    with open(file_target, "w") as myfile:
                        myfile.write(file_data_dec)

                    EXPORT_JOB_DATA.write([cur_file.id], update_data)
                except Exception as ex:
                    update_data['eq_data_state'] = 'exception'
                    EXPORT_JOB_DATA.write([cur_file.id], update_data)
                    # print ex
                    # _logger.exception("eq_instances Error '" + ex.strerror + "' while copying file to " + file_target)

                    self.create_eq_instance_log("Error while copying file", 'check_for_files', self.module_info,
                                           "EXCEPTION", "Error '" + str(ex) + "' while copying file to " + file_target, self.use_log)


    def _get_param_value_as_bool(self, param_name):
        result = CONFIG_PARAMS.get_param(param_name)
        if not result:
            return False
        return result in ['True', 'true']


    def create_eq_instance_log(self, name, func, path, level, message, create_log_entry = False):
        """
            Erstellt Logeintrag direkt im Odoo
            @cr: Kursor
            @message: Logeintrag mit allen Daten
        """
        if not create_log_entry:
            return

        logger_vals = {
            'name': name,
            'func': func,
            'path': path,
            'line': "/",
            'type': 'server',
            'level': level,
            'message': message
        }
        LOGGING.create(logger_vals)

    def file_copy_process(self):
        """
        Reads the settings of the instance and initiates the check for files process for an active instance
        :return:
        """

        self.use_log = self._get_param_value_as_bool("eq.instances.activate_log")
        self.create_eq_instance_log("file_copy_process - START", 'file_copy_process', self.module_info,
                                         "INFO", "deli file_copy_process wurde gestartet", self.use_log)

        old_settings = '0_'
        while True:
            interval, path = self.get_instance_settings(instance_id)

            if interval > 0 and path:
                self.check_for_files(path)
            print 'Interval: ', interval,'', 'path: ', path
            # _logger.info('Interval: ' + str(interval) + '; path: ' + path)
            time.sleep(interval)


file_copier = deli_file_copier()
file_copier.file_copy_process()

Sicherheitshinweis

Wenn Sie einen Server im Rechenzentrum benutzen, empfehlen wir auf jeden Fall eine https-Verbindung!

Nach dem Anpassen des Skriptes können Sie es mittels 

python eq_deli_csv_files_copy.py

starten.

Das Programm zeigt dann in der Konsole an, ob es im Pause-Modus ist oder Exporte durchgeführt hat.



Voraussetzungen

  • Basiert auf Odoo 8.0 
  • Abhängigkeiten: base, delivery, equitania, eq_instances
  • es wird DeliSprint Programmversion 6.x unterstützt. Ältere Versionen des Programmes sind kein Gegenstand der Anforderung



Release Note

  • Änderungen vom 01.02.2017

Modul in Version 10: https://equitania.atlassian.net/wiki/x/AwDgDQ