Table of Contents

FLOW-STK-001 — Registrazione di un movimento di magazzino (carico/scarico/ordine/inventario) — Stock

Flusso end-to-end di registrazione di un movimento di stock su un articolo di magazzino (carico, scarico, ordine, rettifica inventariale) del modulo Stock / Magazzino (StockCenterWeb, sotto la shell CASSANDRA). Path pilota: scheda MovementDetailControl.ascx (inserimento interattivo da parte di un operatore di magazzino). Backend Oracle INFOCAD_TEST38, accesso via stored procedure ODP.NET STK_ADDITEMMOVE (nessun ORM). Il movimento è persistito nella tabella STOCK_ITEM_HISTORY e la giacenza dell'articolo è aggiornata in STOCK_ITEM.

  • Flow ID: FLOW-STK-001
  • Repository: InfocadWeb (ASP.NET Web Forms, VB.NET, StockCenterWeb sotto CASSANDRA) + InfocadServer (StockControllers/StockBL/StockDAL, VB.NET)
  • Confidence complessiva: VERIFIED (catena UI → code-behind → controller → BL → DAO → stored procedure, confermata su codice E su sorgente DB USER_SOURCE + USER_DEPENDENCIES + USER_TAB_COLUMNS + USER_TRIGGERS)

Obiettivo di business

Consentire a un operatore di magazzino di registrare un movimento su un articolo di stock scegliendo il tipo di operazione (Ordine, Carico, Scarico, Inventario), la quantità, l'eventuale fornitore/costo e un eventuale collegamento a un ticket/richiesta. Al termine il movimento è storicizzato in STOCK_ITEM_HISTORY, la giacenza (QSTOCK) e l'ordinato (QORDERED) dell'articolo in STOCK_ITEM sono ricalcolati in funzione della direzione del movimento, ed è restituito il nuovo ID_ITEM_HISTORY generato.

Attori

  • Operatore di magazzino (utente autenticato) — path interattivo scheda MovementDetailControl.ascx. Grant funzionali verificati lato UI: 6410 (accesso sezione movimenti), 6420 (Save/edit), 6430 (add/delete movimento), 6450 (selezione fornitore/costo reale) — MovementDetailControl.ascx.vb:171,188,189,210.
  • Operatore su ordini multipli — path alternativo MultipleOrderControl.ascx / OrderListControl.ascx (stessa StockItemHistoryController).
  • Oracle INFOCAD_TEST38 (procedura STK_ADDITEMMOVE; sequence SEQ_STOCK_ITEM_HISTORY; trigger di INSERT su STOCK_ITEM_HISTORY).

Trigger

Click sul pulsante Salva della toolbar della scheda movimento: evento rtbCommands.ButtonClick gestito da rtbCommands_ButtonClick in MovementDetailControl.ascx.vb:296, ramo Case "Save"SaveCommand() (:299,307).

Frontend entry point

  • Shell: StockCenterWeb/Default.aspx (modello shell-page CASSANDRA con UserControl caricati dinamicamente).
  • Control scheda: StockCenterWeb/UserControls/Details/MovementDetailControl.ascx (+ code-behind .ascx.vb), che eredita da StockItemDetailBaseDetailBase.
  • Griglia di contesto: StockCenterWeb/UserControls/Grids/MovementGridControl.ascx (elenco movimenti).
  • Gate di accesso: CheckPermissions() (:170-174) blocca l'accesso se manca il grant 6410 e l'utente non è SuperAdmin; visibilità dei comandi Save/Delete pilotata dai grant 6420/6430.

Sequenza principale (main sequence)

  1. Operatore apre la scheda movimento per un articolo (IdItem), sceglie il tipo operazione (rblMovementType: 1=Ordine, 2=Carico, 3=Scarico, 4=Inventario), la quantità (rnbQuantity), eventuale fornitore/ticket, e preme Salva.
  2. MovementDetailControl.ascx.vbrtbCommands_ButtonClick (:296) → SaveCommand() (:307): legge la giacenza corrente (StockQuantity), applica SetErrorTooltips() (:312-316), e se TryValidate() passa (:318) chiama MyBase.Save(InstantiateDto) (:319).
  3. InstantiateDto() (:685) costruisce un DTO StockItemHistory popolando: IdStockItem=IdItem, Cause (note), QuantityMoved, DateMove=Date.Now, Direction (enum StockMoveDirection), TotalCostMove/TotalRealCostMove, IdLink/LinkDescription/LinkApplicationID (collegamento RequestCenter), IdItemCompany (fornitore), OldQuantity=StockQuantity, PriceListType, ID_Tenancy (:686-717).
  4. DetailBase.Save (DetailBase.vb:239): valida il DTO, ottiene il controller tramite StockControllers.ControllerFactory.CreateControllerFromType(dto.GetType) (:253) e, se ID_DTO = 0 (nuovo), chiama _ctrlEntity.Insert(dto) (:257).
  5. StockItemHistoryController.Insert (StockItemHistoryController.vb:14) inoltra al layer BL: DirectCast(Me.DAO, IStockItemHistory_BL).Insert(dto) (:15).
  6. StockItemHistory_BL.Insert (StockItemHistory_BL.vb:10) mappa i campi del DTO ai parametri posizionali e chiama StockDALFactory.GetStockItemHistoryDAL.Insert(...) (:14-29).
  7. StockItemHistory_DAL.Insert (StockDAL/OracleODP/StockItemHistory_DAL.vb:125) prepara 15 parametri di input + 1 OUT (PNEWINDEX) e invoca dl.ExecuteNonQueryStoredProcedure("STK_ADDITEMMOVE") (:185), restituendo PNEWINDEX come nuovo id (:187).
  8. Oracle STK_ADDITEMMOVE (INFOCAD_TEST38, procedura standalone, src:1-77):
    • legge il flag price-list dello stock dell'articolo (STOCK_STOCK.ISPRICELIST join STOCK_ITEM) (src:23-28);
    • INSERT una riga in STOCK_ITEM_HISTORY (con MOVE_DATE = SYSDATE) (src:30-33);
    • aggiorna la giacenza in STOCK_ITEM in base a PDIRECTION:
      • =1 Ordine: QORDERED = QORDERED + PQMOVE (src:35-40);
      • =2 Carico: QSTOCK = QSTOCK + PQMOVE, QORDERED = QORDERED - PQMOVE (src:42-47);
      • =3 Scarico (solo se non price-list): QSTOCK = QSTOCK - PQMOVE (src:49-55);
      • =4 Inventario: QSTOCK = PQMOVE (rettifica assoluta) (src:57-62);
    • legge SEQ_STOCK_ITEM_HISTORY.CURRVAL in PNEWINDEX (src:64-66);
    • se PIDLINK IS NOT NULL, INSERT una riga di collegamento in STOCK_ITEM_LINK (src:68-74).
  9. Il DAL legge PNEWINDEX (OracleDecimal) e lo propaga come ID_DTO (StockItemHistory_DAL.vb:187).
  10. Post-salvataggio (MovementDetailControl.ascx.vb:325-373): eventuale chiusura/aggiornamento delle richieste collegate (StockItemRequestController.CloseRequest/UpdateEscape) quando l'operazione è di tipo "Ordine con richieste", refresh contatti (RefreshStockCenterContacts), refresh valori articolo (RefreshItemValues), reset scheda.

API / service

  • Path interattivo: nessun servizio SOAP/WCF — postback ASP.NET Web Forms diretto sulla scheda.
  • I controller Stock sono richiamati in-process dal web app (referenza a DLL Descor.Stock.StockControllers / StockBL / StockDAL), non tramite WCF.

Backend

  • UI/Code-behind: MovementDetailControl.ascx.vb (scheda), erede di StockItemDetailBaseDetailBase.
  • Classe base editing: StockCenterWeb.UserControls.DetailBase (DetailBase.vb) — Save (:239).
  • Factory controller: StockControllers.ControllerFactory.CreateControllerFromType(...) (DetailBase.vb:253).
  • Controller server: Descor.Stock.StockControllers.StockItemHistoryController (StockControllers/StockItemHistoryController.vb), inoltra al BL via Ctrl_EntityBase.DAO.
  • BL: StockBL.StockItemHistory_BL (StockBL/StockItemHistory_BL.vb) — mappa DTO → parametri DAL.
  • DAO/DAL: StockDAL.OracleODP.StockItemHistory_DAL (StockDAL/OracleODP/StockItemHistory_DAL.vb).
  • Pattern DAL: Dim dl As New DataLayer(My.Settings.ConnectionName)dl.Parameters.Add(OracleParameter...)dl.ExecuteNonQueryStoredProcedure("STK_ADDITEMMOVE"); nuovo id via parametro OUT PNEWINDEX (NUMBER).

Query / stored procedure

Passo Stored procedure (Oracle) Chiamata da (DAL)
Registrazione movimento (INSERT STOCK_ITEM_HISTORY + UPDATE STOCK_ITEM + eventuale INSERT STOCK_ITEM_LINK) INFOCAD_TEST38.STK_ADDITEMMOVE (OUT PNEWINDEX NUMBER) StockItemHistory_DAL.vb:185
Generazione ID_ITEM_HISTORY (implicita, via trigger di INSERT) trigger STOCK_ITEM_HISTORYSEQ_STOCK_ITEM_HISTORY.NEXTVAL trigger DB su STOCK_ITEM_HISTORY
Progressivo ordine (path Ordine) INFOCAD_TEST38.STK_GETSTOCKORDERPROGRESSIVE StockItemHistoryController.GetStockOrderProgressive
Chiusura/aggiornamento richieste collegate INFOCAD_TEST38.STK_UPDATEREQUEST / STK_UPDATEESCAPE StockItemRequestController (MovementDetailControl.ascx.vb:334,337,347,349)

Tabelle lette (read)

  • INFOCAD_TEST38: STOCK_STOCK (flag ISPRICELIST), STOCK_ITEM (join per lo stock dell'articolo), SEQ_STOCK_ITEM_HISTORY (sequence, CURRVAL), DUAL.

(da USER_DEPENDENCIES di STK_ADDITEMMOVE: STOCK_STOCK, STOCK_ITEM, STOCK_ITEM_HISTORY, STOCK_ITEM_LINK, SEQ_STOCK_ITEM_HISTORY, DUAL, STANDARD, SYS_STUB_FOR_PURITY_ANALYSIS)

Tabelle modificate (write)

  • INFOCAD_TEST38: STOCK_ITEM_HISTORY (RW — INSERT della riga di movimento; MOVE_DATE=SYSDATE; ID_ITEM_HISTORY popolato dal trigger di INSERT via SEQ_STOCK_ITEM_HISTORY.NEXTVAL; VERIFIED su sorgente + USER_TAB_COLUMNS + USER_TRIGGERS), STOCK_ITEM (RW — UPDATE QSTOCK/QORDERED in funzione di PDIRECTION; VERIFIED su sorgente), STOCK_ITEM_LINK (RW — INSERT del collegamento a ticket/richiesta solo se PIDLINK IS NOT NULL; VERIFIED su sorgente).

Validazione

  • Lato UI: CheckPermissions() (grant 6410, :170-174); SetErrorTooltips() (:748) verifica tipo operazione selezionato, quantità > 0, e per lo scarico (dir. 3) che rnbQuantity <= StockQuantity quando l'articolo non è price-list (:751-761); TryValidate() prima del salvataggio (:318). Visibilità Save/Delete pilotata dai grant 6420/6430 e dalla giacenza disponibile (:207-211,569-577).
  • Lato DTO: dto.Validate() in DetailBase.Save (:246) — blocca con messaggio se non valido.
  • Lato DB: STK_ADDITEMMOVE non esegue check espliciti di business; la coerenza (es. non scendere sotto zero) è demandata al livello UI. La SELECT ... INTO TMP_ISPRICELIST (src:23-28) presuppone che esista esattamente una riga stock per l'articolo.

Side effects

  • Generazione automatica ID_ITEM_HISTORY tramite trigger di INSERT su STOCK_ITEM_HISTORY (SEQ_STOCK_ITEM_HISTORY.NEXTVAL); la procedura restituisce CURRVAL come PNEWINDEX.
  • Ricalcolo giacenza/ordinato dell'articolo in STOCK_ITEM (semantica dipendente dalla direzione).
  • Creazione riga di collegamento in STOCK_ITEM_LINK verso l'applicazione originante (LinkApplicationID = GUID di "RequestCenter", MovementDetailControl.ascx.vb:703).
  • Eventuale chiusura/decurtazione delle richieste collegate (STK_UPDATEREQUEST/STK_UPDATEESCAPE) quando l'operazione è di tipo Ordine con richieste (:326-354).
  • Refresh cache contatti StockCenter (RefreshStockCenterContacts) e refresh valori articolo (:356,357).

Percorsi alternativi / di errore

  • Ordini multipli: MultipleOrderControl.ascx / OrderListControl.ascx usano la stessa StockItemHistoryController per registrare più movimenti (MultipleOrderControl.ascx.vb:8,633,634).
  • Secondo chiamante DAL di STK_ADDITEMMOVE: StockItem_DAL.vb:301 (e variante Oracle/StockItem_DAL.vb:328) invoca la stessa procedura passando però solo 5 parametri di input + OUT (PIDITEM, PCAUSE, PQMOVE, PDIRECTION, PMOVE_TOTAL_COST, PNEWINDEX), non coerenti con la firma attuale a 16 parametri: verosimilmente path legacy/non più attivo (vedi Open questions).
  • Errore/eccezione: il DAL logga via Descor.Infrastructure.LogManager.ExceptionLogger.LogException e rilancia (StockItemHistory_DAL.vb:188-190); DetailBase.Save cattura e mostra l'errore in UI (DetailBase.vb:307+).
  • Scarico su articolo price-list: il ramo PDIRECTION=3 non decrementa QSTOCK se TMP_ISPRICELIST <> 0 (src:49-55).

Diagramma di sequenza

sequenceDiagram
    actor Op as Operatore Magazzino
    participant UI as MovementDetailControl.ascx (Default.aspx shell)
    participant CB as MovementDetailControl.ascx.vb (SaveCommand)
    participant DB0 as DetailBase.Save
    participant CT as StockItemHistoryController.Insert
    participant BL as StockItemHistory_BL.Insert
    participant DAL as StockItemHistory_DAL.Insert
    participant DB as Oracle INFOCAD_TEST38 (STK_ADDITEMMOVE)

    Op->>UI: compila movimento + click Salva
    UI->>CB: rtbCommands_ButtonClick -> SaveCommand()
    CB->>CB: InstantiateDto() -> StockItemHistory (Direction, QuantityMoved, ...)
    CB->>DB0: MyBase.Save(dto)
    DB0->>CT: CreateControllerFromType(dto) -> Insert(dto)
    CT->>BL: Insert(dto)
    BL->>DAL: Insert(idItem, cause, qmove, direction, ...)
    DAL->>DB: STK_ADDITEMMOVE (15 IN + OUT PNEWINDEX)
    DB->>DB: INSERT STOCK_ITEM_HISTORY (MOVE_DATE=SYSDATE); trigger -> ID_ITEM_HISTORY
    alt PDIRECTION=1 (Ordine)
        DB->>DB: UPDATE STOCK_ITEM QORDERED += PQMOVE
    else PDIRECTION=2 (Carico)
        DB->>DB: UPDATE STOCK_ITEM QSTOCK += PQMOVE, QORDERED -= PQMOVE
    else PDIRECTION=3 (Scarico, non price-list)
        DB->>DB: UPDATE STOCK_ITEM QSTOCK -= PQMOVE
    else PDIRECTION=4 (Inventario)
        DB->>DB: UPDATE STOCK_ITEM QSTOCK = PQMOVE
    end
    opt PIDLINK IS NOT NULL
        DB->>DB: INSERT STOCK_ITEM_LINK
    end
    DB-->>DAL: PNEWINDEX (SEQ_STOCK_ITEM_HISTORY.CURRVAL)
    DAL-->>CT: nuovo ID_ITEM_HISTORY
    CT-->>CB: ID_DTO
    CB-->>Op: reset scheda + refresh valori articolo

Matrice di tracciabilità

Layer Artefatto Evidenza (file:riga)
UI MovementDetailControl.ascx (scheda movimento) StockCenterWeb/UserControls/Details/MovementDetailControl.ascx:1
Code-behind rtbCommands_ButtonClickSaveCommandInstantiateDto MovementDetailControl.ascx.vb:296,299,307,318,319,685
Base editing DetailBase.SaveInsert DetailBase.vb:239,253,257
Controller StockItemHistoryController.Insert → BL StockItemHistoryController.vb:14,15
BL StockItemHistory_BL.Insert → DAL StockItemHistory_BL.vb:10,14-29
DAO/DAL StockItemHistory_DAL.InsertSTK_ADDITEMMOVE StockDAL/OracleODP/StockItemHistory_DAL.vb:125,144-185,187
DB STK_ADDITEMMOVE (firma 16 param) USER_SOURCE STK_ADDITEMMOVE src:1-16
DB INSERT STOCK_ITEM_HISTORY (MOVE_DATE=SYSDATE) src:30-33
DB UPDATE STOCK_ITEM per direzione src:35-62
DB SEQ_STOCK_ITEM_HISTORY.CURRVALPNEWINDEX src:64-66
DB INSERT STOCK_ITEM_LINK (se PIDLINK) src:68-74
DB (trigger) trigger INSERT su STOCK_ITEM_HISTORYSEQ_STOCK_ITEM_HISTORY.NEXTVAL USER_TRIGGERS STOCK_ITEM_HISTORY
DB (schema) colonne STOCK_ITEM_HISTORY / STOCK_ITEM / STOCK_ITEM_LINK USER_TAB_COLUMNS
Enum StockMoveDirection Order=1/Load=2/Unload=3/StockTaking=4 StockItemHistory.vb:322-329

Reverse trace (dal DB/DAL ai chiamanti)

  • STK_ADDITEMMOVE è referenziata nei sorgenti solo da: StockItemHistory_DAL.Insert (path canonico, 16 parametri — coerente con la firma DB), e da StockItem_DAL.vb:301 / Oracle/StockItem_DAL.vb:328 (5 parametri, non coerente — vedi Open questions).
  • StockItemHistory_DAL.Insert è invocato da StockItemHistory_BL.Insert (StockItemHistory_BL.vb:14), a sua volta da StockItemHistoryController.Insert (StockItemHistoryController.vb:15).
  • StockItemHistoryController (e Insert via DetailBase.Save/ControllerFactory) è usato dai control web: scheda movimento (MovementDetailControl.ascx.vb:7), ordini multipli (MultipleOrderControl.ascx.vb:8,633, OrderListControl.ascx.vb:6,296), griglie movimenti (MovementGridControl.ascx.vb:7, MovementCategoryGridControl.ascx.vb:9).
  • Forward e reverse concordano: la scheda movimento → StockItemHistoryController.InsertStockItemHistory_BL.InsertStockItemHistory_DAL.InsertSTK_ADDITEMMOVE con INSERT su STOCK_ITEM_HISTORY + UPDATE STOCK_ITEMNO CONFLICTING.
  • Semantica della direzione del movimento (STK_ADDITEMMOVE src:35-62, enum StockMoveDirection): Ordine(1) incrementa l'ordinato; Carico(2) incrementa la giacenza e decrementa l'ordinato; Scarico(3) decrementa la giacenza (salvo articoli price-list); Inventario(4) imposta la giacenza al valore assoluto rilevato.
  • MOVE_DATE è sempre impostata a SYSDATE lato DB (il parametro moveDate/DateMove calcolato in UI non viene passato come parametro alla procedura — vedi Open questions).
  • Multi-tenant: ID_TENANCY è propagato dal DTO (ID_Tenancy) quando la tenancy è abilitata (MovementDetailControl.ascx.vb:715-717).
  • Collegamento cross-modulo: STOCK_ITEM_LINK lega il movimento a un'entità di un'altra applicazione (tipicamente RequestCenter) via APPLICATION_ID + ID_LINK.

Evidenza (file:line)

Punti chiave (codice): MovementDetailControl.ascx.vb:170-174,296,299,307,312-319,685-717; DetailBase.vb:239,246,253,257; StockItemHistoryController.vb:14,15; StockItemHistory_BL.vb:10,14-29; StockItemHistory_DAL.vb:125,144-185,187; StockItemHistory.vb:322-329 (enum StockMoveDirection).

Punti chiave (DB, INFOCAD_TEST38, letti in sola lettura via USER_SOURCE/USER_DEPENDENCIES/USER_TAB_COLUMNS/USER_TRIGGERS): STK_ADDITEMMOVE firma 16 parametri src:1-16; INSERT STOCK_ITEM_HISTORY con MOVE_DATE=SYSDATE src:30-33; UPDATE STOCK_ITEM per direzione src:35-62; SEQ_STOCK_ITEM_HISTORY.CURRVALPNEWINDEX src:64-66; INSERT STOCK_ITEM_LINK condizionale src:68-74. Dipendenze: STOCK_STOCK, STOCK_ITEM, STOCK_ITEM_HISTORY, STOCK_ITEM_LINK, SEQ_STOCK_ITEM_HISTORY, DUAL. Trigger di INSERT su STOCK_ITEM_HISTORY che valorizza ID_ITEM_HISTORY da SEQ_STOCK_ITEM_HISTORY.NEXTVAL. Catalogo: STK_ADDITEMMOVE è PROCEDURE standalone di INFOCAD_TEST38 (database-catalog.jsonuser_procedures[7704]).

Confidence

  • VERIFIED: catena completa UI → code-behind → base editing → controller → BL → DAO → nome stored procedure (letta sui sorgenti) e sorgente della stored procedure STK_ADDITEMMOVE (INSERT STOCK_ITEM_HISTORY, UPDATE STOCK_ITEM, INSERT STOCK_ITEM_LINK) letto da USER_SOURCE; esistenza tabelle/colonne da USER_TAB_COLUMNS; dipendenze da USER_DEPENDENCIES; trigger da USER_TRIGGERS.
  • SUPPORTED: side-effect sulle richieste collegate (STK_UPDATEREQUEST/STK_UPDATEESCAPE) e progressivo ordine (STK_GETSTOCKORDERPROGRESSIVE) — confermati da chiamate nel code-behind ma non ispezionati riga per riga a livello DB in questo flusso.

Open questions

  • Il parametro moveDate/DateMove è calcolato in UI/DAL ma non viene passato come OracleParameter alla procedura (STK_ADDITEMMOVE usa SYSDATE): confermare che sia intenzionale (data movimento sempre = data server, non modificabile).
  • Il secondo chiamante StockItem_DAL.vb:301 invoca STK_ADDITEMMOVE con soli 5 parametri di input, incompatibili con la firma attuale a 16 parametri: verificare se è codice morto/legacy o se punta a un overload diverso non presente nel DB attuale.
  • PPROGRESSIVE è passato dal DTO (itemHis.Progressive) ma nel path scheda MovementDetailControl non risulta valorizzato esplicitamente prima del Save (probabile default 0): il progressivo ordine è gestito nel path MultipleOrder/OrderList — non approfondito qui.
  • Comportamento della SELECT ... INTO TMP_ISPRICELIST in presenza di articolo senza stock associato (potenziale NO_DATA_FOUND) — non gestito esplicitamente nella procedura.
  • Comportamento in configurazioni PROD (osservato solo ambiente TEST38).