Verwerking van de optimisatie van een doos. De metadefinitie definieert de BoxSelect van de Optimizer en geeft defaults voor de BoxData BL.Prod.OptiBox,Prod.Product,vhLib.Macro 1 %RegisteredObject 192.168.1.15 8888 0 %String WS.Prod.PanOpti.q1.OPTIREQ %Boolean %Integer Bijhouden van de referenties (ObjType.ObjRef) tijdens opbouw van de optimisationrequest %String 1 Als dit ingevuld is dan wordt de MachineID onthouden in de OptiData zodanig dat bij ontvangst van een optimalisation result het snijden onmiddellijk wordt gestart %String Als dit ingevuld is dan wordt de PPSOutput onthouden in de OptiData 0 = rechtdoor, 1 = rechts, 2 = links %String Als dit ingevuld is dan wordt de SnijPrioriteit onthouden in de OptiData If de SnijPrioriteit is NEGATIEF dan wordt er SNIJSIMULATIE uitgevoerd en wordt de doos niet echt gesneden %String Onthouden welke dozen onmiddellijk moeten gesneden worden bij ontvangst van een optimalisation result waarbij in de OptiData de machineID is ingevuld %String 1 Mapping van BoxDataID op BoxData instance die al is gemaakt omdat er een subvolume van gebruikt wordt. %String 1 BL.Prod.OptiBox.BoxReferentieParser TECH.Process.ProcessAPI 1 Deze method is gemaakt om unit tests te kunnen doen op de stateless methods van deze klasse. 1 BL.Prod.OptiBox.Optimize initvalue:%CacheString %Status 1 expression BoxDataObjType:%String %String D ##class(BL.Prod.OptiBox.Optimize).GetStatus() 1 Hierachische structuur serialiseren met parentlinks OptiRes:BL.Prod.OptiBox.sub.pxOptiResult 1 Do ; Callback . . Set (Msg,Ref)="" For Set Ref=$O(arErrors(Ref)) Quit:Ref="" Set Msg=Msg_$S($L(Msg):"; ",1:"")_arErrors(Ref) . . Set Status=$S($L(Msg):$$$qsError,1:$$$qsFinished) . . Do $zobjclassmethod($LI(CallBack), $LI(CallBack,2) ,oQ.ObjType, oQ.ObjRef, $LG(CallBack,3), OptiRes.OptiID,$$$qtOptimizer, Status, Msg) // Direct snijden van de ontvangen optimalisatie, indien nodig. If $D(..SnijRefs) Do . Set MachineID="" . For MachineID=$O(..SnijRefs(MachineID)) Quit:MachineID="" Do . . Set SnijPrioriteit=$G(..SnijRefs(MachineID),5) . . Kill SnijRefs . . Merge SnijRefs=..SnijRefs(MachineID) . . Set MachineID2=MachineID . . If MachineID="?" Do ; Bepalen aan de hand van snijdef . . . Set VolgNr="" . . . For Set VolgNr=$O(SnijRefs(VolgNr)) Quit:VolgNr="" Do . . . . Set oSnijData=SnijRefs(VolgNr) . . . . Set MaID="" . . . . For Set MaID=oSnijData.SnijDefs.Next(MaID) Quit:MaID="" Do . . . . . Set MaID(MaID)=$G(MaID(MaID))+1 ; aantal keer dat MaID voorkomt . . . Set MachineID2="",Max=0,MaID="" . . . For Set MaID=$O(MaID(MaID)) Quit:MaID="" Set:Max pxBox,OptiID oSnijData,BoxUsage,arSnijDefs oSnijParent,oSnijData,BoxUsage 0 splits in meerdere snijdefs Set oOptiData.UpdateTijdStip=$$$TimeStamp($H) Do oOptiData.%Save() Do ..MarkParentOptiData(oOptiData.Parent) If $L(oOptiData.MachineID)&&(oSnijData.Errors="") Do ; Onmiddellijk snijden indien er geen errors zijn . Set ..SnijRefs(oOptiData.MachineID,$O(..SnijRefs(oOptiData.MachineID,""),-1)+1)=oSnijData . Set ..SnijRefs(oOptiData.MachineID)=oOptiData.SnijPrioriteit ]]> sommige parent hebben geen optimalisatie zijn alleen bedoeld voor groeping daarom worden deze gemarkeerd van uit de parent link van een child oOptiData OptiID:%String OptiID:%String OptiID:%String OptiID:%String QueryString:%String,Parameters:%List 1 QueryString:%String,Parameters:%List 1 %String D ##class(BL.Prod.OptiBox.Optimize).TestOneBox() 1 W ##class(BL.Prod.OptiBox.Optimize).HasOptiData("PR",435361) 1 ObjType,ObjRef 0 ;&SQL(DECLARE HasOptiData CURSOR FOR ;SELECT ID INTO :Key FROM Prod.OptiBox_BoxData WHERE ObjType= :ObjType and ObjRef= :ObjRef and (Aantal<>-99 AND AantalExec<>-99) and (OptiType='BOX' OR OptiType='FILLER' OR Meta->OptiType='BOX' OR Meta->OptiType='FILLER' OR VolumeVan IS NOT NULL)) ;&sql(OPEN HasOptiData) ;&sql(FETCH HasOptiData) ;Quit:SQLCODE "" ;&sql(CLOSE HasOptiData) ;Quit 1 ]]> 1 ObjType,ObjRef -99 AND AantalExec<>-99) and (OptiType='BOX' OR OptiType='FILLER' OR Meta->OptiType='BOX' OR Meta->OptiType='FILLER' OR VolumeVan IS NOT NULL)) Quit Aantal ]]> d ##class(BL.Prod.OptiBox.Optimize).%New().GetVolume(403427,1,.B,.D,.H) 1 Do ;aantal verdelen overmeerdere dozen . . Set lbQty=..SplitQty(Qty,oData.MaxCombinAantal) . Else Do ; Geen meerdere aantallen van het zelfde product in 1 doos . . Set lbQty=$LB($LB(Qty,0)) . . For LoopCnt=1:1:$LL(lbQty) Do . . Set ProdQty=$LG($LI(lbQty,LoopCnt),2) . . Set Qty=$LG($LI(lbQty,LoopCnt),1) . . Set Params("PRODAANTAL")=ProdQty . . Set Params("AANTAL")=Qty . . Set Breedte=..Calc(oData.BreedteExec,.Params) . . Set Diepte=..Calc(oData.DiepteExec,.Params) . . Set Hoogte=..Calc(oData.HoogteExec,.Params) &sql(CLOSE GetVolume) ]]> 1 PRNr:%String 1 PRNr:%String,Qty:%Integer 1 BL.Sys.Proxy.pxStatus 1 KLNr,ObjType,ObjRef,DebugInfo 1 ObjType,ObjRef KlantNaam,Priority:%Integer,CallBack:%List,SnijPrioriteit:%Integer,PPSOutput:%Integer,MachineID:%String %String 1 %String 1 OptiboxServer:BL.Prod.OptiBox.enu.OptiServer 1 %String 1 OptimizerLocation:%String 1 WS.Prod.PanOpti.OptimizerBindingPanOptimizerWS InSync WS.Prod.PanOpti.q1.STATUSRES wordt opgevangen worden door een errortrap ! . Do oLog.Update("E",,,,,"NO STATUS") Quit Status ]]> pxParent,Ref,Product,Breedte,Diepte,Hoogte Vanuit de verpakkings definitie van een product wordt de doos of dozen gedefinieerd volgende de cutvolgorde WS.Prod.PanOpti.q1.BOXDEF Vanuit de verpakkingsdefinitie wordt de te optimizeren doos of dozen gedefinieerd volgende de cutvolgorde WS.Prod.PanOpti.q1.BOXDEF , ) = // Koppelingen naar verzameldozen (via BoxData.VolumeVan) worden in deze stap nog NIET gevonden. // "delen van" een andere verpakkingdefintie (bvb een scheiding S binnen een ORGALUX-productdoos D), komen als Nest(D,S)=, ) = "" // en Sort(, , , ) = "" Set ID1="" For Set ID1=$O(Nest(ID1)) Quit:ID1="" Do . Set Sort(Nest(ID1),ID1)="" . Set ID2="" . For Set ID2=$O(Nest(ID1,ID2)) Quit:ID2="" Do . . Set Sort(Nest(ID1),ID1,Nest(ID1,ID2),ID2)="" ;k %Sort m %Sort=Sort zw %Sort ; Creatie volgens CutOrder // STAP 3: Optimalisatierequest aanvullen met de verpakkingdefinities, in de juiste volgorde. Set Sort1="" Set SubSubCnt=0 Set pxBox="" #dim VerpakkingVolgnummer As %Integer = 0 For Set Sort1=$O(Sort(Sort1)) Quit:Sort1="" Do . Set ID1="" . For Set ID1=$O(Sort(Sort1,ID1)) Quit:ID1="" Do . . Set VerpakkingVolgnummer = 1 + VerpakkingVolgnummer . . Set pxBoxTmp=..AddOptiBox(.pxParent, ID1, .Params, .Opties, .Qty, .BasisRef, .LijnRef,.PRNr,.ProductRef, .Gewicht, .Plaats,.IsSubBox, VerpakkingVolgnummer) . . Set:'$isObject(pxBox) pxBox=pxBoxTmp . . Set Sort2="" . . For Set Sort2=$O(Sort(Sort1,ID1,Sort2)) Quit:Sort2="" Do . . . Set ID2="" . . . For Set ID2=$O(Sort(Sort1,ID1,Sort2,ID2)) Quit:ID2="" Do . . . . Set VerpakkingVolgnummer = 1 + VerpakkingVolgnummer . . . . Set pxSubBox=..AddOptiBox(pxBox, ID2,.Params, .Opties, 1, .BasisRef, .LijnRef,.PRNr,.ProductRef, 0, "INSIDE", 1, VerpakkingVolgnummer) Quit $G(pxBox) ]]> OrigQty,Combin Lowlevel : Invullen van een te optimiseren box WS.Prod.PanOpti.q1.BOXDEF 1 Do ;aantal verdelen overmeerdere dozen . Set lbQty=..SplitQty(Qty,oData.MaxCombinAantal) Else Do ; Geen meerdere aantallen van het zelfde product in 1 doos . Set lbQty=$LB($LB(Qty,0)) // Formaat van lbQty: een lijst met in de items: veld 1= een aantal verpakkingen; veld 2 = het aantal producten in die verpakkingen. #Dim SuperVolumeRefNietInOptimalisatieRequest As %String = "" If $isObject(oData.VolumeVan) { // De verzameldoos moet in dit geval gekoppeld worden aan de parent, en oData (meestal een volume) wordt onderdeel van de verzameldoos. // Zoekt of maakt de BOXDEF waarvan de huidige een deelvolume van is. #dim SuperVolume As WS.Prod.PanOpti.q1.BOXDEF = ..DefineVolumeVan(pxParent, oData, BasisRef) If ("VOLUME" '= SuperVolume.OPTITYPE) { // Niet bij VOLUME, want delen van VOLUMES worden niet verwerkt door Panotec, en moeten we dus later zelf terug nesten. Set pxParent = SuperVolume Set IsSubBox = 1 } Else { Set SuperVolumeRefNietInOptimalisatieRequest = ..BoxReferentieParser.GeefOptiDataID(SuperVolume.REF) } } Set ParamsAantalExist=$D(Params("AANTAL")) For LoopCnt=1:1:$LL(lbQty) Do . Set ProdQty=$LG($LI(lbQty,LoopCnt),2) . Set Qty=$LG($LI(lbQty,LoopCnt),1) . Set Params("PRODAANTAL")=ProdQty . Set Params("AANTAL")=Qty . Set pxBox=##class(WS.Prod.PanOpti.q1.BOXDEF).%New() . ; BoxSelect afhankelijk van klant . If $L(oData.BoxSelect) Do . . Set BoxSelectID=oData.BoxSelect . Else Do . . Set Key="",AlgBoxSelectID="" . . For Set oBoxSelect=oMeta.BoxSelect.GetNext(.Key) Quit:Key="" Do:$isObject(oBoxSelect) . . . If ($Length(oBoxSelect.Naam)>0) Do . . . . Set:oBoxSelect.Klanten="" AlgBoxSelectID=oBoxSelect.Naam . . . . Set:(..KLNr?4.6N)&&$LF(oBoxSelect.Klanten,..KLNr) BoxSelectID=oBoxSelect.Naam . . Set:$G(BoxSelectID)="" BoxSelectID=AlgBoxSelectID . Set pxBox.BOXSELECT=BoxSelectID . ;Do WL^vhDBG("BoxSelectID"_BoxSelectID) . Set pxBox.QTY=..Calc(oData.AantalExec,.Params) . ;Do WL^vhDBG("Qty"_pxBox.QTY) . If ..SnijPrioriteit<0 Quit:+pxBox.QTY=-99 Set:pxBox.QTY<0 pxBox.QTY=-pxBox.QTY ; Bij SIMULATIE wordt alle aantallen met -99 niet toegevoegd de negatieve aantallen die niet gesneden worden worden wel opgenomen als pos. getallen . Else Quit:+pxBox.QTY<0 ; Negatief of 0 aantal, dan niet toevoegen . . Set pxBox.OPTITYPE=$ZCVT($S(oData.OptiType'="":oData.OptiType,oMeta.OptiType'="":oMeta.OptiType,1:"VOLUME"),"U") ; eerst bij Data, dan Meta en dan default . Set pxBox.PLACE=$ZCVT($S(oData.Plaatsing'="":oData.Plaatsing,1:oMeta.Plaatsing),"U") . Set pxBox.ROTATE=$TR($ZCVT($S(oData.Rotatie'="":oData.Rotatie,oMeta.Rotatie'="":oMeta.Rotatie,1:""),"U"),";","") . Set pxBox.LEVEL=$TR($ZCVT($S(oData.Positie'="":oData.Positie,oMeta.Positie'="":oMeta.Positie,1:"OIB"),"U"),"OIB;","BIT") ; Onder->Bottom, BinnenIn->Inside, Boven->Top . Set pxBox.REF=$G(BasisRef) . If $L($G(ProductRef)) Do . . Set pxBox.PRODUCT=$TR(ProductRef,"/\"," ") . Else If $G(PRNr)?4.7N Do . . Set pxBox.PRODUCT=$TR($P(^KPR(PRNr,0),"\"),"/\"," ") . If (VerpakkingVolgnummer > 1) Do . . Set pxBox.PRODUCT = pxBox.PRODUCT _ " deel " _ VerpakkingVolgnummer . ;d WL^vhDBG(oData.BreedteExec) . ;d WL^vhDBG(oData.DiepteExec) . Set pxBox.WIDTH=..CalcMetDefault(1, oData.BreedteExec,.Params) . Set pxBox.DEPTH=..CalcMetDefault(1, oData.DiepteExec,.Params) . Set pxBox.HEIGHT=..CalcMetDefault(1, oData.HoogteExec,.Params) . Set:(BoxSelectID="OL SEPARATOR")&&('pxBox.HEIGHT) pxBox.HEIGHT=99 ; Heigth moet ingevuld zijn ook voor een separator . Set pxBox.WEIGHT=+$J($S($G(Gewicht):$J(Gewicht,0,0),1:"")/1000,0,2) ; in grammen . ;De properties : PassThrough, NestedWidth, Overhangsize, Overhangtickness, ... zijn speciale properties die indirect via de params gedefinieerd worden . . ; Koppelen van meta met data om extra properties voor de optimizer of extra params voor het snijrecept te bekomen . Set Key="" . For Set oMetaParam=oMeta.Params.GetNext(.Key) Quit:Key="" Do . . ;Do WL^vhDBG("MetaParam "_Key_" type:"_oMetaParam.Type) . . Set oDataParam=oData.Params.GetAt(Key) . . Quit:'$isObject(oDataParam) . . ;D WL^vhDBG("DataParam "_Key_" "_oDataParam.WaardeExec) . . Set Type=$S($E(Key,1,2)="O;":"X",1:oMetaParam.Type) . . If Type="O" Do ;Extra property voor optimizer . . . Set $zobjproperty(pxBox,Key)=..Calc(oDataParam.WaardeExec,.Params) . . Else If Type="X" Do ;Special OPTIONS voor optimizer . . . Set Val=..Calc(oDataParam.WaardeExec,.Params) . . . Quit:Val="" . . . Set $zobjproperty(pxBox,"OPTIONS")=$zobjproperty(pxBox,"OPTIONS")_$S($L($zobjproperty(pxBox,"OPTIONS")):";",1:"")_$P(Key,";",$L(Key,";"))_":"_Val . . . ;d WL^vhDBG("options property"_Key_" "_$zobjproperty(pxBox,"OPTIONS")) . . Else If Type="S" Do ;Extra property voor snijrecept . . . If '$IsObject(pxBox.PARAM) Set pxBox.PARAM=##class(WS.Prod.PanOpti.q1.ArrayOfBOXDEFPARAM).%New() . . . Set pxParam=##class(WS.Prod.PanOpti.q1.BOXDEFPARAM).%New() . . . Set pxParam.Key=Key . . . Set pxParam.Value=..Calc(oDataParam.WaardeExec,.Params) . . . Do pxBox.PARAM.BOXDEFPARAM.Insert(pxParam) . . ;. d WL^vhDBG(Key_"="_..Calc(oDataParam.WaardeExec,.Params)) . Set pxBox.ParentBox=pxParent . Do ..AddBox2OptiData(pxBox, oData, .Opties, .LijnRef,.ProdQty, .PRNr, .ProductRef,.IsSubBox, SuperVolumeRefNietInOptimalisatieRequest) . Set:$L($P(pxBox.REF,".",1,2)) ..QueueRefs($P(pxBox.REF,".",1,2))="" ; onthouden voor opbouw van de queue . . Set:'$isObject(pxParent.BOX) pxParent.BOX=##class(WS.Prod.PanOpti.q1.ArrayOfBOXDEF).%New() . Do pxParent.BOX.BOXDEF.Insert(pxBox) . ;Do pxParent.BOX.Insert(pxBox) Quit $G(pxBox) ]]> pxParent,oData,BasisRef 0:ProdQty,1:1) Set oOptiData.DoosAantal=pxBox.QTY Set:$D(Opties("PPSGROEP")) oOptiData.PPSGroep=Opties("PPSGROEP") Set:$D(Opties("PPSSUBGROEP")) oOptiData.PPSSubgroep=Opties("PPSSUBGROEP") Set:$D(Opties("PPSOUTPUT")) oOptiData.PPSOutput=Opties("PPSOUTPUT") Set oOptiData.PPSPrioriteit=oData.PPSPrioriteit Set Status=oOptiData.%Save() Do:Status'=$$$OK WL^vhDBG($$ParseStatus^vhLib(Status)),WO^vhDBG(oOptiData) Set pxBox.OptiData=oOptiData ; om het OptiQueue object terug te vinden vanuit het resultaat Set Ref3=pxBox.REF,$P(Ref3,".",3)=oOptiData.%Id(),pxBox.REF=Ref3 ; om het OptiQueue object terug te vinden vanuit het resultaat Set:("" '= SuperVolumeRefNietInOptimalisatieRequest) pxBox.REF = ..BoxReferentieParser.ZetSuperVolumeRefNietInOptimalisatieRequest(pxBox.REF, SuperVolumeRefNietInOptimalisatieRequest) ]]> Vertaling van een pseudo functie naar een objectscript functie String,aParams:BL.Prod.OptiBox.sub.pxemSnijParamList=$$$NULLOREF %String (Start-1) Result=Result_$E(String,LastPoint,Start-1) . . Set ULabel=$ZCVT(Label,"U") . . Set Result=Result_"Params("""_ULabel_""")" . . Do:($IsObject(aParams)) aParams.Add(ULabel,Label) . . Set LastPoint=Point . Else Set Point=Point+1 Set:LastPoint'>(Point-1) Result=Result_$E(String,LastPoint,Point-1) Quit Result ]]> Berekent een dimensie, en valt terug op een default-waarde. Reden hiervoor: Dimensies moeten verplicht ingevuld zijn in optimalisatierequests, anders crasht de Panotec-software! N.B. Als de dimensies 0 zijn, wordt een volume-element genegeerd door de Panotec-software. Wat dan resulteert in afwezig zijn van dat element in het resultaat, met als gevolg geen etiket en geen vermelding in de Vhintra "ORGALUX verpakking werkpost"-applicatie. Berekenen van een expressie door gebruik te maken van de waarden in Params 0 ",1)_"> "_Expression New msg Set $ECODE="" Set msg="EXECUTE FOUT: "_Expression_$$ArrayToText^vhLib("Params",.Params) Do WLFMT^vhDBG(msg,"B-Red") Set Result="ERR" Quit Result ]]> ObjType,ObjRef Do ##class(BL.Prod.OptiBox.Snijden).CleanOld($H) 1 Datum:%Date