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