Template dati: Da ordine a incasso - Gestione ordini di vendita
Il Suo Template di Dati per l'Elaborazione degli Ordini di Vendita nel Ciclo Dall'Ordine all'Incasso.
- Attributi consigliati da raccogliere
- Attività chiave da tracciare
- Guida all’estrazione per SAP ECC
Order to Cash - Attributi della gestione ordini di vendita
| Nome | Descrizione | ||
|---|---|---|---|
Ordine cliente SalesOrder | L'identificativo univoco del documento di ordine di vendita, che funge da case primario per tracciare l'intero processo da ordine a incasso. | ||
Descrizione L'Ordine di vendita è il documento centrale del processo commerciale e rappresenta la richiesta del cliente di beni o servizi. Contiene tutte le informazioni necessarie per gestire la richiesta del cliente dall'inizio alla fine. Nel Process Mining, questo attributo è utilizzato come Case ID. Ogni numero d'Ordine di vendita univoco rappresenta un'istanza di processo end-to-end. Analizzare i processi per Ordine di vendita consente di tracciare l'intero ciclo di vita, misurare i tempi di ciclo e identificare le varianti per ogni singolo ordine cliente. Perché è importante È la chiave essenziale per collegare tutte le attività e gli eventi correlati, consentendo un’analisi end-to-end completa del percorso di ogni ordine cliente. Dove trovare Presente nella tabella Dati testata del documento di vendita (VBAK) come campo VBELN. Esempi 900001234590000123469000012347 | |||
Activity Activity | Il nome di una specifica fase o di un evento di processo avvenuto nel processo dell'ordine di vendita. | ||
Descrizione Questo attributo descrive un singolo passaggio del processo Order to Cash, ad esempio 'Sales Order Created', 'Delivery Created' o 'Payment Received'. Queste attività sono i tasselli con cui si ricostruisce il flusso del processo per ogni ordine di vendita. L'analisi della sequenza e delle tempistiche di queste attività è il cuore del Process Mining. Consente di visualizzare la mappa del processo, individuare i colli di bottiglia, scoprire varianti e verificare la conformità rispetto a un modello standard. Le attività derivano in genere da una combinazione di eventi di creazione dei documenti, cambi di stato o specifici codici di transazione registrati nel sistema. Perché è importante Le attività sono la spina dorsale della mappa di processo e consentono di visualizzare e analizzare il flusso, le deviazioni e i colli di bottiglia. Dove trovare Attributo derivato, solitamente generato in fase di estrazione dei dati mappando i T-Code SAP, i cambi di stato dei documenti (es. da VBUK, VBUP) o i log di modifica (tabelle CDHDR, CDPOS) in nomi di attività comprensibili. Esempi Ordine cliente creatoConsegna creataUscita merciFattura CreataPagamento ricevuto | |||
Ora di Inizio StartTime | Il timestamp che indica quando è iniziata un'attività o un evento. | ||
Descrizione L'ora di inizio, nota anche come timestamp dell'evento, registra la data e l'ora precise in cui si è verificata una specifica attività. Ad esempio, indica quando è stato creato un ordine di vendita, quando è stata effettuata l'uscita merci o quando è stata registrata una fattura. Questo timestamp è fondamentale per tutte le analisi basate sul tempo nel Process Mining. Serve per calcolare i tempi di ciclo tra le attività, misurare la durata totale di un caso e identificare ritardi o colli di bottiglia. I timestamp accurati sono fondamentali per le dashboard sulle prestazioni, ad esempio quelle che monitorano la puntualità di consegna o i lead time di evasione. Perché è importante Attributo fondamentale per calcolare tutte le metriche di performance, come tempi di ciclo e durate, indispensabili per individuare i colli di bottiglia. Dove trovare Attributo composito, in genere ottenuto combinando un campo data (ad es. ERDAT) e un campo ora (ad es. ERZET) da diverse tabelle SAP, come VBAK (Ordine di vendita), LIKP (Consegna) e VBRK (Fattura). Esempi 2023-04-15T09:00:12Z2023-04-16T14:30:00Z2023-04-20T11:22:45Z | |||
Sistema di Origine SourceSystem | Identifica il sistema sorgente da cui sono stati estratti i dati. | ||
Descrizione Questo attributo specifica il sistema di origine, ad esempio il nome di una particolare istanza SAP ECC o il numero di mandante. Fornisce contesto ai dati, soprattutto in ambienti con più sistemi di produzione o con dati provenienti da sistemi legacy. Nelle analisi, si usa per filtrare o segmentare i dati in base all'origine. È particolarmente utile per confrontare i processi tra sistemi diversi o durante progetti di migrazione, garantendo l'integrità e la coerenza dei dati. Perché è importante Fornisce un contesto essenziale, soprattutto in ambienti con più sistemi, consente il confronto dei processi e garantisce una tracciabilità dei dati chiara. Dove trovare Questo valore viene in genere aggiunto durante l’estrazione dei dati ed è spesso un valore statico che rappresenta l’ID del sistema SAP (SAPSID) o il mandante (MANDT). Esempi ECC_PROD_800SAP_ERP_EU1ECC_QAS_300 | |||
Ultimo Data Update LastDataUpdate | Timestamp che indica quando i dati di questo record sono stati aggiornati l’ultima volta dal sistema sorgente. | ||
Descrizione Questo attributo registra la data e l'ora dell'ultima estrazione o aggiornamento dei dati per uno specifico evento o caso. Offre trasparenza sul livello di aggiornamento dei dati analizzati. Nelle dashboard e nei report, questa informazione è fondamentale per comprendere la tempestività delle analisi. Aiuta a verificare se i risultati riflettono lo stato operativo più recente o se si basano su dati meno aggiornati, gestendo le aspettative degli utenti sul grado di aggiornamento dei dati. Perché è importante Garantisce agli utenti di sapere quanto sono aggiornati i dati, aspetto fondamentale per prendere decisioni tempestive e informate basate sul Process Mining. Dove trovare Attributo di metadati valorizzato dallo strumento o dal processo di estrazione al momento dell’ingestione. Non è presente nelle tabelle sorgente di SAP. Esempi 2024-06-10T05:00:00Z2024-06-11T05:00:00Z2024-06-12T05:00:00Z | |||
Blocco consegna DeliveryBlock | Un codice che indica se un ordine di vendita è bloccato per la consegna, impedendo la creazione del documento di consegna. | ||
Descrizione Il 'Blocco consegna' è uno stato impostato su un ordine di vendita (a livello di testata o di riga) per sospendere temporaneamente il processo prima della fase di consegna. I blocchi possono essere impostati manualmente da un utente o automaticamente dal sistema per motivi come superamento del limite di credito o dati incompleti. Questo attributo è fondamentale per la dashboard 'Analisi dei blocchi e delle rilavorazioni degli ordini di vendita'. Analizzare frequenza, durata e motivazioni dei blocchi consente di identificare i principali colli di bottiglia nell'evasione. Ridurre questi blocchi è decisivo per migliorare la puntualità delle consegne e il tempo di ciclo complessivo. Perché è importante Individua direttamente i colli di bottiglia nell’evasione. Analizzare perché e quanto spesso gli ordini vengono bloccati è cruciale per migliorare l’efficienza del flusso. Dove trovare Presente nella tabella Dati testata del documento di vendita (VBAK) come campo LIFSK. Esempi 0102Z1 | |||
Importo Netto NetAmount | Il valore totale dell'ordine di vendita, al netto di imposte e sconti a livello di testata. | ||
Descrizione Il Net Amount rappresenta il valore monetario dell’ordine di vendita. È una metrica finanziaria chiave associata a ciascuna istanza di processo. Questo attributo è essenziale per il Process Mining orientato al valore. Consente di dare priorità alle iniziative di miglioramento concentrandosi sugli ordini ad alto valore. Gli analisti possono correlare i problemi di processo, come ritardi o rework, con l’impatto economico, supportando un business case più solido per il cambiamento. Ad esempio, permette di verificare se gli ordini di valore elevato sono gestiti in modo più o meno efficiente rispetto a quelli di valore inferiore. Perché è importante Consente analisi basate sul valore, aiutando a dare priorità ai miglioramenti sugli ordini con l’impatto economico più rilevante. Dove trovare Presente nella tabella Dati testata del documento di vendita (VBAK) come campo NETWR. Esempi 1500.0012550.75850.50 | |||
Motivo del Rigetto RejectionReason | Un codice che indica il motivo per cui una riga d'ordine di vendita è stata rifiutata o annullata. | ||
Descrizione Il 'Motivo del rifiuto' spiega perché un ordine di vendita o una specifica riga non è stata evasa. Le cause possono essere annullamento da parte del cliente, indisponibilità del prodotto o altri motivi di business. Questo attributo è essenziale per la dashboard 'Tendenze di annullamento degli ordini di vendita'. Analizzando i motivi di rifiuto più ricorrenti, l'azienda può individuare le cause alla radice delle vendite perse. Queste informazioni guidano miglioramenti nella gestione delle scorte, nella strategia dei prezzi o nella comunicazione al cliente, riducendo il tasso di annullamento degli ordini. Perché è importante Spiega il perché delle cancellazioni d'ordine, consentendo l'analisi delle cause alla radice per ridurre le vendite perse e migliorare l'accuratezza delle previsioni. Dove trovare Presente nella tabella Dati posizione del documento di vendita (VBAP) come campo ABGRU. Esempi 0215Z5 | |||
Numero cliente CustomerNumber | L'identificativo univoco del cliente che ha effettuato l'ordine di vendita. | ||
Descrizione Questo attributo rappresenta il 'Sold-to Party', ovvero il cliente principale associato all'ordine di vendita. Collega la transazione a un cliente specifico nell'anagrafica clienti. L'analisi per numero cliente consente di segmentare il processo per comprendere comportamenti e prestazioni specifici per cliente. Aiuta a rispondere a domande come: quali clienti hanno i tempi di ciclo più lunghi, i tassi di rilavorazione più alti o le modifiche d'ordine più frequenti. È fondamentale per migliorare la gestione della relazione con i clienti e i livelli di servizio. Perché è importante Consente analisi in ottica cliente, aiutando a individuare problemi di processo che impattano clienti specifici e a misurare le performance per cliente. Dove trovare Presente nella tabella Dati testata del documento di vendita (VBAK) come campo KUNNR. Esempi 100234100567200112 | |||
Numero materiale MaterialNumber | L'identificativo univoco del prodotto o servizio venduto. | ||
Descrizione Il 'Numero materiale' identifica l'articolo specifico su una riga di ordine di vendita. Poiché un singolo ordine può contenere più materiali, questo attributo è in genere analizzato a livello di riga. Analizzare il processo per 'Numero materiale' aiuta a far emergere criticità legate ai prodotti. Può rivelare se alcuni articoli sono associati a tempi di evasione più lunghi, tassi più elevati di blocchi in consegna o discrepanze di fatturazione più frequenti. Ciò è cruciale per la supply chain e il product management per ottimizzare il processo sulle diverse linee di prodotto. Perché è importante Consente un'analisi del processo per prodotto, rivelando quali prodotti sono associati a inefficienze come ritardi, blocchi o rilavorazioni. Dove trovare Presente nella tabella Dati posizione del documento di vendita (VBAP) come campo MATNR. Esempi FG-1001-ARAW-205BSERV-INSTALL | |||
Organizzazione di vendita SalesOrganization | L'unità organizzativa responsabile della vendita di prodotti o servizi. | ||
Descrizione L'Organizzazione di vendita è un'entità organizzativa chiave in SAP che struttura l'azienda in base alle esigenze commerciali. È responsabile della negoziazione delle condizioni di vendita e della distribuzione di beni e servizi. Nel Process Mining, questo attributo è una dimensione di analisi fondamentale. Consente di confrontare le prestazioni di processo, l'efficienza e la conformità tra diverse unità, regioni o divisioni. Questo aiuta a individuare le best practice nelle organizzazioni più performanti e le aree di miglioramento nelle altre. Perché è importante Consente il benchmarking organizzativo, confrontando l'efficienza e la Conformità del processo tra diverse business unit o aree geografiche. Dove trovare Presente nella tabella Dati testata del documento di vendita (VBAK) come campo VKORG. Esempi 100025003100 | |||
Tempo di ciclo dell'ordine cliente SalesOrderCycleTime | La durata totale dalla creazione dell'ordine di vendita fino alla sua chiusura finale o al pagamento. | ||
Descrizione Questa metrica calcolata misura il tempo di ciclo end-to-end per un singolo ordine di vendita. In genere si ottiene come differenza tra il timestamp della prima attività ('Sales Order Created') e quello dell'ultima attività (ad es. 'Payment Received' o 'Order Item Closed'). È la misura principale per la dashboard 'Sales Order End-to-End Cycle Time' e per il KPI 'Sales Order Fulfillment Cycle Time'. Fornisce una vista di alto livello sull'efficienza del processo ed è una metrica critica per individuare gli ordini con durata elevata e lo stato di salute complessivo del processo. Analizzarne la distribuzione aiuta a definire benchmark e a monitorare l'impatto delle iniziative di miglioramento nel tempo. Perché è importante Il KPI primario per misurare la velocità e l’efficienza complessive del processo, fornendo una base di riferimento per le iniziative di miglioramento. Dove trovare Si tratta di una metrica calcolata derivata dall'Event Log, ottenuta calcolando la differenza tra il valore massimo e quello minimo di StartTime per un determinato SalesOrder. Esempi 10 giorni 4 ore25 giorni 11 ore5 giorni 2 ore | |||
Utente User | L'ID utente del dipendente che ha creato o modificato per ultimo il documento o che ha eseguito l'attività. | ||
Descrizione Questo attributo registra l'ID utente SAP responsabile di uno specifico evento nel processo. Ad esempio, consente di individuare l'addetto alle vendite che ha creato l'ordine o l'operatore di magazzino che ha contabilizzato l'uscita merci. Analizzare il processo per utente aiuta a comprendere la distribuzione del carico di lavoro, a identificare le esigenze di formazione e a rilevare le differenze nel modo in cui utenti diversi svolgono la stessa attività. È essenziale per dashboard incentrate sulle prestazioni delle risorse, sulla conformità e sull'individuazione di interventi manuali. Perché è importante Offre visibilità sulle prestazioni e sul carico di lavoro delle risorse, aiuta a individuare deviazioni di processo specifiche per utente ed è fondamentale per le analisi di conformità e di automazione. Dove trovare Presente in molte tabelle di testata SAP come campo 'Creato da' (ERNAM) o 'Modificato da' (AENAM), ad esempio in VBAK, LIKP, VBRK. Esempi CBURKEJSMITHRWILLIAMS | |||
Condizioni di spedizione ShippingConditions | Definisce la strategia di spedizione generale per la consegna delle merci al cliente. | ||
Descrizione Le condizioni di spedizione determinano come verrà spedito un ordine, ad esempio 'Standard', 'Express' o 'Ritiro'. Sono concordate con il cliente e influenzano la pianificazione logistica. Questo attributo è utilizzato nell'analisi 'Efficienza e costo del metodo di spedizione'. Segmentando il processo per condizioni di spedizione, le aziende possono verificare se alcuni metodi sono più soggetti a ritardi o presentano tempi di ciclo più lunghi. Questi dati aiutano a ottimizzare la logistica e a gestire le aspettative dei clienti riguardo ai tempi di consegna. Perché è importante Consente di analizzare le performance logistiche, aiutando a capire se determinati metodi di spedizione sono correlati a ritardi o a una maggiore efficienza. Dove trovare Presente nella tabella Dati testata del documento di vendita (VBAK) come campo VSBED. Esempi 011020 | |||
Consegna puntuale IsOnTimeDelivery | Un indicatore booleano che segnala se la merce è stata spedita entro la data di consegna confermata. | ||
Descrizione Questo attributo calcolato confronta la data effettiva di uscita merci con il 'ConfirmedDeliveryDate' per un ordine di vendita. Se la data di uscita merci è uguale o precedente a quella confermata, il valore è true; altrimenti è false. L'attributo semplifica la creazione della dashboard 'On-Time Delivery Performance' e il calcolo del KPI 'On-Time Delivery Rate'. Consente un'aggregazione e una visualizzazione più immediate delle prestazioni, senza dover eseguire confronti di date al volo in ogni analisi o grafico, offrendo un indicatore immediato dell'affidabilità delle consegne. Perché è importante Fornisce una misura chiara e semplice delle prestazioni di consegna, semplificando il calcolo del KPI complessivo On-Time Delivery Rate. Dove trovare Si tratta di un attributo calcolato. La logica confronta il timestamp dell'attività 'Goods Issued' con il valore dell'attributo 'ConfirmedDeliveryDate'. Esempi truefalse | |||
Data di consegna confermata ConfirmedDeliveryDate | La data in cui la consegna di beni o servizi è stata confermata al cliente. | ||
Descrizione È la data di consegna confermata al cliente, definita in base alla disponibilità dei materiali e alla pianificazione. Costituisce la base di riferimento per misurare le performance di consegna. Questo attributo è alla base della Dashboard "On-Time Delivery Performance" e del KPI On-Time Delivery Rate. Confrontando la data di consegna confermata con la data effettiva di "Uscita merci", l’analisi determina se un ordine è stato consegnato puntuale, in anticipo o in ritardo. È una misura fondamentale dell’affidabilità della supply chain e della soddisfazione del cliente. Perché è importante Il riferimento per misurare la puntualità delle consegne, un KPI cruciale per la soddisfazione del cliente e l’efficienza della supply chain. Dove trovare Presente nella tabella Righe di pianificazione del documento di vendita (VBEP) come campo EDATU. Esempi 2023-05-102023-06-202023-07-01 | |||
È una Rilavorazione IsRework | Un indicatore booleano che segnala se un ordine di vendita ha subito una modifica significativa o un'attività di rilavorazione dopo la creazione iniziale. | ||
Descrizione Questo attributo calcolato identifica le istanze di processo che hanno subito rilavorazioni, ad esempio una o più attività 'Sales Order Changed'. La logica che definisce cosa si intende per rilavorazione (ad esempio modifiche a prezzo, quantità o data di consegna) viene stabilita in fase di impostazione del progetto. È un attributo fondamentale per la dashboard 'Sales Order Rework and Change Frequency' e per il KPI 'Sales Order Rework Rate'. Semplifica l'analisi consentendo il filtro diretto e il confronto tra ordini che hanno seguito un percorso lineare e ordini che hanno richiesto modifiche manuali. Aiuta a quantificare l'impatto delle rilavorazioni su tempi di ciclo e costi. Perché è importante Quantifica direttamente la frequenza delle rilavorazioni, consentendo di analizzarne le cause e l’impatto sull’efficienza complessiva e sul tempo di ciclo. Dove trovare Si tratta di un attributo calcolato derivato dall'Event Log. La logica verifica la presenza di attività 'Sales Order Changed' oppure di specifici eventi di modifica dalle tabelle CDHDR/CDPOS. Esempi truefalse | |||
Stato della verifica del credito CreditCheckStatus | Indica lo stato del controllo del credito del documento di vendita. | ||
Descrizione Questo attributo mostra l'esito della verifica del credito, automatica o manuale, eseguita su un ordine di vendita. Gli stati più comuni sono 'Approved', 'Rejected' o 'Blocked'. È un attributo chiave per la dashboard 'Analisi dei tempi di verifica del credito'. Ritardi o blocchi in questa fase possono incidere in modo significativo sul tempo di ciclo complessivo di evasione dell'ordine. Analizzare questo stato aiuta a comprendere l'efficienza del processo di gestione del credito e il suo impatto sulla velocità delle vendite. Perché è importante Incide direttamente sulla velocità di elaborazione degli ordini. L’analisi di questo stato aiuta a individuare i colli di bottiglia nella gestione del credito che ritardano l’evasione. Dove trovare Presente nella tabella Stato testata del documento di vendita (VBUK) o direttamente in VBAK come campo di stato del credito (es. CMGST). Esempi ABD | |||
Order to Cash - Attività di gestione ordini di vendita
| Activity | Descrizione | ||
|---|---|---|---|
Fattura Creata | Segna la creazione della fattura cliente o del documento di fatturazione. È un evento esplicito che genera un nuovo documento nel sistema e avvia la fase di pagamento del processo. | ||
Perché è importante Traguardo cruciale che fa partire il conteggio del "Invoice to Payment Cycle Time". I ritardi nella fatturazione impattano direttamente sul flusso di cassa. Dove trovare Registrato nella tabella VBRK (Documento di fatturazione: dati di testata) in base alla data di creazione (ERDAT). Il collegamento all'ordine cliente o alla consegna è nella tabella VBFA. Acquisisci Evento basato sul timestamp di creazione (ERDAT) nella tabella VBRK. Tipo di evento explicit | |||
Ordine cliente creato | Segna la creazione di un nuovo ordine di vendita. È un evento esplicito registrato quando un utente salva un nuovo ordine, tipicamente tramite la transazione VA01 in SAP. | ||
Perché è importante È l’evento di avvio principale del processo Order to Cash. Analizzarne la tempistica è essenziale per misurare il tempo di ciclo complessivo e il tasso di acquisizione degli ordini. Dove trovare Registrato nella tabella VBAK (Dati testata documento di vendita) utilizzando la data di creazione (ERDAT) e l'ora (ERZET). Il codice di transazione è memorizzato in VBAK-TCODE. Acquisisci Evento basato sul timestamp di creazione (ERDAT, ERZET) nella tabella VBAK. Tipo di evento explicit | |||
Ordine confermato | Questa attività indica che l'ordine di vendita ha superato tutti i controlli iniziali ed è confermato ai fini dell'evasione. In genere si deduce quando l'ordine non è più bloccato e presenta quantità confermate nelle righe di programmazione. | ||
Perché è importante Traguardo chiave che separa l’inserimento dell’ordine dall’evasione. È il punto di partenza per misurare i lead time di evasione e la puntualità delle consegne. Dove trovare Si può dedurre quando le righe di programma in VBEP hanno una quantità confermata (BMENG > 0) e l'ordine non è bloccato per la consegna (ad es. VBUK-LIFSK è vuoto). Acquisisci Deducibile dalla conferma delle righe di programmazione (VBEP-BMENG > 0) e dalla rimozione dei blocchi a livello di testata. Tipo di evento inferred | |||
Pagamento ricevuto | Questo evento indica che il pagamento del cliente è stato ricevuto e registrato sulla fattura, chiudendo la partita clienti aperta. È un evento contabile, dedotto dalla compensazione di un documento contabile. | ||
Perché è importante È l’ultimo passo per trasformare la vendita in incasso. Rappresenta il punto finale per misurare il "Invoice to Payment Cycle Time" e, in generale, il "Sales Order Fulfillment Cycle Time". Dove trovare Deducibile dalle informazioni del documento di compensazione nella tabella BSEG per la riga cliente. Quando BSEG-AUGBL (Clearing Document) e BSEG-AUGDT (Clearing Date) sono valorizzati, il pagamento risulta ricevuto. Acquisisci Deducibile dalla valorizzazione della data di compensazione (AUGDT) nella tabella BSEG per la partita cliente. Tipo di evento inferred | |||
Riga dell’ordine chiusa | Questa attività segna la chiusura finale di una riga di ordine di vendita, indicando che è completamente consegnata, fatturata e considerata conclusa. L'informazione è dedotta dallo stato complessivo della riga. | ||
Perché è importante Rappresenta l'evento di chiusura positiva del processo. Analizzare quando si chiudono gli ordini aiuta a comprendere la durata end-to-end e a individuare quelli che restano aperti inutilmente. Dove trovare Deducibile dal campo di stato complessivo nella tabella VBUP (Sales Document: Item Status) per la riga. Quando VBUP-GBSTA è 'C' (Completely processed), la riga risulta chiusa. Acquisisci Deducibile quando lo stato della riga (VBUP-GBSTA) passa a 'C' (Completely processed). Tipo di evento inferred | |||
Uscita merci | Evento critico in cui la proprietà della merce viene trasferita e i beni lasciano ufficialmente il magazzino. Si tratta di una registrazione contabile esplicita che crea un documento di materiale e aggiorna le giacenze. | ||
Perché è importante È l’evento di spedizione e un traguardo chiave per misurare la puntualità di consegna e i lead time di evasione. Attiva aggiornamenti contabili ed è un punto di non ritorno nell’evasione fisica. Dove trovare Creazione di un documento materiale (MKPF/MSEG) con un movimento di uscita merci (es. 601), collegato al documento di consegna. Acquisisci Creazione di un documento materiale (MKPF/MSEG) con un movimento di uscita merci, collegato alla consegna. Tipo di evento explicit | |||
Blocco consegna impostato | Rappresenta l'azione con cui si applica un blocco di consegna all'ordine cliente, impedendo la creazione del documento di consegna. Può essere rilevata esplicitamente dai log delle modifiche o dedotta dalle tabelle di stato. | ||
Perché è importante Questa attività è direttamente correlata al KPI 'Tasso di blocco degli ordini di vendita'. Identificare perché e con quale frequenza vengono impostati i blocchi aiuta a far emergere le cause dei ritardi nell'evasione. Dove trovare Reperibile nei log di modifica (CDHDR/CDPOS) per il campo VBAK-LIFSK. In alternativa, si può dedurre osservando quando il campo VBAK-LIFSK viene valorizzato. Acquisisci Evento dai documenti di modifica per il campo VBAK-LIFSK o VBAP-LIFSP. Tipo di evento explicit | |||
Consegna creata | Questo evento segna la creazione del documento di consegna in uscita: l'istruzione al magazzino per avviare le attività di picking e spedizione. Si tratta di un evento esplicito rilevato dal flusso documentale. | ||
Perché è importante È il primo passo dell’evasione fisica. Il tempo tra la conferma dell’ordine e la creazione della consegna indica quanto rapidamente si avvia il processo logistico. Dove trovare La creazione di un record nella tabella LIKP (SD Document: Delivery Header Data). Il collegamento all'ordine di vendita è tracciato nella tabella del flusso documenti VBFA. Acquisisci Evento basato sul timestamp di creazione nella tabella LIKP, collegata tramite la tabella VBFA. Tipo di evento explicit | |||
Fattura Annullata | Rappresenta lo storno di un documento di fatturazione precedentemente creato. È una transazione esplicita che genera un nuovo documento di storno per compensare l'originale. | ||
Perché è importante Monitorare gli annullamenti di fattura aiuta a individuare problemi di prezzi, discrepanze di spedizione o errori nei dati. Questo alimenta il KPI "Invoice Discrepancy Rate". Dove trovare Evento esplicito rilevato dalla creazione di un documento di fatturazione di storno (VBRK-VBTYP = 'N' o 'O'). La fattura originale è richiamata in VBRK-SFAKN. Acquisisci Creazione di un documento di storno in VBRK con riferimento alla fattura originale. Tipo di evento explicit | |||
Ordine annullato | Indica che un ordine di vendita è stato annullato prima dell’evasione. Di solito è registrato applicando un 'motivo di rifiuto' a tutte le posizioni interessate dell’ordine. | ||
Perché è importante Punto di fallimento critico che alimenta direttamente il KPI "Order Cancellation Rate". Capire quando e perché gli ordini vengono annullati fornisce indicazioni preziose sulle criticità del processo di vendita. Dove trovare Deducibile dal popolamento del campo VBAP-ABGRU (Reason for rejection) per tutte le righe attive di un ordine di vendita. La data della modifica è reperibile in CDHDR/CDPOS. Acquisisci Deducibile dalla valorizzazione del campo 'Reason for Rejection' (VBAP-ABGRU) su tutte le righe. Tipo di evento inferred | |||
Ordine cliente modificato | Rappresenta una modifica apportata a un ordine cliente esistente dopo la creazione iniziale. Queste variazioni sono tracciate nelle tabelle di log delle modifiche dedicate (CDHDR, CDPOS) quando vengono alterati campi come quantità, prezzo o date. | ||
Perché è importante Tracciare le modifiche aiuta a identificare rilavorazioni, instabilità del processo e problemi di qualità dei dati. Un’elevata frequenza di modifiche può indicare criticità nella fase di inserimento dell’ordine, con conseguenti ritardi. Dove trovare Recuperato dalle tabelle dei documenti di modifica CDHDR (testata) e CDPOS (posizione) per OBJECTCLAS = 'VERKBELEG'. È possibile identificare il timestamp e il campo modificato. Acquisisci Evento dalle tabelle dei documenti di modifica (CDHDR, CDPOS) per gli oggetti dei documenti di vendita. Tipo di evento explicit | |||
Picking completato | Indica che tutti gli articoli della consegna sono stati prelevati fisicamente dal magazzino. Se è in uso Warehouse Management (WM), ciò può essere dedotto dallo stato dell'ordine di trasferimento. | ||
Perché è importante Analizzare i tempi di picking aiuta a ottimizzare le operazioni di magazzino. I ritardi in questa fase impattano direttamente sui tempi di spedizione e sull'intero ciclo di evasione. Dove trovare Deducibile dal passaggio dello stato di picking della riga di consegna in LIPS-KOSTA a 'C' (fully picked). Se WM è attivo, può essere dedotto dalla conferma del Transfer Order (tabelle LTAK/LTAP). Acquisisci Deducibile da una variazione dello stato di picking (LIPS-KOSTA) o dalla conferma del Transfer Order WM. Tipo di evento inferred | |||
Proof of Delivery (POD) confermata | Questa attività rappresenta la conferma che il cliente ha ricevuto la merce. È registrata quando la prova di consegna viene inserita a sistema, spesso aggiornando lo stato del documento di consegna. | ||
Perché è importante Questo evento fornisce la data di consegna effettiva, essenziale per misurare con precisione l'On-Time Delivery Rate rispetto alla data promessa. Dove trovare Deducibile dallo stato di proof of delivery (VBUK-PODAT) impostato a 'C' (Confirmed). La data di conferma è memorizzata in VLPOD-PODAT. Questa funzionalità non è sempre implementata. Acquisisci Deducibile dall’aggiornamento dello stato POD sulla consegna (VBUK-PODAT) o da una voce nella tabella VLPOD. Tipo di evento inferred | |||
Verifica del credito eseguita | Indica il completamento del controllo del credito, automatico o manuale, del cliente relativo all'ordine di vendita. In genere si deduce da una variazione dello stato complessivo del credito del documento. | ||
Perché è importante La verifica del credito è spesso un collo di bottiglia critico. Misurare il tempo impiegato per questo passaggio è essenziale per la dashboard 'Analisi dei tempi di elaborazione della verifica del credito' e per accelerare l'elaborazione degli ordini. Dove trovare Deducibile dai campi di stato del credito nella tabella VBUK (Sales Document: Header Status). Un passaggio di VBUK-CMGST da bloccato a rilasciato contrassegna questa attività. Acquisisci Deducibile dalle variazioni del campo di stato del credito complessivo (VBUK-CMGST). Tipo di evento inferred | |||
Guide all'Estrazione
Fasi
- Sviluppo del programma: Con la transazione SE38 o SE80, crei un nuovo programma ABAP eseguibile. Questo programma conterrà l'intera logica di estrazione.
- Definizione della schermata di selezione: Nel programma, crei una schermata di selezione per filtrare i dati. Includa i parametri per la data di creazione del documento di vendita (VBAK-ERDAT), l'organizzazione di vendita (VBAK-VKORG) e il tipo di documento di vendita (VBAK-AUART). Questo rende l'estrazione riutilizzabile e gestibile.
- Dichiarazioni dei dati: Definisca le tabelle interne e le strutture necessarie a contenere i dati provenienti da varie tabelle SAP (ad es. VBAK, VBAP, VBFA, CDHDR, CDPOS, VBRK, BSAD). Definisca inoltre la struttura di output finale per l'Event Log in linea con gli attributi richiesti.
- Selezione degli ordini base: Scriva lo statement SELECT iniziale per recuperare le testate (VBAK) e le posizioni (VBAP) degli ordini di vendita in base ai valori immessi nella schermata di selezione. Questo costituisce l'insieme principale di casi da analizzare.
- Estrazione dell'evento di creazione: Scorra in ciclo i record VBAK selezionati. Per ciascun record, compili la struttura dell'Event Log con l'attività 'Ordine di vendita creato', utilizzando VBAK-ERDAT e VBAK-ERZET per il StartTime.
- Estrazione degli eventi dal Change Log: Selezioni i record da CDHDR e CDPOS in cui OBJECTCLAS è 'VERKBELEG' per gli ordini selezionati. Scorra i risultati per identificare variazioni specifiche di campo. Ad esempio, una modifica a VBAK-LIFSK indica 'Blocco consegna impostato', mentre una modifica a VBUK-CMGST indica 'Controllo credito eseguito'. Qualsiasi altra modifica rilevante può essere registrata come 'Ordine di vendita modificato'.
- Estrazione del flusso documenti: Per gli ordini selezionati, interroghi la tabella del flusso documentale (VBFA). Questa tabella collega gli ordini di vendita a documenti successivi come consegne, movimenti di magazzino e fatture. Selezioni tutti i documenti correlati per l'elaborazione successiva.
- Estrazione degli eventi di consegna ed evasione: Utilizzando i numeri di consegna da VBFA, interroghi LIKP e LIPS per gli eventi 'Consegna creata'. Interroghi MKPF e MSEG per i documenti di uscita merce (tipo movimento '601') per rilevare l'evento 'Uscita merce registrata'. Se Warehouse Management è attivo, interroghi LTAK e LTAP per trovare l'ora di conferma dell'ultima posizione dell'ordine di trasferimento e determinare 'Picking completato'. Controlli lo stato di testata di consegna VBUK-PODAT per 'Proof of Delivery confermata'.
- Estrazione di fatturazione e pagamento: Utilizzando i numeri di documento di fatturazione da VBFA, interroghi VBRK e VBRP per rilevare gli eventi 'Fattura creata' e 'Fattura stornata' (dove VBRK-FKSTO = 'X'). Per individuare 'Pagamento ricevuto', colleghi la fattura di VBRK al documento contabile in BKPF, quindi trovi il documento di compensazione e la relativa data in BSAD.
- Estrazione basata sugli stati: Utilizzi le tabelle di stato VBUP (stato riga) e VBUK (stato testata) per dedurre eventi di business. Ad esempio, una riga è considerata 'Riga ordine chiusa' quando VBUP-GBSTA è uguale a 'C'. Un ordine è 'Ordine annullato' quando per tutte le righe rilevanti è impostato un 'Motivo di rifiuto' (VBAP-ABGRU).
- Consolidamento e formattazione: Combini tutti gli eventi raccolti in un'unica tabella interna finale. Si assicuri che tutti gli attributi (SalesOrder, Activity, StartTime, User, ecc.) siano valorizzati correttamente per ogni record evento. Aggiunga i timestamp SourceSystem e LastDataUpdate.
- Generazione del file di output: Utilizzi il modulo funzione GUI_DOWNLOAD o il metodo cl_gui_frontend_services=>gui_download per esportare la tabella interna finale in un file CSV sul computer locale dell'utente. Verifichi che il file sia salvato con codifica UTF-8.
Configurazione
- Prerequisiti: Autorizzazioni da sviluppatore ABAP (ad es. accesso alla transazione SE38) e permessi di lettura per tutte le tabelle SAP necessarie, incluse VBAK, VBAP, CDHDR, CDPOS, VBFA, LIKP, LIPS, VBRK, VBRP, MKPF, MSEG e BSAD.
- Parametri di selezione: Il programma deve prevedere una schermata di selezione con parametri di filtro. Principali parametri:
- Intervallo di date: Intervallo obbligatorio per la data di creazione degli ordini di vendita (VBAK-ERDAT). Per mantenere il volume dei dati gestibile, si consiglia di partire da un periodo recente di 3 a 6 mesi.
- Organizzazione di vendita: Filtri tramite VBAK-VKORG per concentrare l'analisi su specifiche unità aziendali.
- Tipo di documento di vendita: Filtri tramite VBAK-AUART per includere solo i tipi di ordine rilevanti (ad es. ordini standard) ed escludere gli altri (ad es. preventivi, resi).
- Considerazioni sulle prestazioni: L'estrazione dalle tabelle del log delle modifiche (CDHDR, CDPOS) e dal flusso dei documenti (VBFA) può risultare molto lenta con grandi volumi di dati. Il programma va ottimizzato usando campi indicizzati nelle clausole WHERE. Per estrazioni molto ampie, pianifichi l'esecuzione come job in background nelle ore di minor carico tramite la transazione SM36.
- Attivazione del log delle modifiche: Questo metodo si basa sulla funzionalità di SAP per i documenti di modifica. Verifichi che la registrazione delle modifiche sia abilitata per gli elementi dati chiave (ad es. LIFSK, CMGST, ABGRU). Il controllo può essere effettuato tramite la transazione SCDO per l'oggetto VERKBELEG.
a Query di Esempio abap
REPORT Z_O2C_PM_EXTRACTOR.
*&---------------------------------------------------------------------*
*& Data Declarations
*&---------------------------------------------------------------------*
TABLES: vbak.
TYPES: BEGIN OF ty_event_log,
salesorder TYPE vbeln_va,
activity TYPE string,
starttime TYPE string,
sourcesystem TYPE logsys,
lastdataupdate TYPE string,
user TYPE ernam,
customernumber TYPE kunnr,
salesorganization TYPE vkorg,
netamount TYPE netwr,
materialnumber TYPE matnr,
deliveryblock TYPE lifsk,
rejectionreason TYPE abgru,
salesordercycletime TYPE string, " Placeholder for calculation
END OF ty_event_log.
DATA: gt_event_log TYPE TABLE OF ty_event_log.
DATA: gs_event_log TYPE ty_event_log.
DATA: gv_sysid TYPE logsys.
DATA: gv_last_update TYPE string.
*&---------------------------------------------------------------------*
*& Selection Screen
*&---------------------------------------------------------------------*
SELECT-OPTIONS: s_erdat FOR vbak-erdat OBLIGATORY,
s_vkorg FOR vbak-vkorg,
s_auart FOR vbak-auart.
PARAMETERS: p_file TYPE rlgrap-filename OBLIGATORY DEFAULT 'C:\temp\o2c_event_log.csv'.
*&---------------------------------------------------------------------*
*& Main Processing Block
*&---------------------------------------------------------------------*
START-OF-SELECTION.
CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET'
IMPORTING
own_logical_system = gv_sysid.
CONCATENATE sy-datum sy-uzeit INTO gv_last_update.
PERFORM get_base_data.
PERFORM write_output_file.
*&---------------------------------------------------------------------*
*& Form get_base_data
*&---------------------------------------------------------------------*
FORM get_base_data.
TYPES: BEGIN OF ty_order_item,
vbeln TYPE vbeln_va,
posnr TYPE posnr_va,
erdat TYPE erdat,
erzet TYPE erzet,
ernam TYPE ernam,
kunnr TYPE kunnr,
vkorg TYPE vkorg,
netwr TYPE netwr_ak,
matnr TYPE matnr,
lifsk TYPE lifsk,
abgru TYPE abgru,
END OF ty_order_item.
DATA: lt_order_items TYPE TABLE OF ty_order_item.
SELECT h~vbeln i~posnr h~erdat h~erzet h~ernam h~kunnr h~vkorg h~netwr i~matnr h~lifsk i~abgru
INTO TABLE lt_order_items
FROM vbak AS h
INNER JOIN vbap AS i ON h~vbeln = i~vbeln
WHERE h~erdat IN s_erdat
AND h~vkorg IN s_vkorg
AND h~auart IN s_auart.
CHECK sy-subrc = 0.
DATA(lt_vbeln_range) = VALUE rsdsselopt_t(
FOR <fs_item> IN lt_order_items WHERE ( vbeln = <fs_item>-vbeln )
( sign = 'I' option = 'EQ' low = <fs_item>-vbeln ) ).
SORT lt_vbeln_range BY low.
DELETE ADJACENT DUPLICATES FROM lt_vbeln_range COMPARING low.
PERFORM extract_order_created USING lt_order_items.
PERFORM extract_changes USING lt_vbeln_range lt_order_items.
PERFORM extract_doc_flow_events USING lt_vbeln_range lt_order_items.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form extract_order_created
*&---------------------------------------------------------------------*
FORM extract_order_created USING it_order_items TYPE ANY TABLE.
FIELD-SYMBOLS: <fs_item> TYPE any.
DATA: lt_unique_orders TYPE HASHED TABLE OF vbeln_va WITH UNIQUE KEY table_line.
lt_unique_orders = VALUE #( FOR <order> IN it_order_items ( CONV vbeln_va( <order>-vbeln ) ) ).
LOOP AT it_order_items ASSIGNING <fs_item> WHERE table_line IN lt_unique_orders.
CLEAR gs_event_log.
gs_event_log-salesorder = <fs_item>-vbeln.
gs_event_log-activity = 'Sales Order Created'.
CONCATENATE <fs_item>-erdat <fs_item>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_item>-ernam.
gs_event_log-customernumber = <fs_item>-kunnr.
gs_event_log-salesorganization = <fs_item>-vkorg.
gs_event_log-netamount = <fs_item>-netwr.
APPEND gs_event_log TO gt_event_log.
DELETE lt_unique_orders WHERE table_line = <fs_item>-vbeln.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form extract_changes
*&---------------------------------------------------------------------*
FORM extract_changes USING it_vbeln_range TYPE rsdsselopt_t it_order_items TYPE ANY TABLE.
DATA: lt_cdhdr TYPE TABLE OF cdhdr,
lt_cdpos TYPE TABLE OF cdpos.
SELECT * INTO TABLE lt_cdhdr FROM cdhdr
WHERE objectclas = 'VERKBELEG'
AND objectid IN it_vbeln_range
AND tcode = 'VA02'.
IF sy-subrc = 0.
SELECT * INTO TABLE lt_cdpos FROM cdpos
FOR ALL ENTRIES IN lt_cdhdr
WHERE objectclas = lt_cdhdr-objectclas
AND objectid = lt_cdhdr-objectid
AND changenr = lt_cdhdr-changenr.
ENDIF.
LOOP AT lt_cdhdr ASSIGNING FIELD-SYMBOL(<fs_cdhdr>).
DATA(lv_order_info) = REF #( it_order_items[ vbeln = <fs_cdhdr>-objectid ] ).
IF lv_order_info IS NOT BOUND. CONTINUE. ENDIF.
CLEAR gs_event_log.
gs_event_log-salesorder = <fs_cdhdr>-objectid.
gs_event_log-user = <fs_cdhdr>-username.
CONCATENATE <fs_cdhdr>-udate <fs_cdhdr>-utime INTO gs_event_log-starttime.
gs_event_log-customernumber = lv_order_info->kunnr.
gs_event_log-salesorganization = lv_order_info->vkorg.
gs_event_log-netamount = lv_order_info->netwr.
" Generic Change Event
gs_event_log-activity = 'Sales Order Changed'.
APPEND gs_event_log TO gt_event_log.
LOOP AT lt_cdpos ASSIGNING FIELD-SYMBOL(<fs_cdpos>)
WHERE objectclas = <fs_cdhdr>-objectclas
AND objectid = <fs_cdhdr>-objectid
AND changenr = <fs_cdhdr>-changenr.
CASE <fs_cdpos>-fname.
WHEN 'LIFSK'. " Delivery Block
gs_event_log-activity = 'Delivery Block Set'.
gs_event_log-deliveryblock = <fs_cdpos>-value_new.
APPEND gs_event_log TO gt_event_log.
WHEN 'CMGST'. " Credit Status
IF <fs_cdpos>-value_new = 'B'. " B = Credit Check OK
gs_event_log-activity = 'Credit Check Performed'.
APPEND gs_event_log TO gt_event_log.
ENDIF.
WHEN 'ABGRU'. " Rejection Reason
IF <fs_cdpos>-value_new IS NOT INITIAL.
gs_event_log-activity = 'Order Cancelled'.
gs_event_log-rejectionreason = <fs_cdpos>-value_new.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDCASE.
ENDLOOP.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form extract_doc_flow_events
*&---------------------------------------------------------------------*
FORM extract_doc_flow_events USING it_vbeln_range TYPE rsdsselopt_t it_order_items TYPE ANY TABLE.
DATA: lt_vbfa TYPE TABLE OF vbfa,
lt_vbrk TYPE TABLE OF vbrk,
lt_likp TYPE TABLE OF likp,
lt_mseg TYPE TABLE OF mseg,
lt_bsad TYPE TABLE OF bsad,
lt_vbup TYPE TABLE OF vbup.
SELECT * INTO TABLE lt_vbfa FROM vbfa
WHERE vbelv IN it_vbeln_range
AND ( vbtyp_n = 'J' " Delivery
OR vbtyp_n = 'M' " Invoice
OR vbtyp_n = 'N' " Invoice Cancellation
OR vbtyp_n = 'R' ). " Goods Movement
IF lt_vbfa IS INITIAL. RETURN. ENDIF.
SELECT vbeln, erdat, erzet, ernam, fksto, belnr FROM vbrk INTO TABLE lt_vbrk
FOR ALL ENTRIES IN lt_vbfa
WHERE vbeln = lt_vbfa-vbeln
AND ( lt_vbfa-vbtyp_n = 'M' OR lt_vbfa-vbtyp_n = 'N' ).
SELECT vbeln, erdat, erzet, ernam, podat FROM likp INTO TABLE lt_likp
FOR ALL ENTRIES IN lt_vbfa
WHERE vbeln = lt_vbfa-vbeln AND lt_vbfa-vbtyp_n = 'J'.
SELECT mblnr, mjahr, zeile, bwart, budat, cpuzt, usnam FROM mseg INTO TABLE lt_mseg
FOR ALL ENTRIES IN lt_vbfa
WHERE mblnr = lt_vbfa-vbeln AND mjahr = lt_vbfa-mjahr AND zeile = lt_vbfa-posnn AND lt_vbfa-vbtyp_n = 'R' AND bwart = '601'.
SELECT augdt, belnr, gjahr, kunnr FROM bsad INTO TABLE lt_bsad
FOR ALL ENTRIES IN lt_vbrk
WHERE belnr = lt_vbrk-belnr AND gjahr = SUBSTRING( val = lt_vbrk-erdat len = 4 ).
SELECT vbeln, posnr, gbsta FROM vbup INTO TABLE lt_vbup
FOR ALL ENTRIES IN lt_vbfa
WHERE vbeln = lt_vbfa-vbelv AND posnr = lt_vbfa-posnv.
LOOP AT lt_vbfa ASSIGNING FIELD-SYMBOL(<fs_vbfa>).
DATA(lv_order_info) = REF #( it_order_items[ vbeln = <fs_vbfa>-vbelv ] ).
IF lv_order_info IS NOT BOUND. CONTINUE. ENDIF.
CLEAR gs_event_log.
gs_event_log-salesorder = <fs_vbfa>-vbelv.
gs_event_log-customernumber = lv_order_info->kunnr.
gs_event_log-salesorganization = lv_order_info->vkorg.
gs_event_log-netamount = lv_order_info->netwr.
gs_event_log-materialnumber = lv_order_info->matnr.
CASE <fs_vbfa>-vbtyp_n.
WHEN 'J'. " Delivery
READ TABLE lt_likp ASSIGNING FIELD-SYMBOL(<fs_likp>) WITH KEY vbeln = <fs_vbfa>-vbeln.
IF sy-subrc = 0.
gs_event_log-activity = 'Delivery Created'.
CONCATENATE <fs_likp>-erdat <fs_likp>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_likp>-ernam.
APPEND gs_event_log TO gt_event_log.
" Picking Completed - simplified logic, check status
gs_event_log-activity = 'Picking Completed'. APPEND gs_event_log TO gt_event_log.
" POD Confirmed
IF <fs_likp>-podat IS NOT INITIAL.
gs_event_log-activity = 'Proof Of Delivery Confirmed'.
gs_event_log-starttime = <fs_likp>-podat.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDIF.
WHEN 'R'. " Goods Issue
READ TABLE lt_mseg ASSIGNING FIELD-SYMBOL(<fs_mseg>) WITH KEY mblnr = <fs_vbfa>-vbeln mjahr = <fs_vbfa>-mjahr zeile = <fs_vbfa>-posnn.
IF sy-subrc = 0.
gs_event_log-activity = 'Goods Issued'.
CONCATENATE <fs_mseg>-budat <fs_mseg>-cpuzt INTO gs_event_log-starttime.
gs_event_log-user = <fs_mseg>-usnam.
APPEND gs_event_log TO gt_event_log.
ENDIF.
WHEN 'M'. " Invoice
READ TABLE lt_vbrk ASSIGNING FIELD-SYMBOL(<fs_vbrk>) WITH KEY vbeln = <fs_vbfa>-vbeln.
IF sy-subrc = 0.
gs_event_log-activity = 'Invoice Created'.
CONCATENATE <fs_vbrk>-erdat <fs_vbrk>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_vbrk>-ernam.
APPEND gs_event_log TO gt_event_log.
" Payment Received
READ TABLE lt_bsad ASSIGNING FIELD-SYMBOL(<fs_bsad>) WITH KEY belnr = <fs_vbrk>-belnr.
IF sy-subrc = 0 AND <fs_bsad>-augdt IS NOT INITIAL.
gs_event_log-activity = 'Payment Received'.
gs_event_log-starttime = <fs_bsad>-augdt.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDIF.
WHEN 'N'. " Invoice Cancellation
READ TABLE lt_vbrk ASSIGNING <fs_vbrk> WITH KEY vbeln = <fs_vbfa>-vbeln.
IF sy-subrc = 0 AND <fs_vbrk>-fksto = 'X'.
gs_event_log-activity = 'Invoice Cancelled'.
CONCATENATE <fs_vbrk>-erdat <fs_vbrk>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_vbrk>-ernam.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDCASE.
ENDLOOP.
" Infer other events from status
LOOP AT lt_vbup ASSIGNING FIELD-SYMBOL(<fs_vbup>).
IF <fs_vbup>-gbsta = 'C'.
DATA(lv_order_info_stat) = REF #( it_order_items[ vbeln = <fs_vbup>-vbeln ] ).
IF lv_order_info_stat IS NOT BOUND. CONTINUE. ENDIF.
gs_event_log-salesorder = <fs_vbup>-vbeln.
gs_event_log-activity = 'Order Item Closed'.
" Timestamp for closed is harder, using current time as placeholder
CONCATENATE sy-datum sy-uzeit INTO gs_event_log-starttime.
gs_event_log-user = sy-uname.
gs_event_log-customernumber = lv_order_info_stat->kunnr.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDLOOP.
" Order Confirmed (Simplified - assumes if not blocked it's confirmed)
LOOP AT it_order_items ASSIGNING FIELD-SYMBOL(<fs_item>).
IF <fs_item>-lifsk IS INITIAL.
gs_event_log-salesorder = <fs_item>-vbeln.
gs_event_log-activity = 'Order Confirmed'.
CONCATENATE <fs_item>-erdat <fs_item>-erzet INTO gs_event_log-starttime.
gs_event_log-user = <fs_item>-ernam.
gs_event_log-customernumber = <fs_item>-kunnr.
APPEND gs_event_log TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form write_output_file
*&---------------------------------------------------------------------*
FORM write_output_file.
DATA: lt_final_output TYPE TABLE OF ty_event_log.
" Add common fields
LOOP AT gt_event_log ASSIGNING FIELD-SYMBOL(<fs_event>).
<fs_event>-sourcesystem = gv_sysid.
<fs_event>-lastdataupdate = gv_last_update.
ENDLOOP.
SORT gt_event_log BY salesorder starttime.
DELETE ADJACENT DUPLICATES FROM gt_event_log COMPARING ALL FIELDS.
lt_final_output = gt_event_log.
DATA: lt_fieldnames TYPE TABLE OF string.
APPEND 'SalesOrder' TO lt_fieldnames.
APPEND 'Activity' TO lt_fieldnames.
APPEND 'StartTime' TO lt_fieldnames.
APPEND 'SourceSystem' TO lt_fieldnames.
APPEND 'LastDataUpdate' TO lt_fieldnames.
APPEND 'User' TO lt_fieldnames.
APPEND 'CustomerNumber' TO lt_fieldnames.
APPEND 'SalesOrganization' TO lt_fieldnames.
APPEND 'NetAmount' TO lt_fieldnames.
APPEND 'MaterialNumber' TO lt_fieldnames.
APPEND 'DeliveryBlock' TO lt_fieldnames.
APPEND 'RejectionReason' TO lt_fieldnames.
APPEND 'SalesOrderCycleTime' TO lt_fieldnames.
DATA(lv_header) = REDUCE string(
INIT s = ''
FOR field IN lt_fieldnames
NEXT s = s && COND #( WHEN s = '' THEN field ELSE |,{ field }| ) ).
DATA: lt_file_content TYPE TABLE OF string.
APPEND lv_header TO lt_file_content.
LOOP AT lt_final_output INTO DATA(ls_output).
DATA(lv_line) = |"{ ls_output-salesorder }","{ ls_output-activity }","{ ls_output-starttime }","{ ls_output-sourcesystem }","{ ls_output-lastdataupdate }","{ ls_output-user }","{ ls_output-customernumber }","{ ls_output-salesorganization }",{ ls_output-netamount },"{ ls_output-materialnumber }","{ ls_output-deliveryblock }","{ ls_output-rejectionreason }","{ ls_output-salesordercycletime }"|.
APPEND lv_line TO lt_file_content.
ENDLOOP.
cl_gui_frontend_services=>gui_download(
EXPORTING
filename = p_file
filetype = 'ASC'
CHANGING
data_tab = lt_file_content ).
ENDFORM.Fasi
- Prerequisiti: Si assicuri di avere accesso diretto in sola lettura al database SAP ECC. Le servirà un client per database come DBeaver, SQL Server Management Studio o Oracle SQL Developer per connettersi ed eseguire le query.
- Ottenere lo script SQL: Copi l'intera query SQL riportata nella sezione 'query' di questo documento.
- Connettersi al database: Apra il client del database e stabilisca una connessione all'istanza del database SAP ECC. Le saranno necessari l'indirizzo del server, la porta, il nome del database e credenziali di accesso adeguate.
- Configurare la query: Incolli lo script SQL in una nuova finestra dell'editor di query. Individui la sezione di configurazione all'interno della Common Table Expression (CTE) principale denominata SalesOrders. Sostituisca i segnaposto per la data di inizio ('{StartDate}'), la data di fine ('{EndDate}'), le organizzazioni di vendita ('{SalesOrgs}') e i tipi di documento ('{DocTypes}') con i valori effettivi per la sua analisi.
- Eseguire la query: Esegua lo script SQL configurato. In base all'intervallo di date e alle dimensioni del database SAP, l'esecuzione può richiedere alcuni minuti.
- Verificare i risultati: Al termine verrà visualizzato un set di risultati. Controlli rapidamente che i dati contengano le colonne attese (SalesOrder, Activity, StartTime, ecc.) e che vengano restituite righe per le diverse attività.
- Esportare i dati: Utilizzi la funzionalità di esportazione del client del database per salvare il set di risultati in un file CSV. Assegni un nome descrittivo, ad esempio SAP_O2C_Event_Log.csv.
- Formattare per ProcessMind: Apra il file CSV in un foglio di calcolo. Verifichi che le intestazioni di colonna corrispondano esattamente agli attributi richiesti (ad es. SalesOrder, Activity, StartTime). Si assicuri che il formato data/ora per StartTime e LastDataUpdate sia coerente e supportato da ProcessMind, ad esempio YYYY-MM-DD HH:MI:SS.
- Upload su ProcessMind: Carichi il file CSV finale, formattato, nel suo progetto ProcessMind per l'analisi.
Configurazione
- Intervallo di date: La query usa i segnaposto ('{StartDate}' e '{EndDate}') per filtrare gli ordini di vendita in base alla data di creazione (VBAK.ERDAT). Un periodo di analisi tipico va da 3 a 6 mesi, così da ottenere un campione rappresentativo senza gravare eccessivamente sul database.
- Filtro per organizzazione di vendita: Utilizzi il segnaposto '{SalesOrgs}' per limitare l'estrazione a specifiche organizzazioni di vendita (ad es. '1000', '2000'). È fondamentale per concentrare l'analisi e migliorare le prestazioni della query.
- Filtro per tipo di documento: Utilizzi il segnaposto '{DocTypes}' per selezionare specifici tipi di ordine di vendita (ad es. 'OR' per ordine standard). In questo modo esclude dal flusso principale documenti non pertinenti, come consegne a titolo gratuito o resi.
- Identificativo del sistema di origine: Il segnaposto fisso '{SourceSystemName}' serve a etichettare ogni record con il sistema di provenienza. Imposti un nome chiaro e significativo per la Sua istanza SAP ECC (ad es. SAP_ECC_PRD).
- Compatibilità con il database: La funzione usata per combinare data e ora, [Your DB-specific timestamp function], è un segnaposto: lo sostituisca con la funzione corretta per il database in uso (ad es. TO_TIMESTAMP(CONCAT(CDHDR.UDATE, CDHDR.UZEIT), 'YYYYMMDDHH24MISS') per SAP HANA oppure CAST(CDHDR.UDATE AS DATETIME) + CAST(CDHDR.UZEIT AS DATETIME) per SQL Server).
- Prerequisiti: Questo metodo richiede credenziali di accesso diretto, in sola lettura, al database. L'utente del database deve essere autorizzato ad accedere a tutte le tabelle menzionate nella query, incluse VBAK, VBAP, VBFA, CDHDR, CDPOS, LIKP, VBRK e BSAD.
a Query di Esempio sql
WITH SalesOrders AS (
SELECT VBELN
FROM VBAK
WHERE ERDAT BETWEEN '{StartDate}' AND '{EndDate}' -- Filter by creation date
AND VKORG IN ('{SalesOrgs}') -- Filter by Sales Organization(s)
AND AUART IN ('{DocTypes}') -- Filter by Sales Document Type(s)
)
-- 1. Sales Order Created
SELECT
vbak.VBELN AS "SalesOrder",
'Sales Order Created' AS "Activity",
[Your DB-specific timestamp function](vbak.ERDAT, vbak.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
vbak.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBAK vbak
JOIN SalesOrders so ON vbak.VBELN = so.VBELN
UNION ALL
-- 2. Sales Order Changed
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Sales Order Changed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG' AND cdhdr.TCODE IN ('VA02')
UNION ALL
-- 3. Credit Check Performed (Release)
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Credit Check Performed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBUK'
AND cdpos.FNAME = 'CMGST'
AND cdpos.VALUE_NEW = 'B' -- Credit status 'Released'
UNION ALL
-- 4. Order Confirmed (Overall status not blocked)
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Order Confirmed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBUK'
AND cdpos.FNAME = 'GBSTK'
AND cdpos.VALUE_OLD <> 'A' AND cdpos.VALUE_NEW = 'A' -- Status changes to 'Not yet processed'
UNION ALL
-- 5. Delivery Block Set
SELECT
cdhdr.OBJECTID AS "SalesOrder",
'Delivery Block Set' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
cdpos.VALUE_NEW AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBAK'
AND cdpos.FNAME = 'LIFSK'
AND cdpos.VALUE_NEW IS NOT NULL AND cdpos.VALUE_NEW <> ''
UNION ALL
-- 6. Delivery Created
SELECT
vbfa.VBELV AS "SalesOrder",
'Delivery Created' AS "Activity",
[Your DB-specific timestamp function](likp.ERDAT, likp.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
likp.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
vbak.LIFSK AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN LIKP likp ON vbfa.VBELN = likp.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'J'
UNION ALL
-- 7. Picking Completed
SELECT
vbfa.VBELV AS "SalesOrder",
'Picking Completed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN CDHDR cdhdr ON vbfa.VBELN = cdhdr.OBJECTID
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'J'
AND cdhdr.OBJECTCLASS = 'LIEFERUNG'
AND cdpos.TABNAME = 'VBUK'
AND cdpos.FNAME = 'PKSTK'
AND cdpos.VALUE_NEW = 'C'
UNION ALL
-- 8. Goods Issued
SELECT
vbfa_gi.VBELV AS "SalesOrder",
'Goods Issued' AS "Activity",
[Your DB-specific timestamp function](mkpf.BUDAT, mkpf.CPUTM) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
mkpf.USNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa_gi
JOIN SalesOrders so ON vbfa_gi.VBELV = so.VBELN
JOIN MKPF mkpf ON vbfa_gi.VBELN = mkpf.XBLNR -- XBLNR is Reference Document Number
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa_gi.VBTYP_V = 'J' AND vbfa_gi.VBTYP_N = 'R'
UNION ALL
-- 9. Proof Of Delivery Confirmed
SELECT
vbfa.VBELV AS "SalesOrder",
'Proof Of Delivery Confirmed' AS "Activity",
[Your DB-specific timestamp function](likp.PODAT, '000000') AS "StartTime", -- PODAT is only a date
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
likp.AENAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN LIKP likp ON vbfa.VBELN = likp.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'J' AND likp.PODAT IS NOT NULL AND likp.PODAT <> '00000000'
UNION ALL
-- 10. Invoice Created
SELECT
vbfa.VBELV AS "SalesOrder",
'Invoice Created' AS "Activity",
[Your DB-specific timestamp function](vbrk.ERDAT, vbrk.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
vbrk.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN VBRK vbrk ON vbfa.VBELN = vbrk.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'M'
UNION ALL
-- 11. Invoice Cancelled
SELECT
vbfa.VBELV AS "SalesOrder",
'Invoice Cancelled' AS "Activity",
[Your DB-specific timestamp function](vbrk.ERDAT, vbrk.ERZET) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
vbrk.ERNAM AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN VBRK vbrk ON vbfa.VBELN = vbrk.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'M' AND vbfa.VBTYP_N = 'N'
UNION ALL
-- 12. Payment Received
SELECT
vbfa.VBELV AS "SalesOrder",
'Payment Received' AS "Activity",
[Your DB-specific timestamp function](bsad.AUGDT, '000000') AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
NULL AS "User", -- Clearing user not readily available here
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
NULL AS "MaterialNumber",
NULL AS "DeliveryBlock",
NULL AS "RejectionReason"
FROM VBFA vbfa
JOIN SalesOrders so ON vbfa.VBELV = so.VBELN
JOIN VBRK vbrk ON vbfa.VBELN = vbrk.VBELN
JOIN BSAD bsad ON vbrk.VBELN = bsad.VBLNR
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE vbfa.VBTYP_V = 'C' AND vbfa.VBTYP_N = 'M'
AND bsad.AUGDT IS NOT NULL AND bsad.AUGDT <> '00000000'
UNION ALL
-- 13. Order Item Closed
SELECT DISTINCT
cdhdr.OBJECTID AS "SalesOrder",
'Order Item Closed' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
vbap.MATNR AS "MaterialNumber",
NULL AS "DeliveryBlock",
vbap.ABGRU AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN VBAP vbap ON cdhdr.OBJECTID = vbap.VBELN AND SUBSTRING(cdpos.TABKEY, 4, 6) = vbap.POSNR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBUP'
AND cdpos.FNAME = 'GBSTA'
AND cdpos.VALUE_NEW = 'C' -- Item is completely processed
UNION ALL
-- 14. Order Cancelled
SELECT DISTINCT
cdhdr.OBJECTID AS "SalesOrder",
'Order Cancelled' AS "Activity",
[Your DB-specific timestamp function](cdhdr.UDATE, cdhdr.UZEIT) AS "StartTime",
'{SourceSystemName}' AS "SourceSystem",
CURRENT_TIMESTAMP AS "LastDataUpdate",
cdhdr.USERNAME AS "User",
vbak.KUNNR AS "CustomerNumber",
vbak.VKORG AS "SalesOrganization",
vbak.NETWR AS "NetAmount",
vbap.MATNR AS "MaterialNumber",
NULL AS "DeliveryBlock",
cdpos.VALUE_NEW AS "RejectionReason"
FROM CDHDR cdhdr
JOIN CDPOS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
JOIN VBAP vbap ON cdhdr.OBJECTID = vbap.VBELN AND SUBSTRING(cdpos.TABKEY, 4, 6) = vbap.POSNR
JOIN SalesOrders so ON cdhdr.OBJECTID = so.VBELN
JOIN VBAK vbak ON so.VBELN = vbak.VBELN
WHERE cdhdr.OBJECTCLASS = 'VERKBELEG'
AND cdpos.TABNAME = 'VBAP'
AND cdpos.FNAME = 'ABGRU'
AND cdpos.VALUE_NEW IS NOT NULL AND cdpos.VALUE_NEW <> '';