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: schedaMovementDetailControl.ascx(inserimento interattivo da parte di un operatore di magazzino). Backend OracleINFOCAD_TEST38, accesso via stored procedure ODP.NETSTK_ADDITEMMOVE(nessun ORM). Il movimento è persistito nella tabellaSTOCK_ITEM_HISTORYe la giacenza dell'articolo è aggiornata inSTOCK_ITEM.
- Flow ID: FLOW-STK-001
- Repository: InfocadWeb (ASP.NET Web Forms, VB.NET,
StockCenterWebsotto 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(stessaStockItemHistoryController). - Oracle
INFOCAD_TEST38(proceduraSTK_ADDITEMMOVE; sequenceSEQ_STOCK_ITEM_HISTORY; trigger di INSERT suSTOCK_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 daStockItemDetailBase→DetailBase. - Griglia di contesto:
StockCenterWeb/UserControls/Grids/MovementGridControl.ascx(elenco movimenti). - Gate di accesso:
CheckPermissions()(:170-174) blocca l'accesso se manca il grant6410e l'utente non è SuperAdmin; visibilità dei comandi Save/Delete pilotata dai grant6420/6430.
Sequenza principale (main sequence)
- 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. MovementDetailControl.ascx.vb→rtbCommands_ButtonClick(:296) →SaveCommand()(:307): legge la giacenza corrente (StockQuantity), applicaSetErrorTooltips()(:312-316), e seTryValidate()passa (:318) chiamaMyBase.Save(InstantiateDto)(:319).InstantiateDto()(:685) costruisce un DTOStockItemHistorypopolando:IdStockItem=IdItem,Cause(note),QuantityMoved,DateMove=Date.Now,Direction(enumStockMoveDirection),TotalCostMove/TotalRealCostMove,IdLink/LinkDescription/LinkApplicationID(collegamento RequestCenter),IdItemCompany(fornitore),OldQuantity=StockQuantity,PriceListType,ID_Tenancy(:686-717).DetailBase.Save(DetailBase.vb:239): valida il DTO, ottiene il controller tramiteStockControllers.ControllerFactory.CreateControllerFromType(dto.GetType)(:253) e, seID_DTO = 0(nuovo), chiama_ctrlEntity.Insert(dto)(:257).StockItemHistoryController.Insert(StockItemHistoryController.vb:14) inoltra al layer BL:DirectCast(Me.DAO, IStockItemHistory_BL).Insert(dto)(:15).StockItemHistory_BL.Insert(StockItemHistory_BL.vb:10) mappa i campi del DTO ai parametri posizionali e chiamaStockDALFactory.GetStockItemHistoryDAL.Insert(...)(:14-29).StockItemHistory_DAL.Insert(StockDAL/OracleODP/StockItemHistory_DAL.vb:125) prepara 15 parametri di input + 1 OUT (PNEWINDEX) e invocadl.ExecuteNonQueryStoredProcedure("STK_ADDITEMMOVE")(:185), restituendoPNEWINDEXcome nuovo id (:187).- Oracle
STK_ADDITEMMOVE(INFOCAD_TEST38, procedura standalone,src:1-77):- legge il flag price-list dello stock dell'articolo (
STOCK_STOCK.ISPRICELISTjoinSTOCK_ITEM) (src:23-28); - INSERT una riga in
STOCK_ITEM_HISTORY(conMOVE_DATE = SYSDATE) (src:30-33); - aggiorna la giacenza in
STOCK_ITEMin base aPDIRECTION:=1Ordine:QORDERED = QORDERED + PQMOVE(src:35-40);=2Carico:QSTOCK = QSTOCK + PQMOVE, QORDERED = QORDERED - PQMOVE(src:42-47);=3Scarico (solo se non price-list):QSTOCK = QSTOCK - PQMOVE(src:49-55);=4Inventario:QSTOCK = PQMOVE(rettifica assoluta) (src:57-62);
- legge
SEQ_STOCK_ITEM_HISTORY.CURRVALinPNEWINDEX(src:64-66); - se
PIDLINK IS NOT NULL, INSERT una riga di collegamento inSTOCK_ITEM_LINK(src:68-74).
- legge il flag price-list dello stock dell'articolo (
- Il DAL legge
PNEWINDEX(OracleDecimal) e lo propaga comeID_DTO(StockItemHistory_DAL.vb:187). - 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 diStockItemDetailBase→DetailBase. - 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 viaCtrl_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 OUTPNEWINDEX(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_HISTORY → SEQ_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(flagISPRICELIST),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_HISTORYpopolato dal trigger di INSERT viaSEQ_STOCK_ITEM_HISTORY.NEXTVAL; VERIFIED su sorgente +USER_TAB_COLUMNS+USER_TRIGGERS),STOCK_ITEM(RW — UPDATEQSTOCK/QORDEREDin funzione diPDIRECTION; VERIFIED su sorgente),STOCK_ITEM_LINK(RW — INSERT del collegamento a ticket/richiesta solo sePIDLINK IS NOT NULL; VERIFIED su sorgente).
Validazione
- Lato UI:
CheckPermissions()(grant6410,:170-174);SetErrorTooltips()(:748) verifica tipo operazione selezionato, quantità > 0, e per lo scarico (dir. 3) chernbQuantity <= StockQuantityquando l'articolo non è price-list (:751-761);TryValidate()prima del salvataggio (:318). Visibilità Save/Delete pilotata dai grant6420/6430e dalla giacenza disponibile (:207-211,569-577). - Lato DTO:
dto.Validate()inDetailBase.Save(:246) — blocca con messaggio se non valido. - Lato DB:
STK_ADDITEMMOVEnon esegue check espliciti di business; la coerenza (es. non scendere sotto zero) è demandata al livello UI. LaSELECT ... INTO TMP_ISPRICELIST(src:23-28) presuppone che esista esattamente una riga stock per l'articolo.
Side effects
- Generazione automatica
ID_ITEM_HISTORYtramite trigger di INSERT suSTOCK_ITEM_HISTORY(SEQ_STOCK_ITEM_HISTORY.NEXTVAL); la procedura restituisceCURRVALcomePNEWINDEX. - Ricalcolo giacenza/ordinato dell'articolo in
STOCK_ITEM(semantica dipendente dalla direzione). - Creazione riga di collegamento in
STOCK_ITEM_LINKverso 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.ascxusano la stessaStockItemHistoryControllerper registrare più movimenti (MultipleOrderControl.ascx.vb:8,633,634). - Secondo chiamante DAL di
STK_ADDITEMMOVE:StockItem_DAL.vb:301(e varianteOracle/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.LogExceptione rilancia (StockItemHistory_DAL.vb:188-190);DetailBase.Savecattura e mostra l'errore in UI (DetailBase.vb:307+). - Scarico su articolo price-list: il ramo
PDIRECTION=3non decrementaQSTOCKseTMP_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_ButtonClick → SaveCommand → InstantiateDto |
MovementDetailControl.ascx.vb:296,299,307,318,319,685 |
| Base editing | DetailBase.Save → Insert |
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.Insert → STK_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.CURRVAL → PNEWINDEX |
src:64-66 |
| DB | INSERT STOCK_ITEM_LINK (se PIDLINK) |
src:68-74 |
| DB (trigger) | trigger INSERT su STOCK_ITEM_HISTORY → SEQ_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 daStockItem_DAL.vb:301/Oracle/StockItem_DAL.vb:328(5 parametri, non coerente — vedi Open questions).StockItemHistory_DAL.Insertè invocato daStockItemHistory_BL.Insert(StockItemHistory_BL.vb:14), a sua volta daStockItemHistoryController.Insert(StockItemHistoryController.vb:15).StockItemHistoryController(eInsertviaDetailBase.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.Insert→StockItemHistory_BL.Insert→StockItemHistory_DAL.Insert→STK_ADDITEMMOVEcon INSERT suSTOCK_ITEM_HISTORY+ UPDATESTOCK_ITEM→ NO CONFLICTING.
Regole correlate (related rules)
- Semantica della direzione del movimento (
STK_ADDITEMMOVE src:35-62, enumStockMoveDirection): 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 aSYSDATElato DB (il parametromoveDate/DateMovecalcolato 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_LINKlega il movimento a un'entità di un'altra applicazione (tipicamenteRequestCenter) viaAPPLICATION_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.CURRVAL → PNEWINDEX 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.json → user_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(INSERTSTOCK_ITEM_HISTORY, UPDATESTOCK_ITEM, INSERTSTOCK_ITEM_LINK) letto daUSER_SOURCE; esistenza tabelle/colonne daUSER_TAB_COLUMNS; dipendenze daUSER_DEPENDENCIES; trigger daUSER_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 comeOracleParameteralla procedura (STK_ADDITEMMOVEusaSYSDATE): confermare che sia intenzionale (data movimento sempre = data server, non modificabile). - Il secondo chiamante
StockItem_DAL.vb:301invocaSTK_ADDITEMMOVEcon 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 schedaMovementDetailControlnon risulta valorizzato esplicitamente prima del Save (probabile default 0): il progressivo ordine è gestito nel pathMultipleOrder/OrderList— non approfondito qui.- Comportamento della
SELECT ... INTO TMP_ISPRICELISTin presenza di articolo senza stock associato (potenzialeNO_DATA_FOUND) — non gestito esplicitamente nella procedura. - Comportamento in configurazioni PROD (osservato solo ambiente TEST38).