In Diskussion FFN Kartonagen abrechnen

Torge

Gut bekanntes Mitglied
19. November 2021
111
11
Moin Moin,
wie rechnen hier die anderen FFN Nutzer die unterschiedlichen Kartonagen ab? Wir nutzen aktuell noch WAWI 1.5, ich mag in einer aktiven Produktivumgebung nicht ein in der betaphase laufendes System einsetzen.

kleine Extra FRAGE... Wird es eigentlich noch eine extra FFN Abteilung im Forum geben?? Wäre zum durchlesen mal ein bisschen angenehmer, man weiß ja nicht immer ob man die richten Suchbegriffe nutzt.

Danke

Vg
Torge
 

unblack

Sehr aktives Mitglied
23. November 2007
411
25
Kleiner workaround um Kartonagen in der 1.6 im FFN abzurechnen. Workflow mit einer erweiterten Eigenschaft machen, die checkt ob ein Karton in den Artikelpositionen enthalten ist:

Code:
{% assign Kartonage = false %}\
{% for Artikel in Vorgang.Positionen -%}\
{% capture query %}
SELECT nSonderTyp from tArtikel where cArtNr = '{{ Artikel.Artikelnummer }}'
{% endcapture -%}\
{% assign result = query | DirectQueryScalar %}\
{%if result == 1 -%}\
    {% assign Kartonage = true %}\
{% endif -%}\
{% endfor -%}\
{{ Kartonage }}

Wenn die Bedingung erfüllt ist, Abrechnungsposition Artikel hinzufügen:

Code:
{% for Artikel in Vorgang.Positionen -%}\
{% capture query %}
SELECT nSonderTyp from tArtikel where cArtNr = '{{ Artikel.Artikelnummer }}'
{% endcapture -%}\
{% assign result = query | DirectQueryScalar %}\
{%if result == 1 -%}\
    {% assign Kartonage = Artikel.Artikelnummer %}\
{% endif -%}\
{% endfor -%}\
{{ Kartonage }}
 
  • Gefällt mir
Reaktionen: wortek und Stetto

RobbyLorenz

Mitglied
14. Januar 2022
36
1
Guten Morgen,

das würde mich auch sehr interessieren. Hinzu kommt meine Frage wie kann ich nachträglich die Kartonage als Abrechnugsposition hinzufügen per Workflow. Wir wollen am Montag den ersten Csv Export der FFN Abrechnung durchführen, allerdings wurde kein Workflow für die Kartonage angelegt.

Ich hoffe sehr das von euch eine Idee dazu hat.

Viele Grüße
 

LCR

Aktives Mitglied
4. Mai 2021
1
0
Kleiner workaround um Kartonagen in der 1.6 im FFN abzurechnen. Workflow mit einer erweiterten Eigenschaft machen, die checkt ob ein Karton in den Artikelpositionen enthalten ist:

Code:
{% assign Kartonage = false %}\
{% for Artikel in Vorgang.Positionen -%}\
{% capture query %}
SELECT nSonderTyp from tArtikel where cArtNr = '{{ Artikel.Artikelnummer }}'
{% endcapture -%}\
{% assign result = query | DirectQueryScalar %}\
{%if result == 1 -%}\
    {% assign Kartonage = true %}\
{% endif -%}\
{% endfor -%}\
{{ Kartonage }}

Wenn die Bedingung erfüllt ist, Abrechnungsposition Artikel hinzufügen:

Code:
{% for Artikel in Vorgang.Positionen -%}\
{% capture query %}
SELECT nSonderTyp from tArtikel where cArtNr = '{{ Artikel.Artikelnummer }}'
{% endcapture -%}\
{% assign result = query | DirectQueryScalar %}\
{%if result == 1 -%}\
    {% assign Kartonage = Artikel.Artikelnummer %}\
{% endif -%}\
{% endfor -%}\
{{ Kartonage }}
Super Beitrag, das hilft enorm! Wie würde ich mir die Menge jetzt ziehen? Es könnten im Auftrag 2 Kartonagen hinterlegt worden sein. Karton A mit Menge 2 und Karton B mit Menge 1.
 

unblack

Sehr aktives Mitglied
23. November 2007
411
25
Super Beitrag, das hilft enorm! Wie würde ich mir die Menge jetzt ziehen? Es könnten im Auftrag 2 Kartonagen hinterlegt worden sein. Karton A mit Menge 2 und Karton B mit Menge 1.

Sorry, habe hier eine Weile nicht reingeschaut.

Der Workflow muss dort angelegt werden, wo man seine Abrechnung eingebaut hat. Also in der Regel unter Versand -> Lieferscheine -> Versendet
Bei mehreren Kartonagen sollte man zwangsläufig Lieferscheinbasiert abrechnen (also nicht mehrere Pakete pro Lieferschein machen, sondern teilliefern).
Mengen könnte man noch abfangen, aber unterschiedliche Kartonagen pro Lieferschein müsste ich länger drüber nachdenken, das ist dann ein bisschen komplexer.
 

Xndrei

Gut bekanntes Mitglied
7. Juli 2018
116
12
Hallo, müssen die Codes irgendwie noch ergänzt werden? Ich bekomme nur den Karton auf die Abrechnung. Muss man für jeden Karton einen WorkFlow erstellen?
 

wortek

Offizieller Servicepartner
SPBanner
1. Juli 2016
1.534
319
Landsberg am Lech
Sorry, habe hier eine Weile nicht reingeschaut.

Der Workflow muss dort angelegt werden, wo man seine Abrechnung eingebaut hat. Also in der Regel unter Versand -> Lieferscheine -> Versendet
Bei mehreren Kartonagen sollte man zwangsläufig Lieferscheinbasiert abrechnen (also nicht mehrere Pakete pro Lieferschein machen, sondern teilliefern).
Mengen könnte man noch abfangen, aber unterschiedliche Kartonagen pro Lieferschein müsste ich länger drüber nachdenken, das ist dann ein bisschen komplexer.
Einer unserer Kunden hatte vor längerem mal Probleme mit Teillieferungen. Die hat das FFN nicht korrekt übertragen. Laut JTL wurden die damal nicht unterstützt. Ist das inzwischen der Fall?
 

SK15

Aktives Mitglied
2. November 2022
1
0
Aktuell nutzen wir für die Kartonerfassung PackFix (https://www.jtl-software.de/extensi...packungsverwaltung-fuer-jtl-packtisch-und-wms)
Auswertung und Abrechnung über Workflow->SQL->.csv
Anbei eine Kleine Procedure, welche es ermöglicht mehrere Positionen mit verschiedenen Mengen über einen Workflow abzurechnen.

Es wird beim Lieferschein - Workflow folgendes übergeben
1. Kunden-ID
2. JSON - Inhalt der Abzurechnenden Positionen - [{"id":X1,"qty":Y1}, {"id":X2,"qty":Y2},...,{"id":XN,"qty":YN} -- X entspricht der ArtikelId und Y der Menge
3. MwSt.
4. Positionshinweis - Gilt für jede Pos.

Man könnt die Procedure noch ein bisschen optimieren und die Anzahl der Datenbankabfrage reduzieren, Sonderpreise werden ebenfalls berücksichtigt
Beim Workflow Aufruf sicher gehen, dass es sich um einen FFN-Auftrag bzw FFN-Kunden handelt.

SQL:
CREATE TYPE CustomWorkflows.Parameter_spLSFulfillmentAbrechnungPosSetzen_JSON
    FROM NVARCHAR(4000);
GO
EXEC CustomWorkflows._SetActionParameterDisplayName
    @parameterName = 'Parameter_spLSFulfillmentAbrechnungPosSetzen_JSON',
    @displayname   = 'Positionen JSON [{"id":x,"qty":y},..]';
GO

CREATE TYPE CustomWorkflows.Parameter_spLSFulfillmentAbrechnungPosSetzen_KundenId
    FROM NVARCHAR(255);
GO
EXEC CustomWorkflows._SetActionParameterDisplayName
    @parameterName = 'Parameter_spLSFulfillmentAbrechnungPosSetzen_KundenId',
    @displayname   = 'FFN-KundenId';
GO

CREATE TYPE CustomWorkflows.Parameter_spLSFulfillmentAbrechnungPosSetzen_MwSt
    FROM NVARCHAR(255);
GO
EXEC CustomWorkflows._SetActionParameterDisplayName
    @parameterName = 'Parameter_spLSFulfillmentAbrechnungPosSetzen_MwSt',
    @displayname   = 'Mehrwertssteuersatz';
GO

CREATE TYPE CustomWorkflows.Parameter_spLSFulfillmentAbrechnungPosSetzen_Hinweis
    FROM NVARCHAR(4000);
GO
EXEC CustomWorkflows._SetActionParameterDisplayName
    @parameterName = 'Parameter_spLSFulfillmentAbrechnungPosSetzen_Hinweis',
    @displayname   = 'AbrechnungsPos. Hinweis';
GO


CREATE PROCEDURE CustomWorkflows.spLSFulfillmentAbrechnungPosSetzen
    @kLieferschein          INT,
    @KundenId               CustomWorkflows.Parameter_spLSFulfillmentAbrechnungPosSetzen_KundenId,
    @PositionenJson         CustomWorkflows.Parameter_spLSFulfillmentAbrechnungPosSetzen_JSON,
    @Mehrwertssteuersatz    CustomWorkflows.Parameter_spLSFulfillmentAbrechnungPosSetzen_MwSt,
    @cHinweis               CustomWorkflows.Parameter_spLSFulfillmentAbrechnungPosSetzen_Hinweis
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

    BEGIN TRANSACTION;
    BEGIN TRY
        -- 1) Variablen deklarieren und default setzen
        DECLARE
            @nObjektPk                  INT              = @kLieferschein,
            @nObjekt                    TINYINT          = 7,
            @kKunde                     INT,
            @fMwSt                      DECIMAL(25,13),
            @kFulfillerEinstellungen    INT,
            @kBenutzer                  INT             = 1,    -- Default-User
            @kAbrechnung                INT,
            @nNeueAbrechnung            TINYINT;

        -- 2) Kunden-ID validieren
        SET @kKunde = TRY_CAST(@KundenId AS INT);
        IF @kKunde IS NULL
        BEGIN
            RAISERROR(N'Die übergebene Kunden-ID muss eine gültige Ganzzahl sein.',16,1);
            RETURN;
        END

        -- 3) MwSt validieren
        SET @fMwSt = TRY_CAST(@Mehrwertssteuersatz AS DECIMAL(25,13));
        IF @fMwSt IS NULL
        BEGIN
            RAISERROR(
              N'Der angegebene Mehrwertsteuersatz muss ein gültiger Decimal(25,13)-Wert sein (z. B. ''0'' oder ''19.00'').',
              16,1
            );
            RETURN;
        END

        -- 4) Einstellungen für diesen Kunden holen
        SELECT TOP 1
            @kFulfillerEinstellungen = kFulfillerEinstellungen
        FROM FulfillmentNetwork.tFulfillerEinstellungen
        WHERE kKunde = @kKunde;

        IF @kFulfillerEinstellungen IS NULL
        BEGIN
            RAISERROR(N'Für Kundennummer %d sind keine Fulfillment-Einstellungen hinterlegt.',16,1,@kKunde);
            RETURN;
        END

        -- 5) Aktuelle Abrechnung und ggf. neue ID holen
        EXEC FulfillmentNetwork.spGetAktuelleAbrechnung
             @kFulfillerEinstellungen = @kFulfillerEinstellungen,
             @kBenutzer               = @kBenutzer,
             @kAbrechnung             = @kAbrechnung       OUTPUT,
             @nNeueAbrechnung         = @nNeueAbrechnung   OUTPUT;

        -- 6) JSON validieren und parsen
        IF ISJSON(@PositionenJson) <> 1
        BEGIN
            RAISERROR(N'Ungültiges JSON-Format für PositionenJson. Erwartet: Array von Objekten.',16,1);
            RETURN;
        END

        DECLARE @tblPosTemp TABLE (
            kArtikel INT,
            fAnzahl  DECIMAL(25,13)
        );

        INSERT INTO @tblPosTemp(kArtikel,fAnzahl)
        SELECT id, qty
        FROM OPENJSON(@PositionenJson)
        WITH (
            id  INT             '$.id',
            qty DECIMAL(25,13)  '$.qty'
        );

        DECLARE
            @origCount INT = (SELECT COUNT(*) FROM OPENJSON(@PositionenJson)),
            @goodCount INT = (SELECT COUNT(*) FROM @tblPosTemp);

        IF @origCount <> @goodCount
        BEGIN
            RAISERROR(
              N'Die JSON-Struktur stimmt nicht: Jedes Element muss ein Integer-Feld "id" und ein Decimal-Feld "qty" haben.',
              16,1
            );
            RETURN;
        END

        DECLARE @tblPos TABLE (
            kArtikel INT,
            fAnzahl  DECIMAL(25,13)
        );

        INSERT INTO @tblPos(kArtikel,fAnzahl)
        SELECT kArtikel, fAnzahl
        FROM @tblPosTemp;

        -- 7) Loop über alle Positionen und Aufruf der Abrechnungs-SP
        DECLARE
            @kArtikel     INT,
            @fAnzahl      DECIMAL(25,13),
            @cBezeichnung NVARCHAR(256),
            @fVkNetto     DECIMAL(25,13),
            @fVKPreis     DECIMAL(25,13),
            @fEKNetto     DECIMAL(25,13),
            @cArtNr       NVARCHAR(100),
            @cEinheit     NVARCHAR(255),
            @kPreis       INT,
            @kEinheit      INT,
            @fSonderpreis DECIMAL(25,13),
            @dErstellt DATETIME = GETDATE();

        DECLARE pos_cursor CURSOR LOCAL FAST_FORWARD FOR
            SELECT kArtikel, fAnzahl
              FROM @tblPos;

        OPEN pos_cursor;
        FETCH NEXT FROM pos_cursor INTO @kArtikel, @fAnzahl;
        WHILE @@FETCH_STATUS = 0
        BEGIN
            -- 7.1) Stammdaten aus tArtikel holen
            SELECT
                @fVkNetto     = fVkNetto,
                @fEKNetto     = fEKNetto,
                @cArtNr       = cArtNr,
                @kEinheit     = kVerkaufsEinheit
            FROM dbo.tArtikel
            WHERE kArtikel = @kArtikel;

            -- Bezeichnung aus Sprach-Tabelle
            SELECT
                @cBezeichnung = cName
            FROM dbo.tArtikelBeschreibung
            WHERE kArtikel = @kArtikel;

            -- Einheit in der richtigen Sprache
            SELECT
                @cEinheit = cName
            FROM dbo.tEinheitSprache
            WHERE kEinheit = @kEinheit;

            -- 7.2) Vereinfachter Sonderpreis-Check
            -- **Reset beider Variablen am Schleifenbeginn**
            SET @kPreis       = NULL;
            SET @fSonderpreis = NULL;

            SELECT TOP 1 @kPreis = kPreis
            FROM dbo.tPreis
            WHERE kKunde   = @kKunde
              AND kArtikel = @kArtikel;

            IF @kPreis IS NOT NULL
            BEGIN
                -- Staffelpreis bestimmen: nAnzahlAb ≤ bestellte Menge, höchste nAnzahlAb zuerst
                SELECT TOP 1
                    @fSonderpreis = fNettoPreis
                FROM dbo.tPreisDetail
                WHERE kPreis     = @kPreis
                  AND nAnzahlAb <= @fAnzahl
                ORDER BY nAnzahlAb DESC;
            END

            IF @fSonderpreis IS NOT NULL
            BEGIN
                -- Override auf den Sonderpreis (auch wenn 0.00)
                SET @fVkNetto = @fSonderpreis;
                SET @fVKPreis = @fSonderpreis * (1 + (@fMwSt/100));
            END
            ELSE
            BEGIN
                -- Kein Sonderpreis: Standard-Bruttopreis aus fVkNetto
                SET @fVKPreis = @fVkNetto * (1 + (@fMwSt/100));
            END

            -- 7.3) Call der bestehenden Procedure
            EXEC FulfillmentNetwork.spAbrechnungPositionAnlegen
                @kArtikel     = @kArtikel,
                @kAbrechnung  = @kAbrechnung,
                @cBezeichnung = @cBezeichnung,
                @fVkNetto     = @fVkNetto,
                @fVKPreis     = @fVKPreis,
                @fEKNetto     = @fEKNetto,
                @fAnzahl      = @fAnzahl,
                @fRabatt      = 0,
                @fMwSt        = @fMwSt,
                @cArtNr       = @cArtNr,
                @cEinheit     = @cEinheit,
                @cHinweis     = @cHinweis,
                @nType        = 1,
                @kObjektPk    = @nObjektPk,
                @nObjekt      = @nObjekt,
                @dErstellt      = @dErstellt;

            FETCH NEXT FROM pos_cursor INTO @kArtikel, @fAnzahl;
        END

        CLOSE pos_cursor;
        DEALLOCATE pos_cursor;

        COMMIT;
    END TRY
    BEGIN CATCH
        IF XACT_STATE() <> 0 ROLLBACK;
        DECLARE
            @ErrMsg NVARCHAR(4000) = ERROR_MESSAGE(),
            @ErrSev INT           = ERROR_SEVERITY(),
            @ErrSta INT           = ERROR_STATE();
        RAISERROR(@ErrMsg,@ErrSev,@ErrSta);
    END CATCH
END;
GO

-- 4) Action-DisplayName und CheckAction
EXEC CustomWorkflows._SetActionDisplayName
    @actionName = 'spLSFulfillmentAbrechnungPosSetzen',
    @displayName = 'LS-Fulfillment: Abrechnungs-Positionen setzen';
GO
EXEC CustomWorkflows._CheckAction
    @actionName = 'spLSFulfillmentAbrechnungPosSetzen';
GO