Warenfluss
Zuletzt geändert: 11.04.2026 10:36

Warenfluss (Bestellung bis Wareneingang) #

Diese Seite zeigt den vollständigen Warenfluss von EULANDA auf SQL-Ebene – von der Bestellung beim Lieferanten bis zum Wareneingang ins Lager. Jeder Schritt enthält ein lauffähiges SQL-Beispiel und einen Verweis auf die detaillierte Prozedurdokumentation. Zusätzlich wird der direkte Wareneingang ohne Bestellung beschrieben.

Übersicht #

graph TD KF["Bestellung anlegen
cn_KfNewAndSave + cn_KfpNew"] KFBU["Bestellung buchen
cn_KfBuchen"] KFSR["Restmengen stornieren
cn_KfStornoRest"] KFSB["Buchung stornieren
cn_KfStornoBuchung"] WE["Direkter Wareneingang
cn_WejobCre"] WEI["Positionen hinzufügen
cn_WeJobItemAdd"] WEX["WE-Job ausführen
cn_WeJobExec"] KF --> KFBU KFBU -->|"komplett"| KFSR KFBU -->|"Teilstorno"| KFSR KFBU -->|"Storno"| KFSB WE --> WEI WEI --> WEX style KF fill:#2e86c1,color:#fff style KFBU fill:#27ae60,color:#fff style KFSR fill:#e67e22,color:#fff style KFSB fill:#c0392b,color:#fff style WE fill:#2e86c1,color:#fff style WEI fill:#2e86c1,color:#fff style WEX fill:#27ae60,color:#fff

Blau: Anlegen | Grün: Buchen/Ausführen | Orange: Teilstorno | Rot: Storno

Bestellungs-Flow #

1. Bestellung anlegen #

Eine Bestellung wird über cn_KfNewAndSave (Kopf) und cn_KfpNew (Positionen) erstellt. Der Kopf wird einem Kreditor (Lieferant) zugeordnet.

DECLARE @kf_id int, @kf_nummer int

-- Bestellungskopf anlegen (Kreditor-ID = Lieferant)
EXEC cn_KfNewAndSave
  @KreditorId = 15,
  @KopfId = @kf_id OUT,
  @KopfNummer = @kf_nummer OUT

-- Positionen hinzufügen
EXEC cn_KfpNew @KopfId = @kf_id, @ArtikelId = 100, @Menge = 50
EXEC cn_KfpNew @KopfId = @kf_id, @ArtikelId = 200, @Menge = 30

PRINT 'Bestellung ' + CAST(@kf_nummer AS varchar) + ' angelegt'
ParameterTypBeschreibung
@KreditorIdintKreditor-ID (Lieferant)
@KopfIdint OUTID der neuen Bestellung
@KopfNummerint OUTBestellnummer
@BearbeitetDurchvarchar(50)Sachbearbeiter (optional)

Alternativ kann cn_KfNew + cn_KfNewPost separat aufgerufen werden, um zwischen Anlage und Nummernvergabe noch Änderungen vorzunehmen.

Positionen mit cn_KfpNew #

ParameterTypBeschreibung
@KopfIdintBestellungs-ID
@ArtikelIdintArtikel-ID
@Mengenumeric(18,4)Bestellmenge (Standard: aus Positionsmengen-Init)
@AutoAddKrArtikelbit1 = Kreditor-Artikel automatisch anlegen

Die Preisfindung erfolgt automatisch über cn_KfpGetPreis. Staffelpreise aus der Kreditor-Artikelzuordnung werden berücksichtigt.

Artikel hinzufügen oder Menge addieren #

Falls ein Artikel bereits in der Bestellung vorhanden ist, kann cn_KfAddUpdateAr verwendet werden. Diese Prozedur legt eine neue Position an oder addiert die Menge auf eine bestehende Position:

-- Fügt 20 Stück hinzu (oder addiert auf bestehende Position)
EXEC cn_KfAddUpdateAr
  @KopfId = @kf_id,
  @ArtikelId = 100,
  @Menge = 20

2. Bestellung buchen (Wareneingang) #

Das Buchen einer Bestellung erzeugt die Lagerbuchung – der physische Lagerbestand wird erhöht. Der Vorgang entspricht dem Wareneingang.

EXEC cn_KfBuchen @Kf_id = @kf_id
-- oder:
EXEC cn_KfBuchen @Kf_Nummer = @kf_nummer
ParameterTypBeschreibung
@Kf_idintBestellungs-ID (alternativ: @Kf_Nummer)
@Kf_NummerintBestellnummer

Beim Buchen passiert intern:

  1. Währungsprüfung
  2. Lagerbuchungsjob wird aus den Bestellpositionen erzeugt
  3. Lagerbuchung wird über cn_Lb_DoJobEx1 ausgeführt
  4. Status wird auf 3 (gebucht) gesetzt
  5. Automatisches Ausziffern über cn_KfAusziff
  6. Optional: Lieferquellen-Pflege in den Kreditor-Artikeln

Das SQL-Ereignis KfBuchen.OnSuccess (10011) wird nach dem Buchen ausgelöst.

3. Restmengen stornieren #

Wenn eine Bestellung nicht vollständig geliefert werden soll, können die verbleibenden Mengen storniert werden:

EXEC cn_KfStornoRest
  @Kf_id = @kf_id,
  @StornoGrund = 'Lieferant kann Restmenge nicht liefern'
ParameterTypBeschreibung
@Kf_idintBestellungs-ID (alternativ: @Kf_Nummer)
@Kf_NummerintBestellnummer
@StornoGrundvarchar(100)Begründung für die Stornierung

Für die Stornierung einzelner Teilmengen steht cn_KfStornoMengen zur Verfügung. Die zu stornierenden Mengen werden über eine temporäre Tabelle #KfStornoMengen übergeben.

4. Buchung stornieren #

Eine bereits gebuchte Bestellung kann über cn_KfStornoBuchung rückgängig gemacht werden. Dabei wird eine Umkehrbuchung erzeugt und der Status zurückgesetzt:

EXEC cn_KfStornoBuchung @Kf_id = @kf_id
-- oder:
EXEC cn_KfStornoBuchung @Kf_Nummer = @kf_nummer
ParameterTypBeschreibung
@Kf_idintBestellungs-ID (alternativ: @Kf_Nummer)
@Kf_NummerintBestellnummer

Intern wird cn_Lb_Umkehr aufgerufen, um die Lagerbuchung umzukehren. Der Bestellstatus wird auf 0 (offen) zurückgesetzt.

5. Bestellung kopieren #

Eine bestehende Bestellung kann als Vorlage für eine neue verwendet werden:

DECLARE @neue_kf_id int, @neue_kf_nummer int

EXEC cn_KfCopyFromKf
  @KreditorId = 15,
  @SourceKopfId = @kf_id,
  @KopfId = @neue_kf_id OUT,
  @KopfNummer = @neue_kf_nummer OUT,
  @CopyPreise = 1
ParameterTypBeschreibung
@KreditorIdintKreditor-ID für die neue Bestellung
@SourceKopfIdintID der Quellbestellung
@CopyPreisebit1 = Preise übernehmen

6. Bestellung löschen #

Eine nicht gebuchte Bestellung kann gelöscht werden:

EXEC cn_KfDel @id = @kf_id

Das Ereignis KfDelete.Before (10026) wird vor dem Löschen aufgerufen und erlaubt ein Veto. Nach dem Löschen wird KfDelete.OnSuccess (10025) ausgelöst. Gebuchte Bestellungen mit Lieferungsverknüpfung können nicht gelöscht werden (Option KfDenyDeleteWhenCleared).

Direkter Wareneingang (ohne Bestellung) #

Für Wareneingänge, die nicht über eine Bestellung laufen (z.B. Muster, Gratisware, Korrekturen), steht der direkte Wareneingang über das Job-System zur Verfügung.

1. WE-Job anlegen #

DECLARE @JobID int

EXEC cn_WejobCre
  @GegenLO = 8000,
  @LagerGr = 1,
  @Info = 'Wareneingang Musterlieferung',
  @JobID = @JobID OUT
ParameterTypBeschreibung
@GegenLOintGegenlagerort-ID (8000 = Wareneingangskonto)
@LagerGrintLagergruppe
@Infovarchar(100)Beschreibung des Wareneingangs
@JobIDint OUTID des angelegten Jobs
@DatumdatetimeBuchungsdatum (Standard: heute)

Detaillierte Parameter: cn_WeJobCre

2. Positionen hinzufügen #

Für jede eingehende Position wird cn_WeJobItemAdd aufgerufen:

-- Position 1: 50 Stück Artikel 100
EXEC cn_WeJobItemAdd
  @JobID = @JobID,
  @ar_id = 100,
  @Menge = 50

-- Position 2: 30 Stück Artikel 200 mit EK-Preis
EXEC cn_WeJobItemAdd
  @JobID = @JobID,
  @ar_id = 200,
  @Menge = 30,
  @EkNetto = 12.50
ParameterTypBeschreibung
@JobIDintJob-ID aus cn_WejobCre
@ar_idintArtikel-ID
@Mengenumeric(18,4)Eingangsmenge
@lo_idintLagerort-ID (optional, sonst aus Lagergruppenmatrix)
@lg_idintLagergruppe (optional, ermittelt Lagerort automatisch)
@ari_nrvarchar(100)Identnummer (optional, für identpflichtige Artikel)
@ari_altnrvarchar(100)Alternative Identnummer (optional)
@lp_nrvarchar(50)Lagerplatznummer (optional)
@lp_idintLagerplatz-ID (optional)
@ari_diversebitDiverse Ident (optional)
@EkNettonumeric(18,2)Einkaufspreis netto (optional)

3. WE-Job ausführen #

Der Job wird ausgeführt und die Lagerbuchung erzeugt:

DECLARE @lbs_id int

EXEC cn_WeJobExec
  @JobID = @JobID,
  @lbs_id = @lbs_id OUT

PRINT 'Lagerbuchungssatz ' + CAST(@lbs_id AS varchar) + ' erzeugt'
ParameterTypBeschreibung
@JobIDintJob-ID aus cn_WejobCre
@lbs_idint OUTID des erzeugten Lagerbuchungssatzes

Abhängig von der Einstellung WE_EkBerechnen in konOptionen wird der EK-Preis aktualisiert:

WertVerhalten
0Keine EK-Aktualisierung
1Letzter EK wird übernommen
2Gleitender Durchschnitts-EK (gewichtet nach Bestand und Liefermenge)

Komplettbeispiel: Bestellung mit Wareneingang (SQL) #

-- ============================================
-- Bestellung anlegen und Ware einbuchen
-- ============================================
DECLARE @kf_id int, @kf_nummer int

-- 1. Bestellung anlegen (Kreditor 15 = Lieferant)
EXEC cn_KfNewAndSave
  @KreditorId = 15,
  @KopfId = @kf_id OUT,
  @KopfNummer = @kf_nummer OUT

-- 2. Positionen hinzufügen
EXEC cn_KfpNew @KopfId = @kf_id, @ArtikelId = 100, @Menge = 50
EXEC cn_KfpNew @KopfId = @kf_id, @ArtikelId = 200, @Menge = 30

-- 3. Bestellung buchen (= Wareneingang)
EXEC cn_KfBuchen @Kf_id = @kf_id

PRINT 'Bestellung ' + CAST(@kf_nummer AS varchar) + ' gebucht (Ware eingelagert)'

Komplettbeispiel: Direkter Wareneingang (SQL) #

-- ============================================
-- Wareneingang ohne Bestellung
-- ============================================
DECLARE @JobID int, @lbs_id int

-- 1. Job anlegen (Gegenlagerort 8000 = WE-Konto)
EXEC cn_WejobCre
  @GegenLO = 8000,
  @LagerGr = 1,
  @Info = 'Musterlieferung April 2026',
  @JobID = @JobID OUT

-- 2. Positionen
EXEC cn_WeJobItemAdd @JobID = @JobID, @ar_id = 100, @Menge = 10
EXEC cn_WeJobItemAdd @JobID = @JobID, @ar_id = 200, @Menge = 5, @EkNetto = 12.50

-- 3. Ausführen
EXEC cn_WeJobExec @JobID = @JobID, @lbs_id = @lbs_id OUT

PRINT 'Lagerbuchungssatz ' + CAST(@lbs_id AS varchar) + ' erzeugt'

PowerShell-Beispiele #

Die folgenden Beispiele verwenden das Modul EulandaXtools und eine ADODB-Verbindung über Get-Conn. Da EulandaXtools aktuell keine dedizierten Einkaufs-Cmdlets enthält, werden die SQL-Prozeduren direkt über $conn.Execute() aufgerufen.

Bestellung anlegen und buchen #

Import-Module EulandaXTools.psm1 -Force

# Verbindung über UDL-Datei
$conn = Get-Conn -Udl 'C:\Eulanda\EULANDA_1 Mustermann.udl'

# Bestellungskopf anlegen
$rs = $conn.Execute("
    DECLARE @id int, @nr int
    EXEC cn_KfNewAndSave @KreditorId = 15, @KopfId = @id OUT, @KopfNummer = @nr OUT
    SELECT @id AS KfId, @nr AS KfNummer
")
$kfId = $rs.Fields.Item('KfId').Value
$kfNummer = $rs.Fields.Item('KfNummer').Value
Write-Host "Bestellung $kfNummer angelegt (ID: $kfId)"

# Positionen hinzufügen
$conn.Execute("EXEC cn_KfpNew @KopfId = $kfId, @ArtikelId = 100, @Menge = 50")
$conn.Execute("EXEC cn_KfpNew @KopfId = $kfId, @ArtikelId = 200, @Menge = 30")

# Buchen (= Wareneingang)
$conn.Execute("EXEC cn_KfBuchen @Kf_id = $kfId")
Write-Host "Bestellung $kfNummer gebucht - Ware eingelagert"

Direkter Wareneingang #

Import-Module EulandaXTools.psm1 -Force

$conn = Get-Conn -Udl 'C:\Eulanda\EULANDA_1 Mustermann.udl'

# WE-Job anlegen
$rs = $conn.Execute("
    DECLARE @JobID int
    EXEC cn_WejobCre @GegenLO = 8000, @LagerGr = 1,
        @Info = 'Musterlieferung', @JobID = @JobID OUT
    SELECT @JobID AS JobID
")
$jobId = $rs.Fields.Item('JobID').Value

# Positionen
$conn.Execute("EXEC cn_WeJobItemAdd @JobID = $jobId, @ar_id = 100, @Menge = 10")
$conn.Execute("EXEC cn_WeJobItemAdd @JobID = $jobId, @ar_id = 200, @Menge = 5, @EkNetto = 12.50")

# Ausführen
$rs = $conn.Execute("
    DECLARE @lbs int
    EXEC cn_WeJobExec @JobID = $jobId, @lbs_id = @lbs OUT
    SELECT @lbs AS LbsId
")
$lbsId = $rs.Fields.Item('LbsId').Value
Write-Host "Lagerbuchungssatz $lbsId erzeugt"

Nächste Dokumentnummer ermitteln #

Für die Dokumenttypen PurchaseOrder und GoodsReceipt kann die nächste freie Nummer über Get-NextDocumentNumber ermittelt werden:

$nextKfNr = Get-NextDocumentNumber -DocumentType 'PurchaseOrder' -Conn $conn
$nextWeNr = Get-NextDocumentNumber -DocumentType 'GoodsReceipt' -Conn $conn
Write-Host "Nächste Bestellnummer: $nextKfNr, nächste WE-Nummer: $nextWeNr"

Zusammenfassung der Prozeduren #

SchrittProzedurEreignis
Bestellung anlegencn_KfNewAndSave + cn_KfpNew10012 (KfpCreate)
Bestellung buchencn_KfBuchen10011 (KfBuchen)
Restmengen stornierencn_KfStornoRest
Teilmengen stornierencn_KfStornoMengen
Buchung stornierencn_KfStornoBuchung
Bestellung löschencn_KfDel10025 / 10026
Bestellung kopierencn_KfCopyFromKf
WE-Job anlegencn_WejobCre
WE-Position hinzufügencn_WeJobItemAdd
WE-Job ausführencn_WeJobExec

Abkürzungen #

KürzelTabelleBedeutung
KFKrAuftragBestellungskopf
KFPKrAuftragPosBestellpositionen
KRKreditorLieferant
KRARKrArtikelKreditor-Artikelzuordnung
LBSLagerBuchungsSatzLagerbuchungskopf
LBZLagerBuchungsZeileLagerbuchungszeile
LGLagerGruppeLagergruppe
LKTLagerOrtLagerort

Siehe auch #