Neu Preishistorie sehen

jtldudel

Sehr aktives Mitglied
4. Januar 2018
610
194
Das gibt es so nicht, nein. Wir haben uns eine eigene Historie gebaut, funktioniert aber erst ab 1.6 (könnte man auch mit 1.5 umsetzen). Rückwirkend wird das natürlich nichts mehr, wenn du nicht zufällig ein Backup aus der Zeit hast oder einen Export.
 
  • Gefällt mir
Reaktionen: Harald Weingaertner

Tina CRC

Aktives Mitglied
10. Mai 2018
76
16
Das gibt es so nicht, nein. Wir haben uns eine eigene Historie gebaut, funktioniert aber erst ab 1.6 (könnte man auch mit 1.5 umsetzen). Rückwirkend wird das natürlich nichts mehr, wenn du nicht zufällig ein Backup aus der Zeit hast oder einen Export.
Wie habt ihr euch die gebaut?
Wir hätten so gerne eine Übersicht aus der man ersehen kann wann und wie die Preise in der Wawi geändert wurden.

Grüße,
 

jtldudel

Sehr aktives Mitglied
4. Januar 2018
610
194
Wie habt ihr euch die gebaut?
Wir hätten so gerne eine Übersicht aus der man ersehen kann wann und wie die Preise in der Wawi geändert wurden.

Grüße,
Eigene Datenbanktabelle in die dann die Änderungen geschrieben werden per Custom Workflow. Es wird die Änderung sowie der User eingetragen, welcher die Änderung ausgelöst hat. Bei Ameisen Importen steht da dann immer Administrator, wenn man da anderen Bedarf hat müsste man sich einen Weg überlegen.
Auch ist es möglich, änerungen einzuspielen, ohne Workflows auszulösen, damit kann das immer umgangen werden.

Bei näherem Interesse kannst du dich auch bei mir per PN melden.
 

Tina CRC

Aktives Mitglied
10. Mai 2018
76
16
Eigene Datenbanktabelle in die dann die Änderungen geschrieben werden per Custom Workflow. Es wird die Änderung sowie der User eingetragen, welcher die Änderung ausgelöst hat. Bei Ameisen Importen steht da dann immer Administrator, wenn man da anderen Bedarf hat müsste man sich einen Weg überlegen.
Auch ist es möglich, änerungen einzuspielen, ohne Workflows auszulösen, damit kann das immer umgangen werden.

Bei näherem Interesse kannst du dich auch bei mir per PN melden.
Vielen Dank für deine Antwort. Natürlich haben wir näheres Interesse, ich weiß nur ganz und gar nichts vom Thema Datenbanken u.ä. Ich werde mal mit unserem IT-ler sprechen und dann kann der sich vielleicht, wenn nötig, mit dir in Verbindung setzen.

LG
 
  • Gefällt mir
Reaktionen: jtldudel

spn_simon

Aktives Mitglied
2. November 2014
16
1
Hierzu eine doofe Nachfrage: Im Lichte des neuen Lizenzmodels habe ich versucht eine Lösung mit den normalen Workflows zu finden.
Es scheitert für mich daran, dass es keinen Trigger [Alter VK Preis] != [Neuer VK Preis] im Artikel_Geändert gibt.

Gibt es eine Lösung ohne Custom Workflow?
 

jtldudel

Sehr aktives Mitglied
4. Januar 2018
610
194
Den custom workflow brauchst du, um direkt in die eigene DB Tabelle zu schreiben.
Du kannst den Teil auch über ein externes Skript lösen, ein custom workflow ist also nicht zwingend notwendig.

Was du anscheinend suchst, ist die Bedingung. Du natürlich einen Weg haben, den alten Preis aufzurufen nachdem der Preis geändert wurde. Wenn du wie bei mir beschrieben eine eigene Tabelle in der DB hast, kannst du dort den letzten Preis abfragen und mit dem aktuellen vergleichen, dafür musst du eine erweiterte Eigenschaft schreiben.
Alternativ kannst du auch den Preis immer in ein eigenes Feld im Artikel schreiben lassen. Das Feld kannst du leichter im Workflow abfragen, allerdings hab ich den Weg jetzt auch noch nicht gebaut also keine Ahnung ob das so easy ist wie ich hier behaupte...

Es gibt verschiedene Möglichkeiten, sowas umzusetzen.
 
  • Gefällt mir
Reaktionen: spn_simon

spn_simon

Aktives Mitglied
2. November 2014
16
1
Den custom workflow brauchst du, um direkt in die eigene DB Tabelle zu schreiben.
Du kannst den Teil auch über ein externes Skript lösen, ein custom workflow ist also nicht zwingend notwendig.

Was du anscheinend suchst, ist die Bedingung. Du natürlich einen Weg haben, den alten Preis aufzurufen nachdem der Preis geändert wurde. Wenn du wie bei mir beschrieben eine eigene Tabelle in der DB hast, kannst du dort den letzten Preis abfragen und mit dem aktuellen vergleichen, dafür musst du eine erweiterte Eigenschaft schreiben.
Alternativ kannst du auch den Preis immer in ein eigenes Feld im Artikel schreiben lassen. Das Feld kannst du leichter im Workflow abfragen, allerdings hab ich den Weg jetzt auch noch nicht gebaut also keine Ahnung ob das so easy ist wie ich hier behaupte...

Es gibt verschiedene Möglichkeiten, sowas umzusetzen.
super danke dir. Werde mal übers WE etwas drauf rumdenken - sitze erstmal an Versandworkflows, um unter die 10 manuellen und alles mit Standard zu kommen :D

Deshalb wird es wohl auch erstmal das externe Skript via Standard sein.
Wir sind online noch zu klein, dass sich eine größere JTL Edition lohnt
 

CT Cool Time

Aktives Mitglied
26. Februar 2020
13
5
Hi zusammen,

also prinzipiell wäre doch eine offizielle Lösung seitens JTL dazu ganz cool.
An sich ist es ja eigentlich nichts ungewöhnliches, dass man sich im B2C-Geschäft den Preisverlauf je Artikel anguckt.
Theoretisch könnte ich auch auf Idealo gehen, praktisch eher nicht so IDEAL(o).

Gibt's dazu denn schon einen Issue Tracker?

LG,
Jonas
 
  • Gefällt mir
Reaktionen: MichaelH

MichaelH

Sehr aktives Mitglied
17. November 2008
14.221
1.799
Preishistorie wird Ressourcen fressen, wird wohl das Argument sein ...

Allerdings könnte dies optional gemacht werden, d.h. in den Firmeneinstellungen wir einfach festgelegt ob die Historie gespeichert werden soll oder nicht.
Allerdings würde ich mit einer baldigen Umsetzung, wenn überhaupt, nicht rechnen.

  • Aus der Praxis:
    Ja, diese Historie wäre eine wertvolle Info.
  • Wir machen dies heute manuell über Excel.
  • Ein Trauerspiel, aber was soll's, hilf dir selbst, sonst hilft dir keiner.
 
  • Traurig
Reaktionen: CT Cool Time

Verkäuferlein

Sehr aktives Mitglied
29. April 2012
2.579
1.041
An sich ist es ja eigentlich nichts ungewöhnliches, dass man sich im B2C-Geschäft den Preisverlauf je Artikel anguckt.

Nicht nur das, es gibt ja zwischenzeitlich auch den 30-Tage-Preis in der PAngV, insofern würde man damit auch die Erfüllung rechtlicher Pflichten ermöglichen.

Gibt's dazu denn schon einen Issue Tracker?
Scheinbar ja:
https://issues.jtl-software.de/issues/WAWI-34972

Aber abgewiesen.
 
  • Gefällt mir
Reaktionen: CT Cool Time

spn_simon

Aktives Mitglied
2. November 2014
16
1
Kurzes Update von meiner Seite - nach langem hin und her und mit den Beschränkungen im Preismodel von JTL, haben wir es rein Datenbankseitig umgesetzt:
Custom Tabelle mit Trigger in der Datenbank und Stored Procedure.

Nachteil ist, dass diese Lösung zurzeit nur Änderungen im Netto Verkaufspreis, nicht im Sonderpreis, Kundenspezifischen Preisen oder Staffeln abdeckt. Aber nach 3h war die Luft raus ;)
Außerdem besteht natürlich die Gefahr das eine Änderung in JTL WaWi Änderungen in der Datenbank überschreiben kann. Und es ist keine schöne Ausgabe im JTL, sondern man muss sich einen Bericht selbst bauen.

Vorteil ist, so haben wir eine JTL unabhängige Lösung alle möglichen Änderungen zu protokollieren. Und gerade wenn man mehrere Benutzer hat, verhindert es eine Verzögerung beim Speichern von Artikeländerungen und es sind keine Customer Workflow nötig.

Disclaimer
Für alle die etwas ähnliches machen wollen und Ahnung von SQL haben, habe ich meinen Weg hier zusammengefasst. Für etwaige Kommentare & Verbesserungen bin ich dankbar.
ACHTUNG! Das greift direkt in die produktive Datenbank ein, also bitte nur den Code kopieren und ausführen, wenn ihr mit der SQL Datenbank vertraut seid. Unbedingt vorher alles sichern, wenn ihr euch unsicher seid :)

Diese Lösung funktioniert wie folgt
  1. Der Trigger wird aktiviert, wenn in tArtikel eine Aktualisierung stattfindet.
  2. Er prüft, ob das Feld fVKNetto geändert wurde.
  3. Wenn ja, holt er die relevanten Informationen (ArtikelID, neuer Preis, BenutzerID) aus der inserted Tabelle.
  4. Dann ruft er die Stored Procedure spUpdatePreisHistorie mit diesen Parametern auf.
  5. Die Stored Procedure prüft, ob der neue Preis sich vom letzten Preis in tArtikelPreisHistorie unterscheidet.
  6. Wenn ja, fügt sie einen neuen Eintrag in tArtikelPreisHistorie hinzu.

Diese Lösung erfüllt die Anforderungen

  • Sie erfasst Änderungen in fVKNetto in tArtikel.
  • Sie verwendet tArtikelPreisHistorie für die komplette Preishistorie.
  • Sie vergleicht mit dem letzten geänderten Preis je Artikel.
  • Sie verwendet den Benutzer der letzten Änderung aus kBenutzerLetzteAenderung in tArtikel.

Diese triggerbasierte Lösung sollte zuverlässig alle Preisänderungen erfassen, unabhängig davon, wie sie in tArtikel vorgenommen werden.
=> Auch nicht in JTL, sondern in der DB direkt erfasste Änderungen werden protokolliert

Technische Umsetzung

Erstellung neue Tabelle in der Datenbank [SQL]

SQL:
-- Tabelle für Preishistorie erstellen (falls noch nicht vorhanden)
CREATE TABLE tArtikelPreisHistorie (
kArtikelPreisHistorie INT IDENTITY(1,1) PRIMARY KEY,
kArtikel INT NOT NULL,
fVKNetto DECIMAL(10,2) NOT NULL,
dAenderungsDatum DATETIME NOT NULL,
kBenutzer INT NOT NULL
)

Initialisierung der Tabelle [SQL]
SQL:
-- Initialisieren der tArtikelPreisHistorie mit aktuellen Preisen
INSERT INTO tArtikelPreisHistorie (kArtikel, fVKNetto, dAenderungsDatum, kBenutzer)
SELECT p.kArtikel, p.fVKNetto, GETDATE(), p.kBenutzerLetzteAenderung
FROM tArtikel p
WHERE NOT EXISTS (
SELECT 1
FROM tArtikelPreisHistorie h
WHERE h.kArtikel = p.kArtikel
);

Einrichtung der Stored Procedure [SQL]
SQL:
CREATE PROCEDURE spUpdatePreisHistorie
    @ArtikelID INT,
    @NeuerPreis DECIMAL(10, 2),
    @BenutzerID INT
AS
BEGIN
    DECLARE @AlterPreis DECIMAL(10, 2);
    
    SELECT TOP 1 @AlterPreis = fVKNetto
    FROM tArtikelPreisHistorie
    WHERE kArtikel = @ArtikelID
    ORDER BY dAenderungsDatum DESC;
    
    IF @AlterPreis IS NULL OR @AlterPreis != @NeuerPreis
    BEGIN
        INSERT INTO tArtikelPreisHistorie (kArtikel, fVKNetto, dAenderungsDatum, kBenutzer)
        VALUES (@ArtikelID, @NeuerPreis, GETDATE(), @BenutzerID);
    END
END;

Die Stored Procedure ist nach Anlage zu finden unter Datenbank > Programmability > Stored Procedures

Einrichtung eines Triggers auf der Tabelle tArtikel
SQL:
CREATE TRIGGER trg_UpdatePreisHistorie
ON [dbo].[tArtikel]
AFTER UPDATE
AS
BEGIN
    IF UPDATE(fVKNetto)
    BEGIN
        DECLARE @ArtikelID INT, @NeuerPreis DECIMAL(10, 2), @BenutzerID INT;
        
        SELECT @ArtikelID = i.kArtikel,
               @NeuerPreis = i.fVKNetto,
               @BenutzerID = i.kBenutzerLetzteAenderung
        FROM inserted i
        INNER JOIN deleted d ON i.kArtikel = d.kArtikel
        WHERE i.fVKNetto <> d.fVKNetto;
        
        IF @ArtikelID IS NOT NULL
        BEGIN
            EXEC [dbo].[spUpdatePreisHistorie] @ArtikelID, @NeuerPreis, @BenutzerID;
        END
    END
END;
 

spn_simon

Aktives Mitglied
2. November 2014
16
1
Kurzes Update von meiner Seite - nach langem hin und her und mit den Beschränkungen im Preismodel von JTL, haben wir es rein Datenbankseitig umgesetzt:
Custom Tabelle mit Trigger in der Datenbank und Stored Procedure.

Nachteil ist, dass diese Lösung zurzeit nur Änderungen im Netto Verkaufspreis, nicht im Sonderpreis, Kundenspezifischen Preisen oder Staffeln abdeckt. Aber nach 3h war die Luft raus ;)
Außerdem besteht natürlich die Gefahr das eine Änderung in JTL WaWi Änderungen in der Datenbank überschreiben kann. Und es ist keine schöne Ausgabe im JTL, sondern man muss sich einen Bericht selbst bauen.

Vorteil ist, so haben wir eine JTL unabhängige Lösung alle möglichen Änderungen zu protokollieren. Und gerade wenn man mehrere Benutzer hat, verhindert es eine Verzögerung beim Speichern von Artikeländerungen und es sind keine Customer Workflow nötig.

Disclaimer
Für alle die etwas ähnliches machen wollen und Ahnung von SQL haben, habe ich meinen Weg hier zusammengefasst. Für etwaige Kommentare & Verbesserungen bin ich dankbar.
ACHTUNG! Das greift direkt in die produktive Datenbank ein, also bitte nur den Code kopieren und ausführen, wenn ihr mit der SQL Datenbank vertraut seid. Unbedingt vorher alles sichern, wenn ihr euch unsicher seid :)

Diese Lösung funktioniert wie folgt
  1. Der Trigger wird aktiviert, wenn in tArtikel eine Aktualisierung stattfindet.
  2. Er prüft, ob das Feld fVKNetto geändert wurde.
  3. Wenn ja, holt er die relevanten Informationen (ArtikelID, neuer Preis, BenutzerID) aus der inserted Tabelle.
  4. Dann ruft er die Stored Procedure spUpdatePreisHistorie mit diesen Parametern auf.
  5. Die Stored Procedure prüft, ob der neue Preis sich vom letzten Preis in tArtikelPreisHistorie unterscheidet.
  6. Wenn ja, fügt sie einen neuen Eintrag in tArtikelPreisHistorie hinzu.

Diese Lösung erfüllt die Anforderungen
  • Sie erfasst Änderungen in fVKNetto in tArtikel.
  • Sie verwendet tArtikelPreisHistorie für die komplette Preishistorie.
  • Sie vergleicht mit dem letzten geänderten Preis je Artikel.
  • Sie verwendet den Benutzer der letzten Änderung aus kBenutzerLetzteAenderung in tArtikel.

Diese triggerbasierte Lösung sollte zuverlässig alle Preisänderungen erfassen, unabhängig davon, wie sie in tArtikel vorgenommen werden.
=> Auch nicht in JTL, sondern in der DB direkt erfasste Änderungen werden protokolliert

Technische Umsetzung

Erstellung neue Tabelle in der Datenbank [SQL]

SQL:
-- Tabelle für Preishistorie erstellen (falls noch nicht vorhanden)
CREATE TABLE tArtikelPreisHistorie (
kArtikelPreisHistorie INT IDENTITY(1,1) PRIMARY KEY,
kArtikel INT NOT NULL,
fVKNetto DECIMAL(10,2) NOT NULL,
dAenderungsDatum DATETIME NOT NULL,
kBenutzer INT NOT NULL
)

Initialisierung der Tabelle [SQL]
SQL:
-- Initialisieren der tArtikelPreisHistorie mit aktuellen Preisen
INSERT INTO tArtikelPreisHistorie (kArtikel, fVKNetto, dAenderungsDatum, kBenutzer)
SELECT p.kArtikel, p.fVKNetto, GETDATE(), p.kBenutzerLetzteAenderung
FROM tArtikel p
WHERE NOT EXISTS (
SELECT 1
FROM tArtikelPreisHistorie h
WHERE h.kArtikel = p.kArtikel
);

Einrichtung der Stored Procedure [SQL]
SQL:
CREATE PROCEDURE spUpdatePreisHistorie
    @ArtikelID INT,
    @NeuerPreis DECIMAL(10, 2),
    @BenutzerID INT
AS
BEGIN
    DECLARE @AlterPreis DECIMAL(10, 2);
   
    SELECT TOP 1 @AlterPreis = fVKNetto
    FROM tArtikelPreisHistorie
    WHERE kArtikel = @ArtikelID
    ORDER BY dAenderungsDatum DESC;
   
    IF @AlterPreis IS NULL OR @AlterPreis != @NeuerPreis
    BEGIN
        INSERT INTO tArtikelPreisHistorie (kArtikel, fVKNetto, dAenderungsDatum, kBenutzer)
        VALUES (@ArtikelID, @NeuerPreis, GETDATE(), @BenutzerID);
    END
END;

Die Stored Procedure ist nach Anlage zu finden unter Datenbank > Programmability > Stored Procedures

Einrichtung eines Triggers auf der Tabelle tArtikel
SQL:
CREATE TRIGGER trg_UpdatePreisHistorie
ON [dbo].[tArtikel]
AFTER UPDATE
AS
BEGIN
    IF UPDATE(fVKNetto)
    BEGIN
        DECLARE @ArtikelID INT, @NeuerPreis DECIMAL(10, 2), @BenutzerID INT;
       
        SELECT @ArtikelID = i.kArtikel,
               @NeuerPreis = i.fVKNetto,
               @BenutzerID = i.kBenutzerLetzteAenderung
        FROM inserted i
        INNER JOIN deleted d ON i.kArtikel = d.kArtikel
        WHERE i.fVKNetto <> d.fVKNetto;
       
        IF @ArtikelID IS NOT NULL
        BEGIN
            EXEC [dbo].[spUpdatePreisHistorie] @ArtikelID, @NeuerPreis, @BenutzerID;
        END
    END
END;
Der Code hatte einen Fehler: Es wurde nur bei einem Update ein Preishistorien Eintrag erzeugt. :( Hier jetzt die angepasste Version.

Eine kleine Änderung an dieser Stelle ist auch anstatt des aktuellen Datums wird das letzte Änderungsdatum bei der initialen Ladung geschrieben.
Das ist nicht ganz genau, weil es kann ja zum Beispiel sein, dass die letzte Änderung eine neue Beschreibung ohne Preisänderung war. Leider habe ich keinen Weg gesehen, wie man Änderungen im Artikel auseinanderhalten kann, wenn man nicht selbst eine Historientabelle schreibt.

Auch hier bin ich für jeden Tipp / Kommentar dankbar.

Erstellung neue Tabelle in der Datenbank [SQL]
SQL:
-- Tabelle für Preishistorie erstellen (falls noch nicht vorhanden)
CREATE TABLE tArtikelPreisHistorie (
kArtikelPreisHistorie INT IDENTITY(1,1) PRIMARY KEY,
kArtikel INT NOT NULL,
fVKNetto DECIMAL(10,2) NOT NULL,
dAenderungsDatum DATETIME NOT NULL,
kBenutzer INT NOT NULL
)

Initialisierung der Tabelle [SQL]
SQL:
-- Initialisieren der tArtikelPreisHistorie mit aktuellen Preisen
INSERT INTO tArtikelPreisHistorie (kArtikel, fVKNetto, dAenderungsDatum, kBenutzer)
SELECT p.kArtikel, p.fVKNetto, p.dMod, p.kBenutzerLetzteAenderung
FROM tArtikel p
WHERE NOT EXISTS (
SELECT 1
FROM tArtikelPreisHistorie h
WHERE h.kArtikel = p.kArtikel
);

Einrichtung der Stored Procedure [SQL]
SQL:
--Einrichtung Stored Procedure die Preisaktualisierungen und Neuanlage (initialer Datensatz) erfasst
CREATE OR ALTER PROCEDURE spUpdatePreisHistorie
    @ArtikelID INT,
    @NeuerPreis DECIMAL(10, 2),
    @BenutzerID INT,
    @IsNewArticle BIT = 0
AS
BEGIN
    DECLARE @AlterPreis DECIMAL(10, 2);
    
    IF @IsNewArticle = 0
    BEGIN
        SELECT TOP 1 @AlterPreis = fVKNetto
        FROM tArtikelPreisHistorie
        WHERE kArtikel = @ArtikelID
        ORDER BY dAenderungsDatum DESC;
    END
    
    IF @AlterPreis IS NULL OR @AlterPreis != @NeuerPreis OR @IsNewArticle = 1
    BEGIN
        INSERT INTO tArtikelPreisHistorie (kArtikel, fVKNetto, dAenderungsDatum, kBenutzer)
        VALUES (@ArtikelID, @NeuerPreis, GETDATE(), @BenutzerID);
    END
END;
Die Stored Procedure ist zu finden unter Datenbank > Programmability > Stored Procedures

Einrichtung eines Triggers auf der Tabelle tArtikel für aktualisierte Artikel [SQL]
SQL:
--Trigger der einen Eintrag über spUpdatePreisHistorie in tArtikelPreisHistorie bei einer Artikelaktualisierung schreibt
CREATE OR ALTER TRIGGER trg_UpdatePreisHistorie
ON [dbo].[tArtikel]
AFTER UPDATE
AS
BEGIN
    IF UPDATE(fVKNetto)
    BEGIN
        DECLARE @ArtikelID INT, @NeuerPreis DECIMAL(10, 2), @BenutzerID INT;
        
        SELECT @ArtikelID = i.kArtikel,
               @NeuerPreis = i.fVKNetto,
               @BenutzerID = i.kBenutzerLetzteAenderung
        FROM inserted i
        INNER JOIN deleted d ON i.kArtikel = d.kArtikel
        WHERE i.fVKNetto <> d.fVKNetto;
        
        IF @ArtikelID IS NOT NULL
        BEGIN
            EXEC [dbo].[spUpdatePreisHistorie] @ArtikelID, @NeuerPreis, @BenutzerID, 0;
        END
    END
END;

Einrichtung eines Triggers auf der Tabelle tArtikel für neu angelegte Artikel [SQL]
SQL:
--Trigger der einen Eintrag über spUpdatePreisHistorie in tArtikelPreisHistorie bei einer ArtikelNEUanlage schreibt
CREATE OR ALTER TRIGGER trg_InsertPreisHistorie
ON [dbo].[tArtikel]
AFTER INSERT
AS
BEGIN
    DECLARE @ArtikelID INT, @NeuerPreis DECIMAL(10, 2), @BenutzerID INT;
    
    SELECT @ArtikelID = i.kArtikel,
           @NeuerPreis = i.fVKNetto,
           @BenutzerID = i.kBenutzerLetzteAenderung
    FROM inserted i;
    
    IF @ArtikelID IS NOT NULL
    BEGIN
        EXEC [dbo].[spUpdatePreisHistorie] @ArtikelID, @NeuerPreis, @BenutzerID, 1;
    END
END;
 
  • Gefällt mir
Reaktionen: Xnightman