diff --git a/LSL2/OIWIN/PROD_SPEC_SI4.json b/LSL2/OIWIN/PROD_SPEC_SI4.json index f36fc13..6c4a1cd 100644 --- a/LSL2/OIWIN/PROD_SPEC_SI4.json +++ b/LSL2/OIWIN/PROD_SPEC_SI4.json @@ -22,15 +22,19 @@ "<1,9>": "Measurement Detail", "<1,10>": { "<1,10,1>": "0x82C00000", - "<1,10,2>": "0x0" + "<1,10,2>": "0x100" }, "<1,11>": { - "<1,11,1>": "0x0", + "<1,11,1>": "0x8000", "<1,11,2>": "0x80000000" }, - "<1,12>": "0", - "<1,13>": "-2", - "<1,14>": "0", + "<1,12>": "", + "<1,13>": { + "<1,13,1>": "-2", + "<1,13,2>": "-2", + "<1,13,3>": "" + }, + "<1,14>": "", "<1,15>": "", "<1,16>": "", "<1,17>": "CREATE", @@ -41,38 +45,43 @@ "<1,22>": "", "<1,23>": "", "<1,24>": { - "<1,24,1>": "0", + "<1,24,1>": "", "<1,24,2>": "0", "<1,24,3>": "0", "<1,24,4>": "0", - "<1,24,5>": "0", - "<1,24,6>": "0" + "<1,24,5>": "", + "<1,24,6>": "0", + "<1,24,7>": "", + "<1,24,8>": "", + "<1,24,9>": "", + "<1,24,10>": "0", + "<1,24,11>": "0", + "<1,24,12>": "0", + "<1,24,13>": "0", + "<1,24,14>": "0", + "<1,24,15>": "0", + "<1,24,16>": "0", + "<1,24,17>": "0" }, - "<1,25>": "0", - "<1,26>": "0", + "<1,25>": "", + "<1,26>": "", "<1,27>": "", "<1,28>": "", "<1,29>": "", "<1,30>": "", "<1,31>": "", - "<1,32>": { - "<1,32,1>": "0x7FFFE", - "<1,32,2>": "0xF001E808" - }, + "<1,32>": "", "<1,33>": "", - "<1,34>": "LSL2*IMAGE*ICO*DATASET", + "<1,34>": "", "<1,35>": "", "<1,36>": "", "<1,37>": { - "<1,37,1>": "0x10001", - "<1,37,2>": "0x10001" - }, - "<1,38>": { - "<1,38,1>": "1", - "<1,38,2>": "1" + "<1,37,1>": "0X10001", + "<1,37,2>": "0X10001" }, + "<1,38>": "", "<1,39>": "", - "<1,40>": "0", + "<1,40>": "", "<1,41>": "", "<1,42>": "", "<1,43>": "", @@ -84,7 +93,74 @@ "<1,49>": "", "<1,50>": "", "<1,51>": "", - "<1,52>": "" + "<1,52>": "", + "<1,53>": "", + "<1,54>": "", + "<1,55>": "", + "<1,56>": "", + "<1,57>": "", + "<1,58>": "", + "<1,59>": "", + "<1,60>": "", + "<1,61>": "", + "<1,62>": { + "<1,62,1>": "0", + "<1,62,2>": "", + "<1,62,3>": "", + "<1,62,4>": "0", + "<1,62,5>": "0", + "<1,62,6>": "0", + "<1,62,7>": "", + "<1,62,8>": "0.50", + "<1,62,9>": "5.00", + "<1,62,10>": "0.00" + }, + "<1,63>": "", + "<1,64>": "", + "<1,65>": "", + "<1,66>": "", + "<1,67>": "", + "<1,68>": "", + "<1,69>": "", + "<1,70>": "", + "<1,71>": "", + "<1,72>": "", + "<1,73>": "", + "<1,74>": "", + "<1,75>": "", + "<1,76>": "", + "<1,77>": "", + "<1,78>": "", + "<1,79>": "", + "<1,80>": "", + "<1,81>": "", + "<1,82>": "", + "<1,83>": "", + "<1,84>": "", + "<1,85>": "", + "<1,86>": "", + "<1,87>": "", + "<1,88>": "", + "<1,89>": "", + "<1,90>": "", + "<1,91>": "", + "<1,92>": "", + "<1,93>": "", + "<1,94>": "", + "<1,95>": "", + "<1,96>": "", + "<1,97>": "", + "<1,98>": "", + "<1,99>": "", + "<1,100>": "", + "<1,101>": "", + "<1,102>": "", + "<1,103>": "", + "<1,104>": "", + "<1,105>": "", + "<1,106>": "0", + "<1,107>": "", + "<1,108>": "" } }, "record3": { @@ -104,10 +180,14 @@ }, "<1,11>": { "<1,11,1>": "0x4", - "<1,11,2>": "0x80000000" + "<1,11,2>": "0x80000C00" }, "<1,12>": "1", - "<1,13>": "-2", + "<1,13>": { + "<1,13,1>": "-2", + "<1,13,2>": "-2", + "<1,13,3>": "" + }, "<1,14>": "0", "<1,15>": { "<1,15,1>": { @@ -136,17 +216,14 @@ "<1,22>": "", "<1,23>": "", "<1,24>": "", - "<1,25>": "0", - "<1,26>": "0", + "<1,25>": "", + "<1,26>": "", "<1,27>": "", "<1,28>": "<>", "<1,29>": "<>", "<1,30>": "<>", "<1,31>": "0", - "<1,32>": { - "<1,32,1>": "0x7fffe", - "<1,32,2>": "0xf0016108" - }, + "<1,32>": "", "<1,33>": "", "<1,34>": "", "<1,35>": "", @@ -166,7 +243,71 @@ "<1,49>": "", "<1,50>": "", "<1,51>": "", - "<1,52>": "" + "<1,52>": "", + "<1,53>": "", + "<1,54>": "", + "<1,55>": "", + "<1,56>": "", + "<1,57>": "", + "<1,58>": "", + "<1,59>": "", + "<1,60>": "", + "<1,61>": "", + "<1,62>": "0", + "<1,63>": "", + "<1,64>": { + "<1,64,1>": "", + "<1,64,2>": "", + "<1,64,3>": "" + }, + "<1,65>": "-2", + "<1,66>": { + "<1,66,1>": "", + "<1,66,2>": "", + "<1,66,3>": "" + }, + "<1,67>": "-2", + "<1,68>": "", + "<1,69>": "", + "<1,70>": "", + "<1,71>": "", + "<1,72>": "", + "<1,73>": "", + "<1,74>": "", + "<1,75>": "", + "<1,76>": "", + "<1,77>": "", + "<1,78>": "", + "<1,79>": "", + "<1,80>": "", + "<1,81>": "", + "<1,82>": "", + "<1,83>": "", + "<1,84>": "", + "<1,85>": "", + "<1,86>": "", + "<1,87>": "", + "<1,88>": "", + "<1,89>": "", + "<1,90>": "", + "<1,91>": "", + "<1,92>": "", + "<1,93>": "", + "<1,94>": "", + "<1,95>": "", + "<1,96>": "", + "<1,97>": "", + "<1,98>": "", + "<1,99>": "", + "<1,100>": "", + "<1,101>": "", + "<1,102>": "", + "<1,103>": "", + "<1,104>": "", + "<1,105>": "", + "<1,106>": "", + "<1,107>": "", + "<1,108>": "" }, "<2>": { "<2,1>": "TYPE", @@ -184,10 +325,14 @@ }, "<2,11>": { "<2,11,1>": "0x0", - "<2,11,2>": "0x80000000" + "<2,11,2>": "0x80000C00" }, "<2,12>": "2", - "<2,13>": "-2", + "<2,13>": { + "<2,13,1>": "-2", + "<2,13,2>": "-2", + "<2,13,3>": "" + }, "<2,14>": "0", "<2,15>": { "<2,15,1>": { @@ -216,17 +361,14 @@ "<2,22>": "", "<2,23>": "", "<2,24>": "", - "<2,25>": "0", - "<2,26>": "0", + "<2,25>": "", + "<2,26>": "", "<2,27>": "", "<2,28>": "<>", "<2,29>": "<>", "<2,30>": "<>", "<2,31>": "0", - "<2,32>": { - "<2,32,1>": "0x7fff6", - "<2,32,2>": "0xf0016808" - }, + "<2,32>": "", "<2,33>": "", "<2,34>": "", "<2,35>": { @@ -258,7 +400,71 @@ "<2,49>": "", "<2,50>": "", "<2,51>": "", - "<2,52>": "" + "<2,52>": "", + "<2,53>": "", + "<2,54>": "", + "<2,55>": "", + "<2,56>": "", + "<2,57>": "", + "<2,58>": "", + "<2,59>": "", + "<2,60>": "", + "<2,61>": "", + "<2,62>": "0", + "<2,63>": "", + "<2,64>": { + "<2,64,1>": "", + "<2,64,2>": "", + "<2,64,3>": "" + }, + "<2,65>": "-2", + "<2,66>": { + "<2,66,1>": "", + "<2,66,2>": "", + "<2,66,3>": "" + }, + "<2,67>": "-2", + "<2,68>": "", + "<2,69>": "", + "<2,70>": "", + "<2,71>": "", + "<2,72>": "", + "<2,73>": "", + "<2,74>": "", + "<2,75>": "", + "<2,76>": "", + "<2,77>": "", + "<2,78>": "", + "<2,79>": "", + "<2,80>": "", + "<2,81>": "", + "<2,82>": "", + "<2,83>": "", + "<2,84>": "", + "<2,85>": "", + "<2,86>": "", + "<2,87>": "", + "<2,88>": "", + "<2,89>": "", + "<2,90>": "", + "<2,91>": "", + "<2,92>": "", + "<2,93>": "", + "<2,94>": "", + "<2,95>": "", + "<2,96>": "", + "<2,97>": "", + "<2,98>": "", + "<2,99>": "", + "<2,100>": "", + "<2,101>": "", + "<2,102>": "", + "<2,103>": "", + "<2,104>": "", + "<2,105>": "", + "<2,106>": "", + "<2,107>": "", + "<2,108>": "" }, "<3>": { "<3,1>": "RECIPE", @@ -276,10 +482,14 @@ }, "<3,11>": { "<3,11,1>": "0x0", - "<3,11,2>": "0x80000000" + "<3,11,2>": "0x80000C00" }, "<3,12>": "3", - "<3,13>": "-2", + "<3,13>": { + "<3,13,1>": "-2", + "<3,13,2>": "-2", + "<3,13,3>": "" + }, "<3,14>": "0", "<3,15>": { "<3,15,1>": { @@ -308,17 +518,14 @@ "<3,22>": "", "<3,23>": "", "<3,24>": "", - "<3,25>": "0", - "<3,26>": "0", + "<3,25>": "", + "<3,26>": "", "<3,27>": "", "<3,28>": "<>", "<3,29>": "<>", "<3,30>": "<>", "<3,31>": "0", - "<3,32>": { - "<3,32,1>": "0x7fffe", - "<3,32,2>": "0xf0016808" - }, + "<3,32>": "", "<3,33>": "", "<3,34>": "", "<3,35>": "", @@ -338,7 +545,71 @@ "<3,49>": "", "<3,50>": "", "<3,51>": "", - "<3,52>": "" + "<3,52>": "", + "<3,53>": "", + "<3,54>": "", + "<3,55>": "", + "<3,56>": "", + "<3,57>": "", + "<3,58>": "", + "<3,59>": "", + "<3,60>": "", + "<3,61>": "", + "<3,62>": "0", + "<3,63>": "", + "<3,64>": { + "<3,64,1>": "", + "<3,64,2>": "", + "<3,64,3>": "" + }, + "<3,65>": "-2", + "<3,66>": { + "<3,66,1>": "", + "<3,66,2>": "", + "<3,66,3>": "" + }, + "<3,67>": "-2", + "<3,68>": "", + "<3,69>": "", + "<3,70>": "", + "<3,71>": "", + "<3,72>": "", + "<3,73>": "", + "<3,74>": "", + "<3,75>": "", + "<3,76>": "", + "<3,77>": "", + "<3,78>": "", + "<3,79>": "", + "<3,80>": "", + "<3,81>": "", + "<3,82>": "", + "<3,83>": "", + "<3,84>": "", + "<3,85>": "", + "<3,86>": "", + "<3,87>": "", + "<3,88>": "", + "<3,89>": "", + "<3,90>": "", + "<3,91>": "", + "<3,92>": "", + "<3,93>": "", + "<3,94>": "", + "<3,95>": "", + "<3,96>": "", + "<3,97>": "", + "<3,98>": "", + "<3,99>": "", + "<3,100>": "", + "<3,101>": "", + "<3,102>": "", + "<3,103>": "", + "<3,104>": "", + "<3,105>": "", + "<3,106>": "", + "<3,107>": "", + "<3,108>": "" }, "<4>": { "<4,1>": "FREQ", @@ -351,7 +622,7 @@ "<4,8>": "21", "<4,9>": "", "<4,10>": { - "<4,10,1>": "0x56800080", + "<4,10,1>": "0x56000080", "<4,10,2>": "0x200" }, "<4,11>": { @@ -359,7 +630,11 @@ "<4,11,2>": "0x80000000" }, "<4,12>": "4", - "<4,13>": "-2", + "<4,13>": { + "<4,13,1>": "-2", + "<4,13,2>": "-2", + "<4,13,3>": "" + }, "<4,14>": "0", "<4,15>": { "<4,15,1>": { @@ -388,21 +663,21 @@ "<4,22>": "", "<4,23>": "", "<4,24>": "", - "<4,25>": "0", - "<4,26>": "0", + "<4,25>": "", + "<4,26>": "", "<4,27>": "", "<4,28>": "(MD0)", "<4,29>": "MD0", "<4,30>": "<>", "<4,31>": "0", - "<4,32>": { - "<4,32,1>": "0x7fffe", - "<4,32,2>": "0xc0016c08" - }, + "<4,32>": "", "<4,33>": "", "<4,34>": "", "<4,35>": "", - "<4,36>": "", + "<4,36>": { + "<4,36,1>": "0", + "<4,36,2>": "0" + }, "<4,37>": "", "<4,38>": "", "<4,39>": "", @@ -418,7 +693,63 @@ "<4,49>": "", "<4,50>": "", "<4,51>": "", - "<4,52>": "" + "<4,52>": "", + "<4,53>": "", + "<4,54>": "", + "<4,55>": "", + "<4,56>": "", + "<4,57>": "", + "<4,58>": "", + "<4,59>": "", + "<4,60>": "", + "<4,61>": "", + "<4,62>": "0", + "<4,63>": "", + "<4,64>": "", + "<4,65>": "", + "<4,66>": "", + "<4,67>": "", + "<4,68>": "", + "<4,69>": "", + "<4,70>": "", + "<4,71>": "", + "<4,72>": "", + "<4,73>": "", + "<4,74>": "", + "<4,75>": "", + "<4,76>": "", + "<4,77>": "", + "<4,78>": "", + "<4,79>": "", + "<4,80>": "", + "<4,81>": "", + "<4,82>": "", + "<4,83>": "", + "<4,84>": "", + "<4,85>": "", + "<4,86>": "", + "<4,87>": "", + "<4,88>": "", + "<4,89>": "", + "<4,90>": "", + "<4,91>": "", + "<4,92>": "", + "<4,93>": "", + "<4,94>": "", + "<4,95>": "", + "<4,96>": "", + "<4,97>": "", + "<4,98>": "", + "<4,99>": "", + "<4,100>": "", + "<4,101>": "", + "<4,102>": "", + "<4,103>": "", + "<4,104>": "", + "<4,105>": "", + "<4,106>": "", + "<4,107>": "", + "<4,108>": "" }, "<5>": { "<5,1>": "PROVE_TYPE", @@ -436,10 +767,14 @@ }, "<5,11>": { "<5,11,1>": "0x0", - "<5,11,2>": "0x80000000" + "<5,11,2>": "0x80000C00" }, "<5,12>": "5", - "<5,13>": "-2", + "<5,13>": { + "<5,13,1>": "-2", + "<5,13,2>": "-2", + "<5,13,3>": "" + }, "<5,14>": "0", "<5,15>": { "<5,15,1>": { @@ -468,17 +803,14 @@ "<5,22>": "", "<5,23>": "", "<5,24>": "", - "<5,25>": "0", - "<5,26>": "0", + "<5,25>": "", + "<5,26>": "", "<5,27>": "", "<5,28>": "<>", "<5,29>": "<>", "<5,30>": "<>", "<5,31>": "0", - "<5,32>": { - "<5,32,1>": "0x7fff6", - "<5,32,2>": "0xf0016808" - }, + "<5,32>": "", "<5,33>": "", "<5,34>": "", "<5,35>": { @@ -510,7 +842,71 @@ "<5,49>": "", "<5,50>": "", "<5,51>": "", - "<5,52>": "" + "<5,52>": "", + "<5,53>": "", + "<5,54>": "", + "<5,55>": "", + "<5,56>": "", + "<5,57>": "", + "<5,58>": "", + "<5,59>": "", + "<5,60>": "", + "<5,61>": "", + "<5,62>": "0", + "<5,63>": "", + "<5,64>": { + "<5,64,1>": "", + "<5,64,2>": "", + "<5,64,3>": "" + }, + "<5,65>": "-2", + "<5,66>": { + "<5,66,1>": "", + "<5,66,2>": "", + "<5,66,3>": "" + }, + "<5,67>": "-2", + "<5,68>": "", + "<5,69>": "", + "<5,70>": "", + "<5,71>": "", + "<5,72>": "", + "<5,73>": "", + "<5,74>": "", + "<5,75>": "", + "<5,76>": "", + "<5,77>": "", + "<5,78>": "", + "<5,79>": "", + "<5,80>": "", + "<5,81>": "", + "<5,82>": "", + "<5,83>": "", + "<5,84>": "", + "<5,85>": "", + "<5,86>": "", + "<5,87>": "", + "<5,88>": "", + "<5,89>": "", + "<5,90>": "", + "<5,91>": "", + "<5,92>": "", + "<5,93>": "", + "<5,94>": "", + "<5,95>": "", + "<5,96>": "", + "<5,97>": "", + "<5,98>": "", + "<5,99>": "", + "<5,100>": "", + "<5,101>": "", + "<5,102>": "", + "<5,103>": "", + "<5,104>": "", + "<5,105>": "", + "<5,106>": "", + "<5,107>": "", + "<5,108>": "" }, "<6>": { "<6,1>": "SAVE_BUTTON", @@ -523,15 +919,19 @@ "<6,8>": "21", "<6,9>": "&Save", "<6,10>": { - "<6,10,1>": "0x56000000", + "<6,10,1>": "0x56000300", "<6,10,2>": "0x0" }, "<6,11>": { - "<6,11,1>": "0x100", + "<6,11,1>": "0x0", "<6,11,2>": "0x80000000" }, "<6,12>": "6", - "<6,13>": "-2", + "<6,13>": { + "<6,13,1>": "-2", + "<6,13,2>": "-2", + "<6,13,3>": "0" + }, "<6,14>": "0", "<6,15>": { "<6,15,1>": { @@ -560,17 +960,14 @@ "<6,22>": "", "<6,23>": "", "<6,24>": "", - "<6,25>": "0", - "<6,26>": "0", + "<6,25>": "", + "<6,26>": "", "<6,27>": "", - "<6,28>": "<>", - "<6,29>": "<>", - "<6,30>": "<>", - "<6,31>": "0", - "<6,32>": { - "<6,32,1>": "0x7fffe", - "<6,32,2>": "0xf0016408" - }, + "<6,28>": "", + "<6,29>": "", + "<6,30>": "", + "<6,31>": "", + "<6,32>": "", "<6,33>": "", "<6,34>": "", "<6,35>": "", @@ -579,7 +976,10 @@ "<6,38>": "", "<6,39>": "", "<6,40>": "1", - "<6,41>": "", + "<6,41>": { + "<6,41,1>": "", + "<6,41,2>": "-1" + }, "<6,42>": "", "<6,43>": "", "<6,44>": "", @@ -590,7 +990,67 @@ "<6,49>": "", "<6,50>": "", "<6,51>": "", - "<6,52>": "" + "<6,52>": "", + "<6,53>": "", + "<6,54>": "", + "<6,55>": "", + "<6,56>": "", + "<6,57>": "", + "<6,58>": "", + "<6,59>": "", + "<6,60>": "", + "<6,61>": "", + "<6,62>": "0", + "<6,63>": "", + "<6,64>": { + "<6,64,1>": "-2", + "<6,64,2>": "-2", + "<6,64,3>": "0" + }, + "<6,65>": "-2", + "<6,66>": "", + "<6,67>": "", + "<6,68>": "", + "<6,69>": "", + "<6,70>": "", + "<6,71>": "", + "<6,72>": "", + "<6,73>": "", + "<6,74>": "", + "<6,75>": "", + "<6,76>": "", + "<6,77>": "", + "<6,78>": "", + "<6,79>": "", + "<6,80>": "", + "<6,81>": "", + "<6,82>": "", + "<6,83>": "", + "<6,84>": "", + "<6,85>": "", + "<6,86>": "", + "<6,87>": "", + "<6,88>": "", + "<6,89>": "", + "<6,90>": "0", + "<6,91>": "0", + "<6,92>": "", + "<6,93>": "", + "<6,94>": "", + "<6,95>": "", + "<6,96>": "", + "<6,97>": "", + "<6,98>": "", + "<6,99>": "", + "<6,100>": "", + "<6,101>": "", + "<6,102>": "", + "<6,103>": "", + "<6,104>": "", + "<6,105>": "", + "<6,106>": "", + "<6,107>": "", + "<6,108>": "" }, "<7>": { "<7,1>": "CANCEL_BUTTON", @@ -603,15 +1063,19 @@ "<7,8>": "21", "<7,9>": "&Cancel", "<7,10>": { - "<7,10,1>": "0x56000000", + "<7,10,1>": "0x56000300", "<7,10,2>": "0x0" }, "<7,11>": { - "<7,11,1>": "0x100", + "<7,11,1>": "0x0", "<7,11,2>": "0x80000000" }, "<7,12>": "7", - "<7,13>": "-2", + "<7,13>": { + "<7,13,1>": "-2", + "<7,13,2>": "-2", + "<7,13,3>": "0" + }, "<7,14>": "0", "<7,15>": { "<7,15,1>": { @@ -640,17 +1104,14 @@ "<7,22>": "", "<7,23>": "", "<7,24>": "", - "<7,25>": "0", - "<7,26>": "0", + "<7,25>": "", + "<7,26>": "", "<7,27>": "", - "<7,28>": "<>", - "<7,29>": "<>", - "<7,30>": "<>", - "<7,31>": "0", - "<7,32>": { - "<7,32,1>": "0x7fffe", - "<7,32,2>": "0xf0016408" - }, + "<7,28>": "", + "<7,29>": "", + "<7,30>": "", + "<7,31>": "", + "<7,32>": "", "<7,33>": "", "<7,34>": "", "<7,35>": "", @@ -659,7 +1120,10 @@ "<7,38>": "", "<7,39>": "", "<7,40>": "1", - "<7,41>": "", + "<7,41>": { + "<7,41,1>": "", + "<7,41,2>": "-1" + }, "<7,42>": "", "<7,43>": "", "<7,44>": "", @@ -670,7 +1134,67 @@ "<7,49>": "", "<7,50>": "", "<7,51>": "", - "<7,52>": "" + "<7,52>": "", + "<7,53>": "", + "<7,54>": "", + "<7,55>": "", + "<7,56>": "", + "<7,57>": "", + "<7,58>": "", + "<7,59>": "", + "<7,60>": "", + "<7,61>": "", + "<7,62>": "0", + "<7,63>": "", + "<7,64>": { + "<7,64,1>": "-2", + "<7,64,2>": "-2", + "<7,64,3>": "0" + }, + "<7,65>": "-2", + "<7,66>": "", + "<7,67>": "", + "<7,68>": "", + "<7,69>": "", + "<7,70>": "", + "<7,71>": "", + "<7,72>": "", + "<7,73>": "", + "<7,74>": "", + "<7,75>": "", + "<7,76>": "", + "<7,77>": "", + "<7,78>": "", + "<7,79>": "", + "<7,80>": "", + "<7,81>": "", + "<7,82>": "", + "<7,83>": "", + "<7,84>": "", + "<7,85>": "", + "<7,86>": "", + "<7,87>": "", + "<7,88>": "", + "<7,89>": "", + "<7,90>": "0", + "<7,91>": "0", + "<7,92>": "", + "<7,93>": "", + "<7,94>": "", + "<7,95>": "", + "<7,96>": "", + "<7,97>": "", + "<7,98>": "", + "<7,99>": "", + "<7,100>": "", + "<7,101>": "", + "<7,102>": "", + "<7,103>": "", + "<7,104>": "", + "<7,105>": "", + "<7,106>": "", + "<7,107>": "", + "<7,108>": "" }, "<8>": { "<8,1>": "FIRST_CHECK", @@ -683,15 +1207,19 @@ "<8,8>": "21", "<8,9>": "First Wafer", "<8,10>": { - "<8,10,1>": "0x56000003", + "<8,10,1>": "0x56000103", "<8,10,2>": "0x0" }, "<8,11>": { - "<8,11,1>": "0x100", + "<8,11,1>": "0x0", "<8,11,2>": "0x80000000" }, "<8,12>": "8", - "<8,13>": "-1", + "<8,13>": { + "<8,13,1>": "-1", + "<8,13,2>": "-1", + "<8,13,3>": "" + }, "<8,14>": "0", "<8,15>": { "<8,15,1>": { @@ -720,17 +1248,14 @@ "<8,22>": "", "<8,23>": "", "<8,24>": "", - "<8,25>": "0", - "<8,26>": "0", + "<8,25>": "", + "<8,26>": "", "<8,27>": "", - "<8,28>": "<>", - "<8,29>": "<>", - "<8,30>": "<>", - "<8,31>": "0", - "<8,32>": { - "<8,32,1>": "0x7fffe", - "<8,32,2>": "0xf0016408" - }, + "<8,28>": "", + "<8,29>": "", + "<8,30>": "", + "<8,31>": "", + "<8,32>": "", "<8,33>": "", "<8,34>": "", "<8,35>": "", @@ -738,7 +1263,7 @@ "<8,37>": "", "<8,38>": "", "<8,39>": "", - "<8,40>": "1", + "<8,40>": "", "<8,41>": "", "<8,42>": "", "<8,43>": "", @@ -750,7 +1275,76 @@ "<8,49>": "", "<8,50>": "", "<8,51>": "", - "<8,52>": "" + "<8,52>": "", + "<8,53>": "", + "<8,54>": "", + "<8,55>": "", + "<8,56>": "", + "<8,57>": "", + "<8,58>": "", + "<8,59>": "", + "<8,60>": "", + "<8,61>": "", + "<8,62>": "0", + "<8,63>": { + "<8,63,1>": "", + "<8,63,2>": "", + "<8,63,3>": "", + "<8,63,4>": "", + "<8,63,5>": "", + "<8,63,6>": "", + "<8,63,7>": "", + "<8,63,8>": "" + }, + "<8,64>": { + "<8,64,1>": "", + "<8,64,2>": "", + "<8,64,3>": "" + }, + "<8,65>": "-2", + "<8,66>": "", + "<8,67>": "", + "<8,68>": "", + "<8,69>": "", + "<8,70>": "", + "<8,71>": "", + "<8,72>": "", + "<8,73>": "", + "<8,74>": "", + "<8,75>": "", + "<8,76>": "", + "<8,77>": "", + "<8,78>": "", + "<8,79>": "", + "<8,80>": "", + "<8,81>": "", + "<8,82>": "", + "<8,83>": "", + "<8,84>": "", + "<8,85>": "", + "<8,86>": "", + "<8,87>": "", + "<8,88>": "", + "<8,89>": "", + "<8,90>": "0", + "<8,91>": "0", + "<8,92>": "", + "<8,93>": "", + "<8,94>": "", + "<8,95>": "", + "<8,96>": "", + "<8,97>": "", + "<8,98>": "", + "<8,99>": "", + "<8,100>": "", + "<8,101>": "", + "<8,102>": "", + "<8,103>": "", + "<8,104>": "", + "<8,105>": "", + "<8,106>": "", + "<8,107>": "", + "<8,108>": "" }, "<9>": { "<9,1>": "LAST_CHECK", @@ -763,15 +1357,19 @@ "<9,8>": "21", "<9,9>": "Last Wafer", "<9,10>": { - "<9,10,1>": "0x56000003", + "<9,10,1>": "0x56000103", "<9,10,2>": "0x0" }, "<9,11>": { - "<9,11,1>": "0x100", + "<9,11,1>": "0x0", "<9,11,2>": "0x80000000" }, "<9,12>": "9", - "<9,13>": "-1", + "<9,13>": { + "<9,13,1>": "-1", + "<9,13,2>": "-1", + "<9,13,3>": "" + }, "<9,14>": "0", "<9,15>": { "<9,15,1>": { @@ -800,17 +1398,14 @@ "<9,22>": "", "<9,23>": "", "<9,24>": "", - "<9,25>": "0", - "<9,26>": "0", + "<9,25>": "", + "<9,26>": "", "<9,27>": "", - "<9,28>": "<>", - "<9,29>": "<>", - "<9,30>": "<>", - "<9,31>": "0", - "<9,32>": { - "<9,32,1>": "0x7fffe", - "<9,32,2>": "0xf0016408" - }, + "<9,28>": "", + "<9,29>": "", + "<9,30>": "", + "<9,31>": "", + "<9,32>": "", "<9,33>": "", "<9,34>": "", "<9,35>": "", @@ -818,7 +1413,7 @@ "<9,37>": "", "<9,38>": "", "<9,39>": "", - "<9,40>": "1", + "<9,40>": "", "<9,41>": "", "<9,42>": "", "<9,43>": "", @@ -830,7 +1425,76 @@ "<9,49>": "", "<9,50>": "", "<9,51>": "", - "<9,52>": "" + "<9,52>": "", + "<9,53>": "", + "<9,54>": "", + "<9,55>": "", + "<9,56>": "", + "<9,57>": "", + "<9,58>": "", + "<9,59>": "", + "<9,60>": "", + "<9,61>": "", + "<9,62>": "0", + "<9,63>": { + "<9,63,1>": "", + "<9,63,2>": "", + "<9,63,3>": "", + "<9,63,4>": "", + "<9,63,5>": "", + "<9,63,6>": "", + "<9,63,7>": "", + "<9,63,8>": "" + }, + "<9,64>": { + "<9,64,1>": "", + "<9,64,2>": "", + "<9,64,3>": "" + }, + "<9,65>": "-2", + "<9,66>": "", + "<9,67>": "", + "<9,68>": "", + "<9,69>": "", + "<9,70>": "", + "<9,71>": "", + "<9,72>": "", + "<9,73>": "", + "<9,74>": "", + "<9,75>": "", + "<9,76>": "", + "<9,77>": "", + "<9,78>": "", + "<9,79>": "", + "<9,80>": "", + "<9,81>": "", + "<9,82>": "", + "<9,83>": "", + "<9,84>": "", + "<9,85>": "", + "<9,86>": "", + "<9,87>": "", + "<9,88>": "", + "<9,89>": "", + "<9,90>": "0", + "<9,91>": "0", + "<9,92>": "", + "<9,93>": "", + "<9,94>": "", + "<9,95>": "", + "<9,96>": "", + "<9,97>": "", + "<9,98>": "", + "<9,99>": "", + "<9,100>": "", + "<9,101>": "", + "<9,102>": "", + "<9,103>": "", + "<9,104>": "", + "<9,105>": "", + "<9,106>": "", + "<9,107>": "", + "<9,108>": "" }, "<10>": { "<10,1>": "TW_TYPE_LABEL", @@ -843,7 +1507,7 @@ "<10,8>": "15", "<10,9>": "Prove-In Wafer Type:", "<10,10>": { - "<10,10,1>": "0x56000002", + "<10,10,1>": "0x56000800", "<10,10,2>": "0x0" }, "<10,11>": { @@ -851,7 +1515,11 @@ "<10,11,2>": "0x80000000" }, "<10,12>": "10", - "<10,13>": "-1", + "<10,13>": { + "<10,13,1>": "-1", + "<10,13,2>": "-1", + "<10,13,3>": "" + }, "<10,14>": "0", "<10,15>": { "<10,15,1>": { @@ -880,17 +1548,14 @@ "<10,22>": "", "<10,23>": "", "<10,24>": "", - "<10,25>": "0", - "<10,26>": "0", + "<10,25>": "", + "<10,26>": "", "<10,27>": "", - "<10,28>": "<>", - "<10,29>": "<>", - "<10,30>": "<>", - "<10,31>": "0", - "<10,32>": { - "<10,32,1>": "0x7fffe", - "<10,32,2>": "0xf0016808" - }, + "<10,28>": "", + "<10,29>": "", + "<10,30>": "", + "<10,31>": "", + "<10,32>": "", "<10,33>": "", "<10,34>": "", "<10,35>": "", @@ -910,7 +1575,76 @@ "<10,49>": "", "<10,50>": "", "<10,51>": "", - "<10,52>": "" + "<10,52>": "", + "<10,53>": "", + "<10,54>": "", + "<10,55>": "", + "<10,56>": "", + "<10,57>": "", + "<10,58>": "", + "<10,59>": "", + "<10,60>": "", + "<10,61>": "", + "<10,62>": "0", + "<10,63>": { + "<10,63,1>": "", + "<10,63,2>": "", + "<10,63,3>": "", + "<10,63,4>": "", + "<10,63,5>": "", + "<10,63,6>": "", + "<10,63,7>": "", + "<10,63,8>": "" + }, + "<10,64>": { + "<10,64,1>": "", + "<10,64,2>": "", + "<10,64,3>": "" + }, + "<10,65>": "-2", + "<10,66>": "", + "<10,67>": "", + "<10,68>": "", + "<10,69>": "", + "<10,70>": "", + "<10,71>": "", + "<10,72>": "", + "<10,73>": "", + "<10,74>": "", + "<10,75>": "", + "<10,76>": "", + "<10,77>": "", + "<10,78>": "", + "<10,79>": "", + "<10,80>": "", + "<10,81>": "", + "<10,82>": "", + "<10,83>": "", + "<10,84>": "", + "<10,85>": "", + "<10,86>": "", + "<10,87>": "", + "<10,88>": "", + "<10,89>": "", + "<10,90>": "0", + "<10,91>": "0", + "<10,92>": "", + "<10,93>": "", + "<10,94>": "", + "<10,95>": "", + "<10,96>": "", + "<10,97>": "", + "<10,98>": "", + "<10,99>": "", + "<10,100>": "", + "<10,101>": "", + "<10,102>": "", + "<10,103>": "", + "<10,104>": "", + "<10,105>": "", + "<10,106>": "", + "<10,107>": "", + "<10,108>": "" }, "<11>": { "<11,1>": "SPC", @@ -923,15 +1657,19 @@ "<11,8>": "21", "<11,9>": "Control by SPC", "<11,10>": { - "<11,10,1>": "0x56000003", + "<11,10,1>": "0x56000103", "<11,10,2>": "0x0" }, "<11,11>": { - "<11,11,1>": "0x100", + "<11,11,1>": "0x0", "<11,11,2>": "0x80000000" }, "<11,12>": "11", - "<11,13>": "-1", + "<11,13>": { + "<11,13,1>": "-1", + "<11,13,2>": "-1", + "<11,13,3>": "" + }, "<11,14>": "0", "<11,15>": { "<11,15,1>": { @@ -960,17 +1698,14 @@ "<11,22>": "", "<11,23>": "", "<11,24>": "", - "<11,25>": "0", - "<11,26>": "0", + "<11,25>": "", + "<11,26>": "", "<11,27>": "", - "<11,28>": "<>", - "<11,29>": "<>", - "<11,30>": "<>", - "<11,31>": "0", - "<11,32>": { - "<11,32,1>": "0x7fffe", - "<11,32,2>": "0xf0016408" - }, + "<11,28>": "", + "<11,29>": "", + "<11,30>": "", + "<11,31>": "", + "<11,32>": "", "<11,33>": "", "<11,34>": "", "<11,35>": "", @@ -978,7 +1713,7 @@ "<11,37>": "", "<11,38>": "", "<11,39>": "", - "<11,40>": "1", + "<11,40>": "", "<11,41>": "", "<11,42>": "", "<11,43>": "", @@ -990,7 +1725,76 @@ "<11,49>": "", "<11,50>": "", "<11,51>": "", - "<11,52>": "" + "<11,52>": "", + "<11,53>": "", + "<11,54>": "", + "<11,55>": "", + "<11,56>": "", + "<11,57>": "", + "<11,58>": "", + "<11,59>": "", + "<11,60>": "", + "<11,61>": "", + "<11,62>": "0", + "<11,63>": { + "<11,63,1>": "", + "<11,63,2>": "", + "<11,63,3>": "", + "<11,63,4>": "", + "<11,63,5>": "", + "<11,63,6>": "", + "<11,63,7>": "", + "<11,63,8>": "" + }, + "<11,64>": { + "<11,64,1>": "", + "<11,64,2>": "", + "<11,64,3>": "" + }, + "<11,65>": "-2", + "<11,66>": "", + "<11,67>": "", + "<11,68>": "", + "<11,69>": "", + "<11,70>": "", + "<11,71>": "", + "<11,72>": "", + "<11,73>": "", + "<11,74>": "", + "<11,75>": "", + "<11,76>": "", + "<11,77>": "", + "<11,78>": "", + "<11,79>": "", + "<11,80>": "", + "<11,81>": "", + "<11,82>": "", + "<11,83>": "", + "<11,84>": "", + "<11,85>": "", + "<11,86>": "", + "<11,87>": "", + "<11,88>": "", + "<11,89>": "", + "<11,90>": "0", + "<11,91>": "0", + "<11,92>": "", + "<11,93>": "", + "<11,94>": "", + "<11,95>": "", + "<11,96>": "", + "<11,97>": "", + "<11,98>": "", + "<11,99>": "", + "<11,100>": "", + "<11,101>": "", + "<11,102>": "", + "<11,103>": "", + "<11,104>": "", + "<11,105>": "", + "<11,106>": "", + "<11,107>": "", + "<11,108>": "" }, "<12>": { "<12,1>": "OVERGROW", @@ -1003,15 +1807,19 @@ "<12,8>": "21", "<12,9>": "Overgrow Method", "<12,10>": { - "<12,10,1>": "0x56000003", + "<12,10,1>": "0x56000103", "<12,10,2>": "0x0" }, "<12,11>": { - "<12,11,1>": "0x100", + "<12,11,1>": "0x0", "<12,11,2>": "0x80000000" }, "<12,12>": "12", - "<12,13>": "-1", + "<12,13>": { + "<12,13,1>": "-1", + "<12,13,2>": "-1", + "<12,13,3>": "" + }, "<12,14>": "0", "<12,15>": { "<12,15,1>": { @@ -1040,17 +1848,14 @@ "<12,22>": "", "<12,23>": "", "<12,24>": "", - "<12,25>": "0", - "<12,26>": "0", + "<12,25>": "", + "<12,26>": "", "<12,27>": "", - "<12,28>": "<>", - "<12,29>": "<>", - "<12,30>": "<>", - "<12,31>": "0", - "<12,32>": { - "<12,32,1>": "0x7fffe", - "<12,32,2>": "0xf0016408" - }, + "<12,28>": "", + "<12,29>": "", + "<12,30>": "", + "<12,31>": "", + "<12,32>": "", "<12,33>": "", "<12,34>": "", "<12,35>": "", @@ -1058,7 +1863,7 @@ "<12,37>": "", "<12,38>": "", "<12,39>": "", - "<12,40>": "1", + "<12,40>": "", "<12,41>": "", "<12,42>": "", "<12,43>": "", @@ -1070,7 +1875,76 @@ "<12,49>": "", "<12,50>": "", "<12,51>": "", - "<12,52>": "" + "<12,52>": "", + "<12,53>": "", + "<12,54>": "", + "<12,55>": "", + "<12,56>": "", + "<12,57>": "", + "<12,58>": "", + "<12,59>": "", + "<12,60>": "", + "<12,61>": "", + "<12,62>": "0", + "<12,63>": { + "<12,63,1>": "", + "<12,63,2>": "", + "<12,63,3>": "", + "<12,63,4>": "", + "<12,63,5>": "", + "<12,63,6>": "", + "<12,63,7>": "", + "<12,63,8>": "" + }, + "<12,64>": { + "<12,64,1>": "", + "<12,64,2>": "", + "<12,64,3>": "" + }, + "<12,65>": "-2", + "<12,66>": "", + "<12,67>": "", + "<12,68>": "", + "<12,69>": "", + "<12,70>": "", + "<12,71>": "", + "<12,72>": "", + "<12,73>": "", + "<12,74>": "", + "<12,75>": "", + "<12,76>": "", + "<12,77>": "", + "<12,78>": "", + "<12,79>": "", + "<12,80>": "", + "<12,81>": "", + "<12,82>": "", + "<12,83>": "", + "<12,84>": "", + "<12,85>": "", + "<12,86>": "", + "<12,87>": "", + "<12,88>": "", + "<12,89>": "", + "<12,90>": "0", + "<12,91>": "0", + "<12,92>": "", + "<12,93>": "", + "<12,94>": "", + "<12,95>": "", + "<12,96>": "", + "<12,97>": "", + "<12,98>": "", + "<12,99>": "", + "<12,100>": "", + "<12,101>": "", + "<12,102>": "", + "<12,103>": "", + "<12,104>": "", + "<12,105>": "", + "<12,106>": "", + "<12,107>": "", + "<12,108>": "" }, "<13>": { "<13,1>": "EXPECTED_TW_QTY", @@ -1091,7 +1965,11 @@ "<13,11,2>": "0x80000000" }, "<13,12>": "13", - "<13,13>": "-2", + "<13,13>": { + "<13,13,1>": "-2", + "<13,13,2>": "-2", + "<13,13,3>": "" + }, "<13,14>": "0", "<13,15>": { "<13,15,1>": { @@ -1120,21 +1998,21 @@ "<13,22>": "", "<13,23>": "", "<13,24>": "", - "<13,25>": "0", - "<13,26>": "0", + "<13,25>": "", + "<13,26>": "", "<13,27>": "", "<13,28>": "<>", "<13,29>": "<>", "<13,30>": "<>", "<13,31>": "0", - "<13,32>": { - "<13,32,1>": "0x7fffe", - "<13,32,2>": "0xf0016908" - }, + "<13,32>": "", "<13,33>": "", "<13,34>": "", "<13,35>": "", - "<13,36>": "", + "<13,36>": { + "<13,36,1>": "0", + "<13,36,2>": "0" + }, "<13,37>": "", "<13,38>": "", "<13,39>": "", @@ -1150,7 +2028,63 @@ "<13,49>": "", "<13,50>": "", "<13,51>": "", - "<13,52>": "" + "<13,52>": "", + "<13,53>": "", + "<13,54>": "", + "<13,55>": "", + "<13,56>": "", + "<13,57>": "", + "<13,58>": "", + "<13,59>": "", + "<13,60>": "", + "<13,61>": "", + "<13,62>": "0", + "<13,63>": "", + "<13,64>": "", + "<13,65>": "", + "<13,66>": "", + "<13,67>": "", + "<13,68>": "", + "<13,69>": "", + "<13,70>": "", + "<13,71>": "", + "<13,72>": "", + "<13,73>": "", + "<13,74>": "", + "<13,75>": "", + "<13,76>": "", + "<13,77>": "", + "<13,78>": "", + "<13,79>": "", + "<13,80>": "", + "<13,81>": "", + "<13,82>": "", + "<13,83>": "", + "<13,84>": "", + "<13,85>": "", + "<13,86>": "", + "<13,87>": "", + "<13,88>": "", + "<13,89>": "", + "<13,90>": "", + "<13,91>": "", + "<13,92>": "", + "<13,93>": "", + "<13,94>": "", + "<13,95>": "", + "<13,96>": "", + "<13,97>": "", + "<13,98>": "", + "<13,99>": "", + "<13,100>": "", + "<13,101>": "", + "<13,102>": "", + "<13,103>": "", + "<13,104>": "", + "<13,105>": "", + "<13,106>": "", + "<13,107>": "", + "<13,108>": "" }, "<14>": { "<14,1>": "FREQ_LABEL", @@ -1163,7 +2097,7 @@ "<14,8>": "15", "<14,9>": "Every:", "<14,10>": { - "<14,10,1>": "0x56000002", + "<14,10,1>": "0x56000800", "<14,10,2>": "0x0" }, "<14,11>": { @@ -1171,7 +2105,11 @@ "<14,11,2>": "0x80000000" }, "<14,12>": "14", - "<14,13>": "-1", + "<14,13>": { + "<14,13,1>": "-1", + "<14,13,2>": "-1", + "<14,13,3>": "" + }, "<14,14>": "0", "<14,15>": { "<14,15,1>": { @@ -1200,17 +2138,14 @@ "<14,22>": "", "<14,23>": "", "<14,24>": "", - "<14,25>": "0", - "<14,26>": "0", + "<14,25>": "", + "<14,26>": "", "<14,27>": "", - "<14,28>": "<>", - "<14,29>": "<>", - "<14,30>": "<>", - "<14,31>": "0", - "<14,32>": { - "<14,32,1>": "0x7fffe", - "<14,32,2>": "0xf0016808" - }, + "<14,28>": "", + "<14,29>": "", + "<14,30>": "", + "<14,31>": "", + "<14,32>": "", "<14,33>": "", "<14,34>": "", "<14,35>": "", @@ -1230,7 +2165,76 @@ "<14,49>": "", "<14,50>": "", "<14,51>": "", - "<14,52>": "" + "<14,52>": "", + "<14,53>": "", + "<14,54>": "", + "<14,55>": "", + "<14,56>": "", + "<14,57>": "", + "<14,58>": "", + "<14,59>": "", + "<14,60>": "", + "<14,61>": "", + "<14,62>": "0", + "<14,63>": { + "<14,63,1>": "", + "<14,63,2>": "", + "<14,63,3>": "", + "<14,63,4>": "", + "<14,63,5>": "", + "<14,63,6>": "", + "<14,63,7>": "", + "<14,63,8>": "" + }, + "<14,64>": { + "<14,64,1>": "", + "<14,64,2>": "", + "<14,64,3>": "" + }, + "<14,65>": "-2", + "<14,66>": "", + "<14,67>": "", + "<14,68>": "", + "<14,69>": "", + "<14,70>": "", + "<14,71>": "", + "<14,72>": "", + "<14,73>": "", + "<14,74>": "", + "<14,75>": "", + "<14,76>": "", + "<14,77>": "", + "<14,78>": "", + "<14,79>": "", + "<14,80>": "", + "<14,81>": "", + "<14,82>": "", + "<14,83>": "", + "<14,84>": "", + "<14,85>": "", + "<14,86>": "", + "<14,87>": "", + "<14,88>": "", + "<14,89>": "", + "<14,90>": "0", + "<14,91>": "0", + "<14,92>": "", + "<14,93>": "", + "<14,94>": "", + "<14,95>": "", + "<14,96>": "", + "<14,97>": "", + "<14,98>": "", + "<14,99>": "", + "<14,100>": "", + "<14,101>": "", + "<14,102>": "", + "<14,103>": "", + "<14,104>": "", + "<14,105>": "", + "<14,106>": "", + "<14,107>": "", + "<14,108>": "" }, "<15>": { "<15,1>": "BOX_LABEL", @@ -1243,7 +2247,7 @@ "<15,8>": "15", "<15,9>": "Cassette(s)", "<15,10>": { - "<15,10,1>": "0x56000002", + "<15,10,1>": "0x56000800", "<15,10,2>": "0x0" }, "<15,11>": { @@ -1251,7 +2255,11 @@ "<15,11,2>": "0x80000000" }, "<15,12>": "15", - "<15,13>": "-1", + "<15,13>": { + "<15,13,1>": "-1", + "<15,13,2>": "-1", + "<15,13,3>": "" + }, "<15,14>": "0", "<15,15>": { "<15,15,1>": { @@ -1280,17 +2288,14 @@ "<15,22>": "", "<15,23>": "", "<15,24>": "", - "<15,25>": "0", - "<15,26>": "0", + "<15,25>": "", + "<15,26>": "", "<15,27>": "", - "<15,28>": "<>", - "<15,29>": "<>", - "<15,30>": "<>", - "<15,31>": "0", - "<15,32>": { - "<15,32,1>": "0x7fffe", - "<15,32,2>": "0xf0016808" - }, + "<15,28>": "", + "<15,29>": "", + "<15,30>": "", + "<15,31>": "", + "<15,32>": "", "<15,33>": "", "<15,34>": "", "<15,35>": "", @@ -1310,7 +2315,76 @@ "<15,49>": "", "<15,50>": "", "<15,51>": "", - "<15,52>": "" + "<15,52>": "", + "<15,53>": "", + "<15,54>": "", + "<15,55>": "", + "<15,56>": "", + "<15,57>": "", + "<15,58>": "", + "<15,59>": "", + "<15,60>": "", + "<15,61>": "", + "<15,62>": "0", + "<15,63>": { + "<15,63,1>": "", + "<15,63,2>": "", + "<15,63,3>": "", + "<15,63,4>": "", + "<15,63,5>": "", + "<15,63,6>": "", + "<15,63,7>": "", + "<15,63,8>": "" + }, + "<15,64>": { + "<15,64,1>": "", + "<15,64,2>": "", + "<15,64,3>": "" + }, + "<15,65>": "-2", + "<15,66>": "", + "<15,67>": "", + "<15,68>": "", + "<15,69>": "", + "<15,70>": "", + "<15,71>": "", + "<15,72>": "", + "<15,73>": "", + "<15,74>": "", + "<15,75>": "", + "<15,76>": "", + "<15,77>": "", + "<15,78>": "", + "<15,79>": "", + "<15,80>": "", + "<15,81>": "", + "<15,82>": "", + "<15,83>": "", + "<15,84>": "", + "<15,85>": "", + "<15,86>": "", + "<15,87>": "", + "<15,88>": "", + "<15,89>": "", + "<15,90>": "0", + "<15,91>": "0", + "<15,92>": "", + "<15,93>": "", + "<15,94>": "", + "<15,95>": "", + "<15,96>": "", + "<15,97>": "", + "<15,98>": "", + "<15,99>": "", + "<15,100>": "", + "<15,101>": "", + "<15,102>": "", + "<15,103>": "", + "<15,104>": "", + "<15,105>": "", + "<15,106>": "", + "<15,107>": "", + "<15,108>": "" }, "<16>": { "<16,1>": "EXP_QTY_LABEL", @@ -1323,7 +2397,7 @@ "<16,8>": "15", "<16,9>": "Expected Qty:", "<16,10>": { - "<16,10,1>": "0x56000002", + "<16,10,1>": "0x56000800", "<16,10,2>": "0x0" }, "<16,11>": { @@ -1331,7 +2405,11 @@ "<16,11,2>": "0x80000000" }, "<16,12>": "16", - "<16,13>": "-1", + "<16,13>": { + "<16,13,1>": "-1", + "<16,13,2>": "-1", + "<16,13,3>": "" + }, "<16,14>": "0", "<16,15>": { "<16,15,1>": { @@ -1360,17 +2438,14 @@ "<16,22>": "", "<16,23>": "", "<16,24>": "", - "<16,25>": "0", - "<16,26>": "0", + "<16,25>": "", + "<16,26>": "", "<16,27>": "", - "<16,28>": "<>", - "<16,29>": "<>", - "<16,30>": "<>", - "<16,31>": "0", - "<16,32>": { - "<16,32,1>": "0x7fffe", - "<16,32,2>": "0xf0016808" - }, + "<16,28>": "", + "<16,29>": "", + "<16,30>": "", + "<16,31>": "", + "<16,32>": "", "<16,33>": "", "<16,34>": "", "<16,35>": "", @@ -1390,7 +2465,76 @@ "<16,49>": "", "<16,50>": "", "<16,51>": "", - "<16,52>": "" + "<16,52>": "", + "<16,53>": "", + "<16,54>": "", + "<16,55>": "", + "<16,56>": "", + "<16,57>": "", + "<16,58>": "", + "<16,59>": "", + "<16,60>": "", + "<16,61>": "", + "<16,62>": "0", + "<16,63>": { + "<16,63,1>": "", + "<16,63,2>": "", + "<16,63,3>": "", + "<16,63,4>": "", + "<16,63,5>": "", + "<16,63,6>": "", + "<16,63,7>": "", + "<16,63,8>": "" + }, + "<16,64>": { + "<16,64,1>": "", + "<16,64,2>": "", + "<16,64,3>": "" + }, + "<16,65>": "-2", + "<16,66>": "", + "<16,67>": "", + "<16,68>": "", + "<16,69>": "", + "<16,70>": "", + "<16,71>": "", + "<16,72>": "", + "<16,73>": "", + "<16,74>": "", + "<16,75>": "", + "<16,76>": "", + "<16,77>": "", + "<16,78>": "", + "<16,79>": "", + "<16,80>": "", + "<16,81>": "", + "<16,82>": "", + "<16,83>": "", + "<16,84>": "", + "<16,85>": "", + "<16,86>": "", + "<16,87>": "", + "<16,88>": "", + "<16,89>": "", + "<16,90>": "0", + "<16,91>": "0", + "<16,92>": "", + "<16,93>": "", + "<16,94>": "", + "<16,95>": "", + "<16,96>": "", + "<16,97>": "", + "<16,98>": "", + "<16,99>": "", + "<16,100>": "", + "<16,101>": "", + "<16,102>": "", + "<16,103>": "", + "<16,104>": "", + "<16,105>": "", + "<16,106>": "", + "<16,107>": "", + "<16,108>": "" }, "<17>": { "<17,1>": "TOOL_LABEL", @@ -1403,7 +2547,7 @@ "<17,8>": "18", "<17,9>": "Tool:", "<17,10>": { - "<17,10,1>": "0x56000002", + "<17,10,1>": "0x56000800", "<17,10,2>": "0x0" }, "<17,11>": { @@ -1411,7 +2555,11 @@ "<17,11,2>": "0x80000000" }, "<17,12>": "17", - "<17,13>": "-1", + "<17,13>": { + "<17,13,1>": "-1", + "<17,13,2>": "-1", + "<17,13,3>": "" + }, "<17,14>": "0", "<17,15>": { "<17,15,1>": { @@ -1440,17 +2588,14 @@ "<17,22>": "", "<17,23>": "", "<17,24>": "", - "<17,25>": "0", - "<17,26>": "0", + "<17,25>": "", + "<17,26>": "", "<17,27>": "", - "<17,28>": "<>", - "<17,29>": "<>", - "<17,30>": "<>", - "<17,31>": "0", - "<17,32>": { - "<17,32,1>": "0x7fffe", - "<17,32,2>": "0xf0016808" - }, + "<17,28>": "", + "<17,29>": "", + "<17,30>": "", + "<17,31>": "", + "<17,32>": "", "<17,33>": "", "<17,34>": "", "<17,35>": "", @@ -1470,7 +2615,76 @@ "<17,49>": "", "<17,50>": "", "<17,51>": "", - "<17,52>": "" + "<17,52>": "", + "<17,53>": "", + "<17,54>": "", + "<17,55>": "", + "<17,56>": "", + "<17,57>": "", + "<17,58>": "", + "<17,59>": "", + "<17,60>": "", + "<17,61>": "", + "<17,62>": "0", + "<17,63>": { + "<17,63,1>": "", + "<17,63,2>": "", + "<17,63,3>": "", + "<17,63,4>": "", + "<17,63,5>": "", + "<17,63,6>": "", + "<17,63,7>": "", + "<17,63,8>": "" + }, + "<17,64>": { + "<17,64,1>": "", + "<17,64,2>": "", + "<17,64,3>": "" + }, + "<17,65>": "-2", + "<17,66>": "", + "<17,67>": "", + "<17,68>": "", + "<17,69>": "", + "<17,70>": "", + "<17,71>": "", + "<17,72>": "", + "<17,73>": "", + "<17,74>": "", + "<17,75>": "", + "<17,76>": "", + "<17,77>": "", + "<17,78>": "", + "<17,79>": "", + "<17,80>": "", + "<17,81>": "", + "<17,82>": "", + "<17,83>": "", + "<17,84>": "", + "<17,85>": "", + "<17,86>": "", + "<17,87>": "", + "<17,88>": "", + "<17,89>": "", + "<17,90>": "0", + "<17,91>": "0", + "<17,92>": "", + "<17,93>": "", + "<17,94>": "", + "<17,95>": "", + "<17,96>": "", + "<17,97>": "", + "<17,98>": "", + "<17,99>": "", + "<17,100>": "", + "<17,101>": "", + "<17,102>": "", + "<17,103>": "", + "<17,104>": "", + "<17,105>": "", + "<17,106>": "", + "<17,107>": "", + "<17,108>": "" }, "<18>": { "<18,1>": "TYPE_RECIPET", @@ -1483,7 +2697,7 @@ "<18,8>": "15", "<18,9>": "Type:", "<18,10>": { - "<18,10,1>": "0x56000002", + "<18,10,1>": "0x56000800", "<18,10,2>": "0x0" }, "<18,11>": { @@ -1491,7 +2705,11 @@ "<18,11,2>": "0x80000000" }, "<18,12>": "18", - "<18,13>": "-1", + "<18,13>": { + "<18,13,1>": "-1", + "<18,13,2>": "-1", + "<18,13,3>": "" + }, "<18,14>": "0", "<18,15>": { "<18,15,1>": { @@ -1520,17 +2738,14 @@ "<18,22>": "", "<18,23>": "", "<18,24>": "", - "<18,25>": "0", - "<18,26>": "0", + "<18,25>": "", + "<18,26>": "", "<18,27>": "", - "<18,28>": "<>", - "<18,29>": "<>", - "<18,30>": "<>", - "<18,31>": "0", - "<18,32>": { - "<18,32,1>": "0x7fffe", - "<18,32,2>": "0xf0016808" - }, + "<18,28>": "", + "<18,29>": "", + "<18,30>": "", + "<18,31>": "", + "<18,32>": "", "<18,33>": "", "<18,34>": "", "<18,35>": "", @@ -1550,7 +2765,76 @@ "<18,49>": "", "<18,50>": "", "<18,51>": "", - "<18,52>": "" + "<18,52>": "", + "<18,53>": "", + "<18,54>": "", + "<18,55>": "", + "<18,56>": "", + "<18,57>": "", + "<18,58>": "", + "<18,59>": "", + "<18,60>": "", + "<18,61>": "", + "<18,62>": "0", + "<18,63>": { + "<18,63,1>": "", + "<18,63,2>": "", + "<18,63,3>": "", + "<18,63,4>": "", + "<18,63,5>": "", + "<18,63,6>": "", + "<18,63,7>": "", + "<18,63,8>": "" + }, + "<18,64>": { + "<18,64,1>": "", + "<18,64,2>": "", + "<18,64,3>": "" + }, + "<18,65>": "-2", + "<18,66>": "", + "<18,67>": "", + "<18,68>": "", + "<18,69>": "", + "<18,70>": "", + "<18,71>": "", + "<18,72>": "", + "<18,73>": "", + "<18,74>": "", + "<18,75>": "", + "<18,76>": "", + "<18,77>": "", + "<18,78>": "", + "<18,79>": "", + "<18,80>": "", + "<18,81>": "", + "<18,82>": "", + "<18,83>": "", + "<18,84>": "", + "<18,85>": "", + "<18,86>": "", + "<18,87>": "", + "<18,88>": "", + "<18,89>": "", + "<18,90>": "0", + "<18,91>": "0", + "<18,92>": "", + "<18,93>": "", + "<18,94>": "", + "<18,95>": "", + "<18,96>": "", + "<18,97>": "", + "<18,98>": "", + "<18,99>": "", + "<18,100>": "", + "<18,101>": "", + "<18,102>": "", + "<18,103>": "", + "<18,104>": "", + "<18,105>": "", + "<18,106>": "", + "<18,107>": "", + "<18,108>": "" }, "<19>": { "<19,1>": "RECIPE_LABEL", @@ -1563,7 +2847,7 @@ "<19,8>": "15", "<19,9>": "Recipe:", "<19,10>": { - "<19,10,1>": "0x56000002", + "<19,10,1>": "0x56000800", "<19,10,2>": "0x0" }, "<19,11>": { @@ -1571,7 +2855,11 @@ "<19,11,2>": "0x80000000" }, "<19,12>": "19", - "<19,13>": "-1", + "<19,13>": { + "<19,13,1>": "-1", + "<19,13,2>": "-1", + "<19,13,3>": "" + }, "<19,14>": "0", "<19,15>": { "<19,15,1>": { @@ -1600,17 +2888,14 @@ "<19,22>": "", "<19,23>": "", "<19,24>": "", - "<19,25>": "0", - "<19,26>": "0", + "<19,25>": "", + "<19,26>": "", "<19,27>": "", - "<19,28>": "<>", - "<19,29>": "<>", - "<19,30>": "<>", - "<19,31>": "0", - "<19,32>": { - "<19,32,1>": "0x7fffe", - "<19,32,2>": "0xf0016808" - }, + "<19,28>": "", + "<19,29>": "", + "<19,30>": "", + "<19,31>": "", + "<19,32>": "", "<19,33>": "", "<19,34>": "", "<19,35>": "", @@ -1630,7 +2915,76 @@ "<19,49>": "", "<19,50>": "", "<19,51>": "", - "<19,52>": "" + "<19,52>": "", + "<19,53>": "", + "<19,54>": "", + "<19,55>": "", + "<19,56>": "", + "<19,57>": "", + "<19,58>": "", + "<19,59>": "", + "<19,60>": "", + "<19,61>": "", + "<19,62>": "0", + "<19,63>": { + "<19,63,1>": "", + "<19,63,2>": "", + "<19,63,3>": "", + "<19,63,4>": "", + "<19,63,5>": "", + "<19,63,6>": "", + "<19,63,7>": "", + "<19,63,8>": "" + }, + "<19,64>": { + "<19,64,1>": "", + "<19,64,2>": "", + "<19,64,3>": "" + }, + "<19,65>": "-2", + "<19,66>": "", + "<19,67>": "", + "<19,68>": "", + "<19,69>": "", + "<19,70>": "", + "<19,71>": "", + "<19,72>": "", + "<19,73>": "", + "<19,74>": "", + "<19,75>": "", + "<19,76>": "", + "<19,77>": "", + "<19,78>": "", + "<19,79>": "", + "<19,80>": "", + "<19,81>": "", + "<19,82>": "", + "<19,83>": "", + "<19,84>": "", + "<19,85>": "", + "<19,86>": "", + "<19,87>": "", + "<19,88>": "", + "<19,89>": "", + "<19,90>": "0", + "<19,91>": "0", + "<19,92>": "", + "<19,93>": "", + "<19,94>": "", + "<19,95>": "", + "<19,96>": "", + "<19,97>": "", + "<19,98>": "", + "<19,99>": "", + "<19,100>": "", + "<19,101>": "", + "<19,102>": "", + "<19,103>": "", + "<19,104>": "", + "<19,105>": "", + "<19,106>": "", + "<19,107>": "", + "<19,108>": "" }, "<20>": { "<20,1>": "PATTERN", @@ -1648,10 +3002,14 @@ }, "<20,11>": { "<20,11,1>": "0x0", - "<20,11,2>": "0x80000000" + "<20,11,2>": "0x80000C00" }, "<20,12>": "20", - "<20,13>": "-2", + "<20,13>": { + "<20,13,1>": "-2", + "<20,13,2>": "-2", + "<20,13,3>": "" + }, "<20,14>": "0", "<20,15>": { "<20,15,1>": { @@ -1680,17 +3038,14 @@ "<20,22>": "", "<20,23>": "", "<20,24>": "", - "<20,25>": "0", - "<20,26>": "0", + "<20,25>": "", + "<20,26>": "", "<20,27>": "", "<20,28>": "<>", "<20,29>": "<>", "<20,30>": "<>", "<20,31>": "0", - "<20,32>": { - "<20,32,1>": "0x7fffe", - "<20,32,2>": "0xf0016808" - }, + "<20,32>": "", "<20,33>": "", "<20,34>": "", "<20,35>": "", @@ -1710,7 +3065,71 @@ "<20,49>": "", "<20,50>": "", "<20,51>": "", - "<20,52>": "" + "<20,52>": "", + "<20,53>": "", + "<20,54>": "", + "<20,55>": "", + "<20,56>": "", + "<20,57>": "", + "<20,58>": "", + "<20,59>": "", + "<20,60>": "", + "<20,61>": "", + "<20,62>": "0", + "<20,63>": "", + "<20,64>": { + "<20,64,1>": "", + "<20,64,2>": "", + "<20,64,3>": "" + }, + "<20,65>": "-2", + "<20,66>": { + "<20,66,1>": "", + "<20,66,2>": "", + "<20,66,3>": "" + }, + "<20,67>": "-2", + "<20,68>": "", + "<20,69>": "", + "<20,70>": "", + "<20,71>": "", + "<20,72>": "", + "<20,73>": "", + "<20,74>": "", + "<20,75>": "", + "<20,76>": "", + "<20,77>": "", + "<20,78>": "", + "<20,79>": "", + "<20,80>": "", + "<20,81>": "", + "<20,82>": "", + "<20,83>": "", + "<20,84>": "", + "<20,85>": "", + "<20,86>": "", + "<20,87>": "", + "<20,88>": "", + "<20,89>": "", + "<20,90>": "", + "<20,91>": "", + "<20,92>": "", + "<20,93>": "", + "<20,94>": "", + "<20,95>": "", + "<20,96>": "", + "<20,97>": "", + "<20,98>": "", + "<20,99>": "", + "<20,100>": "", + "<20,101>": "", + "<20,102>": "", + "<20,103>": "", + "<20,104>": "", + "<20,105>": "", + "<20,106>": "", + "<20,107>": "", + "<20,108>": "" }, "<21>": { "<21,1>": "PATTERN_LABEL", @@ -1723,7 +3142,7 @@ "<21,8>": "15", "<21,9>": "Pattern:", "<21,10>": { - "<21,10,1>": "0x56000002", + "<21,10,1>": "0x56000800", "<21,10,2>": "0x0" }, "<21,11>": { @@ -1731,7 +3150,11 @@ "<21,11,2>": "0x80000000" }, "<21,12>": "21", - "<21,13>": "-1", + "<21,13>": { + "<21,13,1>": "-1", + "<21,13,2>": "-1", + "<21,13,3>": "" + }, "<21,14>": "0", "<21,15>": { "<21,15,1>": { @@ -1760,17 +3183,14 @@ "<21,22>": "", "<21,23>": "", "<21,24>": "", - "<21,25>": "0", - "<21,26>": "0", + "<21,25>": "", + "<21,26>": "", "<21,27>": "", - "<21,28>": "<>", - "<21,29>": "<>", - "<21,30>": "<>", - "<21,31>": "0", - "<21,32>": { - "<21,32,1>": "0x7fffe", - "<21,32,2>": "0xf0016808" - }, + "<21,28>": "", + "<21,29>": "", + "<21,30>": "", + "<21,31>": "", + "<21,32>": "", "<21,33>": "", "<21,34>": "", "<21,35>": "", @@ -1790,7 +3210,76 @@ "<21,49>": "", "<21,50>": "", "<21,51>": "", - "<21,52>": "" + "<21,52>": "", + "<21,53>": "", + "<21,54>": "", + "<21,55>": "", + "<21,56>": "", + "<21,57>": "", + "<21,58>": "", + "<21,59>": "", + "<21,60>": "", + "<21,61>": "", + "<21,62>": "0", + "<21,63>": { + "<21,63,1>": "", + "<21,63,2>": "", + "<21,63,3>": "", + "<21,63,4>": "", + "<21,63,5>": "", + "<21,63,6>": "", + "<21,63,7>": "", + "<21,63,8>": "" + }, + "<21,64>": { + "<21,64,1>": "", + "<21,64,2>": "", + "<21,64,3>": "" + }, + "<21,65>": "-2", + "<21,66>": "", + "<21,67>": "", + "<21,68>": "", + "<21,69>": "", + "<21,70>": "", + "<21,71>": "", + "<21,72>": "", + "<21,73>": "", + "<21,74>": "", + "<21,75>": "", + "<21,76>": "", + "<21,77>": "", + "<21,78>": "", + "<21,79>": "", + "<21,80>": "", + "<21,81>": "", + "<21,82>": "", + "<21,83>": "", + "<21,84>": "", + "<21,85>": "", + "<21,86>": "", + "<21,87>": "", + "<21,88>": "", + "<21,89>": "", + "<21,90>": "0", + "<21,91>": "0", + "<21,92>": "", + "<21,93>": "", + "<21,94>": "", + "<21,95>": "", + "<21,96>": "", + "<21,97>": "", + "<21,98>": "", + "<21,99>": "", + "<21,100>": "", + "<21,101>": "", + "<21,102>": "", + "<21,103>": "", + "<21,104>": "", + "<21,105>": "", + "<21,106>": "", + "<21,107>": "", + "<21,108>": "" }, "<22>": { "<22,1>": "TW_GROUP", @@ -1811,7 +3300,11 @@ "<22,11,2>": "0x80000000" }, "<22,12>": "22", - "<22,13>": "-1", + "<22,13>": { + "<22,13,1>": "-1", + "<22,13,2>": "-1", + "<22,13,3>": "" + }, "<22,14>": "16711680", "<22,15>": { "<22,15,1>": { @@ -1840,17 +3333,14 @@ "<22,22>": "", "<22,23>": "", "<22,24>": "", - "<22,25>": "0", - "<22,26>": "0", + "<22,25>": "", + "<22,26>": "", "<22,27>": "", - "<22,28>": "<>", - "<22,29>": "<>", - "<22,30>": "<>", - "<22,31>": "0", - "<22,32>": { - "<22,32,1>": "0x7fffe", - "<22,32,2>": "0xf0012c08" - }, + "<22,28>": "", + "<22,29>": "", + "<22,30>": "", + "<22,31>": "", + "<22,32>": "", "<22,33>": "", "<22,34>": "", "<22,35>": "", @@ -1870,7 +3360,76 @@ "<22,49>": "", "<22,50>": "", "<22,51>": "", - "<22,52>": "" + "<22,52>": "", + "<22,53>": "", + "<22,54>": "", + "<22,55>": "", + "<22,56>": "", + "<22,57>": "", + "<22,58>": "", + "<22,59>": "", + "<22,60>": "", + "<22,61>": "", + "<22,62>": "0", + "<22,63>": { + "<22,63,1>": "", + "<22,63,2>": "-2", + "<22,63,3>": "", + "<22,63,4>": "", + "<22,63,5>": "", + "<22,63,6>": "", + "<22,63,7>": "", + "<22,63,8>": "0" + }, + "<22,64>": { + "<22,64,1>": "", + "<22,64,2>": "", + "<22,64,3>": "" + }, + "<22,65>": "-2", + "<22,66>": "", + "<22,67>": "", + "<22,68>": "", + "<22,69>": "", + "<22,70>": "", + "<22,71>": "", + "<22,72>": "", + "<22,73>": "", + "<22,74>": "", + "<22,75>": "", + "<22,76>": "", + "<22,77>": "", + "<22,78>": "", + "<22,79>": "", + "<22,80>": "", + "<22,81>": "", + "<22,82>": "", + "<22,83>": "", + "<22,84>": "", + "<22,85>": "", + "<22,86>": "", + "<22,87>": "", + "<22,88>": "", + "<22,89>": "", + "<22,90>": "", + "<22,91>": "", + "<22,92>": "", + "<22,93>": "", + "<22,94>": "", + "<22,95>": "", + "<22,96>": "", + "<22,97>": "", + "<22,98>": "", + "<22,99>": "", + "<22,100>": "", + "<22,101>": "", + "<22,102>": "", + "<22,103>": "", + "<22,104>": "", + "<22,105>": "", + "<22,106>": "", + "<22,107>": "", + "<22,108>": "" }, "<23>": { "<23,1>": "FREQ_GROUP", @@ -1891,7 +3450,11 @@ "<23,11,2>": "0x80000000" }, "<23,12>": "23", - "<23,13>": "-1", + "<23,13>": { + "<23,13,1>": "-1", + "<23,13,2>": "-1", + "<23,13,3>": "" + }, "<23,14>": "16711680", "<23,15>": { "<23,15,1>": { @@ -1920,17 +3483,14 @@ "<23,22>": "", "<23,23>": "", "<23,24>": "", - "<23,25>": "0", - "<23,26>": "0", + "<23,25>": "", + "<23,26>": "", "<23,27>": "", - "<23,28>": "<>", - "<23,29>": "<>", - "<23,30>": "<>", - "<23,31>": "0", - "<23,32>": { - "<23,32,1>": "0x7fffe", - "<23,32,2>": "0xf0012c08" - }, + "<23,28>": "", + "<23,29>": "", + "<23,30>": "", + "<23,31>": "", + "<23,32>": "", "<23,33>": "", "<23,34>": "", "<23,35>": "", @@ -1950,18 +3510,80 @@ "<23,49>": "", "<23,50>": "", "<23,51>": "", - "<23,52>": "" - }, - "<24>": "" + "<23,52>": "", + "<23,53>": "", + "<23,54>": "", + "<23,55>": "", + "<23,56>": "", + "<23,57>": "", + "<23,58>": "", + "<23,59>": "", + "<23,60>": "", + "<23,61>": "", + "<23,62>": "0", + "<23,63>": { + "<23,63,1>": "", + "<23,63,2>": "-2", + "<23,63,3>": "", + "<23,63,4>": "", + "<23,63,5>": "", + "<23,63,6>": "", + "<23,63,7>": "", + "<23,63,8>": "0" + }, + "<23,64>": { + "<23,64,1>": "", + "<23,64,2>": "", + "<23,64,3>": "" + }, + "<23,65>": "-2", + "<23,66>": "", + "<23,67>": "", + "<23,68>": "", + "<23,69>": "", + "<23,70>": "", + "<23,71>": "", + "<23,72>": "", + "<23,73>": "", + "<23,74>": "", + "<23,75>": "", + "<23,76>": "", + "<23,77>": "", + "<23,78>": "", + "<23,79>": "", + "<23,80>": "", + "<23,81>": "", + "<23,82>": "", + "<23,83>": "", + "<23,84>": "", + "<23,85>": "", + "<23,86>": "", + "<23,87>": "", + "<23,88>": "", + "<23,89>": "", + "<23,90>": "", + "<23,91>": "", + "<23,92>": "", + "<23,93>": "", + "<23,94>": "", + "<23,95>": "", + "<23,96>": "", + "<23,97>": "", + "<23,98>": "", + "<23,99>": "", + "<23,100>": "", + "<23,101>": "", + "<23,102>": "", + "<23,103>": "", + "<23,104>": "", + "<23,105>": "", + "<23,106>": "", + "<23,107>": "", + "<23,108>": "" + } }, "record4": { - "<1>": "", - "<2>": { - "<2,1>": "", - "<2,2>": "", - "<2,3>": "", - "<2,4>": "0" - } + "<1>": "" } } } \ No newline at end of file diff --git a/LSL2/STPROC/AUTHENTICATION_API.txt b/LSL2/STPROC/AUTHENTICATION_API.txt index d132e56..69646a7 100644 --- a/LSL2/STPROC/AUTHENTICATION_API.txt +++ b/LSL2/STPROC/AUTHENTICATION_API.txt @@ -1,152 +1,151 @@ -Function Authentication_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Authentication_API - - Description : API logic for the Authentication resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Authentication[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Authentication.POST - - Authentication.ID.PUT - - Authentication.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 07/17/24 djs Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS -$insert LSL_USERS_EQUATES - -Equ USERNAME$ To 1 -Equ GROUP$ To 2 -Equ PASSWORD$ To 3 -Equ CONTEXT$ To 4 - -Declare function Database_Services, MemberOf - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API authentication.POST - - Body = HTTP_Services('GetHTTPPostString') - If Body NE '' then - // The POST string will have been encoded so use percent (URL) decoding - AuthJson = HTTP_Services('DecodePercentString', Body) - hAuthJson = '' - ParseResponse = SRP_JSON(hAuthJson, 'PARSE', AuthJson) - If (ParseResponse EQ '') then - Username = SRP_JSON(hAuthJson, 'GetValue', 'Username') - Password = SRP_JSON(hAuthJson, 'GetValue', 'Password') - Groups = '' - hGroups = SRP_JSON(hAuthJson, 'get', 'Groups') - If hGroups then - ElementHandles = SRP_JSON(hGroups, 'GetElements', @VM) - If ElementHandles NE '' then - For each ElementHandle in ElementHandles using @VM - Groups<0, -1> = SRP_JSON(ElementHandle, 'GetValue') - SRP_JSON(ElementHandle, 'Release') - Next ElementHandle - end - SRP_JSON(hGroups, 'Release') - end - SRP_JSON(hAuthJson, 'Release') - // Validate Credentials - UserRec = Database_Services('ReadDataRow', 'LSL_USERS', Username) - If Error_Services('NoError') then - Credentials = '' - Credentials = Username - Credentials = UserRec - Credentials = UserRec - - Member = False$ - Group = '' - If Groups NE '' then - For each Group in Groups using @VM - Member = MemberOf(Credentials, Group) - Until Member EQ True$ - Next Group - end else - Member = True$ - end - - Begin Case - - Case (Password EQ Credentials) AND (Member EQ True$) - // Return 200, authentication successful - StatusCode = 200 - Message = 'Authentication successful' - HTTP_Services('SetResponseStatus', 200, Message) - Case (Password EQ Credentials) AND (Member EQ False$) - // Return 401, not a member of required groups - NumGroups = DCount(Groups, @VM) - If NumGroups GT 1 then - Swap @VM with ' or ' in Groups - Message = 'User is not a member of the ' : Groups : ' groups.' - end else - Message = 'User is not a member of the ' : Group : ' group.' - end - HTTP_Services('SetResponseStatus', 401, 'Authentication failed. ':Message) - - Case Password NE Credentials - // Return 401, unable to validate password - Message = 'Unable to validate username. Please re-enter.' - HTTP_Services('SetResponseStatus', 401, 'Authentication failed. ':Message) - Case Otherwise$ - HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Unhandled case.') - End Case - end else - // Error reading user record - ErrorMsg = Error_Services('GetMessage') - HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': ErrorMsg) - end - end else - HTTP_Services('SetResponseStatus', 400, 'Error in the ' : CurrentAPI : ' API. Error parsing JSON.') - end - end else - HTTP_Services('SetResponseStatus', 400, 'Error in the ' : CurrentAPI : ' API. Empty request.') - end - -end api - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Internal GoSubs -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - +Function Authentication_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Authentication_API + + Description : API logic for the Authentication resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Authentication[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Authentication.POST + - Authentication.ID.PUT + - Authentication.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 07/17/24 djs Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS +$insert LSL_USERS_EQUATES + +Equ USERNAME$ To 1 +Equ GROUP$ To 2 +Equ PASSWORD$ To 3 +Equ CONTEXT$ To 4 + +Declare function Database_Services, MemberOf + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API authentication.POST + + Body = HTTP_Services('GetHTTPPostString') + If Body NE '' then + // The POST string will have been encoded so use percent (URL) decoding + AuthJson = HTTP_Services('DecodePercentString', Body) + hAuthJson = '' + ParseResponse = SRP_JSON(hAuthJson, 'PARSE', AuthJson) + If (ParseResponse EQ '') then + Username = SRP_JSON(hAuthJson, 'GetValue', 'Username') + Password = SRP_JSON(hAuthJson, 'GetValue', 'Password') + Groups = '' + hGroups = SRP_JSON(hAuthJson, 'get', 'Groups') + If hGroups then + ElementHandles = SRP_JSON(hGroups, 'GetElements', @VM) + If ElementHandles NE '' then + For each ElementHandle in ElementHandles using @VM + Groups<0, -1> = SRP_JSON(ElementHandle, 'GetValue') + SRP_JSON(ElementHandle, 'Release') + Next ElementHandle + end + SRP_JSON(hGroups, 'Release') + end + SRP_JSON(hAuthJson, 'Release') + // Validate Credentials + UserRec = Database_Services('ReadDataRow', 'LSL_USERS', Username) + If Error_Services('NoError') then + Credentials = '' + Credentials = Username + Credentials = UserRec + Credentials = UserRec + + Member = False$ + Group = '' + If Groups NE '' then + For each Group in Groups using @VM + Member = MemberOf(Credentials, Group) + Until Member EQ True$ + Next Group + end else + Member = True$ + end + + Begin Case + + Case (Password EQ Credentials) AND (Member EQ True$) + // Return 200, authentication successful + StatusCode = 200 + Message = 'Authentication successful' + HTTP_Services('SetResponseStatus', 200, Message) + Case (Password EQ Credentials) AND (Member EQ False$) + // Return 401, not a member of required groups + NumGroups = DCount(Groups, @VM) + If NumGroups GT 1 then + Swap @VM with ' or ' in Groups + Message = 'User is not a member of the ' : Groups : ' groups.' + end else + Message = 'User is not a member of the ' : Group : ' group.' + end + HTTP_Services('SetResponseStatus', 401, 'Authentication failed. ':Message) + + Case Password NE Credentials + // Return 401, unable to validate password + Message = 'Unable to validate username. Please re-enter.' + HTTP_Services('SetResponseStatus', 401, 'Authentication failed. ':Message) + Case Otherwise$ + HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Unhandled case.') + End Case + end else + // Error reading user record + ErrorMsg = Error_Services('GetMessage') + HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': ErrorMsg) + end + end else + HTTP_Services('SetResponseStatus', 400, 'Error in the ' : CurrentAPI : ' API. Error parsing JSON.') + end + end else + HTTP_Services('SetResponseStatus', 400, 'Error in the ' : CurrentAPI : ' API. Empty request.') + end + +end api + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Internal GoSubs +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/LSL2/STPROC/CHANGELOG_API.txt b/LSL2/STPROC/CHANGELOG_API.txt index 2e39dbd..3f12752 100644 --- a/LSL2/STPROC/CHANGELOG_API.txt +++ b/LSL2/STPROC/CHANGELOG_API.txt @@ -1,139 +1,138 @@ -Function Changelog_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Changelog_API - - Description : API logic for the Changelog resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Changelog[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Changelog.POST - - Changelog.ID.PUT - - Changelog.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 07/24/24 xxx Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -Declare function Datetime, SRP_Datetime, Change_Log_Services, Environment_Services, Logging_Services -Declare subroutine Logging_Services - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS -EQU Comma$ to ',' - -LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\API\Admin\ChangeLog' -LogDate = Oconv(Date(), 'D4/') -LogTime = Oconv(Time(), 'MTS') -LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' ChangeLogArchiveService.csv' -Headers = 'Logging DTM' : @FM : 'From IP Address' : @FM : 'Message' -objLogChangeLogAPI = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$) -LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM -RequesterIPAddr = HTTP_Services('GetHTTPRemoteAddr') - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API changelog.HEAD - API changelog.GET - StartDtm = Http_Services('GetQueryField', 'FromDatetime') - ToDtm = Http_Services('GetQueryField', 'ToDatetime') - - StartDtm = IConv(StartDtm, 'DT') - ToDtm = IConv(ToDtm, 'DT') - - If StartDtm EQ '' then - StartDtm = SRP_Datetime('AddDays', Datetime(), -60) - end - If ToDtm EQ '' then - ToDtm = Datetime() - end - - EntityName = Http_Services('GetQueryField', 'EntityName') - UserId = Http_Services('GetQueryField', 'UserID') - - ChangeLogIDs = Change_Log_Services('GetChangeLogRecIDs', EntityName, StartDtm, ToDtm, UserId) - If Error_Services('NoError') then - GoSub CreateHALCollection - end else - ErrorMsg = Error_Services('GetMessage') - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = RequesterIPAddr - LogData<3> = ErrorMsg - Logging_Services('AppendLog', objLogChangeLogAPI, LogData, @RM, @FM) - HTTP_Services('SetResponseStatus', 500, 'Error Getting change log records from change_log table.') - end - - end api - -CreateHALCollection: - hJsonCollection = '' - hChangeLogArray = '' - hChangeLogObj = '' - hChangeLog = '' - hChangeLogJson = '' - Abort = False$ - If SRP_JSON(hJSONCollection, 'New', 'Object') then - If SRP_JSON(hChangeLogArray, 'New', 'Array') then - For each ChangeLogID in ChangeLogIDs using @VM setting fPos - //rdsJSON = Rds_Services('ConvertRecordToJSON', rds, '' ,FullEndpointURL:'/':rds) - ChangeLogJson = Change_Log_Services('ConvertRecordToJSON', ChangeLogID) - If Error_Services('NoError') then - If (SRP_JSON(hChangeLog, 'Parse', ChangeLogJson) EQ '') then - SRP_JSON(hChangeLogArray, 'Add', hChangeLog) - SRP_JSON(hChangeLog, 'Release') - end - end else - Abort = True$ - end - Until Abort - Next rds - If Abort EQ False$ then - SRP_JSON(hJSONCollection, 'Set', 'ChangeLogRecords', hChangeLogArray) - end - SRP_JSON(hChangeLogArray, 'Release') - end - JSONCollection = SRP_JSON(hJSONCollection, 'Stringify', 'Styled') - SRP_JSON(hJSONCollection, 'Release') - HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) - HTTP_Services('SetResponseBody', JSONCollection, False$, 'application/hal+json') - HTTP_Services('SetResponseStatus', 200) - end - -return - +Function Changelog_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Changelog_API + + Description : API logic for the Changelog resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Changelog[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Changelog.POST + - Changelog.ID.PUT + - Changelog.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 07/24/24 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +Declare function Datetime, SRP_Datetime, Change_Log_Services, Environment_Services, Logging_Services +Declare subroutine Logging_Services + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS +EQU Comma$ to ',' + +LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\API\Admin\ChangeLog' +LogDate = Oconv(Date(), 'D4/') +LogTime = Oconv(Time(), 'MTS') +LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' ChangeLogArchiveService.csv' +Headers = 'Logging DTM' : @FM : 'From IP Address' : @FM : 'Message' +objLogChangeLogAPI = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$) +LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM +RequesterIPAddr = HTTP_Services('GetHTTPRemoteAddr') + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API changelog.HEAD + API changelog.GET + StartDtm = Http_Services('GetQueryField', 'FromDatetime') + ToDtm = Http_Services('GetQueryField', 'ToDatetime') + + StartDtm = IConv(StartDtm, 'DT') + ToDtm = IConv(ToDtm, 'DT') + + If StartDtm EQ '' then + StartDtm = SRP_Datetime('AddDays', Datetime(), -60) + end + If ToDtm EQ '' then + ToDtm = Datetime() + end + + EntityName = Http_Services('GetQueryField', 'EntityName') + UserId = Http_Services('GetQueryField', 'UserID') + + ChangeLogIDs = Change_Log_Services('GetChangeLogRecIDs', EntityName, StartDtm, ToDtm, UserId) + If Error_Services('NoError') then + GoSub CreateHALCollection + end else + ErrorMsg = Error_Services('GetMessage') + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = RequesterIPAddr + LogData<3> = ErrorMsg + Logging_Services('AppendLog', objLogChangeLogAPI, LogData, @RM, @FM) + HTTP_Services('SetResponseStatus', 500, 'Error Getting change log records from change_log table.') + end + + end api + +CreateHALCollection: + hJsonCollection = '' + hChangeLogArray = '' + hChangeLogObj = '' + hChangeLog = '' + hChangeLogJson = '' + Abort = False$ + If SRP_JSON(hJSONCollection, 'New', 'Object') then + If SRP_JSON(hChangeLogArray, 'New', 'Array') then + For each ChangeLogID in ChangeLogIDs using @VM setting fPos + //rdsJSON = Rds_Services('ConvertRecordToJSON', rds, '' ,FullEndpointURL:'/':rds) + ChangeLogJson = Change_Log_Services('ConvertRecordToJSON', ChangeLogID) + If Error_Services('NoError') then + If (SRP_JSON(hChangeLog, 'Parse', ChangeLogJson) EQ '') then + SRP_JSON(hChangeLogArray, 'Add', hChangeLog) + SRP_JSON(hChangeLog, 'Release') + end + end else + Abort = True$ + end + Until Abort + Next rds + If Abort EQ False$ then + SRP_JSON(hJSONCollection, 'Set', 'ChangeLogRecords', hChangeLogArray) + end + SRP_JSON(hChangeLogArray, 'Release') + end + JSONCollection = SRP_JSON(hJSONCollection, 'Stringify', 'Styled') + SRP_JSON(hJSONCollection, 'Release') + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseBody', JSONCollection, False$, 'application/hal+json') + HTTP_Services('SetResponseStatus', 200) + end + +return diff --git a/LSL2/STPROC/CLEAN_API.txt b/LSL2/STPROC/CLEAN_API.txt new file mode 100644 index 0000000..541c05f --- /dev/null +++ b/LSL2/STPROC/CLEAN_API.txt @@ -0,0 +1,258 @@ +Function Clean_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Clean_API + + Description : API logic for the Clean resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Clean[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Clean.POST + - Clean.ID.PUT + - Clean.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 06/18/25 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +Declare function OI_Wizard_Services, Lot_Operation_Services, Database_Services, Lot_Services, Clean_Services +Declare subroutine Clean_Services, Lot_Services + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS +$insert OI_WIZARD_EQUATES +$insert LOT_OPERATION_EQUATES + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API clean.ID.HEAD +API clean.ID.GET + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + CleanRecId = EndpointSegment + CleanRecJson = Clean_Services('ConvertCleanRecToJson', CleanRecId) + If Error_Services('NoError') then + Http_Services('SetResponseBody', CleanRecJson, False$, 'application/hal+json') + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + + +API clean.ID.markcleanrecordcomplete.POST + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + Body = HTTP_Services('GetHTTPPostString', True$) + // The POST string will have been encoded so use percent (URL) decoding. + DecodedJSON = HTTP_Services('DecodePercentString', Body) + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + CleanRecId = ParentSegment + LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationId') + CleanTool = SRP_JSON(objBody, 'GetValue', 'CleanTool') + CleanRecipe = SRP_JSON(objBody, 'GetValue', 'CleanRecipe') + SRP_JSON(objBody, 'Release') + Clean_Services('MarkCleanRecComplete', CleanRecId, CleanRecipe, CleanTool, UserId) + If Error_Services('NoError') then + CleanRecJson = Clean_Services('ConvertCleanRecToJson', CleanRecId) + HTTP_Services('SetResponseBody', CleanRecJson, False$, 'application/hal+json') + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + end + + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + + +API clean.createcleanrecord.POST + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + Body = HTTP_Services('GetHTTPPostString', True$) + // The POST string will have been encoded so use percent (URL) decoding. + DecodedJSON = HTTP_Services('DecodePercentString', Body) + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + LotId = SRP_JSON(objBody, 'GetValue', 'LotId') + LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationId') + SRP_JSON(objBody, 'Release') + end + CleanRecId = Clean_Services('CreateNewCleanRecord', LotId, LotOperationId, UserId) + If Error_Services('NoError') then + CleanRecJson = Clean_Services('ConvertCleanRecToJson', CleanRecId) + HTTP_Services('SetResponseBody', CleanRecJson, False$, 'application/hal+json') + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + + +API clean.getnewcleanoperationparams.HEAD +API clean.getnewcleanoperationparams.GET + + JSONCollection = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + If ValidSession then + Body = HTTP_Services('GetHTTPGetString') + If Body NE '' then + RequestJson = HTTP_Services('DecodePercentString', Body) + LotId = Http_Services('GetQueryField', 'LotId') + objJSONResponse = '' + If SRP_Json(objJSONResponse, 'New', 'Object') then + //Available Tools + If SRP_Json(objCleanTools, 'New', 'Array') then + CleanTools = Clean_Services('GetCleanToolOptions') + for each CleanTool in CleanTools using @FM + SRP_Json(objCleanTools, 'AddValue', CleanTool, 'String') + Next CleanTool + SRP_Json(objJsonResponse, 'Set', 'CleanToolOptions', objCleanTools) + SRP_Json(objCleanTools, 'Release') + end + //Available Recipes + If SRP_Json(objCleanRecipes, 'New', 'Array') then + CleanRecipes = Clean_Services('GetCleanRecipeOptions') + for each Recipe in CleanRecipes using @VM + SRP_Json(objCleanRecipes, 'AddValue', Recipe, 'String') + Next Recipe + SRP_Json(objJsonResponse, 'Set', 'CleanRecipeOptions', objCleanRecipes) + SRP_Json(objCleanRecipes, 'Release') + end + JsonResponse = SRP_Json(objJsonResponse, 'Stringify', 'Styled') + SRP_Json(objJsonResponse, 'Release') + end else + Error_Services('Add', 'Error when creating JSON response.') + end + end else + Error_Services('Add', 'No body was sent with the request.') + end + If Error_Services('NoError') then + HTTP_Services('SetResponseStatus', 201, 'Success') + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseBody', JsonResponse, False$, 'application/hal+json') + end else + HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage')) + end + end else + HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.') + end + +end api diff --git a/LSL2/STPROC/CLEAN_SERVICES.txt b/LSL2/STPROC/CLEAN_SERVICES.txt new file mode 100644 index 0000000..66f7686 --- /dev/null +++ b/LSL2/STPROC/CLEAN_SERVICES.txt @@ -0,0 +1,217 @@ +Compile function Clean_Services(@Service, @Params) +#pragma precomp SRP_PreCompiler + +Declare Function Database_Services, Error_Services, Logging_Services, Datetime +Declare Function RTI_CreateGUID, Tool_Services, SRP_Json, Date_Services +Declare Subroutine Database_Services, Error_Services, Logging_Services, SRP_Json, Lot_Event_Services + +$insert LOGICAL +$Insert CLEAN_EQUATES +$Insert LOT_EQUATES +$Insert LOT_OPERATION_EQUATES +$Insert TOOL_EQUATES +$Insert TOOL_CLASS_EQUATES + +Options Stage = 'LWI', + +GoToService + +Return Response or "" + +//----------------------------------------------------------------------------- +// SERVICES +//----------------------------------------------------------------------------- + +Service CreateNewCleanRecord(LotId, LotOperationId, UserId) + + ErrorMessage = '' + CleanRecId = '' + If RowExists('LOT', LotId) then + //ToDo check Lot Operation Exists + //Checks complete, create the CLEAN record + TransDtm = Datetime() + CleanRecId = RTI_CreateGUID() + CleanRec = '' + CleanRec = LotId + CleanRec = LotOperationId + CleanRec = TransDtm + CleanRec = UserId + Database_Services('WriteDataRow', 'CLEAN', CleanRecId, CleanRec) + If Error_Services('NoError') then + If LotOperationId NE '' then + LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$) + LotOperationRec = CleanRecId + Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec) + If Error_Services('NoError') then + Lot_Event_Services('CreateLotEvent', LotId, TransDtm, 'CLEAN_START', 'Created clean record.', '', UserId) + end else + ErrorMessage = Error_Services('GetMessage') + end + end + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + //Todo add error message + end + + If ErrorMessage EQ '' then + Response = CleanRecId + end else + // Todo: Add logging + ErrorMessage = 'Error Creating a new clean record: ' : ErrorMessage + Error_Services('Add', ErrorMessage) + end + +End Service + +Service ConvertCleanRecToJson(CleanRecId) + + ErrorMessage = '' + CleanRecJson = '' + + If RowExists('CLEAN', CleanRecId) then + CleanRec = Database_Services('ReadDataRow', 'CLEAN', CleanRecId, True$, 0, False$) + If Error_Services('NoError') then + objJson = '' + If SRP_Json(objJson, 'New', 'Object') then + SRP_Json(objJson, 'SetValue', 'CleanId', CleanRecId, 'String') + SRP_Json(objJson, 'SetValue', 'LotId', CleanRec, 'String') + LegacyLotId = Database_Services('ReadDataColumn', 'LOT', CleanRec, LOT_LEGACY_LOT_ID$) + SRP_Json(objJson, 'SetValue', 'LegacyLotId', LegacyLotId, 'String') + SRP_Json(objJson, 'SetValue', 'Recipe', CleanRec, 'String') + SRP_Json(objJson, 'SetValue', 'Tool', CleanRec, 'String') + SRP_Json(objJson, 'SetValue', 'StartUser', CleanRec, 'String') + StartDtm = Date_Services('ConvertDateTimeToISO8601', CleanRec) + if StartDtm NE '' then + SRP_Json(objJson, 'SetValue', 'StartDtm', StartDtm) + end + SRP_Json(objJson, 'SetValue', 'StopUser', CleanRec, 'String') + StopDtm = Date_Services('ConvertDateTimeToISO8601', CleanRec) + if StopDtm NE '' then + SRP_Json(objJson, 'SetValue', 'StopDtm', StopDtm, 'String') + end + SRP_Json(objJson, 'SetValue', 'LotOperationId', CleanRec, 'String') + CleanRecJson = SRP_Json(objJson, 'Stringify', 'Styled') + SRP_Json(objJson, 'Release') + end else + ErrorMessage = 'Error creating clean record json' + end + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = 'Clean record not found.' + end + + If ErrorMessage EQ '' then + Response = CleanRecJson + end else + Error_Services('Add', 'Error getting clean record : ' : ErrorMessage) + end + +end service + +Service MarkCleanRecComplete(CleanRecId, CleanRecipe, CleanTool, CleanUser) + + ErrorMessage = '' + TransDtm = Datetime() + + If RowExists('CLEAN', CleanRecId) then + CleanRec = Database_Services('ReadDataRow', 'CLEAN', CleanRecId, True$, 0, False$) + If CleanRec NE '' then + If CleanRec EQ '' AND CleanRec EQ '' then + if RowExists('LSL_USERS', CleanUser) then + If CleanRec EQ '' then + CleanRec = CleanTool + CleanRec = CleanRecipe + CleanRec = CleanUser + CleanRec = TransDtm + Database_Services('WriteDataRow', 'CLEAN', CleanRecId, CleanRec) + If Error_Services('NoError') then + LotId = CleanRec + Lot_Event_Services('CreateLotEvent', LotId, TransDtm, 'CLEAN', 'Clean completed', CleanTool, CleanUser) + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = 'Clean is already signed off.' + end + end else + ErrorMessage = 'Clean tool or clean recipe is missing.' + end + end else + ErrorMessage = 'Clean has already been logged.' + end + end else + ErrorMessage = 'Clean has not been started.' + end + end else + ErrorMessage = 'Clean record not found.' + end + + If ErrorMessage NE '' then + Error_Services('Add', ErrorMessage) + end + +end service + +Service ValidateCleanRecord(CleanRecId) + + //ErrorMessage = '' + CleanRecValid = False$ + +* If CleanRecId NE '' then +* If RowExists('CLEAN', CleanRecId) then +* CleanRec = Database_Services('ReadDataRow', 'CLEAN', CleanRecId, True$, 0, False$) +* SpecTool = CleanRec +* ToolUsed = CleanRec +* If ToolUsed EQ SpecTool AND ToolUsed NE '' then +* SpecRecipe = CleanRec +* RecipeUsed = CleanRec +* If RecipeUsed EQ SpecRecipe AND RecipeUsed NE '' then +* CleanRecValid = True$ +* end +* end +* end else +* ErrorMessage = 'Clean record not found in CLEAN database.' +* end +* end else +* ErrorMessage = 'Clean ID was null.' +* end +* +* If ErrorMessage EQ '' then +* Response = CleanRecValid +* end else +* // Todo: Add logging +* ErrorMessage = 'Error validating clean record: ' : ErrorMessage +* Error_Services('Add', ErrorMessage) +* end + + Response = CleanRecValid +End Service + +Service GetCleanToolOptions(CleanRecId) + + If RowExists('CLEAN', CleanRecId) then + CleanTools = Database_Services('ReadDataColumn', 'CLEAN', CleanRecId, CLEAN_SPEC_CLEAN_TOOL$, True$, 0, False$) + end else + CleanTools = Tool_Services('GetTools', 'AKRION') + end + + Response = CleanTools + +end service + +Service GetCleanRecipeOptions(CleanRecId) + + If RowExists('CLEAN', CleanRecId) then + Recipes = Database_Services('ReadDataColumn', 'CLEAN', CleanRecId, CLEAN_SPEC_CLEAN_RECIPE$, True$, 0, False$) + end else + //Todo: Make this smarter, so as to block out pre-epi recipes + Recipes = XLATE('TOOL_CLASS','AKRION',TOOL_CLASS_RECIPES$,'X') + end + + Response = Recipes + +end service diff --git a/LSL2/STPROC/COMM_PROD_SPEC_SI.txt b/LSL2/STPROC/COMM_PROD_SPEC_SI.txt index ea0bdb0..a1a7a58 100644 --- a/LSL2/STPROC/COMM_PROD_SPEC_SI.txt +++ b/LSL2/STPROC/COMM_PROD_SPEC_SI.txt @@ -858,3 +858,4 @@ Result = ReturnData RETURN + diff --git a/LSL2/STPROC/CONFIG_API.txt b/LSL2/STPROC/CONFIG_API.txt index aabcd67..f422801 100644 --- a/LSL2/STPROC/CONFIG_API.txt +++ b/LSL2/STPROC/CONFIG_API.txt @@ -213,4 +213,3 @@ UpdateHALItem: end return - diff --git a/LSL2/STPROC/DATE_SERVICES.txt b/LSL2/STPROC/DATE_SERVICES.txt index 2109487..6e6b575 100644 --- a/LSL2/STPROC/DATE_SERVICES.txt +++ b/LSL2/STPROC/DATE_SERVICES.txt @@ -220,6 +220,13 @@ Service GetWeekNum(InputDate) end service +Service ConvertDateTimeToISO8601(DatetimeToConv) + + Response = OConv(DatetimeToConv, "[SRP_DATETIME,()YYYY-MM-DD hh:mm:ss.000Z]") + swap ' ' with 'T' in Response + +end service + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs diff --git a/LSL2/STPROC/ENGINEINFO_API.txt b/LSL2/STPROC/ENGINEINFO_API.txt index dea853f..3c82bda 100644 --- a/LSL2/STPROC/ENGINEINFO_API.txt +++ b/LSL2/STPROC/ENGINEINFO_API.txt @@ -1,97 +1,96 @@ -Function Engineinfo_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Engineinfo_API - - Description : API logic for the Engineinfo resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Engineinfo[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Engineinfo.POST - - Engineinfo.ID.PUT - - Engineinfo.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 07/17/24 xxx Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS -$insert ENGINE_HEALTH_EQUATES - -Declare function System_Healthcheck_Services - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API remotehealthcheck.HEAD -API remotehealthcheck.GET - - HTTP_Resource_Services('LoremIpsum') - -end api - - -API engineinfo.HEAD -API engineinfo.GET - - HTTP_Resource_Services('LoremIpsum') - -end api - - -API engineinfo.ID.HEAD -API engineinfo.ID.GET - - EngineID = EndpointSegment - If RowExists('APP_INFO', EngineID) then - EngineHealthInfo = System_Healthcheck_Services('GetEngineHealthInfo', EngineID) - If Error_Services('NoError') then - EngineJSON = System_Healthcheck_Services('ConvertEngineHealthInfoToJSON', EngineHealthInfo, FullEndpointURL) - ResponseCode = 200 - HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) - HTTP_Services('SetResponseBody', EngineJSON, False$, 'application/hal+json') - HTTP_Services('SetResponseStatus', ResponseCode) - end else - HTTP_Services('SetResponseStatus', 500, Error_Services('GetMessage')) - end - end else - HTTP_Services('SetResponseStatus', 401, 'Invalid Engine ID.') - end - -end api - +Function Engineinfo_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Engineinfo_API + + Description : API logic for the Engineinfo resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Engineinfo[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Engineinfo.POST + - Engineinfo.ID.PUT + - Engineinfo.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 07/17/24 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS +$insert ENGINE_HEALTH_EQUATES + +Declare function System_Healthcheck_Services + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API remotehealthcheck.HEAD +API remotehealthcheck.GET + + HTTP_Resource_Services('LoremIpsum') + +end api + + +API engineinfo.HEAD +API engineinfo.GET + + HTTP_Resource_Services('LoremIpsum') + +end api + + +API engineinfo.ID.HEAD +API engineinfo.ID.GET + + EngineID = EndpointSegment + If RowExists('APP_INFO', EngineID) then + EngineHealthInfo = System_Healthcheck_Services('GetEngineHealthInfo', EngineID) + If Error_Services('NoError') then + EngineJSON = System_Healthcheck_Services('ConvertEngineHealthInfoToJSON', EngineHealthInfo, FullEndpointURL) + ResponseCode = 200 + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseBody', EngineJSON, False$, 'application/hal+json') + HTTP_Services('SetResponseStatus', ResponseCode) + end else + HTTP_Services('SetResponseStatus', 500, Error_Services('GetMessage')) + end + end else + HTTP_Services('SetResponseStatus', 401, 'Invalid Engine ID.') + end + +end api diff --git a/LSL2/STPROC/HEALTHINFO_API.txt b/LSL2/STPROC/HEALTHINFO_API.txt index 800d691..2270fbd 100644 --- a/LSL2/STPROC/HEALTHINFO_API.txt +++ b/LSL2/STPROC/HEALTHINFO_API.txt @@ -1,72 +1,71 @@ -Function Healthinfo_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Healthinfo_API - - Description : API logic for the Healthinfo resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Healthinfo[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Healthinfo.POST - - Healthinfo.ID.PUT - - Healthinfo.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 07/17/24 xxx Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API remotehealthcheck.HEAD -API remotehealthcheck.GET - - HTTP_Resource_Services('LoremIpsum') - -end api - - -API healthinfo.HEAD -API healthinfo.GET - - HTTP_Resource_Services('LoremIpsum') - -end api - +Function Healthinfo_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Healthinfo_API + + Description : API logic for the Healthinfo resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Healthinfo[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Healthinfo.POST + - Healthinfo.ID.PUT + - Healthinfo.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 07/17/24 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API remotehealthcheck.HEAD +API remotehealthcheck.GET + + HTTP_Resource_Services('LoremIpsum') + +end api + + +API healthinfo.HEAD +API healthinfo.GET + + HTTP_Resource_Services('LoremIpsum') + +end api diff --git a/LSL2/STPROC/LOCK_API.txt b/LSL2/STPROC/LOCK_API.txt index 10038e7..487ecbf 100644 --- a/LSL2/STPROC/LOCK_API.txt +++ b/LSL2/STPROC/LOCK_API.txt @@ -1,167 +1,163 @@ -Function Lock_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Lock_API - - Description : API logic for the Lock resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Lock[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Lock.POST - - Lock.ID.PUT - - Lock.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 03/14/24 djm Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS - -Declare function Database_Services, Oi_Wizard_Services, Memberof, Lock_Services -Declare subroutine Lock_Services - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API Lock.HEAD - - - // GET Method removed until RTI_LH_Info(CMD_LOCKS_INFO$, '') is fixed //////////////////////////////// - - * API Lock.GET - * - * OIWizardID = '' - * Cookies = HTTP_Services('GetHTTPCookie') - * For each Cookie in Cookies using ';' - * Key = Trim(Field(Cookie, '=', 1)) - * If Key EQ 'sessionID' then - * OIWizardID = Field(Cookie, '=', 2) - * end - * If Key EQ 'userID' then - * CurrUser = Field(Cookie, '=', 2) - * end - * Next Cookie - * - * ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) - * - * If ValidSession then - * - * Allowed = Lock_Services("GetLockPermissions", CurrUser) - * - * If Allowed NE FALSE$ then - * - * StatusCode = 200 - * LockJSON = Lock_Services("GetAllowedLocks", CurrUser) - * - * If Error_Services('NoError') then - * HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) - * HTTP_Services('SetResponseBody', LockJSON, False$, 'application/hal+json') - * If Assigned(Message) then - * HTTP_Services('SetResponseStatus', StatusCode, Message) - * end else - * HTTP_Services('SetResponseStatus', StatusCode) - * end - * end else - * Message = Error_Services('GetMessage') - * HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': Message) - * end - * End Else - * HTTP_Services('SetResponseStatus', 403, 'User is not permitted to access this resource.') - * end - * End else - * HTTP_Services('SetResponseStatus', 401, 'User must be signed in to access this resource.') - * end - * - * end api - - - API Lock.POST - - OIWizardID = '' - Cookies = HTTP_Services('GetHTTPCookie') - For each Cookie in Cookies using ';' - Key = Trim(Field(Cookie, '=', 1)) - If Key EQ 'sessionID' then - OIWizardID = Field(Cookie, '=', 2) - end - If Key EQ 'userID' then - CurrUser = Field(Cookie, '=', 2) - end - Next Cookie - - ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) - - If ValidSession then - Allowed = Lock_Services("GetLockPermissions", CurrUser) - - If Allowed NE FALSE$ then - StatusCode = '' - Body = HTTP_Services('GetHTTPPostString', True$) - // The POST string will have been encoded so use percent (URL) decoding. - DecodedJSON = HTTP_Services('DecodePercentString', Body) - If SRP_JSON(objBody, 'Parse', Body) EQ '' then - Table = SRP_JSON(objBody, 'GetValue', 'table') - Key = SRP_JSON(objBody, 'GetValue', 'key') - SRP_JSON(objBody, 'Release') - end - - If (Table NE '') AND (Key NE '') then - Result = Lock_Services("AttemptUnlock",CurrUser, Table, Key) - If Result EQ TRUE$ then - HTTP_Services('SetResponseStatus', 200, 'Record successfully unlocked.') - Lock_Services("LogUnlockRequest", Table, Key, CurrUser, TRUE$) - end else - ErrCode = Error_Services('GetMessage') - HTTP_Services('SetResponseStatus', 500, ErrCode) - Lock_Services("LogUnlockRequest", Table, Key, CurrUser, FALSE$) - end - end else - HTTP_Services('SetResponseStatus', 400, 'The table or key property is missing.') - end - End Else - HTTP_Services('SetResponseStatus', 403, 'User is not permitted to access this resource.') - end - End else - HTTP_Services('SetResponseStatus', 401, 'User must be signed in to access this resource.') - end - -end api - - - - +Function Lock_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Lock_API + + Description : API logic for the Lock resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Lock[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Lock.POST + - Lock.ID.PUT + - Lock.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 03/14/24 djm Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS + +Declare function Database_Services, Oi_Wizard_Services, Memberof, Lock_Services +Declare subroutine Lock_Services + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API Lock.HEAD + + + // GET Method removed until RTI_LH_Info(CMD_LOCKS_INFO$, '') is fixed //////////////////////////////// + + * API Lock.GET + * + * OIWizardID = '' + * Cookies = HTTP_Services('GetHTTPCookie') + * For each Cookie in Cookies using ';' + * Key = Trim(Field(Cookie, '=', 1)) + * If Key EQ 'sessionID' then + * OIWizardID = Field(Cookie, '=', 2) + * end + * If Key EQ 'userID' then + * CurrUser = Field(Cookie, '=', 2) + * end + * Next Cookie + * + * ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + * + * If ValidSession then + * + * Allowed = Lock_Services("GetLockPermissions", CurrUser) + * + * If Allowed NE FALSE$ then + * + * StatusCode = 200 + * LockJSON = Lock_Services("GetAllowedLocks", CurrUser) + * + * If Error_Services('NoError') then + * HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + * HTTP_Services('SetResponseBody', LockJSON, False$, 'application/hal+json') + * If Assigned(Message) then + * HTTP_Services('SetResponseStatus', StatusCode, Message) + * end else + * HTTP_Services('SetResponseStatus', StatusCode) + * end + * end else + * Message = Error_Services('GetMessage') + * HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': Message) + * end + * End Else + * HTTP_Services('SetResponseStatus', 403, 'User is not permitted to access this resource.') + * end + * End else + * HTTP_Services('SetResponseStatus', 401, 'User must be signed in to access this resource.') + * end + * + * end api + + + API Lock.POST + + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Trim(Field(Cookie, '=', 1)) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + If Key EQ 'userID' then + CurrUser = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + Allowed = Lock_Services("GetLockPermissions", CurrUser) + + If Allowed NE FALSE$ then + StatusCode = '' + Body = HTTP_Services('GetHTTPPostString', True$) + // The POST string will have been encoded so use percent (URL) decoding. + DecodedJSON = HTTP_Services('DecodePercentString', Body) + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + Table = SRP_JSON(objBody, 'GetValue', 'table') + Key = SRP_JSON(objBody, 'GetValue', 'key') + SRP_JSON(objBody, 'Release') + end + + If (Table NE '') AND (Key NE '') then + Result = Lock_Services("AttemptUnlock",CurrUser, Table, Key) + If Result EQ TRUE$ then + HTTP_Services('SetResponseStatus', 200, 'Record successfully unlocked.') + Lock_Services("LogUnlockRequest", Table, Key, CurrUser, TRUE$) + end else + ErrCode = Error_Services('GetMessage') + HTTP_Services('SetResponseStatus', 500, ErrCode) + Lock_Services("LogUnlockRequest", Table, Key, CurrUser, FALSE$) + end + end else + HTTP_Services('SetResponseStatus', 400, 'The table or key property is missing.') + end + End Else + HTTP_Services('SetResponseStatus', 403, 'User is not permitted to access this resource.') + end + End else + HTTP_Services('SetResponseStatus', 401, 'User must be signed in to access this resource.') + end + +end api diff --git a/LSL2/STPROC/LOTOPERATION_API.txt b/LSL2/STPROC/LOTOPERATION_API.txt new file mode 100644 index 0000000..7c0a6c6 --- /dev/null +++ b/LSL2/STPROC/LOTOPERATION_API.txt @@ -0,0 +1,460 @@ +Function Lotoperation_API(@API) +/*********************************************************************************************************************** + +This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written +permission from SRP Computer Solutions, Inc. + +Name : Lotoperation_API + +Description : API logic for the Lotoperation resource. + +Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + +Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Lotoperation[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Lotoperation.POST + - Lotoperation.ID.PUT + - Lotoperation.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + +History : (Date, Initials, Notes) + 05/20/25 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +Declare function OI_Wizard_Services, Lot_Operation_Services, Database_Services, Lot_Services, Clean_Services +Declare function Met_Test_Services +Declare subroutine Lot_Services, Met_Test_Services, Wafer_Counter_Services + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS +$insert OI_WIZARD_EQUATES +$insert LOT_OPERATION_EQUATES + +GoToAPI else +// The specific resource endpoint doesn't have a API handler yet. +HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API lotoperation.HEAD +API lotoperation.GET + +HTTP_Resource_Services('LoremIpsum') + +end api + + +API lotoperation.addoperation.POST + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + Body = HTTP_Services('GetHTTPPostString', True$) + // The POST string will have been encoded so use percent (URL) decoding. + DecodedJSON = HTTP_Services('DecodePercentString', Body) + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + LotId = SRP_JSON(objBody, 'GetValue', 'NewLotOperationData.LotId') + OperationId = SRP_JSON(objBody, 'GetValue', 'NewLotOperationData.OperationId') + Sequence = SRP_JSON(objBody, 'GetValue', 'NewLotOperationData.Sequence') + SRP_JSON(objBody, 'Release') + end + If RowExists('LOT', LotId) then + If RowExists('OPERATION', OperationId) then + If Sequence NE '' then + NewOperationId = Lot_Operation_Services('AddOperationToLot', LotId, OperationId, Sequence, UserId) + If Error_Services('NoError') then + LotJsonString = Lot_Services('ConvertLotRecordToJson', LotId, '', UserId) + HTTP_Services('SetResponseBody', LotJsonString, False$, 'application/hal+json') + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + end else + ErrorMessage = 'Invalid Sequence.' + ResponseCode = 500 + end + end else + ErrorMessage = 'Invalid Operation.' + ResponseCode = 500 + end + end else + ErrorMessage = 'Invalid Lot.' + ResponseCode = 500 + end + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + +API lotoperation.removeoperation.POST + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + Body = HTTP_Services('GetHTTPPostString', True$) + // The POST string will have been encoded so use percent (URL) decoding. + DecodedJSON = HTTP_Services('DecodePercentString', Body) + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationIdToRemove') + SRP_JSON(objBody, 'Release') + end + + If RowExists('LOT_OPERATION', LotOperationId) then + LotId = Database_Services('ReadDataColumn', 'LOT_OPERATION', LotOperationId, LOT_OPERATION_LOT_ID$, True$, 0, False$) + Removed = Lot_Operation_Services('RemoveLotOperation', LotOperationId, UserId) + If Error_Services('NoError') then + LotJsonString = Lot_Services('ConvertLotRecordToJson', LotId, '', UserId) + HTTP_Services('SetResponseBody', LotJsonString, False$, 'application/hal+json') + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + end else + ErrorMessage = 'Invalid Operation.' + ResponseCode = 500 + end + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + +API lotoperation.startlotoperation.POST + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + Body = HTTP_Services('GetHTTPPostString', True$) + // The POST string will have been encoded so use percent (URL) decoding. + DecodedJSON = HTTP_Services('DecodePercentString', Body) + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + LotOperationId = SRP_JSON(objBody, 'GetValue', 'lotOperationId') + SRP_JSON(objBody, 'Release') + end + + LotProcessStarted = Lot_Operation_Services('StartLotOperation', LotOperationId, UserId) + If Error_Services('NoError') then + LotOperationJson = Lot_Operation_Services('ConvertRecordToJson', LotOperationId) + HTTP_Services('SetResponseBody', LotOperationJson,False$, 'application/hal+json') + ResponseCode = 200 + end else + ErrorMessage = 'Error while moving lot in. ' : Error_Services('GetMessage') + ResponseCode = 500 + end + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + + +API lotoperation.completelotoperation.POST + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + Body = HTTP_Services('GetHTTPPostString', True$) + // The POST string will have been encoded so use percent (URL) decoding. + DecodedJSON = HTTP_Services('DecodePercentString', Body) + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + LotOperationId = SRP_JSON(objBody, 'GetValue', 'lotOperationId') + SRP_JSON(objBody, 'Release') + end + + LotProcessCompleted = Lot_Operation_Services('CompleteLotOperation', LotOperationId, UserId) + If Error_Services('NoError') then + LotOperationJson = Lot_Operation_Services('ConvertRecordToJson', LotOperationId) + HTTP_Services('SetResponseBody', LotOperationJson) + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + + +API lotoperation.ID.HEAD +API lotoperation.ID.GET + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + LotOperationId = EndpointSegment + If RowExists('LOT_OPERATION', LotOperationId) then + LotOperationJson = Lot_Operation_Services('ConvertRecordToJson', LotOperationId) + HTTP_Services('SetResponseBody', LotOperationJson, False$, 'application/hal+json') + ResponseCode = 200 + end else + ErrorMessage = 'Lot Operation not found in database.' + end + + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + + +API lotoperation.associatemettest.POST + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + Body = HTTP_Services('GetHTTPPostString', True$) + // The POST string will have been encoded so use percent (URL) decoding. + DecodedJSON = HTTP_Services('DecodePercentString', Body) + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationId') + MetTestId = SRP_JSON(objBody, 'GetValue', 'MetTestId') + SRP_JSON(objBody, 'Release') + end + + Met_Test_Services('AttachMetTestToLotOperation', MetTestId, LotOperationId, UserId) + If Error_Services('NoError') then + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + + + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + + +API lotoperation.removemettest.POST + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + Body = HTTP_Services('GetHTTPPostString', True$) + // The POST string will have been encoded so use percent (URL) decoding. + DecodedJSON = HTTP_Services('DecodePercentString', Body) + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationId') + MetTestId = SRP_JSON(objBody, 'GetValue', 'MetTestId') + SRP_JSON(objBody, 'Release') + end + + Met_Test_Services('RemoveMetTestFromLotOperation', MetTestId, LotOperationId, UserId) + If Error_Services('NoError') then + HTTP_Services('SetResponseBody', LotJsonString, False$, 'application/hal+json') + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + + + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + + +API lotoperation.associatewafercounter.POST + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + Body = HTTP_Services('GetHTTPPostString', True$) + // The POST string will have been encoded so use percent (URL) decoding. + DecodedJSON = HTTP_Services('DecodePercentString', Body) + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationId') + WaferCounterId = SRP_JSON(objBody, 'GetValue', 'WaferCounterId') + SRP_JSON(objBody, 'Release') + end + + Wafer_Counter_Services('AssociateWaferCounter', LotOperationId, WaferCounterId, UserId) + If Error_Services('NoError') then + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + + + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api diff --git a/LSL2/STPROC/LOT_API.txt b/LSL2/STPROC/LOT_API.txt index efab9ad..96e79c4 100644 --- a/LSL2/STPROC/LOT_API.txt +++ b/LSL2/STPROC/LOT_API.txt @@ -38,9 +38,12 @@ Function Lot_API(@API) #pragma precomp SRP_PreCompiler +Declare function OI_Wizard_Services, Lot_Services, Database_Services, PSN_Services, Clean_Services + $insert APP_INSERTS $insert API_SETUP $insert HTTP_INSERTS +$Insert OI_WIZARD_EQUATES GoToAPI else // The specific resource endpoint doesn't have a API handler yet. @@ -55,3 +58,159 @@ Return Response OR '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +API lot.ID.HEAD +API lot.ID.GET + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + UserId = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + LotId = EndpointSegment + If RowExists('LOT', LotId) then + LotJson = Lot_Services('ConvertLotRecordToJson', LotId, '', UserId) + HTTP_Services('SetResponseBody', LotJson, False$, 'application/hal+json') + ResponseCode = 200 + end else + ResponseCode = 500 + ErrorMessage = 'Lot not found in database.' + end + + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + + +API lot.getlotbylegacylotid.HEAD +API lot.getlotbylegacylotid.GET + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + If ValidSession then + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + Body = HTTP_Services('GetHTTPGetString') + + LegacyLotId = Http_Services('GetQueryField', 'LegacyLotId') + LegacyLotType = Http_Services('GetQueryField', 'LegacyLotType') + + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType) + LotJson = Lot_Services('ConvertLotRecordToJson', LotId, '', UserId) + If Error_Services('NoError') then + HTTP_Services('SetResponseBody', LotJson, False$, 'application/hal+json') + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + + end else + ErrorMessage = 'Invalid session. Reauthentication required.' + ResponseCode = 401 + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + +end api + + +API lot.ID.getrecipeoptions.HEAD +API lot.ID.getrecipeoptions.GET + + JSONCollection = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + If ValidSession then + LotId = EndpointSegment + PSN = Database_Services('ReadDataColumn', 'LOT', LotId, LOT_PROD_SPEC_ID$, True$, 0, False$) + RecipeParameters = PSN_Services('GetAllMetrologyRecipes', PSN, True$, True$, True$, True$) + If Error_Services('NoError') then + If Body NE '' then + RequestJson = HTTP_Services('DecodePercentString', Body) + objJSONResponse = '' + If SRP_Json(objJSONResponse, 'New', 'Object') then + //Available Tools + If SRP_Json(objCleanTools, 'New', 'Array') then + CleanTools = Clean_Services('GetCleanToolOptions') + for each CleanTool in CleanTools using @FM + SRP_Json(objCleanTools, 'AddValue', CleanTool, 'String') + Next CleanTool + SRP_Json(objJsonResponse, 'Set', 'CleanToolOptions', objCleanTools) + SRP_Json(objCleanTools, 'Release') + end + //Available Recipes + If SRP_Json(objCleanRecipes, 'New', 'Array') then + CleanRecipes = Clean_Services('GetCleanRecipeOptions') + for each Recipe in CleanRecipes using @VM + SRP_Json(objCleanRecipes, 'AddValue', Recipe, 'String') + Next Recipe + SRP_Json(objJsonResponse, 'Set', 'CleanRecipeOptions', objCleanRecipes) + SRP_Json(objCleanRecipes, 'Release') + end + JsonResponse = SRP_Json(objJsonResponse, 'Stringify', 'Styled') + SRP_Json(objJsonResponse, 'Release') + end else + Error_Services('Add', 'Error when creating JSON response.') + end + end else + Error_Services('Add', 'No body was sent with the request.') + end + end else + ErrorMessage = Error_Services('GetMessage') + end + + If Error_Services('NoError') then + HTTP_Services('SetResponseStatus', 201, 'Success') + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseBody', JsonResponse, False$, 'application/hal+json') + end else + HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage')) + end + end else + HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.') + end + +end api + + diff --git a/LSL2/STPROC/LOT_EVENT_SERVICES.txt b/LSL2/STPROC/LOT_EVENT_SERVICES.txt index 71b0cc2..5b62fda 100644 --- a/LSL2/STPROC/LOT_EVENT_SERVICES.txt +++ b/LSL2/STPROC/LOT_EVENT_SERVICES.txt @@ -59,7 +59,7 @@ Declare function Lot_Event_Services, Lot_Services Declare subroutine Error_Services, Logging_Services, Database_Services, Lot_Services, Service_Services Declare subroutine Transaction_Services -Options EVENT_TYPES = 'MOVE_IN', 'MOVE_OUT', 'HOLD_ON', 'HOLD_OFF', 'REDUCE_WAFER_QTY', 'BONUS_WAFER_QTY', 'COMMENT', 'LOCATION', 'LOAD', 'UNSIGN_LOAD', 'TW_USE', 'CLOSE', 'SIGN_FQA', 'UNSIGN_FQA' +Options EVENT_TYPES = 'MOVE_IN', 'MOVE_OUT', 'HOLD_ON', 'HOLD_OFF', 'REDUCE_WAFER_QTY', 'BONUS_WAFER_QTY', 'COMMENT', 'LOCATION', 'LOAD', 'UNSIGN_LOAD', 'TW_USE', 'CLOSE', 'SIGN_FQA', 'UNSIGN_FQA', 'ADD_LOT_OPERATION', 'REMOVE_LOT_OPERATION', 'MET_TEST', 'LOG_WAFER_COUNT', 'PACKAGING' Options LOT_TYPES = 'TW', 'RDS', 'WM_OUT', 'WM_IN', 'WO_MAT', 'LOT' Options LEGACY_LOT_TYPES = 'RDS', 'WM_OUT', 'WM_IN' Options BOOLEAN = 'True', 'False' @@ -230,3 +230,6 @@ InitEventLog: return + + + diff --git a/LSL2/STPROC/LOT_OPERATION_SERVICES.txt b/LSL2/STPROC/LOT_OPERATION_SERVICES.txt index 357fa6e..c5d4e18 100644 --- a/LSL2/STPROC/LOT_OPERATION_SERVICES.txt +++ b/LSL2/STPROC/LOT_OPERATION_SERVICES.txt @@ -3,12 +3,12 @@ Compile function Lot_Operation_Services(@Service, @Params) Declare function Lot_Services, Database_Services, Error_Services, Srp_Sort_Array, Lot_Operation_Services Declare function RTI_CreateGUID, MemberOf, SRP_JSON, Operation_Services, Datetime, Met_Test_Services, PSN_Services +Declare function Date_Services Declare subroutine Database_Services, Error_Services, SRP_JSON, Lot_Services, Lot_Event_Services, Lot_Operation_Services $insert LOGICAL $insert LOT_EQUATES $Insert LOT_OPERATION_EQUATES -$Insert METROLOGY_DATA_EXAMPLE_EQUATES $Insert OPERATION_EQUATES $Insert MET_TEST_EQUATES $Insert WAFER_COUNTER_EQUATES @@ -30,7 +30,7 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId) If RowExists('LOT', LotId) then If RowExists('OPERATION', OperationId) then If PrescribedSequence AND Num(PrescribedSequence) then - If Lot_Operation_Services('CanUserAddLotOperation', UserId) then + If Lot_Services('CanUserModifyLot', UserId) then LotCurrOperation = Lot_Services('GetLotCurrOperationId', LotId) CurrOperationSequence = Xlate('LOT_OPERATION', LotCurrOperation, LOT_OPERATION_OPERATION_SEQUENCE$, 'X') If CurrOperationSequence LT PrescribedSequence then @@ -74,7 +74,8 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId) IsOperationRework = Database_Services('ReadDataColumn', 'OPERATION', OperationId, OPERATION_REWORK$) Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationRecId, LotOperationRec) If Error_Services('NoError') then - Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'ADD_LOT_OPERATION', 'Added operation ' : Operation : ' to lot.', '', UserId) + OperationDesc = XLATE('OPERATION', OperationId, OPERATION_OPERATION_DESCRIPTION$, 'X') + Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'ADD_LOT_OPERATION', 'Added operation ' : Quote(OperationDesc) : ' to lot.', '', UserId) end else ErrorMessage = Error_Services('GetMessage') end @@ -86,7 +87,7 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId) ErrorMessage = 'Not allowed to add new operations prior to current operation' end end else - ErrorMessage = 'User ' : UserId : ' does not have permission to add operations to lots.' + ErrorMessage = 'User ' : UserId : ' does not have permission to modify lots.' end end else ErrorMessage = 'Invalid operation sequence entered.' @@ -102,7 +103,6 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId) Response = Operation end else Error_Services('Add', 'Error in ' : Service : '.' : ErrorMessage) - // todo: add logging end end service @@ -114,48 +114,53 @@ Service RemoveLotOperation(LotOperationId, UserId) Success = False$ If RowExists('LOT_OPERATION', LotOperationId) then - LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$) - LotId = LotOperationRec - MoveInTime = LotOperationRec - MoveOutTime = LotOperationRec - Sequence = LotOperationRec - OperationId = LotOperationRec - OperationClass = XLATE('OPERATION', OperationId, OPERATION_CLASS_ID$, 'X') - If OperationClass NE 'RTF_DEFAULT' AND OperationClass NE 'RTF_DEFAULT_END' then - If MoveInTime EQ '' AND MoveOutTime EQ '' then - LotOperationRec = '';//Nulling this value out should disassociated the lot operation record from the lot. - Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec) - If Error_Services('NoError') then - Lot_Operation_Services('UpdateLotOperationSequence', LotId, Sequence) + If Lot_Services('CanUserModifyLot', UserId) then + LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$) + LotId = LotOperationRec + MoveInTime = LotOperationRec + MoveOutTime = LotOperationRec + Sequence = LotOperationRec + OperationId = LotOperationRec + OperationClass = XLATE('OPERATION', OperationId, OPERATION_CLASS_ID$, 'X') + If OperationClass NE 'RTF_DEFAULT' AND OperationClass NE 'RTF_DEFAULT_END' then + If MoveInTime EQ '' AND MoveOutTime EQ '' then + LotOperationRec = '';//Nulling this value out should disassociated the lot operation record from the lot. + Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec) If Error_Services('NoError') then - Success = True$ + Lot_Operation_Services('UpdateLotOperationSequence', LotId, Sequence) + If Error_Services('NoError') then + Success = True$ + end else + ErrorMessage = Error_Services('GetMessage') + end + OperationDesc = XLATE('OPERATION', OperationId, OPERATION_OPERATION_DESCRIPTION$, 'X') + Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'REMOVE_LOT_OPERATION', 'Removed operation ' : Quote(OperationDesc) : ' from lot.', '', UserId) end else - ErrorMessage = Error_Services('GetMessage') + ErrorMessage = Error_Services('GetMessage') end - Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'REMOVE_LOT_OPERATION', 'Removed operation ' : OperationId : ' from lot.', '', UserId) end else - ErrorMessage = Error_Services('GetMessage') + ErrorMessage = 'Lot has already started processing on operation ' : OperationId end end else - ErrorMessage = 'Lot has already started processing on operation ' : OperationId + ErrorMessage = 'Unable to remove default operations.' end end else - ErrorMessage = 'Unable to remove default operations.' + ErrorMessage = 'User ' : UserId : ' does not have permission modify lots.' end end else ErrorMessage = 'Lot Operation record not found' end If ErrorMessage NE '' then - Error_Services('Add', 'Error in service ': Service : ' : ' : ErrorMessage) + Error_Services('Add', ErrorMessage) end Response = Success - end service Service UpdateLotOperationSequence(LotId, StartSequence) + ErrorMessage = '' If StartSequence EQ '' then StartSequence = 1 @@ -189,17 +194,6 @@ Service UpdateLotOperationSequence(LotId, StartSequence) end service -Service ModifyLotOperationSequence(LotOperationId, NewSequence, UserId) - - ErrorMessage = '' - - If ErrorMessage NE '' then - - - end - -end service - Service GetAvailableSequences(LotId) AvailableSequences = '' @@ -211,9 +205,7 @@ Service GetAvailableSequences(LotId) OperationClass = Database_Services('ReadDataColumn', 'OPERATION', OperationId, OPERATION_CLASS_ID$) StartDtm = LotOperationRec If StartDTM EQ '' then - If OperationClass NE 'RTF_DEFAULT' then - AvailableSequences<1, -1> = Sequence + 1 - end + AvailableSequences<1, -1> = Sequence + 1 end Next LotOperationId end @@ -221,30 +213,6 @@ Service GetAvailableSequences(LotId) Response = AvailableSequences end service - -Service AddSpecsToLotOperation(LotOperationId) - -end service - -Service CanUserAddLotOperation(UserId) - - If UserId NE '' then - Begin Case - Case MemberOf(UserId, 'LEAD') - Response = True$ - Case MemberOf(UserId, 'SUPERVISOR') - Response = True$ - Case MemberOf(UserId, 'ENGINEER') - Response = True$ - Case MemberOf(UserId, 'ENG_TECH') - Response = True$ - Case Otherwise$ - Response = False$ - End Case - end - -end service - Service ConvertRecordToJson(LotOperationId) JsonString = '' @@ -258,8 +226,14 @@ Service ConvertRecordToJson(LotOperationId) SRP_JSON(objJSON, 'SetValue', 'LotId', LotId, 'String') SRP_JSON(objJSON, 'SetValue', 'LegacyLotId', LegacyLotId, 'String') SRP_JSON(objJSON, 'SetValue', 'OperationId', LotOperationRec, 'String') - SRP_JSON(objJSON, 'SetValue', 'DateTimeIn', OConv(LotOperationRec, 'DT'), 'String') - SRP_JSON(objJSON, 'SetValue', 'DateTimeOut', OConv(LotOperationRec, 'DT'), 'String') + OperationDesc = XLATE('OPERATION', LotOperationRec, OPERATION_OPERATION_DESCRIPTION$, 'X') + SRP_JSON(objJSON, 'SetValue', 'Description', OperationDesc, 'String') + OperationClass = XLATE('OPERATION', LotOperationRec, OPERATION_CLASS_ID$, 'X') + SRP_JSON(objJSON, 'SetValue', 'OperationClass', OperationClass) + DatetimeIn = Date_Services('ConvertDateTimeToISO8601', LotOperationRec) + SRP_JSON(objJSON, 'SetValue', 'DateTimeIn', DatetimeIn) + DatetimeOut = Date_Services('ConvertDateTimeToISO8601', LotOperationRec) + SRP_JSON(objJSON, 'SetValue', 'DateTimeOut', DatetimeOut) EquipmentId = LotOperationRec SRP_JSON(objJSON, 'SetValue', 'EquipmentId', EquipmentId) SRP_JSON(objJSON, 'SetValue', 'WaferInQty', LotOperationRec, 'Number') @@ -267,8 +241,10 @@ Service ConvertRecordToJson(LotOperationId) SRP_JSON(objJSON, 'SetValue', 'OperatorInId', LotOperationRec) SRP_JSON(objJSON, 'SetValue', 'OperatorOutId', LotOperationRec) SRP_JSON(objJSON, 'SetValue', 'OperationSequence', LotOperationRec) - SRP_JSON(objJSON, 'SetValue', 'DateTimeStart', OConv(LotOperationRec, 'DT'), 'String') - SRP_JSON(objJSON, 'SetValue', 'DateTimeStop', OConv(LotOperationRec, 'DT'), 'String') + DatetimeStart = Date_Services('ConvertDateTimeToISO8601', LotOperationRec) + SRP_JSON(objJSON, 'SetValue', 'DateTimeStart', DatetimeStart) + DatetimeStop = Date_Services('ConvertDateTimeToISO8601', LotOperationRec) + SRP_JSON(objJSON, 'SetValue', 'DateTimeStop', DatetimeStop) SRP_JSON(objJSON, 'SetValue', 'MetTestId', LotOperationRec) SRP_JSON(objJSON, 'SetValue', 'CleanId', LotOperationRec) SRP_JSON(objJSON, 'SetValue', 'PackagingId', LotOperationRec) @@ -278,7 +254,22 @@ Service ConvertRecordToJson(LotOperationId) SRP_JSON(objJson, 'SetValue', 'PackagingRequired', LotOperationRec, 'Boolean') SRP_JSON(objJson, 'SetValue', 'CleanRequired', LotOperationRec, 'Boolean') SRP_JSON(objJson, 'SetValue', 'WaferCounterRequired', LotOperationRec, 'Boolean') - + PSNo = Xlate('LOT', LotId, LOT_PROD_SPEC_ID$, 'X') + RecipeToolInfo = PSN_Services('GetAllMetrologyRecipes', PSNo, True$, True$, True$, True$) + objRecipeInfo = '' + If SRP_Json(objRecipeInfo, 'New', 'Array') then + for each RecipeLine in RecipeToolInfo using @FM + If SRP_Json(objRecipeLine, 'New', 'Object') then + SRP_Json(objRecipeLine, 'SetValue', 'ToolClass', RecipeLine<1,1>, 'String') + SRP_Json(objRecipeLine, 'SetValue', 'Recipe', RecipeLine<1,2>, 'String') + SRP_Json(objRecipeLine, 'SetValue', 'Stage', RecipeLine<1,3>, 'String') + SRP_Json(objRecipeInfo, 'Add', objRecipeLine) + SRP_Json(objRecipeLine, 'Release') + end + Next RecipeLine + SRP_Json(objJSON, 'Set', 'RecipeInfo', objRecipeInfo) + SRP_Json(objRecipeInfo, 'Release') + end SRP_JSON(objJSON, 'SetValue', 'OperationType', LotOperationRec) //Add OPERATION Object OperationJson = Operation_Services('ConvertRecordToJSON', LotOperationRec) @@ -302,7 +293,7 @@ Service ConvertRecordToJson(LotOperationId) end //Add Available Met Test Record - AvailMetTestIds = Met_Test_Services('GetMetTests', LotId, LegacyLotId, '', EquipmentId, True$) + AvailMetTestIds = Met_Test_Services('GetMetTests', LotId, LegacyLotId, '', '', True$) objAvailMetTest = '' If SRP_Json(objAvailMetTest, 'New', 'Array') then for each MetTestId in AvailMetTestIds using @VM @@ -316,8 +307,6 @@ Service ConvertRecordToJson(LotOperationId) SRP_Json(objAvailMetTest, 'Release') end //Add in relevant recipes - //OperationType = LotOperationRec - //MetTestTypeRequired = LotOperationRec Recipes = '' ShowThickRecipes = False$ ShowResRecipes = False$ @@ -340,7 +329,7 @@ Service ConvertRecordToJson(LotOperationId) ShowCleanRecipes = True$ end ProdSpecNo = XLATE('LOT', LotId, LOT_PROD_SPEC_ID$, 'X') - Recipes = PSN_Services('GetAllMetrologoyRecipes', ProdSpecNo, ShowSurfscanRecipes, ShowCleanRecipes, ShowResRecipes, ShowThickRecipes) + Recipes = PSN_Services('GetAllMetrologyRecipes', ProdSpecNo, ShowSurfscanRecipes, ShowCleanRecipes, ShowResRecipes, ShowThickRecipes) If SRP_JSON(objRecipes, 'New', 'Array') then for each Recipe in Recipes using @FM //ToolClass : @VM : Recipe : @VM : Stage @@ -358,9 +347,8 @@ Service ConvertRecordToJson(LotOperationId) SRP_JSON(objJSON, 'Set', 'RecipeParams', objRecipes) SRP_JSON(objRecipes, 'Release') end - JsonString = SRP_JSON(objJSON, 'Stringify', 'Styled') + JsonString = SRP_JSON(objJSON, 'Stringify', 'Fast') SRP_JSON(objJSON, 'Release') - end Response = JsonString @@ -370,12 +358,6 @@ end service Service StartLotOperation(LotOperationId, UserId) - //1. Validate that it can be moved into the operation passed in. - - //2. Move in the lot - //3. Return true is move in successfully - //4. Return false if error moving in - ErrorMessage = '' If RowExists('LOT_OPERATION', LotOperationId) then @@ -414,11 +396,8 @@ Service StartLotOperation(LotOperationId, UserId) end service Service CompleteLotOperation(LotOperationId, UserId) - - //1. Validate that the lot is moved into the operation - //2. Validate that the lot + ErrorMessage = '' - If RowExists('LOT_OPERATION', LotOperationId) then If RowExists('LSL_USERS', UserId) then //We can also add additional checks like security checks, training checks, etc here if needed. @@ -436,13 +415,15 @@ Service CompleteLotOperation(LotOperationId, UserId) ErrorMessage = Error_Services('GetMessage') end end else - ErrorMessage = 'Lot Operation has not finished processing and cannot be moved out.' + ErrorMessage = 'Lot Operation has not finished processing and cannot be moved out.' end end else - ErrorMessage = 'Lot is already moved into this operation.' + ErrorMessage = 'Cannot complete operation because lot is not currently moved in.' end end else - + CurrOperationId = Xlate('LOT_OPERATION', LotCurrentLotOpId, LOT_OPERATION_OPERATION_ID$, 'X') + CurrOperationDesc = Xlate('OPERATION', CurrOperationId, OPERATION_OPERATION_DESCRIPTION$, 'X') + ErrorMessage = 'Cannot complete operation. Lot is currently at ' : CurrOperationDesc end end else ErrorMessage = 'Invalid user passed to routine.' @@ -452,10 +433,10 @@ Service CompleteLotOperation(LotOperationId, UserId) end If ErrorMessage EQ '' then - Response = True$ + Response = True$ end else - Response = False$ - Error_Services('Add', 'Error in ' : Service : '. ' : ErrorMessage) + Response = False$ + Error_Services('Add', ErrorMessage) end end service @@ -472,14 +453,14 @@ Service ValidateLotOperation(LotOperationId) PackagingRequired = LotOperationRec CleanRequired = LotOperationRec WaferCountRequired = LotOperationRec + OperationClass = XLATE('OPERATION', OperationId, OPERATION_CLASS_ID$, 'X') If MetTestRequired then MetTestsInSpec = True$ AssociatedMetTestIds = LotOperationRec If AssociatedMetTestIds NE '' then for each MetTestId in AssociatedMetTestIds using @VM MetTestOoS = Database_Services('ReadDataColumn', 'MET_TEST', MetTestId, MET_TEST.OUT_OF_SPEC$, True$, 0, False) - If MetTestOoS then - //ToDo Check that the met tests meet the requirements. + If MetTestOoS AND OperationClass NE 'RTF' AND OperationClass NE 'RTF_DEFAULT' then MetTestsInSpec = False$ ErrorMessage = 'An associated Met test record is out of spec.' end @@ -490,14 +471,29 @@ Service ValidateLotOperation(LotOperationId) ErrorMessage = 'Met tests are required and none are assigned.' end end - If PackagingRequired then - + If PackagingRequired AND IsValid then + AssociatedPackagingIds = LotOperationRec + If AssociatedPackagingIds NE '' then + + end else + IsValid = False$ + end end - If CleanRequired then - + If CleanRequired AND IsValid then + AssociatedCleanIds = LotOperationRec + If AssociatedCleanIds NE '' then + IsValid = True$ + end else + IsValid = False$ + end end - If WaferCountRequired then - + If WaferCountRequired AND IsValid then + AssociatedWaferCountIds = LotOperationRec + If AssociatedWaferCountIds NE '' then + IsValid = True$ + end else + IsValid = False$ + end end end else ErrorMessage = 'Lot Operation not found' @@ -509,27 +505,3 @@ Service ValidateLotOperation(LotOperationId) Response = IsValid end service - -Service ValidateFQA(LotOperationId) - - Response = False$ - LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$) - LotId = LotOperationRec - OperationStartDtm = LotOperationRec - RelevantMetTests = '' - MetTests = Met_Test_Services('GetMetTestsByLotId', LotId) - For each MetTestId in MetTests using @VM - ThisMetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId, True$, 0, False$) - - Next MetTestId - -end service - -Service AssociateClean(LotOperationId, CleanId, UserId) - -end service - -Service GetFinalQAOperationJson(LotId, Stage) - -end service - diff --git a/LSL2/STPROC/LOT_SERVICES.txt b/LSL2/STPROC/LOT_SERVICES.txt index 14ce385..433c9f2 100644 --- a/LSL2/STPROC/LOT_SERVICES.txt +++ b/LSL2/STPROC/LOT_SERVICES.txt @@ -46,21 +46,25 @@ Compile function Lot_Services(@Service, @Params) ***********************************************************************************************************************/ #pragma precomp SRP_PreCompiler -$Insert SERVICE_SETUP -$Insert APP_INSERTS + +Declare function TEST_WAFER_PROD_SERVICES, SRP_Datetime, Datetime, Database_Services, Lot_Services, Error_Services, RTI_CREATEGUID +Declare function SRP_Array, SRP_Json, Environment_Services, Logging_Services, MemberOf, Lot_Event_Services, GetTickCount, Lot_Operation_Services +Declare function PSN_Services, Return_To_Fab_Services +Declare subroutine Database_Services, Btree.Extract, Lot_Services, Error_Services, Labeling_Services, SRP_Json, Logging_Services +Declare subroutine SRP_Run_Command, Service_Services, obj_notes, Lot_Event_Services, Mona_Services + +$insert APP_INSERTS $Insert LOT_EQUATES $Insert TEST_WAFER_PROD_EQUATES -$Insert LOT_OPERATION_EQUATES +$Insert Lot_Operation_Equates $Insert PRODUCT_OPERATION_EQUATES $Insert LOT_EVENT_EQUATES $Insert NOTIFICATION_EQUATES $Insert VOIDED_LOT_EQUATES -$Insert IFX_EQUATES - -Declare function TEST_WAFER_PROD_SERVICES, SRP_Datetime, Datetime, Database_Services, Lot_Services, Error_Services, RTI_CREATEGUID -Declare function SRP_Array, SRP_Json, Environment_Services, Logging_Services, MemberOf, Lot_Event_Services, GetTickCount -Declare subroutine Database_Services, Btree.Extract, Lot_Services, Error_Services, Labeling_Services, SRP_Json, Logging_Services -Declare subroutine SRP_Run_Command, Service_Services, obj_notes, Lot_Event_Services, Mona_Services +$Insert RDS_EQUATES +$Insert WO_LOG_EQUATES +$Insert PROD_VER_EQUATES +$Insert OPERATION_EQUATES LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Lot' LogDate = Oconv(Date(), 'D4/') @@ -77,7 +81,7 @@ objLotStartLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', He LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' LotRun.csv' Headers = 'Logging DTM' : @FM : 'Lot Id' : @FM : 'Username' : @FM : 'Tool Id' : @FM : 'Message' -objLotRunLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) +objRunLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' LotMove.csv' Headers = 'Logging DTM' : @FM : 'Lot Id' : @FM : 'Username' : @FM : 'Message' @@ -91,8 +95,9 @@ LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' T Headers = 'Logging DTM' : @FM : 'Lot Id' : @FM : 'Operator' : @FM : 'Message' objLotClosureLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) -Options EVENT_TYPES = 'MOVE_IN', 'MOVE_OUT', 'HOLD_ON', 'HOLD_OFF', 'REDUCE_WAFER_QTY', 'BONUS_WAFER_QTY', 'COMMENT', 'LOCATION', 'LOAD', 'UNSIGN_LOAD', 'TW_USE', 'CLOSE', 'SIGN_FQA', 'UNSIGN_FQA' +Options EVENT_TYPES = 'MOVE_IN', 'MOVE_OUT', 'HOLD_ON', 'HOLD_OFF', 'REDUCE_WAFER_QTY', 'BONUS_WAFER_QTY', 'COMMENT', 'LOCATION', 'LOAD', 'UNSIGN_LOAD', 'TW_USE', 'CLOSE', 'SIGN_FQA', 'UNSIGN_FQA', 'SYSTEM_COMMENT' Options LOT_TYPES = 'TW', 'RDS', 'WM_OUT', 'WM_IN', 'WO_MAT', 'LOT' +Options LEGACY_LOT_TYPES = 'RDS', 'WM_OUT', 'WM_IN', 'WO_MAT' IsProd = Environment_Services('IsProd') If IsProd EQ True$ then @@ -177,71 +182,112 @@ Service GenerateNewLotId(LotType) end service - -Service GetLotIdByLegacyLotIdAndType(LegacyLotId, LegacyLotType) - - StartTick = GetTickCount() +Service GetLotIdByLegacyLotIdAndType(LegacyLotId, LegacyLotType=LEGACY_LOT_TYPES) + StartTick = GetTickCount() MetricName = 'GetLotIdByLegacyLotIdAndType' + ErrorMsg = '' Open 'DICT.LOT' to DictLot then - SearchString = '' - SearchString := 'LEGACY_LOT_ID':@VM:LegacyLotId:@FM - SearchString := 'TYPE':@VM:LegacyLotType:@FM - LotIdKeys = '' - Btree.Extract(SearchString, 'LOT', DictLot, LotIdKeys, '', '') - ErrCode = '' - IF Get_Status(ErrCode) then - ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract. Error code ':ErrCode:'.' - end else - Response = LotIdKeys<1,1> - end - end else - ErrorMsg = 'Error in ':Service:' service. Error opening LOT dictionary.' - end - - EndTick = GetTickCount() - Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick) - - If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) - + + SearchString = '' + SearchString := 'LEGACY_LOT_ID':@VM:LegacyLotId:@FM + SearchString := 'LEGACY_LOT_TYPE':@VM:LegacyLotType:@FM + LotIdKeys = '' + Btree.Extract(SearchString, 'LOT', DictLot, LotIdKeys, '', '') + ErrCode = '' + IF Get_Status(ErrCode) then + ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract. Error code ':ErrCode:'.' + end else + Response = LotIdKeys<1,1> + end + + end else + ErrorMsg = 'Error in ':Service:' service. Error opening LOT dictionary.' + end + + EndTick = GetTickCount() + Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick) + + If ErrorMsg NE '' then + Error_Services('Add', ErrorMsg) + end + end service -Service CreateNewLot(LotType, ProdName, LotQty, VendorPartNo, VendorLotNo, VendorCode, Username, PrinterID, LotId) - +Service CreateNewLot(LotType, ProdName, LotQty, VendorPartNo, VendorLotNo, VendorCode, Username, PrinterID, LegacyLotId) StartTick = GetTickCount() MetricName = 'CreateNewLot' - - CreatedLotNumber = '' - ErrorMessage = '' - Begin Case - Case LotType EQ 'RDS' OR LotType EQ 'WM_IN' OR LotType EQ 'WM_OUT' OR LotType EQ 'WO_MAT' - // Case statement for legacy lot entity types - NewLotId = Lot_Services('GenerateNewLotId', LotType) - If NewLotId NE '' then - If RowExists('LOT', NewLotId) NE False$ then - LotRec = '' - LotRec = LotType - LotRec = '' - LotRec = LotQty - LotRec = LotQty - LotRec = VendorPartNo - LotRec = VendorLotNo - LotRec = VendorCode - LotRec = LotId - Database_Services('WriteDataRow', 'LOT', NewLotId, LotRec) - If Error_Services('HasError') then - ErrorMessage = 'Error in ':Service:' service. ':Error_Services('GetMessage') - end else - CreatedLotNumber = NewLotId - end - end else - ErrorMessage = 'Error in ':Service:' service. LOT record "':NewLotId:'" already exists.' - end - end else - ErrorMessage = 'Error in ':Service:' service. No lot ID passed in.' - end - Case LotType EQ 'TW' + + CreatedLotNumber = '' + ErrorMessage = '' + Begin Case + Case LotType EQ 'RDS' OR LotType EQ 'WM_IN' OR LotType EQ 'WM_OUT' OR LotType EQ 'WO_MAT' + If LegacyLotId NE '' then + LegacyLotType = LotType + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType) + If LotId EQ '' then + LotType = 'PROD' + // Case statement for legacy lot entity types + NewLotId = Lot_Services('GenerateNewLotId', LegacyLotType) + If NewLotId NE '' then + If RowExists('LOT', NewLotId) NE False$ then + WoNo = '' + EpiPartNo = '' + ProdVerNo = '' + Begin Case + Case LegacyLotType EQ 'RDS' + WoNo = XLATE('RDS', LegacyLotId, RDS_WO$, 'X') + Case LegacyLotType EQ 'WM_IN' OR LegacyLotType EQ 'WM_OUT' OR LegacyLotType EQ 'WO_MAT' + WoNo = Field(LegacyLotId, '*', 1) + End Case + + ProdVerNo = XLATE('WO_LOG', WoNo, WO_LOG_PROD_VER_NO$, 'X') + EpiPartNo = XLATE('WO_LOG', WoNo, WO_LOG_EPI_PART_NO$, 'X') + ProdId = EpiPartNo : '*' : ProdVerNo + ProdSpecId = XLATE('WO_LOG', WoNo, WO_LOG_PROD_SPEC_ID$, 'X') + If ProdSpecId EQ '' then + Begin Case + Case LegacyLotType EQ 'RDS' + ProdSpecId = XLATE('RDS', LegacyLotId, RDS_PROD_SPEC_ID$, 'X') + Case Otherwise$ + ProdSpecId = XLATE('PROD_VER', ProdVerNo, PROD_VER_PROC_STEP_PSN$, 'X') + End Case + end + If Not(RowExists('PRODUCT', ProdId)) then ProdId = '' + LotRec = '' + LotRec = 'PROD' + LotRec = ProdId + LotRec = LotQty + LotRec = LotQty + LotRec = VendorPartNo + LotRec = VendorLotNo + LotRec = VendorCode + LotRec = LegacyLotId + LotRec = LegacyLotType + LotRec = WONo + LotRec = ProdSpecId + LotRec = EpiPartNo + LotRec = ProdVerNo + Database_Services('WriteDataRow', 'LOT', NewLotId, LotRec) + If Error_Services('NoError') then + CreatedLotNumber = NewLotId + end else + ErrorMessage = 'Error in ':Service:' service. ':Error_Services('GetMessage') + end + end else + ErrorMessage = 'Error in ':Service:' service. Failed to generate new LOT id. LOT record "':NewLotId:'" already exists.' + end + end else + ErrorMessage = 'Error in ':Service:' service. Failed to generate new LOT id.' + end + end else + ErrorMessage = 'Error in ':Service:' service. Lot Id ':LotId:' already exists for LegacyLotId ':LegacyLotId:'.' + end + end else + ErrorMessage = 'Error in ':Service:' service. Null LegacyLotId passed in.' + end + Case LotType EQ 'TW' If ProdName NE '' then TWProdID = Test_Wafer_Prod_Services('GetTestWaferProdIDsByPartName', ProdName) If TWProdID NE '' then @@ -536,41 +582,45 @@ end service Service CreateInitialLotOperationRecords(LotId) - - ErrorMessage = '' - If LotId NE '' then - LotRec = Database_Services('ReadDataRow', 'LOT', LotId) - LotType = LotRec - ProdId = LotRec - ThisInitialProdOperations = Lot_Services('GetPrescribedOperationsByProdId', ProdId, LotType) - If Error_Services('NoError') AND ThisInitialProdOperations NE '' then - For each ProdOperation in ThisInitialProdOperations using @VM - ProdOperationRec = Database_Services('ReadDataRow', 'PRODUCT_OPERATION', ProdOperation) - OperationID = ProdOperationRec - OperationSequence = ProdOperationRec - LotOperationRecID = Rti_Createguid() - If Not(RowExists('LOT_OPERATION', LotOperationRecID)) then - LotOperationRec = '' - LotOperationRec = LotId - LotOperationRec = OperationID - LotOperationRec = OperationSequence - LotOperationRec = False$ - Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationRecId, LotOperationRec) - TestRec = Database_Services('ReadDataRow', 'LOT', LotId) - end else - ErrorMessage = 'Error in ':Service:' service. Lot Operation already existed, cannot overwrite.' - end - Next Operation - end else - ErrorMessage = 'Error in ':Service:' service. Error getting prescribed operations for lot# ' : LotId - end - end else - ErrorMessage = 'Error in ':Service:' service. Null LotID passed into service.' - end - If ErrorMessage NE '' then Error_Services('Add', ErrorMessage) - -end service + ErrorMessage = '' + If LotId NE '' then + LotRec = Database_Services('ReadDataRow', 'LOT', LotId) + LotType = LotRec + ProdId = LotRec + ThisInitialProdOperations = Lot_Services('GetPrescribedOperationsByProdId', ProdId, LotType) + If Error_Services('NoError') AND ThisInitialProdOperations NE '' then + For each ProdOperation in ThisInitialProdOperations using @VM + + ProdOperationRec = Database_Services('ReadDataRow', 'PRODUCT_OPERATION', ProdOperation) + OperationID = ProdOperationRec + OperationSequence = ProdOperationRec + + LotOperationRecID = Rti_Createguid() + If Not(RowExists('LOT_OPERATION', LotOperationRecID)) then + LotOperationRec = '' + LotOperationRec = LotId + LotOperationRec = OperationID + LotOperationRec = OperationSequence + LotOperationRec = False$ + Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationRecId, LotOperationRec) + If Error_Services('HasError') then + ErrorMessage = 'Error Writing Lot Operation Record.' + end + end else + ErrorMessage = 'Lot Operation already existed, cannot overwrite' + end + Next Operation + end else + ErrorMessage = 'Error getting prescribed operations for lot# ' : LotId + end + end else + ErrorMessage = 'Lot ID was null' + end + If ErrorMessage NE '' then + Error_Services('Add', ErrorMessage) + end +end service // Returns a @FM delimited list of operations in sequence Service GetLotOperationSequence(LotId) @@ -604,9 +654,10 @@ end service Service GetLotCurrOperationId(LotId) - StartTick = GetTickCount() - MetricName = 'GetLotCurrOperationId' - ErrorMsg = '' + ErrorMsg = '' + StartTick = GetTickCount() + MetricName = 'GetLotCurrOperationId' + CurrOperation = '' If LotID NE '' then // Get them in sequence first @@ -1022,126 +1073,145 @@ end service Service ConvertLotRecordToJson(LotId, ItemURL, CurrUser, FullObject=BOOLEAN) - - ErrorMessage = '' - JsonString = '' - If FullObject EQ '' then FullObject = True$ - If RowExists('LOT', LotId) then - objJSON = '' - If SRP_JSON(objJSON, 'New', 'Object') then - LotRec = Database_Services('ReadDataRow', 'LOT', LotId) - If Error_Services('NoError') then - If SRP_JSON(objLot, 'New', 'Object') then - SRP_JSON(objLot, 'SetValue', 'LotId', LotId) - SRP_JSON(objLot, 'SetValue', 'Type', LotRec) - SRP_JSON(objLot, 'SetValue', 'ProdId', LotRec) - Begin Case - Case LotRec = 'TW' - ProdName = XLATE('TEST_WAFER_PROD', LotRec, TEST_WAFER_PROD_PART_NAME$, 'X') - Case Otherwise$ - ProdName = '' - End Case - SRP_JSON(objLot, 'SetValue', 'ProdName', ProdName) - SRP_JSON(objLot, 'SetValue', 'OrigWaferQty', LotRec) - SRP_JSON(objLot, 'SetValue', 'WaferQty', LotRec) - SRP_JSON(objLot, 'SetValue', 'VendorPartNo', LotRec) - SRP_JSON(objLot, 'SetValue', 'VendorLotNo', LotRec) - SRP_JSON(objLot, 'SetValue', 'Vendor', LotRec) - CurrOperation = Lot_Services('GetLotCurrOperationId', LotId) - CurrOperation = XLATE('LOT_OPERATION', CurrOperation, LOT_OPERATION_OPERATION_ID$, 'X') - SRP_JSON(objLot, 'SetValue', 'CurrOperation', CurrOperation) - MostRecentEventId = LotRec - MostRecentEventDtmIConv = Xlate('LOT_EVENT', MostRecentEventId, LOT_EVENT_EVENT_DATETIME$, 'X') - MostRecentEventDtmOConv = OConv(MostRecentEventDtmIConv, 'DT') - SRP_JSON(objLot, 'SetValue', 'MostRecentEventDateTime', MostRecentEventDtmOConv) - If FullObject then - // Events Array - EventsArrayJson = '' - If SRP_Json(EventsArrayJson, 'New', 'Array') then - LotEventKeys = Lot_Event_Services('GetLotEventsInSequence', LotId) - for each LotEventKey in LotEventKeys using @FM - objEvent = '' - EventRec = Database_Services('ReadDataRow', 'LOT_EVENT', LotEventKey) - If SRP_Json(objEvent, 'New', 'Object') then - SRP_JSON(objEvent, 'SetValue', 'LotEventId', LotEventKey) - SRP_JSON(objEvent, 'SetValue', 'LotId', EventRec) - SRP_JSON(objEvent, 'SetValue', 'LotEventType', EventRec) - SRP_JSON(objEvent, 'SetValue', 'EventDatetime', OConv(EventRec, 'DT')) - SRP_JSON(objEvent, 'SetValue', 'EventNote', EventRec) - SRP_JSON(objEvent, 'SetValue', 'EquipmentId', EventRec) - SRP_JSON(objEvent, 'SetValue', 'EventReduceWaferQty', EventRec) - SRP_JSON(objEvent, 'SetValue', 'EventBonusWaferQty', EventRec) - SRP_JSON(objEvent, 'SetValue', 'EventBeginWaferQty', EventRec) - SRP_JSON(objEvent, 'SetValue', 'EventEndWaferQty', EventRec) - SRP_JSON(objEvent, 'SetValue', 'EventOperationId', EventRec) - SRP_JSON(objEvent, 'SetValue', 'EventOperatorId', EventRec) - SRP_JSON(objEvent, 'SetValue', 'Sequence', EventRec) - SRP_JSON(EventsArrayJson, 'Add', objEvent) - SRP_JSON(objEvent, 'Release') - end - Next LotEventKey - SRP_JSON(objLot, 'Set', 'LotEvents', EventsArrayJson) - SRP_JSON(EventsArrayJson, 'Release') - end else - ErrorMessage = 'Error Creating Events JSON Array' - end - // Operations Array - OperationsArrayJson = '' - If SRP_Json(OperationsArrayJson, 'New', 'Array') then - LotOperationKeys = Lot_Services('GetLotOperationSequence', LotId) - for each LotOperationKey in LotOperationKeys using @FM - objOperation = '' - OperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationKey) - If SRP_Json(objOperation, 'New', 'Object') then - SRP_JSON(objOperation, 'SetValue', 'LotOperationId', LotOperationKey) - SRP_JSON(objOperation, 'SetValue', 'LotId', OperationRec) - SRP_JSON(objOperation, 'SetValue', 'OperationId', OperationRec) - SRP_JSON(objOperation, 'SetValue', 'DatetimeIn', OConv(OperationRec, 'DT')) - SRP_JSON(objOperation, 'SetValue', 'DatetimeOut', Oconv(OperationRec, 'DT')) - SRP_JSON(objOperation, 'SetValue', 'EquipmentId', OperationRec) - SRP_JSON(objOperation, 'SetValue', 'WaferInQty', OperationRec) - SRP_JSON(objOperation, 'SetValue', 'WaferOutQty', OperationRec) - SRP_JSON(objOperation, 'SetValue', 'OperatorInId', OperationRec) - SRP_JSON(objOperation, 'SetValue', 'OperatorOutId', OperationRec) - SRP_JSON(objOperation, 'SetValue', 'OperationSequence', OperationRec) - SRP_JSON(objOperation, 'SetValue', 'Rework', OperationRec) - SRP_JSON(objOperation, 'SetValue', 'DatetimeStart', OConv(OperationRec, 'DT')) - SRP_JSON(objOperation, 'SetValue', 'DatetimeStop', OConv(OperationRec, 'DT')) - SRP_JSON(OperationsArrayJson, 'Add', objOperation) - SRP_JSON(objOperation, 'Release') - end - - Next LotOperationKey - SRP_JSON(objLot, 'Set', 'LotOperations', OperationsArrayJson) - SRP_JSON(OperationsArrayJson, 'Release') - end else - ErrorMessage = 'Error Creating Operations JSON Array' - end - end - - SRP_JSON(objJSON, 'Set', 'Lot', objLot) - SRP_JSON(objLot, 'Release') - end else - ErrorMessage = 'Error creating new Lot Json Object' - end - end else - ErrorMessage = 'Error reading ':LotId:' from lot table.' - end - JsonString = SRP_JSON(objJSON, 'Stringify', 'Styled') - SRP_JSON(objJSON, 'Release') - end else - ErrorMessage = 'Error creating new Json Object' - end - end else - ErrorMessage = 'Invalid or null lot number passed to routine.' - end - - If ErrorMessage EQ '' then - Response = JsonString - end else - Error_Services('Add', ErrorMessage) - end - + + ErrorMessage = '' + JsonString = '' + If FullObject EQ '' then + FullObject = True$ + end + If RowExists('LOT', LotId) then + objJSON = '' + If SRP_JSON(objJSON, 'New', 'Object') then + LotRec = Database_Services('ReadDataRow', 'LOT', LotId) + If Error_Services('NoError') then + If SRP_JSON(objLot, 'New', 'Object') then + + SRP_JSON(objLot, 'SetValue', 'LotId', LotId) + SRP_JSON(objLot, 'SetValue', 'LegacyLotId', LotRec, 'String') + SRP_JSON(objLot, 'SetValue', 'LegacyLotType', LotRec, 'String') + CanUserModifyLot = Lot_Services('CanUserModifyLot', CurrUser) + SRP_JSON(objLot, 'SetValue', 'CanUserModifyLot', CanUserModifyLot, 'Boolean') + SRP_JSON(objLot, 'SetValue', 'WorkOrderNo', LotRec, 'String') + SRP_JSON(objLot, 'SetValue', 'EpiPartNo', LotRec, 'String') + SRP_JSON(objLot, 'SetValue', 'Type', LotRec) + SRP_JSON(objLot, 'SetValue', 'ProdId', LotRec) + ProdSpecNo = LotRec + SRP_JSON(objLot, 'SetValue', 'ProdSpecNo', ProdSpecNo, 'String') + Begin Case + Case LotRec = 'TW' + ProdName = XLATE('TEST_WAFER_PROD', LotRec, TEST_WAFER_PROD_PART_NAME$, 'X') + Case Otherwise$ + ProdName = '' + End Case + SRP_JSON(objLot, 'SetValue', 'ProdName', ProdName) + SRP_JSON(objLot, 'SetValue', 'OrigWaferQty', LotRec) + SRP_JSON(objLot, 'SetValue', 'WaferQty', LotRec) + SRP_JSON(objLot, 'SetValue', 'VendorPartNo', LotRec) + SRP_JSON(objLot, 'SetValue', 'VendorLotNo', LotRec) + SRP_JSON(objLot, 'SetValue', 'Vendor', LotRec) + CurrLotOperationId = Lot_Services('GetLotCurrOperationId', LotId) + CurrOperation = XLATE('LOT_OPERATION', CurrLotOperationId, LOT_OPERATION_OPERATION_ID$, 'X') + CurrOperationDesc = XLATE('OPERATION', CurrOperation, OPERATION_OPERATION_DESCRIPTION$, 'X') + SRP_JSON(objLot, 'SetValue', 'CurrLotOperationId', CurrLotOperationId) + SRP_JSON(objLot, 'SetValue', 'CurrOperation', CurrOperation) + SRP_JSON(objLot, 'SetValue', 'CurrOperationDesc', CurrOperationDesc, 'String') + MostRecentEventId = LotRec + MostRecentEventDtmIConv = Xlate('LOT_EVENT', MostRecentEventId, LOT_EVENT_EVENT_DATETIME$, 'X') + MostRecentEventDtmOConv = OConv(MostRecentEventDtmIConv, 'DT') + SRP_JSON(objLot, 'SetValue', 'MostRecentEventDateTime', MostRecentEventDtmOConv) + if LotRec NE '' then + ActiveRTFId = Return_To_Fab_Services('GetOpenReturnToFabRecordIdByCassId', LotRec) + end else + ActiveRTFId = Return_To_Fab_Services('GetOpenReturnToFabRecordIdByCassId', LotId) + end + SRP_JSON(objLot, 'SetValue', 'ActiveRTFId', ActiveRTFId, 'String') + If FullObject then + //Events Array + EventsArrayJson = '' + If SRP_Json(EventsArrayJson, 'New', 'Array') then + LotEventKeys = Lot_Event_Services('GetLotEventsInSequence', LotId) + for each LotEventKey in LotEventKeys using @FM + objEvent = '' + EventRec = Database_Services('ReadDataRow', 'LOT_EVENT', LotEventKey) + If SRP_Json(objEvent, 'New', 'Object') then + SRP_JSON(objEvent, 'SetValue', 'LotEventId', LotEventKey) + SRP_JSON(objEvent, 'SetValue', 'LotId', EventRec) + SRP_JSON(objEvent, 'SetValue', 'LotEventType', EventRec) + SRP_JSON(objEvent, 'SetValue', 'EventDatetime', OConv(EventRec, 'DT')) + SRP_JSON(objEvent, 'SetValue', 'EventNote', EventRec) + SRP_JSON(objEvent, 'SetValue', 'EquipmentId', EventRec) + SRP_JSON(objEvent, 'SetValue', 'EventReduceWaferQty', EventRec) + SRP_JSON(objEvent, 'SetValue', 'EventBonusWaferQty', EventRec) + SRP_JSON(objEvent, 'SetValue', 'EventBeginWaferQty', EventRec) + SRP_JSON(objEvent, 'SetValue', 'EventEndWaferQty', EventRec) + SRP_JSON(objEvent, 'SetValue', 'EventOperationId', EventRec) + SRP_JSON(objEvent, 'SetValue', 'EventOperatorId', EventRec) + SRP_JSON(objEvent, 'SetValue', 'Sequence', EventRec) + SRP_JSON(EventsArrayJson, 'Add', objEvent) + SRP_JSON(objEvent, 'Release') + end + Next LotEventKey + SRP_JSON(objLot, 'Set', 'LotEvents', EventsArrayJson) + SRP_JSON(EventsArrayJson, 'Release') + end else + ErrorMessage = 'Error Creating Events JSON Array' + end + OperationsArrayJson = '' + If SRP_Json(OperationsArrayJson, 'New', 'Array') then + LotOperationKeys = Lot_Services('GetLotOperationSequence', LotId) + for each LotOperationKey in LotOperationKeys using @FM + ThisLotOperationJsonString = Lot_Operation_Services('ConvertRecordToJson', LotOperationKey) + If SRP_Json(objLotOperation, 'PARSE', ThisLotOperationJsonString) EQ '' then + SRP_Json(OperationsArrayJson, 'Add', objLotOperation) + SRP_Json(objLotOperation, 'Release') + end + Next LotOperationKey + SRP_JSON(objLot, 'Set', 'LotOperations', OperationsArrayJson) + SRP_JSON(OperationsArrayJson, 'Release') + Recipes = PSN_Services('GetAllMetrologyRecipes', ProdSpecNo, True$, True$, True$, True$) + //Add in all lot recipe parameters + If SRP_JSON(objRecipes, 'New', 'Array') then + for each Recipe in Recipes using @FM + //ToolClass : @VM : Recipe : @VM : Stage + ToolClass = Recipe<1,1> + RecipeName = Recipe<1,2> + Stage = Recipe<1,3> + If SRP_JSON(objRecipe, 'New', 'Object') then + SRP_JSON(objRecipe, 'SetValue', 'ToolClass', ToolClass, 'String') + SRP_JSON(objRecipe, 'SetValue', 'RecipeName', RecipeName, 'String') + SRP_JSON(objRecipe, 'SetValue', 'StageName', Stage, 'String') + SRP_JSON(objRecipes, 'Add', objRecipe) + SRP_JSON(objRecipe, 'Release') + end + Next Recipe + SRP_JSON(objLot, 'Set', 'AllRecipes', objRecipes) + SRP_JSON(objRecipes, 'Release') + end + end else + ErrorMessage = 'Error Creating Operations JSON Array' + end + end + SRP_JSON(objJSON, 'Set', 'Lot', objLot) + SRP_JSON(objLot, 'Release') + end else + ErrorMessage = 'Error creating new Lot Json Object' + end + end else + ErrorMessage = 'Error reading ':LotId:' from lot table.' + end + JsonString = SRP_JSON(objJSON, 'Stringify', 'Styled') + SRP_JSON(objJSON, 'Release') + end else + ErrorMessage = 'Error creating new Json Object' + end + end else + ErrorMessage = 'Invalid or null lot number passed to routine.' + end + If ErrorMessage NE '' then + Error_Services('Add', ErrorMessage) + end + Response = JsonString + end service @@ -1339,7 +1409,7 @@ Service ReduceLotWaferCount(LotId, ReductionQty, OperatorId) // Write Lot Event Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'REDUCE_WAFER_QTY', 'Reduced wafer count by ' : ReductionQty, '', OperatorId, False$, '') if LotNewWfrQty EQ 0 AND LotType EQ 'TW' then - ServiceParms = 'AutoCloseTestWaferLot' : SD$ : LotId : SD$ : 'SYSTEM' + ServiceParms = 'AutoCloseTestWaferLot' : @VM : LotId : @VM : 'SYSTEM' Service_Services('PostProcedure', 'LOT_SERVICES', ServiceParms) If Error_Services('HasError') then Recipients = Xlate('NOTIFICATION', 'FI_SUPPORT', NOTIFICATION_USER_ID$, 'X') @@ -1509,12 +1579,38 @@ Service CreateNewVoidedLotRecord(LotId, LegacyLotId, LotType=LOT_TYPES, Username EndTick = GetTickCount() Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick) + If ErrorMessage NE '' then Error_Services('Add', ErrorMessage) end service +Service CanUserModifyLot(UserId) + + Begin Case + + Case MemberOf(UserId, 'OI_ADMIN') + Response = true$ + Case MemberOf(UserId, 'ENGINEERING') + Response = true$ + Case MemberOf(UserId, 'ENG_TECH') + Response = true$ + Case MemberOf(UserId, 'SUPERVISOR') + Response = true$ + Case MemberOf(UserId, 'LEAD') + Response = true$ + Case UserId EQ 'SYSTEM' + Response = true$ + Case Otherwise$ + Response = false$ + + End Case + +end service + //---------------------------------------------------------------------------------------------------------------------- // Internal GoSubs //---------------------------------------------------------------------------------------------------------------------- + + diff --git a/LSL2/STPROC/MATERIALS_API.txt b/LSL2/STPROC/MATERIALS_API.txt index 23b0194..ad46701 100644 --- a/LSL2/STPROC/MATERIALS_API.txt +++ b/LSL2/STPROC/MATERIALS_API.txt @@ -132,4 +132,3 @@ CreateHALItem: end return - diff --git a/LSL2/STPROC/METROLOGY_SERVICES.txt b/LSL2/STPROC/METROLOGY_SERVICES.txt index 6732854..1acefef 100644 --- a/LSL2/STPROC/METROLOGY_SERVICES.txt +++ b/LSL2/STPROC/METROLOGY_SERVICES.txt @@ -10,6 +10,19 @@ Function Metrology_Services(@Service, @Params) Notes : The generic parameters should contain all the necessary information to process the services. Often this will be information like the data Record and Key ID. + + Surface Scan Tool Types: + Tencor + SP1 + + Thickness tool types: + Biorad + Stratus + + Resistivity (HgCV) Tool Types: + CDE + 4PP + SRP Parameters : Service [in] -- Name of the service being requested @@ -70,7 +83,7 @@ $Insert RLIST_EQUATES $Insert WM_OUT_EQUATES $Insert IQS_VIOL_DATA_EQUATES -Common /MetrologyServices/ MachineType@, RDSNo@ +Common /MetrologyServices/ MachineType@, LegacyLotId@ Equ RETRY_ATTEMPTS$ TO 3 Equ MINUTES_UNTIL_RETRY$ TO 3 @@ -93,12 +106,12 @@ Equ Comma$ to ',' Declare subroutine SRP_Stopwatch, Error_Services, obj_Tables, Metrology_Services, obj_RDS_Test, SRP_JSON Declare subroutine RTI_Set_Debugger, Database_Services, Btree.Extract, Set_Status, QA_Services, obj_Notes Declare subroutine Logging_Services, SRP_Send_Mail, SRP_Run_Command, PM_Services, Httpclient_Services -Declare subroutine Tool_Services, Mona_Services, Reactor_Services +Declare subroutine Tool_Services, Mona_Services, Reactor_Services, Met_Test_Services, Met_Test_Services Declare function SRP_Sort_Array, Metrology_Services, obj_RDS_Test, obj_Test_Point_Map, Database_Services, UCase Declare function Work_Order_Services, SRP_JSON, Logging_Services, Environment_Services, SRP_Trim, Min, Max Declare function QA_Services, SRP_Join_Arrays, Get_Status, Obj_Clean_Insp, Datetime, SRP_Datetime Declare function Httpclient_Services, PM_Services, Signature_Services, SRP_Array, Math_Services -Declare function Tool_Class_Services, obj_wo_mat +Declare function Tool_Class_Services, obj_Wo_Mat, Met_Test_Services, Lot_Services Declare function SRP_String LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Metrology' @@ -163,6 +176,12 @@ end Return Response else '' +//---------------------------------------------------------------------------------------------------------------------- +// Service Parameter Options +//---------------------------------------------------------------------------------------------------------------------- +Options MACHINE_TYPES = 'Tencor', 'HgCV', 'CDE', 'Biorad', 'Stratus', 'SP1', 'SPV', 'SRP' + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Services //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -387,7 +406,7 @@ end service // // Looks for available Metrology files that are ready to be imported into the MES system. //---------------------------------------------------------------------------------------------------------------------- -Service ImportMetrologyFiles(Machine) +Service ImportMetrologyFiles(Machine=MACHINE_TYPES) If Machine NE '' then hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') @@ -743,7 +762,7 @@ Service ImportStratusData(RunData, ResourceID, PSN) ThickAvg = RunData<12> Positions = '' DataPoints = '' - + ToolClass = Xlate('TOOL', Tool, 'CLASS', 'X') Loop Position = Trim(RunData) DataPoint = Trim(RunData) @@ -765,20 +784,72 @@ Service ImportStratusData(RunData, ResourceID, PSN) Begin Case // Check for WM_OUT first because a work order key may also be an RDS key. Case RowExists('WM_OUT', Cassette) - WorkOrderNo = Field(Cassette, '*', 1) - CassNo = Field(Cassette, '*', 3) - RDSNo@ = Cassette ; // This is used for logging purposes. - IsEpiPro = true$ + WorkOrderNo = Field(Cassette, '*', 1) + CassNo = Field(Cassette, '*', 3) + LegacyLotId@ = Cassette + IsEpiPro = True$ + LegacyLotType = 'WM_OUT' Case RowExists('RDS', RDSNo) - WorkOrderNo = Xlate('RDS', RDSNo, 'WO', 'X') - CassNo = Xlate('RDS', RDSNo, 'CASS_NO', 'X') - RDSNo@ = RDSNo ; // This is used for logging purposes. + WorkOrderNo = Xlate('RDS', RDSNo, 'WO', 'X') + CassNo = Xlate('RDS', RDSNo, 'CASS_NO', 'X') + LegacyLotId@ = RDSNo + LegacyLotType = 'RDS' Case Otherwise$ Error_Services('Add', 'Unrecognized cassette ID ':Cassette:'.') End Case If Error_Services('NoError') then - + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId@, LegacyLotType) + If LotId NE '' then + If DCount(LotId, @VM) EQ 1 then + // Import into new metrology data structures + If Datapoints NE '' then + Done = False$ + For each DataPoint in DataPoints using @VM setting vPos + Slot = Positions<0, vPos> + MetTestId = Met_Test_Services('CreateMetTest', LotId, LegacyLotId@, ToolClass, Recipe) + If Error_Services('NoError') then + Met_Test_Services('SetPropsAndLimits', MetTestId) + If Error_Services('HasError') then + // Failed to set property names and limits based on input data from metrology file. Log this and continue importing data. + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Error_Services('Clear') + end + Met_Test_Services('SetMetTestTool', MetTestId, Tool) + If Error_Services('NoError') then + Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp) + If Error_Services('NoError') then + Met_Test_Services('SetMetTestSlot', MetTestId, Slot) + If Error_Services('NoError') then + Met_Test_Services('AddMetTestData', MetTestId, '', DataPoint) + If Error_Services('HasError') then + Done = True$ + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + Next DataPoint + end else + ErrorMsg = 'Error in ':Service:' service. No DataPoints to import.' + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end else + Swap @VM with ',' in LotId + ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end + // Update WO_MAT record StdDev = '' WOMatKey = WorkOrderNo : '*' : CassNo @@ -804,15 +875,15 @@ Service ImportStratusData(RunData, ResourceID, PSN) end Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$) If Error_Services('HasError') then - Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end end else - Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end // Update the WM_OUT record for EpiPro If IsEpiPro then NumVals = 0 - WMORec = Database_Services('ReadDataRow', 'WM_OUT', RDSNo@) + WMORec = Database_Services('ReadDataRow', 'WM_OUT', LegacyLotId@) For each Wafer in Positions using @VM setting dPos If Wafer NE '' then WMORec = DataPoints<0, dPos> @@ -830,9 +901,9 @@ Service ImportStratusData(RunData, ResourceID, PSN) StdDev = Math_Services('GetStdDev', Vals, StdDevType) StdDev = OConv(IConv(StdDev, 'MD3'), 'MD3') end - Database_Services('WriteDataRow', 'WM_OUT', RDSNo@, WMORec, True$, False$, True$) - end - + Database_Services('WriteDataRow', 'WM_OUT', LegacyLotId@, WMORec, True$, False$, True$) + end + // Update WO_MAT_QA record StdDevMax = '' WOMatQAID = WorkOrderNo : '*' : CassNo @@ -882,15 +953,15 @@ Service ImportStratusData(RunData, ResourceID, PSN) Next Profile Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$) If Error_Services('NoError') then - Metrology_Services('LogResults', RDSNo@, Machine, 'UID000', Service : ' : Success.') + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID000', Service : ' : Success.') end else - Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end end else - Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end end else - Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end end service @@ -1034,32 +1105,82 @@ Service ImportBioRadData(RunData, ResourceID, IsViewerFile, PSN, FileName) RawDataPoints = DataPoints DataPoints = Iconv(DataPoints, 'MD' : Decimals) - Swap ' AM' with 'AM' in Timestamp - Swap ' PM' with 'PM' in Timestamp - Timestamp = IConv(Timestamp,'DT') - RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer - NumDataPoints = DCount(DataPoints, @VM) - RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) - If Error_Services('NoError') then - RDSTestKeyIDs = RDSLayerRec - Found = False$ - If RDSTestKeyIDs NE '' then - For Each RDSTestKeyID in RDSTestKeyIDs using @VM setting mkPos - RDSTestRec = Database_Services('ReadDataRow', 'RDS_TEST', RDSTestKeyID) - If Error_Services('NoError') then - RDSTestZoneID = RDSTestRec - // First test - Look for a Zone ID match. - If (RDSTestZoneID EQ RunDataZone) then - // A match has been found. No need to continue searching. - Found = True$ + Swap ' AM' with 'AM' in Timestamp + Swap ' PM' with 'PM' in Timestamp + Timestamp = IConv(Timestamp,'DT') + + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS') + If LotId NE '' then + If DCount(LotId, @VM) EQ 1 then + // Import into new metrology data structures + ToolId = Field(Filename, ' ', 2, 1) + ToolClass = Xlate('TOOL', ToolId, 'CLASS', 'X') + MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, ToolClass, ScanRecipe, '', RunDataLayer, RunDataZone, '') + If Error_Services('NoError') then + Met_Test_Services('SetPropsAndLimits', MetTestId) + If Error_Services('HasError') then + // Failed to set property names and limits based on input data from metrology file. Log this and continue importing data. + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Error_Services('Clear') + end + Met_Test_Services('SetMetTestTool', MetTestId, ToolId) + If Error_Services('NoError') then + Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp) + If Error_Services('NoError') then + If RawDataPoints NE '' then + Done = False$ + For each DataPoint in RawDataPoints using @VM setting vPos + Position = Positions<0, vPos> + Met_Test_Services('AddMetTestData', MetTestId, Position, DataPoint) + If Error_Services('HasError') then + Done = True$ + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + Until Done + Next DataPoint + end else + ErrorMsg = 'Error in ':Service:' service. No DataPoints to import.' + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Swap @VM with ',' in LotId + ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end + + RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer + NumDataPoints = DCount(DataPoints, @VM) + RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) + If Error_Services('NoError') then + RDSTestKeyIDs = RDSLayerRec + Found = False$ + If RDSTestKeyIDs NE '' then + For Each RDSTestKeyID in RDSTestKeyIDs using @VM setting mkPos + RDSTestRec = Database_Services('ReadDataRow', 'RDS_TEST', RDSTestKeyID) + If Error_Services('NoError') then + RDSTestZoneID = RDSTestRec + // First test - Look for a Zone ID match. + If (RDSTestZoneID EQ RunDataZone) then + // A match has been found. No need to continue searching. + Found = True$ + end end - end - Until Found - Next RDSTestKeyID - end else - Error_Services('Add', 'Unable to obtain a valid Metrology Test Key ID.') - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end + Until Found + Next RDSTestKeyID + end else + Error_Services('Add', 'Unable to obtain a valid Metrology Test Key ID.') + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end // If not found this is because there was no zone. However, if this is not EpiPro, this is still a valid // test so set the found flag to true. @@ -1255,7 +1376,6 @@ Service ImportBioRadData(RunData, ResourceID, IsViewerFile, PSN, FileName) end service - Service ImportCDEQualData(RunData, ResourceID, PSN) Machine = 'CDE' @@ -1288,7 +1408,6 @@ Service ImportCDEQualData(RunData, ResourceID, PSN) end service - Service ImportCDEData(RunData, ResourceID, IsViewerFile, PSN) Machine = 'CDE' @@ -1377,33 +1496,84 @@ Service ImportCDEData(RunData, ResourceID, IsViewerFile, PSN) DataPoints[-1, 1] = '' ; // Strip final @VM DataPoints = Iconv(DataPoints, 'MD' : Decimals) - Swap ' AM' with 'AM' in Timestamp - Swap ' PM' with 'PM' in Timestamp - Timestamp = IConv(Timestamp,'DT') - - RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer - NumDataPoints = DCount(DataPoints, @VM) - RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) - If Error_Services('NoError') then - RDSTestKeyIDs = RDSLayerRec - Found = False$ - If RDSTestKeyIDs NE '' then - For Each RDSTestKeyID in RDSTestKeyIDs using @VM setting mkPos - RDSTestRec = Database_Services('ReadDataRow', 'RDS_TEST', RDSTestKeyID) - If Error_Services('NoError') then - RDSTestZoneID = RDSTestRec - // First test - Look for a Zone ID match. - If (RDSTestZoneID EQ RunDataZone) then - // A match has been found. No need to continue searching. - Found = True$ + Swap ' AM' with 'AM' in Timestamp + Swap ' PM' with 'PM' in Timestamp + Timestamp = IConv(Timestamp,'DT') + + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS') + If LotId NE '' then + If DCount(LotId, @VM) EQ 1 then + // Import into new metrology data structures + ToolRecipe = Trim(Field(ScanRecipe, '\', 1, 1)) + ToolPattern = Trim(Field(ScanRecipe, '\', 2, 1)) + ToolClass = Xlate('TOOL', ToolId, 'CLASS', 'X') + MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, ToolClass, ToolRecipe, ToolPattern, RunDataLayer, RunDataZone) + If Error_Services('NoError') then + Met_Test_Services('SetPropsAndLimits', MetTestId) + If Error_Services('HasError') then + // Failed to set property names and limits based on input data from metrology file. Log this and continue importing data. + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Error_Services('Clear') + end + Met_Test_Services('SetMetTestTool', MetTestId, ToolId) + If Error_Services('NoError') then + Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp) + If Error_Services('NoError') then + If RawDatapoints NE '' then + Done = False$ + TempDataPoints = OConv(IConv(RawDatapoints, 'MD':Decimals), 'MD':Decimals) + For each DataPoint in TempDataPoints using @VM setting vPos + Position = Positions<0, vPos> + Met_Test_Services('AddMetTestData', MetTestId, Position, DataPoint) + If Error_Services('HasError') then + Done = True$ + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + Until Done + Next DataPoint + end else + ErrorMsg = 'Error in ':Service:' service. No DataPoints to import.' + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Swap @VM with ',' in LotId + ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end + + RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer + NumDataPoints = DCount(DataPoints, @VM) + RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) + If Error_Services('NoError') then + RDSTestKeyIDs = RDSLayerRec + Found = False$ + If RDSTestKeyIDs NE '' then + For Each RDSTestKeyID in RDSTestKeyIDs using @VM setting mkPos + RDSTestRec = Database_Services('ReadDataRow', 'RDS_TEST', RDSTestKeyID) + If Error_Services('NoError') then + RDSTestZoneID = RDSTestRec + // First test - Look for a Zone ID match. + If (RDSTestZoneID EQ RunDataZone) then + // A match has been found. No need to continue searching. + Found = True$ + end end - end - Until Found - Next RDSTestKeyID - end else - Error_Services('Add', 'Unable to obtain a valid Metrology Test Key ID.') - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end + Until Found + Next RDSTestKeyID + end else + Error_Services('Add', 'Unable to obtain a valid Metrology Test Key ID.') + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end // If not found this is because there was no zone. However, if this is not EpiPro, this is still a valid // test so set the found flag to true. @@ -1549,7 +1719,7 @@ Service ImportHgCVData(RunData, ResourceID, IsViewerFile, PSN) DataIndex = RDS_TEST_READ_HGCV1_RES$ DTMIndex = RDS_TEST_TEST_RUN_HGCV_DTM$ Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : ' : 'Beginning ImportHgCVData') - RDSNo@ = RDSKeyID + LegacyLotId@ = RDSKeyID RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID) If Error_Services('NoError') then WorkOrderNo = RDSRec @@ -1601,147 +1771,195 @@ Service ImportHgCVData(RunData, ResourceID, IsViewerFile, PSN) end end - If Error_Services('NoError') then - Position = '' - Positions = '' - DataPoints = '' - HgCVDataPoints = '' - Loop - Position = Trim(RunData) - HgCVDataPoint = Trim(RunData) - Until Position EQ '' - Positions := Position : @VM - HgCVDataPoints := HgCVDataPoint : @VM - FieldPos += FieldPosIncrement - Repeat - Positions[-1, 1] = '' ; // Strip final @VM - HgCVDataPoints[-1, 1] = '' ; // Strip final @VM - - HgCVDataPoints = Iconv(HgCVDataPoints, 'MD' : Decimals) - - Swap ' AM' with 'AM' in Timestamp - Swap ' PM' with 'PM' in Timestamp - Timestamp = IConv(Timestamp,'DT') - - RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer - NumDataPoints = DCount(HgCVDataPoints, @VM) - RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) If Error_Services('NoError') then - RDSTestKeyIDs = RDSLayerRec - Found = False$ - If RDSTestKeyIDs NE '' then - For Each RDSTestKeyID in RDSTestKeyIDs using @VM setting mkPos - RDSTestRec = Database_Services('ReadDataRow', 'RDS_TEST', RDSTestKeyID) - If Error_Services('NoError') then - RDSTestZoneID = RDSTestRec - // Determine if this is Hg Concentration Resistivity. - IsHgCvCRes = RDSTestRec _EQC 'HGCV' - // First test - Look for a Zone ID match. - If (RDSTestZoneID EQ RunDataZone) then - // A match has been found. No need to continue searching. - Found = True$ + Position = '' + Positions = '' + DataPoints = '' + HgCVDataPoints = '' + PhaseDataPoints = '' + Loop + Position = Trim(RunData) + HgCVDataPoint = Trim(RunData) + PhaseDataPoint = Trim(RunData) + Until Position EQ '' + Positions := Position : @VM + HgCVDataPoints := HgCVDataPoint : @VM + PhaseDataPoints := PhaseDataPoint : @VM + FieldPos += FieldPosIncrement + Repeat + Positions[-1, 1] = '' ; // Strip final @VM + HgCVDataPoints[-1, 1] = '' ; // Strip final @VM + PhaseDataPoints[-1, 1] = '' ; // Strip final @VM + RawDataPoints = HgCVDataPoints + RawPhaseDataPoints = PhaseDataPoints + HgCVDataPoints = Iconv(HgCVDataPoints, 'MD' : Decimals) + PhaseDataPoints = Iconv(PhaseDataPoints, 'MD' : Decimals) + + Swap ' AM' with 'AM' in Timestamp + Swap ' PM' with 'PM' in Timestamp + Timestamp = IConv(Timestamp,'DT') + + // Recipe field 21 + // Pattern field 24 + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS') + If LotId NE '' then + If DCount(LotId, @VM) EQ 1 then + // Import into new metrology data structures + ToolId = RunData<2> + ToolRecipe = RunData<21> + ToolPattern = RunData<24> + ToolClass = Xlate('TOOL', ToolId, 'CLASS', 'X') + MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, ToolClass, ToolRecipe, ToolPattern, RunDataLayer, RunDataZone) + If Error_Services('NoError') then + Met_Test_Services('SetPropsAndLimits', MetTestId) + If Error_Services('HasError') then + // Failed to set property names and limits based on input data from metrology file. Log this and continue importing data. + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Error_Services('Clear') + end + Met_Test_Services('SetMetTestTool', MetTestId, ToolId) + If Error_Services('NoError') then + Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp) + If Error_Services('NoError') then + If RawDataPoints NE '' then + Done = False$ + For each DataPoint in RawDataPoints using @VM setting vPos + Position = Positions<0, vPos> + PhaseDataPoint = RawPhaseDataPoints<0, vPos> + Met_Test_Services('AddMetTestData', MetTestId, Position, DataPoint, PhaseDataPoint) + If Error_Services('HasError') then + Done = True$ + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + Until Done + Next DataPoint + end else + ErrorMsg = 'Error in ':Service:' service. No DataPoints to import.' + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Swap @VM with ',' in LotId + ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end + + RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer + NumDataPoints = DCount(HgCVDataPoints, @VM) + RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) + If Error_Services('NoError') then + RDSTestKeyIDs = RDSLayerRec + Found = False$ + If RDSTestKeyIDs NE '' then + For Each RDSTestKeyID in RDSTestKeyIDs using @VM setting mkPos + RDSTestRec = Database_Services('ReadDataRow', 'RDS_TEST', RDSTestKeyID) + If Error_Services('NoError') then + RDSTestZoneID = RDSTestRec + // Determine if this is Hg Concentration Resistivity. + IsHgCvCRes = RDSTestRec _EQC 'HGCV' + // First test - Look for a Zone ID match. + If (RDSTestZoneID EQ RunDataZone) then + // A match has been found. No need to continue searching. + Found = True$ + end end - end - Until Found - Next RDSTestKeyID - If (Found EQ True$) then - // Only continue checking if there are data points. Otherwise, there is no data by which - // the code can calculate values to store. - If NumDataPoints GT 0 then - // Second test - If HgCv Res, dig deeper to see if this is a possible CRES entry.. - If IsHgCvCRes then - WOMatQAID = WorkOrderNo : '*' : CassNo - WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatQAID) - If Error_Services('NoError') then - Locate 'CRES' in WOMatQARec using @VM setting vPos then - Stage = WOMatQARec - RequireUnload = False$ - IF (WOMatQARec EQ '' OR IsViewerFile) then - PhaseDataPoints = '' - Positions = '' - Position = '' - FieldPos = 53 - Loop - Position = Trim(RunData) - PhaseDataPoint = Trim(RunData) - Until Position EQ '' - Positions := Position : @VM - PhaseDataPoints := PhaseDataPoint : @VM - FieldPos += FieldPosIncrement - Repeat - Positions[-1, 1] = '' ; // Strip final @VM - PhaseDataPoints[-1, 1] = '' ; // Strip final @VM - PhaseDataPoints = Iconv(PhaseDataPoints, 'MD' : Decimals) - DataPoints = HgCVDataPoints - * GoSub CalculateQAData - Response = QA_Services('CalculateHgCVData', Datapoints) - HgCVMin = Response<0, 2> - HgCVMax = Response<0, 3> - HgCVAvg = Response<0, 1> - HgCVEdgeMean = Response<0, 4> - HgCVRangePct = Response<0, 5> - EdgeMean4mm = Response<0, 6> - Avg9Point = Response<0, 7> - EdgeMean10mm = Response<0, 8> - ResStdDev = Response<0, 9> + Until Found + Next RDSTestKeyID + If (Found EQ True$) then + // Only continue checking if there are data points. Otherwise, there is no data by which + // the code can calculate values to store. + If NumDataPoints GT 0 then + // Second test - If HgCv Res, dig deeper to see if this is a possible CRES entry.. + If IsHgCvCRes then + WOMatQAID = WorkOrderNo : '*' : CassNo + WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatQAID) + If Error_Services('NoError') then + Locate 'CRES' in WOMatQARec using @VM setting vPos then + Stage = WOMatQARec + RequireUnload = False$ + IF (WOMatQARec EQ '' OR IsViewerFile) then + PhaseDataPoints = '' + Positions = '' + Position = '' + FieldPos = 53 + Loop + Position = Trim(RunData) + PhaseDataPoint = Trim(RunData) + Until Position EQ '' + Positions := Position : @VM + PhaseDataPoints := PhaseDataPoint : @VM + FieldPos += FieldPosIncrement + Repeat + Positions[-1, 1] = '' ; // Strip final @VM + PhaseDataPoints[-1, 1] = '' ; // Strip final @VM + PhaseDataPoints = Iconv(PhaseDataPoints, 'MD' : Decimals) + DataPoints = HgCVDataPoints + Response = QA_Services('CalculateHgCVData', Datapoints) + HgCVMin = Response<0, 2> + HgCVMax = Response<0, 3> + HgCVAvg = Response<0, 1> + HgCVEdgeMean = Response<0, 4> + HgCVRangePct = Response<0, 5> + EdgeMean4mm = Response<0, 6> + Avg9Point = Response<0, 7> + EdgeMean10mm = Response<0, 8> + ResStdDev = Response<0, 9> - DataPoints = PhaseDataPoints - Response = QA_Services('CalculateHgCVData', Datapoints) - * GoSub CalculateQAData - PhaseMin = Response<0, 2> - PhaseMax = Response<0, 3> - PhaseAvg = Response<0, 1> - PhaseEdgeMean = Response<0, 4> - PhaseRangePct = Response<0, 5> - // Format data. Round to significant digits. - * HgCVAvg = Oconv(Iconv(Oconv(HgCVAvg, 'MD3L'), 'MD3L'), 'MD3L') - * PhaseAvg = Oconv(Iconv(Oconv(PhaseAvg, 'MD3L'), 'MD3L'), 'MD3L') - * HgCVMin = Oconv(Iconv(Oconv(HgCVMin, 'MD3L'), 'MD3L'), 'MD3L') - * HgCVMax = Oconv(Iconv(Oconv(HgCVMax, 'MD3L'), 'MD3L'), 'MD3L') - * PhaseMin = Oconv(Iconv(Oconv(PhaseMin, 'MD3L'), 'MD3L'), 'MD3L') - * PhaseMax = Oconv(Iconv(Oconv(PhaseMax, 'MD3L'), 'MD3L'), 'MD3L') - * HgCVEdgeMean = OConv(IConv(HgCVEdgeMean, 'MD3L'), 'MD3L') - * PhaseEdgeMean = Oconv(IConv(PhaseEdgeMean, 'MD3L'), 'MD3L') - * HgCVRangePct = Oconv(Iconv(HgCVRangePct, 'MD3L'), 'MD3L') - * PhaseRangePct = Oconv(Iconv(PhaseRangePct, 'MD3L'), 'MD3L') - WOMatQARec = HgCVAvg : @SVM : PhaseAvg - WOMatQARec = HgCVMin : @SVM : PhaseMin - WOMatQARec = HgCVMax : @SVM : PhaseMax - WOMatQARec = HgCVRangePct : @SVM : PhaseRangePct - WOMatQARec = HgCVEdgeMean : @SVM : PhaseEdgeMean - SpecMin = WOMatQARec - SpecMax = WOMatQARec - SpecPhaseMin = WOMatQARec - If SpecPhaseMin EQ '' then - // Phase Min Spec was not added to WO_MAT_QA record when it should have been. - // This bug should be fixed now, but in the meantime current records in production - // may not have a phase min specification value. We need to add it here. - djs - 10/15/18 - PSN = Xlate('RDS', RDSKeyID, 'PROD_SPEC_ID', 'X') - If PSN NE '' then - PRSStageKey = PSN:'*UNLOAD' - Database_Services('ActivateRecord', 'PRS_STAGE', PRSStageKey) - MetProps = {MET_PROP} - Locate 'CRES' in MetProps using @VM setting PropPos then - SpecPhaseMinCol = {MET_PHASE_MIN} - SpecPhaseMin = SpecPhaseMinCol<1, PropPos> - WOMatQARec = SpecPhaseMin - end - end - end - CriticalPoints = '1,2,5,6,9' - // Store data points for HgCV Data Table Project -------------------------------------------------------------- - For Index = 1 to NumDataPoints - CriticalPoint = Index(CriticalPoints, Index, 1) - HgCVData = Oconv(Iconv(Oconv(HgCVDataPoints<0,Index>, 'MD3L'), 'MD3L'), 'MD3L') - PhaseData = Oconv(Iconv(Oconv(PhaseDataPoints<0,Index>, 'MD3L'), 'MD3L'), 'MD3L') - If ( (HgCVData LT SpecMin) OR (HgCVData GT SpecMax) OR (PhaseData LT SpecPhaseMin) ) and CriticalPoint then - // Data point out of spec - WOMatQARec = True$ - end - DataRow = HgCVData : @TM : PhaseData - WOMatQARec = DataRow - Next Index - // ------------------------------------------------------------------------------------------------------------ + DataPoints = PhaseDataPoints + Response = QA_Services('CalculateHgCVData', Datapoints) + PhaseMin = Response<0, 2> + PhaseMax = Response<0, 3> + PhaseAvg = Response<0, 1> + PhaseEdgeMean = Response<0, 4> + PhaseRangePct = Response<0, 5> + // Format data. Round to significant digits. + WOMatQARec = HgCVAvg : @SVM : PhaseAvg + WOMatQARec = HgCVMin : @SVM : PhaseMin + WOMatQARec = HgCVMax : @SVM : PhaseMax + WOMatQARec = HgCVRangePct : @SVM : PhaseRangePct + WOMatQARec = HgCVEdgeMean : @SVM : PhaseEdgeMean + SpecMin = WOMatQARec + SpecMax = WOMatQARec + SpecPhaseMin = WOMatQARec + If SpecPhaseMin EQ '' then + // Phase Min Spec was not added to WO_MAT_QA record when it should have been. + // This bug should be fixed now, but in the meantime current records in production + // may not have a phase min specification value. We need to add it here. - djs - 10/15/18 + PSN = Xlate('RDS', RDSKeyID, 'PROD_SPEC_ID', 'X') + If PSN NE '' then + PRSStageKey = PSN:'*UNLOAD' + Database_Services('ActivateRecord', 'PRS_STAGE', PRSStageKey) + MetProps = {MET_PROP} + Locate 'CRES' in MetProps using @VM setting PropPos then + SpecPhaseMinCol = {MET_PHASE_MIN} + SpecPhaseMin = SpecPhaseMinCol<1, PropPos> + WOMatQARec = SpecPhaseMin + end + end + end + CriticalPoints = '1,2,5,6,9' + // Store data points for HgCV Data Table Project -------------------------------------------------------------- + For Index = 1 to NumDataPoints + CriticalPoint = Index(CriticalPoints, Index, 1) + HgCVData = Oconv(Iconv(Oconv(HgCVDataPoints<0,Index>, 'MD3L'), 'MD3L'), 'MD3L') + PhaseData = Oconv(Iconv(Oconv(PhaseDataPoints<0,Index>, 'MD3L'), 'MD3L'), 'MD3L') + If ( (HgCVData LT SpecMin) OR (HgCVData GT SpecMax) OR (PhaseData LT SpecPhaseMin) ) and CriticalPoint then + // Data point out of spec + WOMatQARec = True$ + end + DataRow = HgCVData : @TM : PhaseData + WOMatQARec = DataRow + Next Index + // ------------------------------------------------------------------------------------------------------------ // Send data to SPC ------------------------------------------------------------------------------------------- LogPath = Environment_Services('GetSpcFilesharePath') @@ -1853,13 +2071,98 @@ Service ImportTencorData(RunData) SoDMin = RunData<41> ScanTool = RunData<43> Swap '%' with ' ' in ScanTool - RDSNo@ = RDSKeyID + LegacyLotId@ = RDSKeyID Convert @Lower_Case to @Upper_Case in ScanTool Swap ' AM' with 'AM' in Timestamp Swap ' PM' with 'PM' in Timestamp Timestamp = IConv(Timestamp,'DT') + + SODWaferArray = '' + WaferNos = '' + SODVals = '' + SortVals = '' + SODStartTime = Time() + SODWaferArray = QA_Services('GetSODPerWafer', RDSKeyID, ScanRecipe, Timestamp) + SODStopTime = Time() + TimeTaken = SODStopTime - SODStartTime + LogData = '' + LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') + LogData<2> = MachineType@ + LogData<3> = LegacyLotId@ + LogData<4> = 'Time taken to import SOD data: ':TimeTaken:' seconds.' + Logging_Services('AppendLog', objSODPerfLog, LogData, @RM, @FM) + If SODWaferArray NE '' then + WaferNos = SODWaferArray<1> + SODVals = SODWaferArray<2> + SortVals = SODWaferArray<3> + For each WaferNo in WaferNos using @VM + If WaferNo NE '' then QA_Services('PostWaferImageRequest', RDSKeyID, WaferNo, ScanRecipe) + Next Wafer + end + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS') + If LotId NE '' then + If DCount(LotId, @VM) EQ 1 then + // Import into new metrology data structures + MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, '', ScanRecipe) + If Error_Services('NoError') then + Met_Test_Services('SetPropsAndLimits', MetTestId) + If Error_Services('HasError') then + // Failed to set property names and limits based on input data from metrology file. Log this and continue importing data. + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Error_Services('Clear') + end + Met_Test_Services('SetMetTestTool', MetTestId, ScanTool) + If Error_Services('NoError') then + Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp) + If Error_Services('NoError') then + // Add SORT property to Tencor surfscan MET_TEST - 'PASS' or 'FAIL' - no min or max + //Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SORT') + If Error_Services('NoError') then + // Prop 1: SURFACE_SCAN_SUM_OF_DEFECTS_MIN + // Prop 2: SURFACE_SCAN_SUM_OF_DEFECTS_MAX + // Prop 3: SURFACE_SCAN_SUM_OF_DEFECTS_AVG + // Prop 4: SURFACE_SCAN_SUM_OF_DEFECTS (per wafer) + // Prop 5: SURFACE_SCAN_HAZE_AVG + // Prop 6: SURFACE_SCAN_SORT (per wafer) + Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SUM_OF_DEFECTS_MIN') + Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SUM_OF_DEFECTS_MAX') + Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SUM_OF_DEFECTS_AVG') + Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SUM_OF_DEFECTS') + Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_HAZE_AVG') + Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SORT') + Met_Test_Services('AddMetTestData', MetTestId, '', SoDMin, SoDMax, SoDAvg, '', HazeAvg) + If Error_Services('HasError') then + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + For each WaferNo in WaferNos using @VM setting vPos + If WaferNo NE '' then + Met_Test_Services('AddMetTestData', MetTestId, WaferNo, '', '', '', SODVals<0, vPos>, '', SortVals<0, vPos>) + If Error_Services('HasError') then + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end + Next WaferNo + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Swap @VM with ',' in LotId + ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end + If RowExists('RDS', RDSKeyID) then // Try to read the CleanInsp datarow. Use this to identify the RDSKeyID. ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSKeyID) @@ -1893,30 +2196,11 @@ Service ImportTencorData(RunData) NumWfrs = 0 Locate ScanRecipe In SpecRecipeList Using @VM Setting RecipeIndex then // Recipe found in spec list - SpecSampleQty = CleanInspRec - SODWaferArray = '' - SODStartTime = Time() - SODWaferArray = QA_Services('GetSODPerWafer', RDSKeyID, ScanRecipe, Timestamp) - SODStopTime = Time() - TimeTaken = SODStopTime - SODStartTime - LogData = '' - LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') - LogData<2> = MachineType@ - LogData<3> = RDSNo@ - LogData<4> = 'Time taken to import SOD data: ':TimeTaken:' seconds.' - Logging_Services('AppendLog', objSODPerfLog, LogData, @RM, @FM) - If SODWaferArray NE '' then - WaferNos = SODWaferArray<1> - SODVals = SODWaferArray<2> - SortVals = SODWaferArray<3> - For each Wfr in SODVals using @VM setting vPos - NumWfrs += (Wfr NE '') - Next Wfr + If SODWaferArray NE '' then For each WaferNo in WaferNos using @VM If WaferNo NE '' then CleanInspRec = SODVals<1,WaferNo> CleanInspRec = SortVals<1,WaferNo> - QA_Services('PostWaferImageRequest', RDSKeyID, WaferNo, ScanRecipe) end Next Wafer end @@ -1969,7 +2253,7 @@ Service ImportTencorData(RunData) // If statement to gate from production below PostStartTime = Time() if Indexc(ScanRecipe, 'POST', 1) then - //Locate 'POST' in ScanRecipe Using "" setting pPos then + // Locate 'POST' in ScanRecipe Using "" setting pPos then ReactRunRec = Xlate('REACT_RUN',RDSKeyID, '', 'X') WONo = ReactRunRec;//WONo WOStep = ReactRunRec;//WOStep @@ -1978,19 +2262,19 @@ Service ImportTencorData(RunData) PSNo = XLATE('RDS',RDSKeyID,RDS_PROD_SPEC_ID$,'X');//PSNo DefectSpec = Xlate('PRS_STAGE', PSNo : '*LWI', PRS_STAGE_SURF_DEFECTS$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step. HazeSpec = Xlate('PRS_STAGE', PSNo : '*LWI', PRS_STAGE_SURF_HAZE$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step. - //Check if CI was created already(usually during cleans) JRO-9-28 + // Check if CI was created already(usually during cleans) JRO-9-28 CIStages = ReactRunRec Locate 'POST' in CIStages using @VM setting sPos then - //Existing POST CI record found, fetch it. + // Existing POST CI record found, fetch it. CINo = ReactRunRec CleanInspRec = Xlate('CLEAN_INSP', CINo,'','X') IF CleanInspRec NE '' THEN - //Append a value mark to the end of the field so that we can add another set of data + // Append a value mark to the end of the field so that we can add another set of data CleanInspRec = CleanInspRec : @VM END exists = True$ end else - //No Exisiting POST CI record found, Create new CI record + // No Exisiting POST CI record found, Create new CI record exists = False$ oCIParms = '' oCIParms = WONo:@RM @@ -2006,41 +2290,31 @@ Service ImportTencorData(RunData) CleanInspRec = Stage CleanInspRec = RDSKeyID end - CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_RECIPE$, -1, 0, ScanRecipe) - CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_TOOL$, -1, 0, ScanTool) - CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MIN$, -1, 0, SoDMin) - CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MAX$, -1, 0, SoDMax) - SoDAvg = Iconv(SoDAvg, 'MD3') - CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_AVG$, -1, 0, SoDAvg) - HazeAvg = Iconv(HazeAvg, 'MD3') - CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_HAZE_AVG_AVG$, -1, 0, HazeAvg) - CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG$, -1, 0, '') - CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG_DTM$, -1, 0, '') - CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_INSP_TEST_RUN_DTM$, -1, 0, Timestamp) - CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SPEC_SURFSCAN_RECIPE$, -1, 0, ScanRecipe) - CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SPEC_SURF_DEFECTS$, -1, 0, DefectSpec) - //Here I am attempting to create the scan details. - SODWaferArray = '' - SODWaferArray = QA_Services('GetSODPerWafer', RDSKeyID, ScanRecipe, Timestamp) - - If SODWaferArray NE '' then - WaferNos = SODWaferArray<1> - SODVals = SODWaferArray<2> - SortVals = SODWaferArray<3> + CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_RECIPE$, -1, 0, ScanRecipe) + CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_TOOL$, -1, 0, ScanTool) + CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MIN$, -1, 0, SoDMin) + CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MAX$, -1, 0, SoDMax) + SoDAvg = Iconv(SoDAvg, 'MD3') + CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_AVG$, -1, 0, SoDAvg) + HazeAvg = Iconv(HazeAvg, 'MD3') + CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_HAZE_AVG_AVG$, -1, 0, HazeAvg) + CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG$, -1, 0, '') + CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG_DTM$, -1, 0, '') + CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_INSP_TEST_RUN_DTM$, -1, 0, Timestamp) + CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SPEC_SURFSCAN_RECIPE$, -1, 0, ScanRecipe) + CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SPEC_SURF_DEFECTS$, -1, 0, DefectSpec) + + // Here I am attempting to create the scan details. + If SODWaferArray NE '' then NumRecipes = DCount(CleanInspRec, @VM) - NumWfrs = '' - For each Wfr in SODVals using @VM setting vPos - NumWfrs += (Wfr NE '') - Next Wfr For each WaferNo in WaferNos using @VM If WaferNo NE '' then CleanInspRec = SODVals<1,WaferNo> CleanInspRec = SortVals<1,WaferNo> - QA_Services('PostWaferImageRequest', RDSKeyID, WaferNo, ScanRecipe) end Next Wafer - end - if exists Eq False$ then + end + If exists EQ False$ then oCIParms := CleanInspRec ; CINo = obj_Clean_Insp('Create',oCIParms) If Error_Services('NoError') then @@ -2053,7 +2327,7 @@ Service ImportTencorData(RunData) LogData = '' LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') LogData<2> = MachineType@ - LogData<3> = RDSNo@ + LogData<3> = LegacyLotId@ LogData<4> = 'Time taken to import POST data: ':TimeTaken:' seconds.' Logging_Services('AppendLog', objPOSTPerfLog, LogData, @RM, @FM) end else @@ -2062,7 +2336,7 @@ Service ImportTencorData(RunData) ErrorMessage = 'Failed to create CLEAN_INSP record. Error UID002.' end end else - //write to existing CI rec. + // Write to existing CI rec. obj_Tables('WriteRec','CLEAN_INSP':@RM:CINo:@RM:@RM:CleanInspRec) end end else @@ -2117,17 +2391,64 @@ Service ImportSP1Data(RunData) end ScanTool = RunData<43> DCNMM2 = RunData<44> - * Swap '%' with ' ' in ScanTool + // The 4th character can be 0 or %, but needs to be ' ' in OpenInsight ScanTool[4,1] = ' ' Convert @Lower_Case to @Upper_Case in ScanTool Convert @Lower_Case to @Upper_Case in CompareScanRecipe - * Convert ' ' to '' in CompareScanRecipe - + Swap ' AM' with 'AM' in Timestamp Swap ' PM' with 'PM' in Timestamp Timestamp = IConv(Timestamp,'DT') - RDSNo@ = RDSKeyID + + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS') + If LotId NE '' then + If DCount(LotId, @VM) EQ 1 then + // Import into new metrology data structures + MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, '', ScanRecipe) + If Error_Services('NoError') then + Met_Test_Services('SetPropsAndLimits', MetTestId) + If Error_Services('HasError') then + // Failed to set property names and limits based on input data from metrology file. Log this and continue importing data. + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Error_Services('Clear') + end + Met_Test_Services('SetMetTestTool', MetTestId, ScanTool) + If Error_Services('NoError') then + Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp) + If Error_Services('NoError') then + // Prop 1: SURFACE_SCAN_SUM_OF_DEFECTS_MIN + // Prop 2: SURFACE_SCAN_SUM_OF_DEFECTS_MAX + // Prop 3: SURFACE_SCAN_SUM_OF_DEFECTS_AVG + // Prop 4: SURFACE_SCAN_SUM_OF_DEFECTS (per wafer) - Currently not captured for SP1 + // Prop 5: SURFACE_SCAN_HAZE_AVG + Met_Test_Services('RemoveProperty', MetTestId, 'SURFACE_SCAN_SUM_OF_DEFECTS') + If Error_Services('NoError') then + // Set SOD min, SOD max, SOD avg, and Haze Avg + Met_Test_Services('AddMetTestData', MetTestId, '', SoDMin, SoDMax, SoDAvg, '', HazeAvg) + If Error_Services('HasError') then + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Swap @VM with ',' in LotId + ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end + + LegacyLotId@ = RDSKeyID RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID) If Error_Services('NoError') then WorkOrderNo = RDSRec @@ -2519,7 +2840,7 @@ The service does the following actions: 5. Determines the spec slot by reading the WO_MAT_QA record -> SLOT field 6. If the detected RunDataSlot matches the spec slot, writes the datapoint to the WO_MAT_QA record - > RESULT field in the same @VM that the iterator is currently set to. */ -Service ImportBioRadEPPFQAData(RunData, FileName) +Service ImportBioRadEPPFQAData(RunData, Filename) Timestamp = RunData<2> WMOKeyID = RunData<6> @@ -2551,21 +2872,67 @@ Service ImportBioRadEPPFQAData(RunData, FileName) Repeat Positions[-1, 1] = '' ; // Strip final @VM DataPoints[-1, 1] = '' ; // Strip final @VM - + + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', WMOKeyID, 'WM_OUT') + If LotId NE '' then + If DCount(LotId, @VM) EQ 1 then + // Import into new metrology data structures + ToolId = Field(Filename, ' ', 2, 1) + ToolClass = Xlate('TOOL', ToolId, 'CLASS', 'X') + If DataPoints NE '' then + For each DataPoint in DataPoints using @VM setting vPos + Slot = Positions<0, vPos> + MetTestId = Met_Test_Services('CreateMetTest', LotId, WMOKeyID, ToolClass, ScanRecipe, '', RunDataLayer) + If Error_Services('NoError') then + Met_Test_Services('SetPropsAndLimits', MetTestId) + If Error_Services('HasError') then + // Failed to set property names and limits based on input data from metrology file. Log this and continue importing data. + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Error_Services('Clear') + end + Met_Test_Services('SetMetTestTool', MetTestId, ToolId) + If Error_Services('NoError') then + Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp) + If Error_Services('NoError') then + Met_Test_Services('SetMetTestSlot', MetTestId, Slot) + If Error_Services('NoError') then + Met_Test_Services('AddMetTestData', MetTestId, '', DataPoint) + If Error_Services('HasError') then + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + Next DataPoint + end else + ErrorMsg = 'Error in ':Service:' service. No DataPoints to import.' + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end else + Swap @VM with ',' in LotId + ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg) + end + end + If Error_Services('NoError') then - If DataSlotId NE '' then - If Num(DataSlotId) then - // Update the WM_OUT record for EpiPro - WMORec = DataPoints - Database_Services('WriteDataRow', 'WM_OUT', WMOKeyID, WMORec, True$, False$, True$) - end else - Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : DataSlotId ':Quote(DataSlotId):' is not a number!') - end - end else - Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : DataSlotId is null!') + If Error_Services('HasError') then + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end + //Update the WM_OUT record for EpiPro + WMORec = DataPoints + Database_Services('WriteDataRow', 'WM_OUT', WMOKeyID, WMORec, True$, False$, True$) end else - Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end // Update WO_MAT_QA record WOMatQAID = Field(WMOKeyID, '*', 1) : '*' : Field(WMOKeyID, '*', 3) @@ -2608,12 +2975,12 @@ Service ImportBioRadEPPFQAData(RunData, FileName) Next Profile Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$) If Error_Services('NoError') then - Metrology_Services('LogResults', RDSNo@, Machine, 'UID000', Service : ' : Success.') + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID000', Service : ' : Success.') end else - Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end end else - Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end end service @@ -3277,3 +3644,6 @@ LoadRunDataToDatabase: return + + + diff --git a/LSL2/STPROC/METTESTS_API.txt b/LSL2/STPROC/METTESTS_API.txt new file mode 100644 index 0000000..d063d2a --- /dev/null +++ b/LSL2/STPROC/METTESTS_API.txt @@ -0,0 +1,98 @@ +Function Mettests_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Mettests_API + + Description : API logic for the Mettests resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Mettests[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Mettests.POST + - Mettests.ID.PUT + - Mettests.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 05/20/25 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS + +Declare function Met_Test_Services + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API mettests.ID.HEAD +API mettests.ID.GET + + // Return JSON payload containing RDS record details + StatusCode = 200 + GoSub CreateHALItem + +end api + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Internal GoSubs +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +//---------------------------------------------------------------------------------------------------------------------- +// CreateHALItem +// +// Creates a HAL+JSON object based on the OpenInsight data row representation of the scan. +//---------------------------------------------------------------------------------------------------------------------- +CreateHALItem: + + MetTestId = EndpointSegment + MetTestJSON = Met_Test_Services('ConvertRecordToJSON', MetTestId, '', FullEndpointURL) + + If Error_Services('NoError') then + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseBody', MetTestJSON, False$, 'application/hal+json') + If Assigned(Message) then + HTTP_Services('SetResponseStatus', StatusCode, Message) + end else + HTTP_Services('SetResponseStatus', StatusCode) + end + end else + Message = Error_Services('GetMessage') + HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': Message) + end + +return diff --git a/LSL2/STPROC/MET_TEST_ACTIONS.txt b/LSL2/STPROC/MET_TEST_ACTIONS.txt new file mode 100644 index 0000000..c668224 --- /dev/null +++ b/LSL2/STPROC/MET_TEST_ACTIONS.txt @@ -0,0 +1,257 @@ +Function MET_TEST_Actions(Action, CalcColName, FSList, Handle, Name, FMC, Record, Status, OrigRecord, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from Infineon. + + Name : Met_Test_Actions + + Description : Handles calculated columns and MFS calls for the current table. + + Notes : This function uses @ID, @RECORD, and @DICT to make sure {ColumnName} references work correctly. + If called from outside of a calculated column these will need to be set and restored. + + Parameters : + Action [in] -- Name of the action to be taken + CalcColName [in] -- Name of the calculated column that needs to be processed. Normally this should only be + populated when the CalcField action is being used. + FSList [in] -- The list of MFSs and the BFS name for the current file or volume. This is an @SVM + delimited array, with the current MFS name as the first value in the array, and the BFS + name as the last value. Normally set by a calling MFS. + Handle [in] -- The file handle of the file or media map being accessed. Note, this does contain the + entire handle structure that the Basic+ Open statement would provide. Normally set by a + calling MFS. + Name [in] -- The name (key) of the record or file being accessed. Normally set by a calling MFS. + FMC [in] -- Various functions. Normally set by a calling MFS. + Record [in] -- The entire record (for record-oriented functions) or a newly-created handle (for + "get handle" functions). Normally set by a calling MFS. + Status [in/out] -- Indicator of the success or failure of an action. Normally set by the calling MFS but + for some actions can be set by the action handler to indicate failure. + OrigRecord [in] -- Original content of the record being processed by the current action. This is + automatically being assigned by the WRITE_RECORD and DELETE_RECORD actions within + BASE_MFS. + Param1-10 [in/out] -- Additional request parameter holders + ActionFlow [out] -- Used to control the action chain (see the ACTION_SETUP insert for more information.) + Can also be used to return a special value, such as the results of the CalcField + method. + + History : (Date, Initials, Notes) + 05/14/25 djs Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$Insert FILE.SYSTEM.EQUATES +$Insert ACTION_SETUP +$Insert APP_INSERTS +$Insert MET_TEST_EQUATES +$Insert MET_TEST_DATA_EQUATES +$Insert MET_TEST_INSERTS +$Insert DICT_EQUATES + +Declare function Database_Services, SRP_Array, Read_Column +Declare subroutine Database_Services, RTI_Xlate_Controller + +If KeyID then GoSub Initialize_System_Variables + +Begin Case + + Case Action _EQC 'CalculateColumn' ; GoSub CalculateColumn + Case Action _EQC 'READ_RECORD_PRE' ; GoSub READ_RECORD_PRE + Case Action _EQC 'READ_RECORD' ; GoSub READ_RECORD + Case Action _EQC 'READONLY_RECORD_PRE' ; GoSub READONLY_RECORD_PRE + Case Action _EQC 'READONLY_RECORD' ; GoSub READONLY_RECORD + Case Action _EQC 'WRITE_RECORD_PRE' ; GoSub WRITE_RECORD_PRE + Case Action _EQC 'WRITE_RECORD' ; GoSub WRITE_RECORD + Case Action _EQC 'DELETE_RECORD_PRE' ; GoSub DELETE_RECORD_PRE + Case Action _EQC 'DELETE_RECORD' ; GoSub DELETE_RECORD + Case Otherwise$ ; Status = 'Invalid Action' + +End Case + +If KeyID then GoSub Restore_System_Variables + +If Assigned(ActionFlow) else ActionFlow = ACTION_CONTINUE$ + +Return ActionFlow + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Calculated Columns +// +// The typical structure of a calculated column will look like this: +// +// Declare function Database_Services +// +// @ANS = Database_Services('CalculateColumn') +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +CalculateColumn: + + // Make sure the ActionFlow return variable is cleared in case nothing is calculated. + ActionFlow = '' + +return + +// ----- MFS calls ----------------------------------------------------------------------------------------------------- + +READ_RECORD_PRE: + + // In order to stop a record from being read in this action these lines of code must be used: + // + // OrigFileError = 100 : @FM : KeyID + // Status = 0 + // Record = '' + // ActionFlow = ACTION_STOP$ + +return + + +READ_RECORD: + + // In order to stop a record from being read in this action these lines of code must be used: + // + // OrigFileError = 100 : @FM : KeyID + // Status = 0 + // Record = '' + +return + + +READONLY_RECORD_PRE: + + // In order to stop a record from being read in this action these lines of code must be used: + // + // OrigFileError = 100 : @FM : KeyID + // Status = 0 + // Record = '' + // ActionFlow = ACTION_STOP$ + +return + + +READONLY_RECORD: + + // In order to stop a record from being read in this action these lines of code must be used: + // + // OrigFileError = 100 : @FM : KeyID + // Status = 0 + // Record = '' + +return + +WRITE_RECORD_PRE: + + MetTestDataIds = {MET_TEST_DATA_IDS} + If MetTestDataIds NE '' then + // Evaluate if MET_TEST is out of spec + RTI_Xlate_Controller('DisableCache') + For PropertyIndex = 1 to NUM_PROPERTIES$ + MetTestOutofSpec = (Sum(Xlate('MET_TEST_DATA', MetTestDataIds, "PROPERTY_":PropertyIndex:'_OUT_OF_SPEC', 'X')) GT 0) + Until MetTestOutofSpec + Next PropertyIndex + Record = MetTestOutofSpec + // Evaluate if MET_TEST is complete (all required data has been recorded) + // If Sample Size set, then each defined property should have that number of related data points (MET_TEST_DATA) records. + // If Sample Size is not set, then each defined property should have at least one related data point (MET_TEST_DATA) record. + MetComplete = True$ + SampleSize = {SAMPLE_SIZE} + If SampleSize EQ '' then SampleSize = 1 + For PropertyIndex = 1 to NUM_PROPERTIES$ + PropColNo = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex, DICT_COLUMN_NO$, 'X') + If (Record NE '') then + // Property is defined, check if number of data points matches SAMPLE_SIZE + PropVals = Xlate('MET_TEST_DATA', MetTestDataIds, 'PROPERTY_':PropertyIndex:'_VALUE', 'X') + PropVals = SRP_Array('Clean', PropVals, 'Trim') + MetComplete = (DCount(PropVals, @VM) GE SampleSize) + end + Until Not(MetComplete) + Next PropertyIndex + Record = MetComplete + RTI_Xlate_Controller('EnableCache') + end else + Record = False$ + Record = False$ + end + SaveRecord = Record + +return + + +WRITE_RECORD: +return + + +DELETE_RECORD_PRE: +return + + +DELETE_RECORD: +return + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Internal GoSubs +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +ClearCursors: + + For counter = 0 to 8 + ClearSelect counter + Next counter + +return + + +Initialize_System_Variables: + + // Save these for restoration later + SaveDict = @DICT + SaveID = @ID + SaveRecord = @RECORD + OrigFileError = @FILE.ERROR + + // Now make sure @DICT, ID, and @RECORD are populated + CurrentDictName = '' + If @DICT then + DictHandle = @DICT<1, 2> + Locate DictHandle in @TABLES(5) Using @FM Setting fPos then + CurrentDictName = Field(@TABLES(0), @FM, fPos, 1) + end + end + + If CurrentDictName NE DictName then + Open DictName to @DICT else Status = 'Unable to initialize @DICT' + end + + @ID = KeyID + If Record else + // Record might not have been passed in. Read the record from the database table just to make sure. + @FILE.ERROR = '' + Open TableName to hTable then + FullFSList = hTable[1, 'F' : @VM] + BFS = FullFSList[-1, 'B' : @SVM] + LastHandle = hTable[-1, 'B' : \0D\] + FileHandle = \0D\ : LastHandle[1, @VM] + + Call @BFS(READO.RECORD, BFS, FileHandle, KeyID, FMC, Record, ReadOStatus) + end + end + @RECORD = Record + +return + + +Restore_System_Variables: + + Transfer SaveDict to @DICT + Transfer SaveID to @ID + Transfer SaveRecord to @RECORD + @FILE.ERROR = OrigFileError + +return + + + + diff --git a/LSL2/STPROC/MET_TEST_DATA_ACTIONS.txt b/LSL2/STPROC/MET_TEST_DATA_ACTIONS.txt new file mode 100644 index 0000000..60b45c5 --- /dev/null +++ b/LSL2/STPROC/MET_TEST_DATA_ACTIONS.txt @@ -0,0 +1,276 @@ +Function MET_TEST_DATA_Actions(Action, CalcColName, FSList, Handle, Name, FMC, Record, Status, OrigRecord, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from Infineon. + + Name : Met_Test_Data_Actions + + Description : Handles calculated columns and MFS calls for the current table. + + Notes : This function uses @ID, @RECORD, and @DICT to make sure {ColumnName} references work correctly. + If called from outside of a calculated column these will need to be set and restored. + + Parameters : + Action [in] -- Name of the action to be taken + CalcColName [in] -- Name of the calculated column that needs to be processed. Normally this should only be + populated when the CalcField action is being used. + FSList [in] -- The list of MFSs and the BFS name for the current file or volume. This is an @SVM + delimited array, with the current MFS name as the first value in the array, and the BFS + name as the last value. Normally set by a calling MFS. + Handle [in] -- The file handle of the file or media map being accessed. Note, this does contain the + entire handle structure that the Basic+ Open statement would provide. Normally set by a + calling MFS. + Name [in] -- The name (key) of the record or file being accessed. Normally set by a calling MFS. + FMC [in] -- Various functions. Normally set by a calling MFS. + Record [in] -- The entire record (for record-oriented functions) or a newly-created handle (for + "get handle" functions). Normally set by a calling MFS. + Status [in/out] -- Indicator of the success or failure of an action. Normally set by the calling MFS but + for some actions can be set by the action handler to indicate failure. + OrigRecord [in] -- Original content of the record being processed by the current action. This is + automatically being assigned by the WRITE_RECORD and DELETE_RECORD actions within + BASE_MFS. + Param1-10 [in/out] -- Additional request parameter holders + ActionFlow [out] -- Used to control the action chain (see the ACTION_SETUP insert for more information.) + Can also be used to return a special value, such as the results of the CalcField + method. + + History : (Date, Initials, Notes) + 05/14/25 djs Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$Insert FILE.SYSTEM.EQUATES +$Insert ACTION_SETUP +$Insert APP_INSERTS +$Insert MET_TEST_EQUATES +$Insert MET_TEST_DATA_EQUATES +$Insert MET_TEST_INSERTS +$Insert DICT_EQUATES + +Declare function Database_Services +Declare subroutine Database_Services + +If KeyID then GoSub Initialize_System_Variables + +Begin Case + + Case Action _EQC 'CalculateColumn' ; GoSub CalculateColumn + Case Action _EQC 'READ_RECORD_PRE' ; GoSub READ_RECORD_PRE + Case Action _EQC 'READ_RECORD' ; GoSub READ_RECORD + Case Action _EQC 'READONLY_RECORD_PRE' ; GoSub READONLY_RECORD_PRE + Case Action _EQC 'READONLY_RECORD' ; GoSub READONLY_RECORD + Case Action _EQC 'WRITE_RECORD_PRE' ; GoSub WRITE_RECORD_PRE + Case Action _EQC 'WRITE_RECORD' ; GoSub WRITE_RECORD + Case Action _EQC 'DELETE_RECORD_PRE' ; GoSub DELETE_RECORD_PRE + Case Action _EQC 'DELETE_RECORD' ; GoSub DELETE_RECORD + Case Otherwise$ ; Status = 'Invalid Action' + +End Case + +If KeyID then GoSub Restore_System_Variables + +If Assigned(ActionFlow) else ActionFlow = ACTION_CONTINUE$ + +Return ActionFlow + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Calculated Columns +// +// The typical structure of a calculated column will look like this: +// +// Declare function Database_Services +// +// @ANS = Database_Services('CalculateColumn') +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +CalculateColumn: + + // Make sure the ActionFlow return variable is cleared in case nothing is calculated. + ActionFlow = '' + +return + +// ----- MFS calls ----------------------------------------------------------------------------------------------------- + +READ_RECORD_PRE: + + // In order to stop a record from being read in this action these lines of code must be used: + // + // OrigFileError = 100 : @FM : KeyID + // Status = 0 + // Record = '' + // ActionFlow = ACTION_STOP$ + +return + + +READ_RECORD: + + // In order to stop a record from being read in this action these lines of code must be used: + // + // OrigFileError = 100 : @FM : KeyID + // Status = 0 + // Record = '' + +return + + +READONLY_RECORD_PRE: + + // In order to stop a record from being read in this action these lines of code must be used: + // + // OrigFileError = 100 : @FM : KeyID + // Status = 0 + // Record = '' + // ActionFlow = ACTION_STOP$ + +return + + +READONLY_RECORD: + + // In order to stop a record from being read in this action these lines of code must be used: + // + // OrigFileError = 100 : @FM : KeyID + // Status = 0 + // Record = '' + +return + +WRITE_RECORD_PRE: + + // Validate Property Values against specs defined in MET_TEST parent record + MetTestId = {MET_TEST_ID} + If MetTestId NE '' then + MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId) + If Error_Services('NoError') then + MetTestOutofSpecOrig = MetTestRec + MetTestOutofSpec = False$ + For PropertyIndex = 1 to NUM_PROPERTIES$ + PropOutofSpec = False$ + Prop = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropertyIndex, 'X') + If Prop NE '' then + PropMin = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropertyIndex:'_SPEC_MIN', 'X') + PropMax = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropertyIndex:'_SPEC_MAX', 'X') + PropValColNo = Xlate('DICT.MET_TEST_DATA', 'PROPERTY_':PropertyIndex:'_VALUE', DICT_COLUMN_NO$, 'X') + PropVal = Record + Begin Case + + Case (PropVal EQ '') + PropOutofSpec = False$ + + Case ( (PropMin NE '') and (PropMax NE '') ) + + PropOutofSpec = ( (PropVal LT PropMin) or (PropVal GT PropMax) ) + + Case (PropMin NE '') + + PropOutofSpec = (PropVal LT PropMin) + + Case (PropMax NE '') + + PropOutofSpec = (PropVal GT PropMax) + + Case (Prop EQ 'SURFACE_SCAN_SORT') + PropOutofSpec = Not((PropVal _EQC 'PASS')) + + Case Otherwise$ + Null + + End Case + PropOOSColNo = Xlate('DICT.MET_TEST_DATA', 'PROPERTY_':PropertyIndex:'_OUT_OF_SPEC', DICT_COLUMN_NO$, 'X') + Record = PropOutofSpec + end + If PropOutofSpec then MetTestOutofSpec = True$ + Next PropertyIndex + SaveRecord = Record + end + end + +return + + +WRITE_RECORD: + + // Trigger MET_TEST_ACTIONS to re-evaluate if the entire MET_TEST record is in spec and comlete + MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', {MET_TEST_ID}) + If Error_Services('NoError') then + Database_Services('WriteDataRow', 'MET_TEST', {MET_TEST_ID}, MetTestRec, True$, False$, False$) + end + +return + + +DELETE_RECORD_PRE: +return + + +DELETE_RECORD: +return + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Internal GoSubs +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +ClearCursors: + For counter = 0 to 8 + ClearSelect counter + Next counter +return + + +Initialize_System_Variables: + + // Save these for restoration later + SaveDict = @DICT + SaveID = @ID + SaveRecord = @RECORD + OrigFileError = @FILE.ERROR + + // Now make sure @DICT, ID, and @RECORD are populated + CurrentDictName = '' + If @DICT then + DictHandle = @DICT<1, 2> + Locate DictHandle in @TABLES(5) Using @FM Setting fPos then + CurrentDictName = Field(@TABLES(0), @FM, fPos, 1) + end + end + + If CurrentDictName NE DictName then + Open DictName to @DICT else Status = 'Unable to initialize @DICT' + end + + @ID = KeyID + If Record else + // Record might not have been passed in. Read the record from the database table just to make sure. + @FILE.ERROR = '' + Open TableName to hTable then + FullFSList = hTable[1, 'F' : @VM] + BFS = FullFSList[-1, 'B' : @SVM] + LastHandle = hTable[-1, 'B' : \0D\] + FileHandle = \0D\ : LastHandle[1, @VM] + + Call @BFS(READO.RECORD, BFS, FileHandle, KeyID, FMC, Record, ReadOStatus) + end + end + @RECORD = Record + +return + + +Restore_System_Variables: + + Transfer SaveDict to @DICT + Transfer SaveID to @ID + Transfer SaveRecord to @RECORD + @FILE.ERROR = OrigFileError + +return + + + diff --git a/LSL2/STPROC/MET_TEST_SERVICES.txt b/LSL2/STPROC/MET_TEST_SERVICES.txt new file mode 100644 index 0000000..0b03b08 --- /dev/null +++ b/LSL2/STPROC/MET_TEST_SERVICES.txt @@ -0,0 +1,1254 @@ +Compile function Met_Test_Services(@Service, @Params) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Met_Test_Services + + Description : Handler program for all module related services. + + Notes : The generic parameters should contain all the necessary information to process the services. Often + this will be information like the data Record and Key ID. + + Parameters : + Service [in] -- Name of the service being requested + Param1-10 [in/out] -- Additional request parameter holders + Response [out] -- Response to be sent back to the Controller (MCP) or requesting procedure + + History : (Date, Initials, Notes) + 05/13/25 djs Original developer + +***********************************************************************************************************************/ +#pragma precomp SRP_PreCompiler + +$Insert SERVICE_SETUP +$Insert APP_INSERTS +$Insert MET_TEST_EQUATES +$Insert MET_TEST_DATA_EQUATES +$Insert MET_TEST_INSERTS +$Insert DICT_EQUATES +$Insert TOOL_EQUATES +$Insert LOT_OPERATION_EQUATES + +Declare function RTI_CreateGuid, Error_Services, Tool_Services, Database_Services, SRP_Array, SRP_JSON, Datetime +Declare function Met_Test_Services, Date_Services +Declare subroutine Database_Services, Error_Services, Btree.Extract, SRP_JSON, Extract_Si_Keys, Lot_Event_Services + +GoToService + +Return Response or "" + +//---------------------------------------------------------------------------------------------------------------------- +// Service Parameter Options +//---------------------------------------------------------------------------------------------------------------------- +Options LAYERS = '1', '2', '3' +Options ZONES = '1', '2' +Options INSPECTION_RECIPES = 'PRE', 'LOAD', 'FWI', 'UNLOAD', 'LWI', 'POST', 'QA' + +//---------------------------------------------------------------------------------------------------------------------- +// Services +//---------------------------------------------------------------------------------------------------------------------- + + +Service ManualMetTestEntry(ToolId, LotId, Recipe, Pattern, RunDataLayer, RunDataZone, Positions, RawDataPoints) + + ToolClass = XLATE('TOOL', ToolId, 'CLASS', 'X') + RDSKeyId = '' + MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyId, ToolClass, Recipe, Pattern, Layer, RunDataZone) + Met_Test_Services('SetPropsAndLimits', MetTestId) + Met_Test_Services('SetMetTestTool', MetTestId, ToolId) + Met_Test_Services('SetMetTestDtm', MetTestId, DateTime()) + + for each DataPoint in RawDataPoints using @VM setting vPos + position = Positions<0, vPos> + Met_Test_Services('AddMetTestData', MetTestId, Position, DataPoint) + Next DataPoint + +end service + +//---------------------------------------------------------------------------------------------------------------------- +// CreateMetTest +// +// Input: +// LotId [Required] - Key of LOT_ID record to relate MET_TEST record to. +// LegacyLotId [Optional] - Key of legacy lot id (e.g., RDS, WO_MAT, WM_OUT) to relate MET_TEST record to +// ToolClass [Optional] - TOOL_CLASS of metrology test. Used for PRS_PROP spec lookup. +// Required parameter for RDS_TEST metrology. +// ToolRecipe [Optional] - Recipe of metrology test prescribed in PSN and selected on metrology tool. +// This can be a recipe from an RDS_TEST, CLEAN_INSP, or WO_MAT_QA metrology test. +// Required parameter for metrology tests (i.e., not visual inspections)! +// ToolPattern [Optional] - Pattern of metrology test prescribed in PSN and selected on metrology tool. +// This will drive the sample size (i.e., number of data points) to require in order +// for the test to be considered "complete". +// Layer [Optional] - Layer of metrology test. Required for RDS_TEST metrology. +// Note: This should be 1, 2, or 3 to match PRS_PROP keys. Not L1, L2, or 2. +// Zone [Optional] - Zone of metrology test. Should be null (""), 1, or 2 +// InspectionRecipe [Optional] - PRS_STAGE to retrieve visual inspection specs from. +// Required parameter for CLEAN_INSP visual inspections. +// +// Output: +// If successful, returns the key of the MET_TEST record created. +// +// Note: +// The SAMPLE_SIZE field derived from the ToolPattern may refer to the number of data points on a +// single wafer (e.g., RDS_TEST metrology) or the number of wafers in a cassette (e.g., surfscan). +// +// Creates a parent MET_TEST record related to a LOT_ID record. +//---------------------------------------------------------------------------------------------------------------------- +Service CreateMetTest(LotId, LegacyLotId, ToolClass, ToolRecipe, ToolPattern, Layer=LAYERS, Zone=ZONES, InspectionRecipe=INSPECTION_RECIPES) + + MetTestRec = '' + MetTestId = '' + ErrorMsg = '' + + If (LotId NE '') then + If RowExists('LOT', LotId) then + If Layer NE '' then + Swap 2 with 3 in Layer + Swap 'L2' with 2 in Layer + Swap 'L1' with 1 in Layer + end + // Create MET_TEST key and write record + MetTestId = RTI_CreateGuid() + MetTestRec = LotId + MetTestRec = LegacyLotId + MetTestRec = ToolClass + MetTestRec = ToolRecipe + MetTestRec = ToolPattern + MetTestRec = Layer + MetTestRec = Zone + MetTestRec = InspectionRecipe + Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec) + If Error_Services('HasError') then + ErrorMsg = 'Error in ':Service:' service. Error writing MET_TEST record. Error message: ':Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. LotId "':LotId:'" does not exist in the LOT table.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null LotId passed into service.' + end + + If ErrorMsg EQ '' then + Response = MetTestId + end else + Error_Services('Add', ErrorMsg) + end + +End Service + + +//---------------------------------------------------------------------------------------------------------------------- +// AddMetTestData +// +// Description: +// Creates a child MET_TEST_DATA record related to a parent MET_TEST record. +// +// Input: +// MetTestId [Required] - Key of MET_TEST parent record +// Position [Optional] - Integer indicating an order or values (e.g., wafer slot or point value of point map) +// PropertyVal1 [Optional] - Metrology value associated with PROPERTY_1 of parent MET_TEST record +// ... +// ... +// ... +// PropertyVal15 [Optional] - Metrology value associated with PROPERTY_15 of parent MET_TEST record +// +// Output: +// Returns true if successful, false otherwise. +// +// Notes: +// At least one property value is required +// Extend PropertyVal input fields as MET_TEST PropertyVal fields are added (e.g., PropertyVal16, PropertyVal17, ...) +//---------------------------------------------------------------------------------------------------------------------- +Service AddMetTestData(MetTestId, Position, PropertyVal1, PropertyVal2, PropertyVal3, PropertyVal4, PropertyVal5, PropertyVal6, PropertyVal7, PropertyVal8, PropertyVal9, PropertyVal10, PropertyVal11, PropertyVal12, PropertyVal13, PropertyVal14, PropertyVal15) + + ErrorMsg = '' + If ( (MetTestId NE '') and (PropertyVal1 NE '') or (PropertyVal2 NE '') or (PropertyVal3 NE '') or (PropertyVal4 NE '') | + or (PropertyVal5 NE '') or (PropertyVal6 NE '') or (PropertyVal7 NE '') or (PropertyVal8 NE '') or (PropertyVal9 NE '') | + or (PropertyVal10 NE '') or (PropertyVal11 NE '') or (PropertyVal12 NE '') or (PropertyVal13 NE '') or (PropertyVal14 NE '') | + or (PropertyVal15 NE '') ) then + If RowExists('MET_TEST', MetTestId) then + MetTestDataKey = RTI_CreateGuid() + MetTestDataRec = '' + MetTestDataRec = MetTestId + MetTestDataRec = Position + MetTestDataRec = PropertyVal1 + MetTestDataRec = PropertyVal2 + MetTestDataRec = PropertyVal3 + MetTestDataRec = PropertyVal4 + MetTestDataRec = PropertyVal5 + MetTestDataRec = PropertyVal6 + MetTestDataRec = PropertyVal7 + MetTestDataRec = PropertyVal8 + MetTestDataRec = PropertyVal9 + MetTestDataRec = PropertyVal10 + MetTestDataRec = PropertyVal11 + MetTestDataRec = PropertyVal12 + MetTestDataRec = PropertyVal13 + MetTestDataRec = PropertyVal14 + MetTestDataRec = PropertyVal15 + Database_Services('WriteDataRow', 'MET_TEST_DATA', MetTestDataKey, MetTestDataRec) + If Error_Services('HasError') then + ErrorMsg = 'Error in ':Service:' service. Failed to write MET_TEST_DATA record. Error message: ':Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. Parent MET_TEST record "':MetTestId:'" does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId, PropertyVal1, PropertyVal2, PropertyVal3, or PropertyVal4 passed into service' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + + + +//---------------------------------------------------------------------------------------------------------------------- +// SetPropsAndLimits +// +// Input: +// MetTestId [Required] - Key of MET_TEST record to update. +// +// Output: +// Returns true if successful, false otherwise. +// +// Searches PROD_SPEC, PRS_PROP, and PRS_STAGe for matching property names and limits to apply to columns +// PROPERTY_1, PROPERTY_1_MIN, PROPERTY_1_MAX, ... PROPERTY_N, PROPERTY_N_MIN, PROPERTY_N_MAX. +//---------------------------------------------------------------------------------------------------------------------- +Service SetPropsAndLimits(MetTestId) + + ErrorMsg = '' + If (MetTestId NE '') then + If RowExists('MET_TEST', MetTestId) then + Open 'MET_TEST' to hTable then + Met_Test_Services('ClearPropsAndLimits', MetTestId) + If Error_Services('NoError') then + MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId) + If Error_Services('NoError') then + LotId = MetTestRec + If (LotId NE '') then + If RowExists('LOT', LotId) then + // Find specs from provided recipe, pattern, tool class, layer, etc. + PSNo = Xlate('LOT', LotId, 'PROD_SPEC_ID', 'X') + If PSNo NE '' then + If RowExists('PROD_SPEC', PSNo) then + SpecFound = False$ + Layer = MetTestRec + ToolRecipe = MetTestRec + ToolPattern = MetTestRec + Tool = MetTestRec + ToolClass = MetTestRec + InspectionRecipe = MetTestRec + If InspectionRecipe NE '' then + // Get Inspection values from PRS_STAGE record + PRSStageKey = PSNo:'*':InspectionRecipe + If RowExists('PRS_STAGE', PRSStageKey) then + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'LPD', 'X') + If MetTestRec NE '' then MetTestRec = 'LPD' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'SCRATCHES', 'X') + If MetTestRec NE '' then MetTestRec = 'Scratches' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'SCRATCH_LEN', 'X') + If MetTestRec NE '' then MetTestRec = 'Scratch Len' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'PITS', 'X') + If MetTestRec NE '' then MetTestRec = 'Pits' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'MOUNDS', 'X') + If MetTestRec NE '' then MetTestRec = 'Mounds' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'STACK_FAULTS', 'X') + If MetTestRec NE '' then MetTestRec = 'Stack Faults' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'SPIKES', 'X') + If MetTestRec NE '' then MetTestRec = 'Spikes' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'SPOTS', 'X') + If MetTestRec NE '' then MetTestRec = 'Spots' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'FOV', 'X') + If MetTestRec NE '' then MetTestRec = 'FOV' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'BL_DEFECTS', 'X') + If MetTestRec NE '' then MetTestRec = 'BL Defects' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'BSIDE_SCRATCHES', 'X') + If MetTestRec NE '' then MetTestRec = 'Backside Scratches' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'BSIDE_SCRATCH_LEN', 'X') + If MetTestRec NE '' then MetTestRec = 'Backside Scratch Len' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'BSIDE_NODULES', 'X') + If MetTestRec NE '' then MetTestRec = 'Backside Nodules' + MetTestRec = Xlate('PRS_PROP', PRSPropKey, 'BSIDE_SPIKES', 'X') + If MetTestRec NE '' then MetTestRec = 'Backside Spikes' + If ( Xlate('PRS_PROP', PRSPropKey, 'EDGE', 'X') EQ 1 ) then MetTestRec = 0 + If MetTestRec NE '' then MetTestRec = 'Edge Defects' + MetTestRec = 1 + end else + ErrorMsg = 'Error in ':Service:' service. Error finding inspection specs. PRS_STAGE record "':PRSStageKey:'" does not exist.' + end + end else + Open 'DICT.PRS_PROP' to dPRSProp then + Open 'DICT.PRS_STAGE' to dPRSStage then + // Search PRS_PROP for matching layer, recipe, tool class, and tool pattern + Query = 'PS_NO':@VM:PSNo:@FM + If Layer NE '' then Query := 'LAYER_NO':@VM:Layer:@FM + If ToolRecipe NE '' then Query := 'MET_RECIPE':@VM:ToolRecipe:@FM + If ToolClass NE '' then Query := 'TOOL':@VM:ToolClass:@FM + If ToolPattern NE '' then Query := 'MET_RECIPE_PATTERN':@VM:ToolPattern:@FM + PRSPropKey = '' + PRSPropKeys = '' + Flag = '' + Btree.Extract(Query, 'PRS_PROP', dPRSProp, PRSPropKeys, 'E', Flag) + If Flag EQ 0 then + If (DCount(PRSPropKeys, @VM) EQ 1) then + SpecFound = True$ + PRSPropKey = PRSPropKeys + // Get RAW_MIN and RAW_MAX from PRS_PROP record (MD5) + MetTestRec = Field(PRSPropKey, '*', 3, 1) + MetTestRec = OConv(Xlate('PRS_PROP', PRSPropKey, 'RAW_MIN', 'X'), 'MD5') + MetTestRec = OConv(Xlate('PRS_PROP', PRSPropKey, 'RAW_MAX', 'X'), 'MD5') + SpecToolPattern = Xlate('PRS_PROP', PRSPropKey, 'MET_RECIPE_PATTERN', 'X') + If SpecToolPattern NE '' then + SpecToolClass = Xlate('PRS_PROP', PRSPropKey, 'TOOL', 'X') + If SpecToolClass NE '' then + SampleSize = Tool_Services('GetNumPoints', SpecToolClass, SpecToolPattern) + If Error_Services('NoError') then + If SampleSize EQ '' then SampleSize = 1 + MetTestRec = SampleSize + end else + ErrorMsg = Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. TOOL (i.e., TOOL_CLASS) in PRS_PROP "':PRSPropKey:'" not set.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_RECIPE_PATTERN in PRS_PROP "':PRSPropKey:'" not set.' + end + end + end + + If Not(SpecFound) then + // Search PRS Stage for matching SURFSCAN_RECIPE + Query = 'PS_NO':@VM:PSNo:@FM + If ToolRecipe NE '' then Query := 'SURFSCAN_RECIPE':@VM:ToolRecipe:@FM + PRSStageKey = '' + PRSStageKeys = '' + Flag = '' + Btree.Extract(Query, 'PRS_STAGE', dPRSStage, PRSStageKeys, 'E', Flag) + If Flag EQ 0 then + If (DCount(PRSStageKeys, @VM) EQ 1) then + PRSStageKey = PRSStageKeys + PRSStageSpecSurfscanRecipes = Xlate('PRS_STAGE', PRSStageKey, 'SURFSCAN_RECIPE', 'X') + If PRSStageSpecSurfscanRecipes NE '' then + For each PRSStageSpecSurfscanRecipe in PRSStageSpecSurfscanRecipes using @VM Setting SpecSurfIndex + SpecFound = (PRSStageSpecSurfscanRecipe EQ ToolRecipe) + If SpecFound then + // Get sum of defects max (SURF_DEFECTS - MD0) and haze max (SURF_HAZE - MD2) from PRS_STAGE record (there is no min spec) + MetTestRec = 'SURFACE_SCAN_SUM_OF_DEFECTS_MIN' + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'SURF_DEFECTS', 'X')<0, SpecSurfIndex> + MetTestRec = 'SURFACE_SCAN_SUM_OF_DEFECTS_MAX' + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'SURF_DEFECTS', 'X')<0, SpecSurfIndex> + MetTestRec = 'SURFACE_SCAN_SUM_OF_DEFECTS_AVG' + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'SURF_DEFECTS', 'X')<0, SpecSurfIndex> + MetTestRec = 'SURFACE_SCAN_SUM_OF_DEFECTS' + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'SURF_DEFECTS', 'X')<0, SpecSurfIndex> + MetTestRec = 'SURFACE_SCAN_HAZE_AVG' + MetTestRec = IConv(Xlate('PRS_STAGE', PRSStageKey, 'SURF_HAZE', 'X')<0, SpecSurfIndex>, 'MD2') + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'SS_SAMP_QTY', 'X')<0, SpecSurfIndex> + end + Until SpecFound + Next PRSStageSpecSurfscanRecipe + end + end + end else + ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract on PRS_STAGE table.' + end + end + + If Not(SpecFound) then + // Search PRS Stage for matching MET_RECIPE and optionally, matching MET_PATTERN + Query = 'PS_NO':@VM:PSNo:@FM + If ToolRecipe NE '' then Query := 'MET_RECIPE':@VM:ToolRecipe:@FM + If ToolPattern NE '' then Query := 'MET_RECIPE_PATTERN':@VM:ToolPattern:@FM + PRSStageKey = '' + PRSStageKeys = '' + Flag = '' + Btree.Extract(Query, 'PRS_STAGE', dPRSStage, PRSStageKeys, 'E', Flag) + If Flag EQ 0 then + If (DCount(PRSStageKeys, @VM) EQ 1) then + PRSStageKey = PRSStageKeys + PRSStageSpecMetRecipes = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE', 'X') + PRSStageSpecMetPatterns = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE_PATTERN', 'X') + If PRSStageSpecMetRecipes NE '' then + For each PRSStageSpecMetRecipe in PRSStageSpecMetRecipes using @VM setting SpecMetIndex + If ToolPattern NE '' then + PRSStageSpecMetPattern = PRSStageSpecMetPatterns<0, SpecMetIndex> + SpecFound = ( (PRSStageSpecMetRecipe EQ ToolRecipe) and (PRSStageSpecMetPattern = ToolPattern) ) + end else + SpecFound = (PRSStageSpecMetRecipe EQ ToolRecipe) + end + If SpecFound then + // Get min and max from MET_MIN and MET_MAX in PRS_STAGE record (MD0) + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'MET_PROP', 'X')<0, SpecMetIndex> + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'MET_MIN', 'X')<0, SpecMetIndex> + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'MET_MAX', 'X')<0, SpecMetIndex> + If MetTestRec EQ 'CRES' then + MetTestRec = 'PHASE' + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'MET_PHASE_MIN', 'X')<0, SpecMetIndex> + end + SpecToolPattern = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE_PATTERN', 'X')<0, SpecMetIndex> + If SpecToolPattern NE '' then + SpecToolClass = Xlate('PRS_STAGE', PRSStageKey, 'MET_TOOL_CLASS', 'X')<0, SpecMetIndex> + If SpecToolClass NE '' then + SampleSize = Tool_Services('GetNumPoints', SpecToolClass, SpecToolPattern) + If Error_Services('NoError') then + If SampleSize EQ '' then SampleSize = 1 + MetTestRec = SampleSize + end else + ErrorMsg = Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TOOL_CLASS in PRS_STAGE "':PRSStageKey:'" not set.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_RECIPE_PATTERN in PRS_STAGE "':PRSStageKey:'" not set.' + end + end + Until SpecFound + Next PRSStageSpecMetRecipe + end + end + end else + ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract on PRS_STAGE table.' + end + end + + If Not(SpecFound) then + // Last resort - look up matching spec limits by PSN and tool class + Query = 'PS_NO':@VM:PSNo:@FM + If ToolClass NE '' then Query := 'MET_TOOL_CLASS':@VM:ToolClass:@FM + PRSStageKey = '' + PRSStageKeys = '' + Flag = '' + Btree.Extract(Query, 'PRS_STAGE', dPRSStage, PRSStageKeys, 'E', Flag) + If Flag EQ 0 then + If (DCount(PRSStageKeys, @VM) EQ 1) then + PRSStageKey = PRSStageKeys + PRSStageSpecToolClasses = Xlate('PRS_STAGE', PRSStageKey, 'MET_TOOL_CLASS', 'X') + If PRSStageSpecToolClasses NE '' then + For each PRSStageSpecToolClass in PRSStageSpecToolClasses using @VM setting SpecMetIndex + SpecFound = (PRSStageSpecToolClass EQ ToolClass) + If SpecFound then + // Get min and max from MET_MIN and MET_MAX in PRS_STAGE record (MD0) + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'MET_PROP', 'X')<0, SpecMetIndex> + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'MET_MIN', 'X')<0, SpecMetIndex> + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'MET_MAX', 'X')<0, SpecMetIndex> + If MetTestRec EQ 'CRES' then + MetTestRec = 'PHASE' + MetTestRec = Xlate('PRS_STAGE', PRSStageKey, 'MET_PHASE_MIN', 'X')<0, SpecMetIndex> + end + SpecToolPattern = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE_PATTERN', 'X')<0, SpecMetIndex> + If SpecToolPattern NE '' then + SpecToolClass = Xlate('PRS_STAGE', PRSStageKey, 'MET_TOOL_CLASS', 'X')<0, SpecMetIndex> + If SpecToolClass NE '' then + SampleSize = Tool_Services('GetNumPoints', SpecToolClass, SpecToolPattern) + If Error_Services('NoError') then + If SampleSize EQ '' then SampleSize = 1 + MetTestRec = SampleSize + end else + ErrorMsg = Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TOOL_CLASS in PRS_STAGE "':PRSStageKey:'" not set.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_RECIPE_PATTERN in PRS_STAGE "':PRSStageKey:'" not set.' + end + end + Until SpecFound + Next PRSStageSpecMetRecipe + end + end + end else + ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract on PRS_STAGE table.' + end + + If Not(SpecFound) then + // Search PRS_PROP for matching PSN, layer, and tool class + Query = 'PS_NO':@VM:PSNo:@FM + If Layer NE '' then Query := 'LAYER_NO':@VM:Layer:@FM + If ToolClass NE '' then Query := 'TOOL':@VM:ToolClass:@FM + PRSPropKey = '' + PRSPropKeys = '' + Flag = '' + Btree.Extract(Query, 'PRS_PROP', dPRSProp, PRSPropKeys, 'E', Flag) + If Flag EQ 0 then + If (DCount(PRSPropKeys, @VM) EQ 1) then + SpecFound = True$ + PRSPropKey = PRSPropKeys + // Get RAW_MIN and RAW_MAX from PRS_PROP record (MD5) + MetTestRec = Field(PRSPropKey, '*', 3, 1) + MetTestRec = OConv(Xlate('PRS_PROP', PRSPropKey, 'RAW_MIN', 'X'), 'MD5') + MetTestRec = OConv(Xlate('PRS_PROP', PRSPropKey, 'RAW_MAX', 'X'), 'MD5') + SpecToolPattern = Xlate('PRS_PROP', PRSPropKey, 'MET_RECIPE_PATTERN', 'X') + If SpecToolPattern NE '' then + SpecToolClass = Xlate('PRS_PROP', PRSPropKey, 'TOOL', 'X') + If SpecToolClass NE '' then + SampleSize = Tool_Services('GetNumPoints', SpecToolClass, SpecToolPattern) + If Error_Services('NoError') then + If SampleSize EQ '' then SampleSize = 1 + MetTestRec = SampleSize + end else + ErrorMsg = Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. TOOL (i.e., TOOL_CLASS) in PRS_PROP "':PRSPropKey:'" not set.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_RECIPE_PATTERN in PRS_PROP "':PRSPropKey:'" not set.' + end + end + end else + ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract on PRS_PROP table.' + end + end + end + end else + ErrorMsg = 'Error in ':Service:' service. Error opening DICT.PRS_STAGE table.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Error opening DICT.PRS_PROP table.' + end + If ErrorMsg EQ '' then + If SpecFound then + // Update MET_TEST record + Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec) + If Error_Services('HasError') then + ErrorMsg = 'Error in ':Service:' service. Error writing MET_TEST record. Error message: ':Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. Error finding metrology specs.' + end + end + end + end else + ErrorMsg = 'Error in ':Service:' service. Error retrieving metrology specs. PROD_SPEC "':PSNo:'" does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Error retrieving metrology specs. Null PROD_SPEC_ID in LOT record "':LotId:'".' + end + end else + ErrorMsg = 'Error in ':Service:' service. LotId "':LotId:'" does not exist in the LOT table.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null LotId passed into service.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId passed into service.' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// ClearPropsAndLimits +// +// Input: +// MetTestId [Required] - Key of MET_TEST record to update. +// +// Output: +// Returns true if successful, false otherwise. +// +// Clears columns PROPERTY_1, PROPERTY_1_MIN, PROPERTY_1_MAX, ... PROPERTY_N, PROPERTY_N_MIN, PROPERTY_N_MAX. +//---------------------------------------------------------------------------------------------------------------------- +Service ClearPropsAndLimits(MetTestId) + + ErrorMsg = '' + If (MetTestId NE '') then + If RowExists('MET_TEST', MetTestId) then + MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId) + If Error_Services('NoError') then + For PropertyIndex = 1 to NUM_PROPERTIES$ + PropColNo = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex, DICT_COLUMN_NO$, 'X') + PropMinColNo = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MIN', DICT_COLUMN_NO$, 'X') + PropMaxColNo = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MAX', DICT_COLUMN_NO$, 'X') + MetTestRec = '' + MetTestRec = '' + MetTestRec = '' + Next PropertyIndex + Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec, True$, False$, False$) + If Error_Services('HasError') then + ErrorMsg = Error_Services('GetMessage') + end + end else + ErrorMsg = Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// SetMetTestRecipe +// +// Input: +// MetTestId [Required] - Key of MET_TEST record to update. +// MetRecipe [Required] - Recipe name of metrology test. +// +// Output: +// Returns true if successful, false otherwise. +// +// Sets the TOOL_RECIPE column of a MET_TEST record. +//---------------------------------------------------------------------------------------------------------------------- +Service SetMetTestRecipe(MetTestId, MetRecipe) + + ErrorMsg = '' + If ( (MetTestId NE '') and (MetRecipe NE '') ) then + If RowExists('MET_TEST', MetTestId) then + Open 'MET_TEST' to hTable then + WriteV MetRecipe on hTable, MetTestId, MET_TEST.TOOL_RECIPE$ else + ErrorMsg = 'Error in ':Service:' service. Failed to write ':MetRecipe:' on TOOL_RECIPE column for MET_TEST ':MetTestId + end + end else + ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// SetMetTestPattern +// +// Input: +// MetTestId [Required] - Key of MET_TEST record to update. +// MetPattern [Required] - Pattern name of metrology test. +// +// Output: +// Returns true if successful, false otherwise. +// +// Sets the TOOL_PATTERN column of a MET_TEST record. +//---------------------------------------------------------------------------------------------------------------------- +Service SetMetTestPattern(MetTestId, MetPattern) + + ErrorMsg = '' + If ( (MetTestId NE '') and (MetPattern NE '') ) then + If RowExists('MET_TEST', MetTestId) then + Open 'MET_TEST' to hTable then + WriteV MetPattern on hTable, MetTestId, MET_TEST.TOOL_PATTERN$ else + ErrorMsg = 'Error in ':Service:' service. Failed to write ':MetPattern:' on TOOL_PATTERN column for MET_TEST ':MetTestId + end + end else + ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// SetMetTestTool +// +// Input: +// MetTestId [Required] - Key of MET_TEST record to update. +// ToolId [Required] - Key of TOOL record, which represents the tool the metrology test was performed on. +// +// Output: +// Returns true if successful, false otherwise. +// +// Sets the TOOL column of a MET_TEST record. +//---------------------------------------------------------------------------------------------------------------------- +Service SetMetTestTool(MetTestId, ToolId) + + ErrorMsg = '' + If ( (MetTestId NE '') and (ToolId NE '') ) then + If RowExists('MET_TEST', MetTestId) then + Open 'MET_TEST' to hTable then + WriteV ToolId on hTable, MetTestId, MET_TEST.TOOL$ else + ErrorMsg = 'Error in ':Service:' service. Failed to write ':ToolId:' on TOOL column for MET_TEST ':MetTestId + end + end else + ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// SetMetTestDtm +// +// Input: +// MetTestId [Required] - Key of MET_TEST record to update. +// TestDtm [Required] - Datetime of the metrology test. Can be internal or external datetime value. +// +// Output: +// Returns true if successful, false otherwise. +// +// Sets the TEST_DTM column of a MET_TEST record. +//---------------------------------------------------------------------------------------------------------------------- +Service SetMetTestDtm(MetTestId, TestDtm) + + ErrorMsg = '' + If ( (MetTestId NE '') and (TestDtm NE '') ) then + If RowExists('MET_TEST', MetTestId) then + Open 'MET_TEST' to hTable then + If Not(Num(TestDtm)) then + Swap ' AM' with 'AM' in TestDtm + Swap ' PM' with 'PM' in TestDtm + TestDtm = IConv(TestDtm,'DT') + end + WriteV TestDtm on hTable, MetTestId, MET_TEST.TEST_DTM$ else + ErrorMsg = 'Error in ':Service:' service. Failed to write ':OConv(TestDtm, 'DT2/^H') + ErrorMsg := ' on TEST_DTM column for MET_TEST ':MetTestId + end + end else + ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// SetMetTestSlot +// +// Input: +// MetTestId [Required] - Key of MET_TEST record to update. +// Slot [Required] - Slot number of metrology test. N/A to cassette level tests like Tencor surface scans. +// +// Output: +// Returns true if successful, false otherwise. +// +// Sets the SLOT column of a MET_TEST record. +//---------------------------------------------------------------------------------------------------------------------- +Service SetMetTestSlot(MetTestId, Slot) + + ErrorMsg = '' + If ( (MetTestId NE '') and (Slot NE '') ) then + If RowExists('MET_TEST', MetTestId) then + Open 'MET_TEST' to hTable then + WriteV Slot on hTable, MetTestId, MET_TEST.SLOT$ else + ErrorMsg = 'Error in ':Service:' service. Failed to write ':Slot:' on SLOT column for MET_TEST ':MetTestId + end + end else + ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// AddProperty (aka parameter) +// +// Input: +// MetTestId [Required] - Key of MET_TEST record to update. +// PropName [Required] - Slot number of metrology test. N/A to cassette level tests like Tencor surface scans. +// PropMin [Optional] - Spec minimum value to validate the property values against. +// PropMax [Optional] - Spec maxiumum value to validate the property values against. +// +// Output: +// Returns true if successful, false otherwise. +// +// Adds a property to a MET_TEST record. +// Note: If a PropMin and PropMax are not set for the property, it will not be validated within MET_TEST_DATA actions. +//---------------------------------------------------------------------------------------------------------------------- +Service AddProperty(MetTestId, PropName, PropMin, PropMax) + + ErrorMsg = '' + If ( (MetTestId NE '') and (PropName NE '') ) then + If RowExists('MET_TEST', MetTestId) then + MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId) + If Error_Services('NoError') then + PosFound = False$ + PropAlreadyPresent = False$ + For PropertyIndex = 1 to NUM_PROPERTIES$ + ThisPropName = Xlate('MET_TEST', MetTestId, "PROPERTY_":PropertyIndex, 'X') + If ( (ThisPropName EQ '') and Not(PropAlreadyPresent) ) then + PosFound = True$ + PropNameIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex, DICT_COLUMN_NO$, 'X') + PropMinIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MIN', DICT_COLUMN_NO$, 'X') + PropMaxIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MAX', DICT_COLUMN_NO$, 'X') + end + If (ThisPropName EQ PropName) then PropAlreadyPresent = True$ + Until PropAlreadyPresent or PosFound + Next PropertyIndex + Begin Case + Case PropAlreadyPresent + ErrorMsg = 'Error in ':Service:' service. Property ':PropName:' already exists in MET_TEST ':MetTestId + Case PosFound + MetTestRec = PropName + MetTestRec = PropMin + MetTestRec = PropMax + Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec, True$, False$, False$) + Case Otherwise$ + ErrorMsg = 'Error in ':Service:' service. Failed to find empty property column in MET_TEST ':MetTestId + End Case + end else + ErrorMsg = 'Error in ':Service:' service. Error reading MET_TEST ':MetTestId:'. Error message: ':Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId, PropName, or PropMin/PropMax passed into service.' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// RemoveProperty +// +// Input: +// MetTestId [Required] - Key of MET_TEST record to update. +// PropName [Required] - Slot number of metrology test. N/A to cassette level tests like Tencor surface scans. +// +// Output: +// Returns true if successful, false otherwise. +// +// Removes a property from a MET_TEST record. +//---------------------------------------------------------------------------------------------------------------------- +Service RemoveProperty(MetTestId, PropName) + + ErrorMsg = '' + If ( (MetTestId NE '') and (PropName NE '') ) then + If RowExists('MET_TEST', MetTestId) then + MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId) + If Error_Services('NoError') then + PosFound = False$ + For PropertyIndex = 1 to NUM_PROPERTIES$ + ThisPropName = Xlate('MET_TEST', MetTestId, "PROPERTY_":PropertyIndex, 'X') + If (ThisPropName EQ PropName) then + PosFound = True$ + PropNameIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex, DICT_COLUMN_NO$, 'X') + PropMinIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MIN', DICT_COLUMN_NO$, 'X') + PropMaxIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MAX', DICT_COLUMN_NO$, 'X') + end + Until PosFound + Next PropertyIndex + If PosFound then + MetTestRec = '' + MetTestRec = '' + MetTestRec = '' + Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec, True$, False$, False$) + end else + ErrorMsg = 'Error in ':Service:' service. Failed to find property column containing "':PropName:'" in MET_TEST record ':MetTestId + end + end else + ErrorMsg = 'Error in ':Service:' service. Error reading MET_TEST ':MetTestId:'. Error message: ':Error_Services('GetMessage') + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId, PropName, or PropMin/PropMax passed into service.' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// ConvertRecordToJson +// +// Input: +// MetTestId [Required] - Key of MET_TEST record to update. +// +// Output: +// metTest JSON object containing parent and child record details +// +// Converts a MET_TEST and its child MET_TEST_DATA records into a JSON object. +//---------------------------------------------------------------------------------------------------------------------- +Service ConvertRecordToJson(MetTestId) + + MetTestJSON = '' + ErrorMsg = '' + If MetTestId NE '' then + If RowExists('MET_TEST', MetTestId) then + Database_Services('ActivateRecord', 'MET_TEST', MetTestId) + If Error_Services('NoError') then + objJSON = '' + If SRP_JSON(objJSON, 'New', 'Object') then + MetTestDataIds = {MET_TEST_DATA_IDS} + SRP_JSON(objJSON, 'SetValue', 'keyId', @ID, 'String') + SRP_JSON(objJSON, 'SetValue', 'lotId', {LOT_ID}, 'String') + SRP_JSON(objJSON, 'SetValue', 'legacyLotId', {LEGACY_LOT_ID}, 'String') + SRP_JSON(objJSON, 'SetValue', 'lotOperationId', {LOT_OPERATION_ID}, 'String') + + TestDtm = Date_Services('ConvertDateTimeToISO8601', {TEST_DTM}) + SRP_JSON(objJSON, 'SetValue', 'testDtm', TestDtm) + SRP_JSON(objJSON, 'SetValue', 'toolRecipe', {TOOL_RECIPE}, 'String') + SRP_JSON(objJSON, 'SetValue', 'toolPattern', {TOOL_PATTERN}, 'String') + SRP_JSON(objJSON, 'SetValue', 'inspectionRecipe', {INSPECTION_RECIPE}, 'String') + SRP_JSON(objJSON, 'SetValue', 'sampleSize', {SAMPLE_SIZE}, 'Number') + SRP_JSON(objJSON, 'SetValue', 'tool', {TOOL}, 'String') + ToolClass = XLATE('TOOL', {TOOL}, TOOL_CLASS$, 'X') + SRP_JSON(objJSON, 'SetValue', 'toolClass', ToolClass, 'String') + SRP_JSON(objJSON, 'SetValue', 'layer', {LAYER}) + SRP_JSON(objJSON, 'SetValue', 'zone', {ZONE}) + SRP_JSON(objJSON, 'SetValue', 'slot', {SLOT}, 'Number') + SRP_JSON(objJSON, 'SetValue', 'outOfSpec', {OUT_OF_SPEC}, 'Boolean') + SRP_JSON(objJSON, 'SetValue', 'complete', {COMPLETE}, 'Boolean') + objMetPropArray = '' + If SRP_JSON(objMetPropArray, 'New', 'Array') then + For PropIndex = 1 to NUM_PROPERTIES$ + PropName = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropIndex, 'X') + PropVals = Xlate('MET_TEST_DATA', MetTestDataIds, 'PROPERTY_':PropIndex:'_VALUE', 'X') + If ( (PropName NE '') or (PropVals NE '') ) then + objMetProp = '' + If SRP_JSON(objMetProp, 'New', 'Object') then + PropSpecMin = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropIndex:'_SPEC_MIN', 'X') + PropSpecMax = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropIndex:'_SPEC_MAX', 'X') + PropPositions = Xlate('MET_TEST_DATA', MetTestDataIds, 'POSITION', 'X') + PropOutOfSpecs = Xlate('MET_TEST_DATA', MetTestDataIds, 'PROPERTY_':PropIndex:'_OUT_OF_SPEC', 'X') + SRP_JSON(objMetProp, 'SetValue', 'property', PropName) + SRP_JSON(objMetProp, 'SetValue', 'propertySpecMin', PropSpecMin, 'Number') + SRP_JSON(objMetProp, 'SetValue', 'propertySpecMax', PropSpecMax, 'Number') + objDatapointsArray = '' + If SRP_JSON(objDatapointsArray, 'New', 'Array') then + For each Datapoint in PropVals using @VM setting vPos + If Datapoint NE '' then + objDatapoint = '' + If SRP_JSON(objDatapoint, 'New', 'Object') then + Position = PropPositions<0, vPos> + OutOfSpec = PropOutofSpecs<0, vPos> + SRP_JSON(objDatapoint, 'SetValue', 'position', Position, 'Number') + SRP_JSON(objDatapoint, 'SetValue', 'value', Datapoint, 'Number') + SRP_JSON(objDatapoint, 'SetValue', 'outOfSpec', OutOfSpec, 'Boolean') + SRP_JSON(objDatapointsArray, 'Add', objDatapoint) + SRP_JSON(objDatapoint, 'Release') + end else + ErrorMsg = 'Error in ':Service:' service. Error initializing objDatapoint object.' + end + end + Next Datapoint + SRP_JSON(objMetProp, 'Set', 'datapoints', objDataPointsArray) + SRP_JSON(objDatapointsArray, 'Release') + end else + ErrorMsg = 'Error in ':Service:' service. Error initializing objDatapointsArray object.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Error initializing objMetProp object.' + end + SRP_JSON(objMetPropArray, 'Add', objMetProp) + SRP_JSON(objMetProp, 'Release') + end + Next PropIndex + SRP_JSON(objJSON, 'Set', 'properties', objMetPropArray) + SRP_JSON(objMetPropArray, 'Release') + end else + ErrorMsg = 'Error in ':Service:' service. Error initializing objMetPropArray object.' + end + MetTestJSON = SRP_JSON(objJSON, 'Stringify', 'Styled') + SRP_JSON(objJSON, 'Release') + end else + ErrorMsg = 'Error in ':Service:' service. Error initializing objJSON object.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Error reading MET_TEST ':MetTestId:'.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId passed into service' + end + + If ErrorMsg EQ '' then + Response = MetTestJSON + end else + Error_Services('Add', ErrorMsg) + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// GetMetTestsByLotId +// +// Input: +// LotId [Required] - Key of LOT record to search MET_TEST table for related records. +// +// Output: +// MET_TEST key ids. +// +//---------------------------------------------------------------------------------------------------------------------- +Service GetMetTestsByLotId(LotId) + + ErrorMsg = '' + MetTestIds = '' + If LotId NE '' then + If RowExists('LOT', LotId) then + Extract_Si_Keys('MET_TEST', 'LOT_ID', LotId, MetTestIds) + end else + ErrorMsg = 'Error in ':Service:' service. LOT ':LotId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null LotId passed into service.' + end + + If ErrorMsg EQ '' then + Response = MetTestIds + end else + Error_Services('Add', ErrorMsg) + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// GetMetTestsByLotId +// +// Input: +// LotId [Required] - Key of LOT record to search MET_TEST table for related records. +// +// Output: +// MET_TEST key ids. +// +//---------------------------------------------------------------------------------------------------------------------- +Service GetMetTests(LotId, LegacyLotId, LotOperationId, ToolId, ExcludeAssociated) + + ErrorMsg = '' + MetTestIds = '' + RespMetTestIds = '' + If LotId NE '' then + If RowExists('LOT', LotId) then + Open 'DICT.MET_TEST' to DictVar then + SearchString = '' + If LotId NE '' then + SearchString := 'LOT_ID':@VM:LotId:@FM + end + If LegacyLotId NE '' then + SearchString := 'LEGACY_LOT_ID':@VM:LegacyLotId:@FM + end + If ToolId NE '' then + SearchString := 'TOOL':@VM:ToolId:@FM + end + Btree.Extract(SearchString, 'MET_TEST', DictVar, MetTestIds, '', '') + If MetTestIds NE '' then + If ExcludeAssociated then + for each MetTestId in MetTestIds using @VM setting mPos + MetTestLotOperationId = Database_Services('ReadDataColumn', 'MET_TEST', MetTestId, MET_TEST.LOT_OPERATION_ID$, True$, 0, False$) + If MetTestLotOperationId EQ '' then + RespMetTestIds<1,-1> = MetTestId + end + Next MetTestId + end else + RespMetTestIds = MetTestIds + end + end + end else + ErrorMsg = 'Error in ' : Service : ' service. Error opening MET_TEST dictionary.' + end + end else + ErrorMsg = 'Error in ':Service:' service. LOT ':LotId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null LotId passed into service.' + end + + If ErrorMsg EQ '' then + Response = RespMetTestIds + end else + Error_Services('Add', ErrorMsg) + end + +end service + + +//---------------------------------------------------------------------------------------------------------------------- +// AttachMetTestToLotOperation +// +// Input: +// MetTestId [Required] - Key of MET_TEST record to relate. +// LotOperationId [Required] - Key of LOT_OPERATION record to relate. +// +// Output: +// True$ (1) if successful, False$ (0) otherwise. +// +//---------------------------------------------------------------------------------------------------------------------- +Service AttachMetTestToLotOperation(MetTestId, LotOperationId, UserId) + + ErrorMsg = '' + If ( (MetTestId NE '') and (LotOperationId NE '') ) then + If RowExists('MET_TEST', MetTestId) then + If RowExists('LOT_OPERATION', LotOperationId) then + Open 'MET_TEST' to hTable then + WriteV LotOperationId on hTable, MetTestId, MET_TEST.LOT_OPERATION_ID$ then + LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$) + LotOperationRec = Insert(LotOperationRec, 1, -1, 1, MetTestId) + Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec) + LotId = LotOperationRec + EquipmentId = Database_Services('ReadDataColumn', 'MET_TEST', MetTestId, MET_TEST.TOOL$, True$, 0, False$) + Lot_Event_Services('CreateLotEvent', LotId, DateTime(), 'MET_TEST', 'Metrology attached to lot.', EquipmentId, UserId) + end else + ErrorMsg = 'Error in ':Service:' service. Failed to write ':LotOperationId + ErrorMsg := ' on LOT_OPERATION_ID column for MET_TEST ':MetTestId + end + end else + ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.' + end + end else + ErrorMsg = 'Error in ':Service:' service. LOT_OPERATION ':LotOperationId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId or LotOperationId passed into service.' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + +Service RemoveMetTestFromLotOperation(MetTestId, LotOperationId, UserId) + + ErrorMsg = '' + If ( (MetTestId NE '') and (LotOperationId NE '') ) then + If RowExists('MET_TEST', MetTestId) then + If RowExists('LOT_OPERATION', LotOperationId) then + MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId, True$, 0, False$) + MetTestRec = '' + Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec) + If Error_Services('NoError') then + LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$) + Locate MetTestId in LotOperationRec using @VM setting MetTestPos then + LotOperationRec = Delete(LotOperationRec, 1, MetTestPos, 1) + end + Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec) + LotId = LotOperationRec + EquipmentId = Database_Services('ReadDataColumn', 'MET_TEST', MetTestId, MET_TEST.TOOL$, True$, 0, False$) + Lot_Event_Services('CreateLotEvent', LotId, DateTime(), 'MET_TEST', 'Metrology attached to lot.', EquipmentId, UserId) + end else + ErrorMsg = 'Error in ':Service:' service. Error removing MET_TEST ':MetTestId:' from operation.' + end + end + end else + ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null MetTestId or LotOperationId passed into service.' + end + + If ErrorMsg EQ '' then + Response = True$ + end else + Error_Services('Add', ErrorMsg) + Response = False$ + end + +end service + + + + diff --git a/LSL2/STPROC/MONAENGINES_API.txt b/LSL2/STPROC/MONAENGINES_API.txt index 3d5d7da..8645704 100644 --- a/LSL2/STPROC/MONAENGINES_API.txt +++ b/LSL2/STPROC/MONAENGINES_API.txt @@ -1,138 +1,137 @@ -Function Monaengines_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Monaengines_API - - Description : API logic for the Monaengines resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Monaengines[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Monaengines.POST - - Monaengines.ID.PUT - - Monaengines.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 07/17/24 xxx Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS -$insert ENGINE_HEALTH_EQUATES - -Equ Comma$ to ',' - -Declare function System_Healthcheck_Services, Environment_Services, Logging_Services -Declare subroutine Logging_Services - -LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Healthchecks\Engines\MonA' -LogDate = Oconv(Date(), 'D4/') -LogTime = Oconv(Time(), 'MTS') -LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Mona_Engine_Health_Check_Log.csv' -Headers = 'Logging DTM' : @FM : 'EngineID' : @FM : 'ResponseCode' : @FM : 'Message' : @FM : 'Requester' -objLogMonaEngines = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$) -LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API monaengines.HEAD -API monaengines.GET - - HTTP_Resource_Services('LoremIpsum') - -end api - - -API monaengines.ID.HEAD -API monaengines.ID.GET - - //Returns status of a defined engine - EngineID = EndpointSegment - If RowExists('APP_INFO', EngineID) then - EngineHealthInfo = System_Healthcheck_Services('GetEngineHealthInfo', EngineID) - If Error_Services('NoError') then - Healthy = EngineHealthInfo - If Healthy then - ResponseCode = 200 - Message = 'Engine is healthy' - HTTP_Services('SetResponseStatus', ResponseCode, Message) - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = EngineID - LogData<3> = ResponseCode - LogData<4> = Message - LogData<5> = FullEndpointURL - Logging_Services('AppendLog', objLogMonaEngines, LogData, @RM, @FM) - end else - ResponseCode = 418 - Message = 'Engine is unhealthy.' - HTTP_Services('SetResponseStatus', ResponseCode, Message) - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = EngineID - LogData<3> = ResponseCode - LogData<4> = Message - LogData<5> = FullEndpointURL - Logging_Services('AppendLog', objLogMonaEngines, LogData, @RM, @FM) - end - end else - ResponseCode = 500 - Message = Error_Services('GetMessage') - HTTP_Services('SetResponseStatus', ResponseCode, Message) - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = EngineID - LogData<3> = ResponseCode - LogData<4> = Message - LogData<5> = FullEndpointURL - Logging_Services('AppendLog', objLogMonaEngines, LogData, @RM, @FM) - end - end else - ResponseCode = 404 - Message = 'Invalid Engine ID' - HTTP_Services('SetResponseStatus', ResponseCode, 'Invalid Engine ID.') - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = EngineID - LogData<3> = ResponseCode - LogData<4> = Message - LogData<5> = FullEndpointURL - Logging_Services('AppendLog', objLogMonaEngines, LogData, @RM, @FM) - end - -end api - +Function Monaengines_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Monaengines_API + + Description : API logic for the Monaengines resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Monaengines[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Monaengines.POST + - Monaengines.ID.PUT + - Monaengines.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 07/17/24 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS +$insert ENGINE_HEALTH_EQUATES + +Equ Comma$ to ',' + +Declare function System_Healthcheck_Services, Environment_Services, Logging_Services +Declare subroutine Logging_Services + +LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Healthchecks\Engines\MonA' +LogDate = Oconv(Date(), 'D4/') +LogTime = Oconv(Time(), 'MTS') +LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Mona_Engine_Health_Check_Log.csv' +Headers = 'Logging DTM' : @FM : 'EngineID' : @FM : 'ResponseCode' : @FM : 'Message' : @FM : 'Requester' +objLogMonaEngines = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$) +LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API monaengines.HEAD +API monaengines.GET + + HTTP_Resource_Services('LoremIpsum') + +end api + + +API monaengines.ID.HEAD +API monaengines.ID.GET + + //Returns status of a defined engine + EngineID = EndpointSegment + If RowExists('APP_INFO', EngineID) then + EngineHealthInfo = System_Healthcheck_Services('GetEngineHealthInfo', EngineID) + If Error_Services('NoError') then + Healthy = EngineHealthInfo + If Healthy then + ResponseCode = 200 + Message = 'Engine is healthy' + HTTP_Services('SetResponseStatus', ResponseCode, Message) + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = EngineID + LogData<3> = ResponseCode + LogData<4> = Message + LogData<5> = FullEndpointURL + Logging_Services('AppendLog', objLogMonaEngines, LogData, @RM, @FM) + end else + ResponseCode = 418 + Message = 'Engine is unhealthy.' + HTTP_Services('SetResponseStatus', ResponseCode, Message) + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = EngineID + LogData<3> = ResponseCode + LogData<4> = Message + LogData<5> = FullEndpointURL + Logging_Services('AppendLog', objLogMonaEngines, LogData, @RM, @FM) + end + end else + ResponseCode = 500 + Message = Error_Services('GetMessage') + HTTP_Services('SetResponseStatus', ResponseCode, Message) + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = EngineID + LogData<3> = ResponseCode + LogData<4> = Message + LogData<5> = FullEndpointURL + Logging_Services('AppendLog', objLogMonaEngines, LogData, @RM, @FM) + end + end else + ResponseCode = 404 + Message = 'Invalid Engine ID' + HTTP_Services('SetResponseStatus', ResponseCode, 'Invalid Engine ID.') + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = EngineID + LogData<3> = ResponseCode + LogData<4> = Message + LogData<5> = FullEndpointURL + Logging_Services('AppendLog', objLogMonaEngines, LogData, @RM, @FM) + end + +end api diff --git a/LSL2/STPROC/MONA_API.txt b/LSL2/STPROC/MONA_API.txt index d1fd25e..3a167c6 100644 --- a/LSL2/STPROC/MONA_API.txt +++ b/LSL2/STPROC/MONA_API.txt @@ -1,64 +1,63 @@ -Function Mona_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Mona_API - - Description : API logic for the Mona resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Mona[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Mona.POST - - Mona.ID.PUT - - Mona.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 07/17/24 xxx Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API mona.HEAD -API mona.GET - - HTTP_Resource_Services('LoremIpsum') - -end api - +Function Mona_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Mona_API + + Description : API logic for the Mona resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Mona[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Mona.POST + - Mona.ID.PUT + - Mona.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 07/17/24 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API mona.HEAD +API mona.GET + + HTTP_Resource_Services('LoremIpsum') + +end api diff --git a/LSL2/STPROC/NDW_ADJUST_LOT_QTY_EVENTS.txt b/LSL2/STPROC/NDW_ADJUST_LOT_QTY_EVENTS.txt index b3269ee..9e3aeb9 100644 --- a/LSL2/STPROC/NDW_ADJUST_LOT_QTY_EVENTS.txt +++ b/LSL2/STPROC/NDW_ADJUST_LOT_QTY_EVENTS.txt @@ -190,9 +190,3 @@ return - - - - - - diff --git a/LSL2/STPROC/NDW_PACKAGING_EVENTS.txt b/LSL2/STPROC/NDW_PACKAGING_EVENTS.txt index 91f856c..79e49c1 100644 --- a/LSL2/STPROC/NDW_PACKAGING_EVENTS.txt +++ b/LSL2/STPROC/NDW_PACKAGING_EVENTS.txt @@ -212,7 +212,7 @@ Event EDL_TRILAM_SCAN.LOSTFOCUS(Flag, FocusID) end event Event EDL_PASSWORD_SCAN.LOSTFOCUS(Flag, FocusID) - + If Flag EQ 1 then ScanData = Get_Property(CtrlEntID, 'TEXT') If ScanData NE '' then @@ -300,3 +300,5 @@ SetDelay: return + + diff --git a/LSL2/STPROC/OPERATION_API.txt b/LSL2/STPROC/OPERATION_API.txt new file mode 100644 index 0000000..0eea6d2 --- /dev/null +++ b/LSL2/STPROC/OPERATION_API.txt @@ -0,0 +1,130 @@ +Function Operation_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Operation_API + + Description : API logic for the Operation resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Operation[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Operation.POST + - Operation.ID.PUT + - Operation.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 05/19/25 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +Declare function OI_Wizard_Services, Operation_Services, Clean_Services, Lot_Operation_Services + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API operation.HEAD +API operation.GET + + JSONCollection = '' + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + If ValidSession then + Body = HTTP_Services('GetHTTPGetString') + If Body NE '' then + RequestJson = HTTP_Services('DecodePercentString', Body) + ClassFilter = Http_Services('GetQueryField', 'Class') + ActiveFilter = Http_Services('GetQueryField', 'Active') + LotId = Http_Services('GetQueryField', 'LotId') + Operations = Operation_Services('GetOperations', ClassFilter, ActiveFilter) + + objJSONResponse = '' + If SRP_Json(objJSONResponse, 'New', 'Object') then + //Available Operations + If SRP_Json(objOperations, 'New', 'Array') then + for each Operation in Operations using @VM + OperationJSONString = Operation_Services('ConvertRecordToJSON', Operation) + objOperation = '' + If SRP_Json(objOperation, 'Parse', OperationJSONString) EQ '' then + SRP_Json(objOperations, 'Add', objOperation) + SRP_Json(objOperation, 'Release') + end + Next Operation + SRP_Json(objJsonResponse, 'Set', 'Operations', objOperations) + SRP_Json(objOperations, 'Release') + end else + Error_Services('Add', 'Error when creating Operation array in JSON response.') + end + //Available Sequences + Sequences = Lot_Operation_Services('GetAvailableSequences', LotId) + If SRP_Json(objSequences, 'New', 'Array') then + for each Sequence in Sequences using @VM + SRP_Json(objSequences, 'AddValue', Sequence, 'Number') + Next Sequence + SRP_Json(objJsonResponse, 'Set', 'AvailableSequences', objSequences) + SRP_Json(objSequences, 'Release') + end else + Error_Services('Add', 'Error when creating Operation array in JSON response.') + end + JsonResponse = SRP_Json(objJsonResponse, 'Stringify', 'Styled') + SRP_Json(objJsonResponse, 'Release') + end else + Error_Services('Add', 'Error when creating JSON response.') + end + end else + Error_Services('Add', 'No body was sent with the request.') + end + If Error_Services('NoError') then + HTTP_Services('SetResponseStatus', 201, 'Success') + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseBody', JsonResponse, False$, 'application/hal+json') + end else + HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage')) + end + end else + HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.') + end + +end api diff --git a/LSL2/STPROC/OPERATION_EQUATES.txt b/LSL2/STPROC/OPERATION_EQUATES.txt new file mode 100644 index 0000000..3282a09 --- /dev/null +++ b/LSL2/STPROC/OPERATION_EQUATES.txt @@ -0,0 +1,21 @@ +compile insert OPERATION_EQUATES +/*---------------------------------------- + Author : Table Create Insert Routine + Written : 29/05/2025 + Description : Insert for Table OPERATION +----------------------------------------*/ +#ifndef __OPERATION_EQUATES__ +#define __OPERATION_EQUATES__ + + equ OPERATION_ACTIVE$ to 1 + equ OPERATION_CLASS_ID$ to 2 + equ OPERATION_OPERATION_DESCRIPTION$ to 3 + equ OPERATION_TYPE$ to 4 + equ OPERATION_REWORK$ to 5 + equ OPERATION_MET_TEST_TYPE_REQUIRED$ to 6 + equ OPERATION_MET_TEST_REQUIRED$ to 7 + equ OPERATION_PACKAGING_REQUIRED$ to 8 + equ OPERATION_CLEAN_REQUIRED$ to 9 + equ OPERATION_WAFER_COUNTER_REQUIRED$ to 10 + +#endif diff --git a/LSL2/STPROC/OPERATION_SERVICES.txt b/LSL2/STPROC/OPERATION_SERVICES.txt new file mode 100644 index 0000000..8ae7750 --- /dev/null +++ b/LSL2/STPROC/OPERATION_SERVICES.txt @@ -0,0 +1,57 @@ +Compile function Operation_Services(@Service, @Params) +#pragma precomp SRP_PreCompiler + +Declare function Database_Services, SRP_Json +Declare subroutine Database_Services, SRP_Json, Btree.Extract + +$insert LOGICAL +$Insert OPERATION_EQUATES + +Options OPERATION_TYPE = 'CLEAN', 'THICK_METROLOGY', 'RES_METROLOGY', 'SURFACE_METROLOGY', 'VISUAL_INSPECTION', 'PACKAGING' + +GoToService + +Return Response or "" + +//----------------------------------------------------------------------------- +// SERVICES +//----------------------------------------------------------------------------- + +Service ConvertRecordToJson(OperationId) + + JsonString = '' + objJSON = '' + OperationRec = Database_Services('ReadDataRow', 'OPERATION', OperationId, True$, 0, False$) + If SRP_JSON(objJSON, 'New', 'Object') then + SRP_JSON(objJSON, 'SetValue', 'OperationId', OperationId) + SRP_JSON(objJSON, 'SetValue', 'Active', OperationRec, 'Boolean') + SRP_JSON(objJSON, 'SetValue', 'ClassId', OperationRec, 'String') + SRP_JSON(objJSON, 'SetValue', 'Description', OperationRec, 'String') + SRP_JSON(objJSON, 'SetValue', 'Type', OperationRec, 'String') + JsonString = SRP_JSON(objJSON, 'Stringify', 'Styled') + SRP_JSON(objJSON, 'Release') + end + + Response = JsonString + +End Service + +Service GetOperations(Class, ActiveFlag) + + ErrorMessage = '' + RTFOperationKeys = '' + + Open 'DICT.OPERATION' to DICT then + SearchString = 'CLASS_ID':@VM:Class:@FM + SearchString := 'ACTIVE':@VM:True$:@FM + Option = '' + Flag = '' + Btree.Extract(SearchString, 'OPERATION', DICT, RTFOperationKeys, Option, Flag) + end else + ErrorMessage = 'Error opening OPERATION table dictionary.' + end + + Response = RTFOperationKeys + +end service + diff --git a/LSL2/STPROC/PACKAGING_SERVICES.txt b/LSL2/STPROC/PACKAGING_SERVICES.txt index 94fdb92..650c2a0 100644 --- a/LSL2/STPROC/PACKAGING_SERVICES.txt +++ b/LSL2/STPROC/PACKAGING_SERVICES.txt @@ -32,11 +32,24 @@ $insert SCANS_EQUATES $insert APP_INSERTS $insert WO_MAT_EQUATES $insert NOTIFICATION_EQU +$insert PACKAGING_EQUATES +$insert LOT_OPERATION_EQUATES +$Insert LOT_EQUATES Declare function Scan_Services, Memory_Services, Database_Services, SRP_JSON, RTI_CreateGUID, Memberof -Declare function Get_Property, RDS_Services, EpiPro_Services, DateTime, Signature_Services +Declare function Get_Property, RDS_Services, EpiPro_Services, DateTime, Signature_Services, Packaging_Services +Declare function Lot_Services, Environment_Services, Logging_Services Declare subroutine Scan_Services, Memory_Services, Database_Services, SRP_JSON, Security_Services, obj_Notes Declare subroutine obj_WO_Mat_Log, obj_WO_Mat, Set_Status, SAP_Services, Rds_Services, Wm_Out_Services, Hold_Services +Declare subroutine Lot_Event_Services, Lot_Services, Packaging_Services, Logging_Services + +LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Packaging' +LogDate = Oconv(Date(), 'D4/') +LogTime = Oconv(Time(), 'MTS') +LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM +LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Packaging Log.csv' +Headers = 'Logging DTM' : @FM : 'Message' +objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$) GoToService else Error_Services('Add', Service : ' is not a valid service request within the ' : ServiceModule : ' module.') @@ -62,6 +75,7 @@ Service CompletePackaging(CassetteID, OperatorID, BaggerIdentifier) RDSKey = CassetteID WMOKey = CassetteID + LotId = '' Convert '.' to '*' in WMOKey CommentEntity = '' Begin Case @@ -70,11 +84,13 @@ Service CompletePackaging(CassetteID, OperatorID, BaggerIdentifier) WOMatKey = Xlate('RDS', RDSKey, 'WO', 'X') WOMatKey = WoMatKey:'*':Xlate('RDS', RDSKey, 'CASS_NO', 'X') CommentEntity = 'RDS' + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKey, 'RDS') Case RowExists('WM_OUT', WMOKey) EQ True$ // WM_OUT key WOMatKey = Xlate('WM_OUT', WMOKey, 'WO_MAT_KEY', 'X') CommentEntity = 'WM_OUT' + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', WMOKey, 'WM_OUT') Case RowExists('WO_MAT', CassetteID) EQ True$ // WO_MAT key @@ -126,7 +142,7 @@ Service CompletePackaging(CassetteID, OperatorID, BaggerIdentifier) WOMLParms := ToolID obj_WO_Mat_Log('Create',WOMLParms) - errCode = '' + errCode = '' IF Get_Status(errCode) THEN swap @SVM with CRLF$ in errCode ErrorMsg = 'Errors calling obj_WO_Mat_Log("Create"). Error code: ':errCode:', Len(errCode)=':Len(errCode) @@ -138,6 +154,24 @@ Service CompletePackaging(CassetteID, OperatorID, BaggerIdentifier) // Add CassComp transaction to SAP queue SAPBatchNo = Xlate('WO_MAT', WOMatKey, 'SAP_BATCH_NO', 'X') If SAPBatchNo EQ '' then SAP_Services('AddCassCompTransaction', WOMatKey) + + //Handle NG lot functions. + If LotId NE '' then + NewPackRecId = Packaging_Services('CreatePackagingRecord', LotId, UserID, ToolID) + CurrOperationId = Lot_Services('GetLotCurrOperationId', LotId) + If CurrOperationId NE '' then + Packaging_Services('AddPackToLotOperation', CurrOperationId, NewPackRecId, UserID) + If Error_Services('NoError') then + Lot_Services('MoveOutLot', LotId, UserId) + end + end + + If Error_Services('HasError') then + //Remove any error messages as a result of NG Lot functions. At the moment we don't want them interrupting production when they occur. + Error_Services('Clear') + end + end + end end @@ -664,3 +698,72 @@ Service ProcessScanData(ScanData, ScanType = SCAN_TYPES, Param1, Param2, Param3) end service +Service CreatePackagingRecord(LotId, UserId, EqpId) + + NewRecId = '' + ErrorMessage = '' + + If RowExists('LOT', LotId) then + NewRecId = RTI_CreateGuid() + TransDtm = Datetime() + NewPackagingRec = '' + NewPackagingRec = LotId + NewPackagingRec = True$ + NewPackagingRec = TransDtm + Database_Services('WriteDataRow', 'PACKAGING', NewRecId, NewPackagingRec, True$, 0, False$) + If Error_Services('NoError') then + Lot_Event_Services('CreateLotEvent', LotId, TransDtm, 'PACKAGING', 'Lot Packaged.', EqpId, UserId) + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = 'LOT: ' LotId : ' not found' + end + If ErrorMessage NE '' then + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = Error_Services('GetMessage') + Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) + Error_Services('Clear') + end + + Response = NewRecId + +end service + +Service AddPackToLotOperation(LotOperationId, PackagingId, UserId) + + ErrorMessage = '' + + If RowExists('LOT_OPERATION', LotOperationId) then + If RowExists('LSL_USERS', UserId) then + //Can add user group check here. + LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$) + LotId = LotOperationRec + ExistingPackId = LotOperationRec + If ExistingPackId EQ '' then + LotOperationRec = PackagingId + Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec) + If Error_Services('NoError') then + TransDtm = Datetime() + Lot_Event_Services('CreateLotEvent', LotId, TransDtm, 'COMMENT', 'PACKAGING record added to operation.', '', UserId) + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = 'A pack scan already exists for the lot operation. Please remove the pack before adding a new one.' + end + end else + ErrorMessage = 'USER ID: ' UserId : ' not found.' + end + end else + ErrorMessage = 'LOT_OPERATION: ' LotOperationId : ' not found.' + end + If ErrorMessage NE '' then + Error_Services('Add', ErrorMessage) + end + +end service + + + diff --git a/LSL2/STPROC/PM_API.txt b/LSL2/STPROC/PM_API.txt index daaf523..ea0acbc 100644 --- a/LSL2/STPROC/PM_API.txt +++ b/LSL2/STPROC/PM_API.txt @@ -1,79 +1,78 @@ -Function Pm_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Pm_API - - Description : API logic for the Pm resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Pm[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Pm.POST - - Pm.ID.PUT - - Pm.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 06/05/24 xxx Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API pm.HEAD -API pm.GET - - HTTP_Resource_Services('LoremIpsum') - -end api - - -API pm.ID.HEAD -API pm.ID.GET - - HTTP_Resource_Services('LoremIpsum') - -end api - - -API pm.ID.POST - - HTTP_Resource_Services('LoremIpsum') - -end api - +Function Pm_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Pm_API + + Description : API logic for the Pm resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Pm[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Pm.POST + - Pm.ID.PUT + - Pm.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 06/05/24 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API pm.HEAD +API pm.GET + + HTTP_Resource_Services('LoremIpsum') + +end api + + +API pm.ID.HEAD +API pm.ID.GET + + HTTP_Resource_Services('LoremIpsum') + +end api + + +API pm.ID.POST + + HTTP_Resource_Services('LoremIpsum') + +end api diff --git a/LSL2/STPROC/PM_SPEC_API.txt b/LSL2/STPROC/PM_SPEC_API.txt index 347a88b..e64245f 100644 --- a/LSL2/STPROC/PM_SPEC_API.txt +++ b/LSL2/STPROC/PM_SPEC_API.txt @@ -1,64 +1,63 @@ -Function Pm_spec_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Pm_spec_API - - Description : API logic for the Pm_spec resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Pm_spec[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Pm_spec.POST - - Pm_spec.ID.PUT - - Pm_spec.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 06/05/24 xxx Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API pm_spec.HEAD -API pm_spec.GET - - HTTP_Resource_Services('LoremIpsum') - -end api - +Function Pm_spec_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Pm_spec_API + + Description : API logic for the Pm_spec resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Pm_spec[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Pm_spec.POST + - Pm_spec.ID.PUT + - Pm_spec.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 06/05/24 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API pm_spec.HEAD +API pm_spec.GET + + HTTP_Resource_Services('LoremIpsum') + +end api diff --git a/LSL2/STPROC/PROD_SPEC_API.txt b/LSL2/STPROC/PROD_SPEC_API.txt index f671fb1..1617364 100644 --- a/LSL2/STPROC/PROD_SPEC_API.txt +++ b/LSL2/STPROC/PROD_SPEC_API.txt @@ -102,5 +102,3 @@ CreateHALItem: end return - - diff --git a/LSL2/STPROC/PSN_SERVICES.txt b/LSL2/STPROC/PSN_SERVICES.txt index a56fb83..c36442b 100644 --- a/LSL2/STPROC/PSN_SERVICES.txt +++ b/LSL2/STPROC/PSN_SERVICES.txt @@ -35,9 +35,11 @@ $Insert RDS_TEST_EQUATES $Insert RDS_TEST_PROP_EQUATES $Insert PRS_LAYER_EQU +Options SpecTypes = 'CLEAN', 'SURFSCAN', 'THICK', 'THICKA', 'RES', 'SRES', 'CRES', 'CONC' + Declare function Database_Services, Psn_Services, obj_Prod_Spec, Error_Services, SRP_JSON, Cust_Epi_Part_Services -Declare function Prod_Ver_Services, PRS_Stage_Services -Declare subroutine Database_Services, Psn_Services, Error_Services, SRP_JSON +Declare function Prod_Ver_Services, PRS_Stage_Services, SRP_Array +Declare subroutine Database_Services, Psn_Services, Error_Services, SRP_JSON, Extract_Si_Keys GoToService else Error_Services('Add', Service : ' is not a valid service request within the ' : ServiceModule : ' services module.') @@ -72,6 +74,216 @@ Service InitializeCritParams(PSNo) end service +Service GetRecipes(PSNo) + + ErrorMsg = '' + Recipes = '' + If PSNo NE '' then + If RowExists('PROD_SPEC', PSNo) then + PropKeys = '' + Extract_Si_Keys('PRS_PROP', 'PS_NO', PSNo, PropKeys) + Recipes = Xlate('PRS_PROP', PropKeys, 'MET_RECIPE', 'X') + PRSStageKeys = '' + Extract_Si_Keys('PRS_STAGE', 'PS_NO', PSNo, PRSStageKeys) + Recipes<0, -1> = Xlate('PRS_STAGE', PRSStageKeys, 'MET_RECIPE', 'X') + Recipes<0, -1> = Xlate('PRS_STAGE', PRSStageKeys, 'SURFSCAN_RECIPE', 'X') + Recipes<0, -1> = @VM : Xlate('PRS_STAGE', PRSStageKeys, 'CLEAN_RECIPE', 'X') + Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @VM) + end else + ErrorMsg = 'Error in ':Service:' service. PROD_SPEC record "':PSNo:'" does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null PSNo passed into service.' + end + + If ErrorMsg EQ '' then + Response = Recipes + end else + Error_Services('Add', ErrorMsg) + end + +end service + +Service GetAllMetrologyRecipes(PSNo, GetSurfscan, GetClean, GetRes, GetThick) + + Recipes = '' + If GetSurfscan EQ '' then GetSurfscan = True$ + If GetClean EQ '' then GetClean = True$ + If GetRes EQ '' then GetRes = True$ + If GetThick EQ '' then GetThick = True$ + + If GetSurfscan then Recipes := PSN_Services('GetSurfscanRecipes', PSNo) : @FM + If GetClean then Recipes := PSN_Services('GetCleanRecipes', PSNo) :@FM + If GetRes then Recipes := PSN_Services('GetResRecipes', PSNo) :@FM + If GetThick then Recipes := PSN_Services('GetThicknessRecipes', PSNo) + + Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @FM) + Response = Recipes + +end service + +Service GetSurfscanRecipes(PSNo) + + Recipes = '' + If PSNo NE '' then + If RowExists('PROD_SPEC', PSNo) then + PropKeys = '' + Extract_Si_Keys('PRS_PROP', 'PS_NO', PSNo, PropKeys) + PRSStageKeys = '' + Extract_Si_Keys('PRS_STAGE', 'PS_NO', PSNo, PRSStageKeys) + for each PRSStageKey in PRSStageKeys using @VM setting pPos + Stage = Xlate('PRS_STAGE', PRSStageKey, 'STAGE', 'X') + TencorRecipes = Xlate('PRS_STAGE', PRSStageKey, 'SURFSCAN_RECIPE', 'X') + for each Recipe in TencorRecipes using @VM + ToolClass = 'TENCOR' + Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage + Next TencorRecipe + Next PRSStageKey + Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @FM) + end + end + Response = Recipes + +end service + +Service GetCleanRecipes(PSNo) + + Recipes = '' + If PSNo NE '' then + If RowExists('PROD_SPEC', PSNo) then + PropKeys = '' + Extract_Si_Keys('PRS_PROP', 'PS_NO', PSNo, PropKeys) + PRSStageKeys = '' + Extract_Si_Keys('PRS_STAGE', 'PS_NO', PSNo, PRSStageKeys) + for each PRSStageKey in PRSStageKeys using @VM setting pPos + Stage = Xlate('PRS_STAGE', PRSStageKey, 'STAGE', 'X') + CleanRecipes = Xlate('PRS_STAGE', PRSStageKey, 'CLEAN_RECIPE', 'X') + for each Recipe in CleanRecipes using @VM + ToolClass = 'CLEAN' + Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage + Next TencorRecipe + Next PRSStageKey + Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @FM) + end + end + Response = Recipes + +end service + +Service GetThicknessRecipes(PSNo) + + ErrorMsg = '' + Recipes = '' + If PSNo NE '' then + If RowExists('PROD_SPEC', PSNo) then + //First get QA Recipes + PropKeys = '' + Extract_Si_Keys('PRS_PROP', 'PS_NO', PSNo, PropKeys) + Recipes = '' + PRSStageKeys = '' + Extract_Si_Keys('PRS_STAGE', 'PS_NO', PSNo, PRSStageKeys) + for each PRSStageKey in PRSStageKeys using @VM setting pPos + Stage = Xlate('PRS_STAGE', PRSStageKey, 'STAGE', 'X') + PRSStageRecipes = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE', 'X') + for each PRSStageRecipe in PRSStageRecipes using @VM setting rPos + PropType = Xlate('PRS_STAGE', PRSStageKey, 'MET_PROP', 'X')<1, rPos> + If PropType EQ 'THICK' OR PropType EQ 'THICKA' then + Recipe = PRSStageRecipe + ToolClass = 'FTIR' + Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage + end + Next PRSStageRecipe + Next PRSStageKey + //Next get Rathole recipes + SpecEpiData = XLATE('PROD_SPEC', PSNo, 'SPEC_EPI', 'X') + swap @VM with @FM in SpecEpiData + swap '~' with @VM in SpecEpiData + ThicknessData = SpecEpiData<13> + ToolClass = ThicknessData<1, 1> + Recipe = ThicknessData<1, 3> + Stage = 'RDS_TEST' + If ToolClass EQ 'FTIR' OR ToolClass EQ 'ADE' then + Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage + end + // Remove any duplicate entries + Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @FM) + end else + ErrorMsg = 'Error in ':Service:' service. PROD_SPEC record "':PSNo:'" does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null PSNo passed into service.' + end + + If ErrorMsg EQ '' then + Response = Recipes + end else + Error_Services('Add', ErrorMsg) + end + +end service + +Service GetResRecipes(PSNo) + + ErrorMsg = '' + Recipes = '' + If PSNo NE '' then + If RowExists('PROD_SPEC', PSNo) then + //First get QA Recipes + PropKeys = '' + Extract_Si_Keys('PRS_PROP', 'PS_NO', PSNo, PropKeys) + Recipes = '' + PRSStageKeys = '' + Extract_Si_Keys('PRS_STAGE', 'PS_NO', PSNo, PRSStageKeys) + for each PRSStageKey in PRSStageKeys using @VM setting pPos + Stage = Xlate('PRS_STAGE', PRSStageKey, 'STAGE', 'X') + PRSStageRecipes = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE', 'X') + for each PRSStageRecipe in PRSStageRecipes using @VM setting rPos + PropType = Xlate('PRS_STAGE', PRSStageKey, 'MET_PROP', 'X')<1, rPos> + ToolClass = Xlate('PRS_STAGE', PRSStageKey, 'MET_TOOL_CLASS', 'X')<1, rPos> + If PropType EQ 'RES' OR PropType EQ 'SRES' OR PropType EQ 'CRES' OR PropType EQ 'CONC' then + Recipe = PRSStageRecipe + ToolClass = ToolClass + Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage + end + Next PRSStageRecipe + Next PRSStageKey + //Next get Rathole recipes + Stage = 'RDS_TEST' + SpecEpiData = XLATE('PROD_SPEC', PSNo, 'SPEC_EPI', 'X') + swap @VM with @FM in SpecEpiData + swap '~' with @VM in SpecEpiData + ResData1 = SpecEpiData<19> + + If ResData1 NE '' then + ToolClass = ResData1<1, 1> + Recipe = ResData1<1, 3> + Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage + end + + ResData2 = SpecEpiData<14> + If ResData2 NE '' then + ToolClass = ResData2<1, 1> + Recipe = ResData2<1, 3> + Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage + end + + // Remove any duplicate entries + Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @FM) + end else + ErrorMsg = 'Error in ':Service:' service. PROD_SPEC record "':PSNo:'" does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null PSNo passed into service.' + end + + If ErrorMsg EQ '' then + Response = Recipes + end else + Error_Services('Add', ErrorMsg) + end + +end service + Service CheckPSNStages(PSNo, Stage) Begin Case @@ -950,3 +1162,8 @@ CheckAdHoc: return + + + + + diff --git a/LSL2/STPROC/REACTORLOADINGS_API.txt b/LSL2/STPROC/REACTORLOADINGS_API.txt index 3401729..ca8f3f1 100644 --- a/LSL2/STPROC/REACTORLOADINGS_API.txt +++ b/LSL2/STPROC/REACTORLOADINGS_API.txt @@ -1,106 +1,105 @@ -Function Reactorloadings_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Reactorloadings_API - - Description : API logic for the Reactorloadings resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Reactorloadings[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Reactorloadings.POST - - Reactorloadings.ID.PUT - - Reactorloadings.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 05/22/24 xxx Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -Declare function Oi_Wizard_Services, Memberof, Oi_Wizard_Services -Declare subroutine Reactor_Services, Oi_Wizard_Services - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API reactorloadings.POST - OIWizardID = '' - CurrUser = '' - Cookies = HTTP_Services('GetHTTPCookie') - For each Cookie in Cookies using ';' - Key = Trim(Field(Cookie, '=', 1)) - If Key EQ 'sessionID' then - OIWizardID = Field(Cookie, '=', 2) - end - Next Cookie - - If OIWizardID NE '' then - // Call validate session to extend session expiry - OI_Wizard_Services('ValidateSession', OIWizardID) - CurrUser = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X') - end - - ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) - - If ValidSession then - If Memberof(CurrUser, 'OI_ADMIN') OR Memberof(CurrUser, 'LEAD') OR Memberof(CurrUser, 'SUPERVISOR') then - Body = HTTP_Services('GetHTTPPostString', True$) - // The POST string will have been encoded so use percent (URL) decoding. - DecodedJSON = HTTP_Services('DecodePercentString', Body) - If SRP_JSON(objBody, 'Parse', Body) EQ '' then - rdsNo = SRP_JSON(objBody, 'GetValue', 'rdsNo') - reactorNo = SRP_JSON(objBody, 'GetValue', 'reactorNo') - SRP_JSON(objBody, 'Release') - end - - Reactor_Services('RemoveRDSFromReactorLoad', rdsNo, reactorNo, CurrUser) - If Error_Services('NoError') then - HTTP_Services('SetResponseStatus', 200, 'RDS Successfully removed.') - end else - ErrCode = Error_Services('GetMessage') - HTTP_Services('SetResponseStatus', 500, ErrCode) - end - end else - HTTP_Services('SetResponseStatus', 503, 'User is not authorized!') - end - End else - HTTP_Services('SetResponseStatus', 401, 'User must be signed in to access this resource.') - end - -end api - +Function Reactorloadings_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Reactorloadings_API + + Description : API logic for the Reactorloadings resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Reactorloadings[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Reactorloadings.POST + - Reactorloadings.ID.PUT + - Reactorloadings.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 05/22/24 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +Declare function Oi_Wizard_Services, Memberof, Oi_Wizard_Services +Declare subroutine Reactor_Services, Oi_Wizard_Services + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API reactorloadings.POST + OIWizardID = '' + CurrUser = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Trim(Field(Cookie, '=', 1)) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + If OIWizardID NE '' then + // Call validate session to extend session expiry + OI_Wizard_Services('ValidateSession', OIWizardID) + CurrUser = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X') + end + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + If Memberof(CurrUser, 'OI_ADMIN') OR Memberof(CurrUser, 'LEAD') OR Memberof(CurrUser, 'SUPERVISOR') then + Body = HTTP_Services('GetHTTPPostString', True$) + // The POST string will have been encoded so use percent (URL) decoding. + DecodedJSON = HTTP_Services('DecodePercentString', Body) + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + rdsNo = SRP_JSON(objBody, 'GetValue', 'rdsNo') + reactorNo = SRP_JSON(objBody, 'GetValue', 'reactorNo') + SRP_JSON(objBody, 'Release') + end + + Reactor_Services('RemoveRDSFromReactorLoad', rdsNo, reactorNo, CurrUser) + If Error_Services('NoError') then + HTTP_Services('SetResponseStatus', 200, 'RDS Successfully removed.') + end else + ErrCode = Error_Services('GetMessage') + HTTP_Services('SetResponseStatus', 500, ErrCode) + end + end else + HTTP_Services('SetResponseStatus', 503, 'User is not authorized!') + end + End else + HTTP_Services('SetResponseStatus', 401, 'User must be signed in to access this resource.') + end + +end api diff --git a/LSL2/STPROC/REACTORLOGS_API.txt b/LSL2/STPROC/REACTORLOGS_API.txt index de0f2d5..47dbe45 100644 --- a/LSL2/STPROC/REACTORLOGS_API.txt +++ b/LSL2/STPROC/REACTORLOGS_API.txt @@ -260,5 +260,3 @@ API reactorlogs.ID.nicaoverride.PUT HTTP_Resource_Services('LoremIpsum') end api - - diff --git a/LSL2/STPROC/REACTORS_API.txt b/LSL2/STPROC/REACTORS_API.txt index 77db978..66411b1 100644 --- a/LSL2/STPROC/REACTORS_API.txt +++ b/LSL2/STPROC/REACTORS_API.txt @@ -259,5 +259,3 @@ CreateHALCollection: end return - - diff --git a/LSL2/STPROC/REMOTEHEALTHCHECK_API.txt b/LSL2/STPROC/REMOTEHEALTHCHECK_API.txt index e6c64cb..254a85b 100644 --- a/LSL2/STPROC/REMOTEHEALTHCHECK_API.txt +++ b/LSL2/STPROC/REMOTEHEALTHCHECK_API.txt @@ -1,64 +1,63 @@ -Function Remotehealthcheck_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Remotehealthcheck_API - - Description : API logic for the Remotehealthcheck resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Remotehealthcheck[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Remotehealthcheck.POST - - Remotehealthcheck.ID.PUT - - Remotehealthcheck.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 07/17/24 xxx Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API remotehealthcheck.HEAD -API remotehealthcheck.GET - - HTTP_Resource_Services('LoremIpsum') - -end api - +Function Remotehealthcheck_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Remotehealthcheck_API + + Description : API logic for the Remotehealthcheck resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Remotehealthcheck[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Remotehealthcheck.POST + - Remotehealthcheck.ID.PUT + - Remotehealthcheck.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 07/17/24 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API remotehealthcheck.HEAD +API remotehealthcheck.GET + + HTTP_Resource_Services('LoremIpsum') + +end api diff --git a/LSL2/STPROC/REPORTS_API.txt b/LSL2/STPROC/REPORTS_API.txt index 5f22b79..e893af3 100644 --- a/LSL2/STPROC/REPORTS_API.txt +++ b/LSL2/STPROC/REPORTS_API.txt @@ -233,5 +233,3 @@ API reports.GET HTTP_Resource_Services('LoremIpsum') end api - - diff --git a/LSL2/STPROC/RETURNTOFAB_API.txt b/LSL2/STPROC/RETURNTOFAB_API.txt index 85ab1a4..c1e0e60 100644 --- a/LSL2/STPROC/RETURNTOFAB_API.txt +++ b/LSL2/STPROC/RETURNTOFAB_API.txt @@ -129,7 +129,7 @@ API returntofab.ID.GET UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X') RTFId = EndpointSegment If Error_Services('NoError') AND RTFId NE '' then - RTFJson = Return_To_Fab_Services('ConvertReturnToFabRecordToJSON', RTFId) + RTFJson = Return_To_Fab_Services('ConvertReturnToFabRecordToJSON', RTFId, UserId) If Error_Services('NoError') then HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json') @@ -247,7 +247,6 @@ end api API returntofab.reportopenforms.HEAD API returntofab.reportopenforms.GET - OIWizardID = '' Cookies = HTTP_Services('GetHTTPCookie') For each Cookie in Cookies using ';' @@ -258,29 +257,19 @@ API returntofab.reportopenforms.GET Next Cookie ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) - - If ValidSession then - UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X') - RTFId = EndpointSegment - If Error_Services('NoError') AND RTFId NE '' then - RTFJson = Return_To_Fab_Services('CreateReturnToFabReportJson', True$) - If Error_Services('NoError') then - HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) - HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json') - If Assigned(Message) then - HTTP_Services('SetResponseStatus', 201, Message) - end else - HTTP_Services('SetResponseStatus', 201) - end - end else - - end - + + UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X') + RTFJson = Return_To_Fab_Services('CreateReturnToFabReportJson', True$) + If RTFJson NE '' then + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json') + If Assigned(Message) then + HTTP_Services('SetResponseStatus', 201, Message) end else - HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage')) + HTTP_Services('SetResponseStatus', 201) end end else - HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.') + ErrorMessage = 'Error getting report data.' end end api @@ -288,7 +277,6 @@ end api API returntofab.reportallforms.HEAD API returntofab.reportallforms.GET - OIWizardID = '' Cookies = HTTP_Services('GetHTTPCookie') For each Cookie in Cookies using ';' @@ -303,9 +291,9 @@ API returntofab.reportallforms.GET If ValidSession then UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X') RTFId = EndpointSegment - If Error_Services('NoError') AND RTFId NE '' then + If RTFId NE '' then RTFJson = Return_To_Fab_Services('CreateReturnToFabReportJson', False$) - If Error_Services('NoError') then + If RTFJson NE '' then HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json') If Assigned(Message) then @@ -314,11 +302,10 @@ API returntofab.reportallforms.GET HTTP_Services('SetResponseStatus', 201) end end else - + ErrorMessage = 'Error getting report data.' end - end else - HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage')) + HTTP_Services('SetResponseStatus', 400, 'Return To Fab ID was null') end end else HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.') @@ -370,6 +357,37 @@ CreateResultOptionCollection: return +CreateOperationOptionCollection: + JSONCollection = '' + Abort = False$ + OperationOptions = Return_To_Fab_Services('GetRTFOperationIDs') + hJSONCollection = '' + If SRP_JSON(hJSONCollection, 'New', 'Object') then + hOperationOptionCollection = '' + If SRP_JSON(hOperationOptionCollection, 'New', 'Array') then + For each OperationOptionId in OperationOptions using @VM setting fPos + SRP_Json(hOperationOptionCollection, 'AddValue', OperationOptionId, 'String') + Next OperationOptionId + SRP_JSON(hJSONCollection, 'Set', 'OperationOptions', hOperationOptionCollection) + SRP_JSON(hOperationOptionCollection, 'Release') + end + JSONCollection = SRP_JSON(hJSONCollection, 'Stringify', 'Fast') + SRP_JSON(hJSONCollection, 'Release') + end + If Error_Services('NoError') then + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseBody', JSONCollection, False$, 'application/hal+json') + If Assigned(Message) then + HTTP_Services('SetResponseStatus', 201, Message) + end else + HTTP_Services('SetResponseStatus', 201) + end + end else + Message = Error_Services('GetMessage') + HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': Message) + end +return + API returntofab.getreturntofablabelzpl.HEAD API returntofab.getreturntofablabelzpl.GET @@ -404,3 +422,26 @@ API returntofab.getreturntofablabelzpl.GET HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.') end end api + + +API returntofab.rtfoperations.HEAD +API returntofab.rtfoperations.GET + + OIWizardID = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + + If ValidSession then + GoSub CreateOperationOptionCollection + end else + HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.') + end + +end api diff --git a/LSL2/STPROC/RETURN_TO_FAB_SERVICES.txt b/LSL2/STPROC/RETURN_TO_FAB_SERVICES.txt index 47b8deb..febb8f8 100644 --- a/LSL2/STPROC/RETURN_TO_FAB_SERVICES.txt +++ b/LSL2/STPROC/RETURN_TO_FAB_SERVICES.txt @@ -4,8 +4,10 @@ Compile function RETURN_TO_FAB_Services(@Service, @Params) Declare subroutine Error_Services, Database_Services, Btree.Extract, Logging_Services, SRP_JSON Declare function Rti_Createguid, Database_Services, Return_To_Fab_Services, Datetime, Error_Services -Declare function Logging_Services, Environment_Services, SRP_JSON, MemberOf -Declare subroutine obj_notes, SRP_Run_Command +Declare function Logging_Services, Environment_Services, SRP_JSON, MemberOf, Lot_Services, RTF_CreateGUID +Declare function Lot_Operation_Services, Date_Services +Declare subroutine obj_notes, SRP_Run_Command, Lot_Services, Return_To_Fab_Services, Lot_Event_Services +Declare subroutine Lot_Operation_Services $insert LOGICAL $Insert APP_INSERTS @@ -14,6 +16,10 @@ $Insert RETURN_TO_FAB_RESULT_OPTION_EQUATES $Insert WO_MAT_EQUATES $Insert RDS_EQUATES $Insert NOTIFICATION_EQUATES +$Insert LOT_EQUATES +$Insert PRS_STAGE_EQUATES +$Insert LOT_OPERATION_EQUATES +$Insert OPERATION_EQUATES LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Return_To_Fab_Services'; //Define the directory where the log will be saved to. This happens the first time of the day that the log is written to. LogDate = Oconv(Date(), 'D4/') @@ -33,6 +39,7 @@ Return Response or "" //----------------------------------------------------------------------------- Service CreateReturnToFabRecord(CassId, UserId) + ErrorMessage = '' NewRTFId = '' If CassId NE '' then @@ -73,21 +80,52 @@ Service CreateReturnToFabRecord(CassId, UserId) RTFRecord = False$ Database_Services('WriteDataRow', 'RETURN_TO_FAB_LOTS', NewRTFId, RTFRecord, True$, False$, True$) If Error_Services('NoError') then - //Send notification that a return to fab record was created. - Message = 'Return to fab form created for ' : CassId : ' by ' : UserId : '.' : CRLF$ - Message := 'Link to Return To Fab form: https://goto.infineon.com/oiwizard/ReturnToFab' - Recipients = XLATE('NOTIFICATION','SHIPPING',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_ENG',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_MANUF',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_GENERAL',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = UserId - SentFrom = 'OI_ADMIN' - Subject = 'Return To Fab Form Created' - SendToGroup = '' - AttachWindow = '' - AttachKey = '' - Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup - obj_Notes('Create',Parms) + //Check to see if a lot already exists. If not create it. + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', CassId, CassType) + If NGLotId EQ '' then + EpiPartNo = XLATE('WO_LOG', WONo, WO_LOG_EPI_PART_NO$, 'X') + ProdVerNo = XLATE('WO_LOG', WONo, WO_LOG_PROD_VER_NO$, 'X') + NGProdName = EpiPartNo : '*' : ProdVerNo + NGLotId = Lot_Services('CreateNewLot', CassType, NGProdName, '', '', '', '', UserId, '', CassId) + If Error_Services('NoError') then + + end + end + If NGLotId NE '' then + //Assign default return to fab operations and move in. + Return_To_Fab_Services('AddDefaultRTFOperations', NGLotId, UserId) + If Error_Services('NoError') then + //Move in the lot + Lot_Services('MoveInLot', NGLotId, UserId) + If Error_Services('NoError') then + Lot_Services('MoveOutLot', NGLotId, UserId) + If Error_Services('NoError') then + //Send notification that a return to fab record was created. + Message = 'Return to fab form created for ' : CassId : ' by ' : UserId : '.' : CRLF$ + Message := 'Link to Return To Fab form: https://goto.infineon.com/oiwizard/ReturnToFab' + Recipients = XLATE('NOTIFICATION','SHIPPING',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_ENG',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_MANUF',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = UserId + SentFrom = 'OI_ADMIN' + Subject = 'Return To Fab Form Created' + SendToGroup = '' + AttachWindow = '' + AttachKey = '' + Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup + obj_Notes('Create',Parms) + end else + ErrorMessage = 'Error moving lot out of the first RTF operation.' + end + end else + ErrorMessage = 'Error moving lot into the first RTF operation.' + end + end else + ErrorMessage = 'Error initializaing lot operation records' + end + end else + ErrorMessage = 'Error getting NG Lot Id.' + end end else ErrorMessage = Error_Services('GetMessage') end @@ -106,7 +144,7 @@ Service CreateReturnToFabRecord(CassId, UserId) end If ErrorMessage EQ '' AND NewRTFId NE '' then LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = CassId LogData<3> = UserId LogData<4> = NewRTFId @@ -115,7 +153,7 @@ Service CreateReturnToFabRecord(CassId, UserId) Response = NewRTFId end else LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = CassId LogData<3> = UserId LogData<4> = NewRTFId @@ -124,17 +162,65 @@ Service CreateReturnToFabRecord(CassId, UserId) Response = NewRTFId Error_Services('Add', ErrorMessage) end + End Service +Service AddDefaultRTFOperations(LotId, UserId) + + ErrorMessage = '' + // Todo: add these to a configuration for return to fab. + CurrentOperationsSeq = Lot_Services('GetLotOperationSequence', LotId) + if CurrentOperationsSeq EQ '' then + CurrSeq = 0 + end else + CurrSeq = DCount(CurrentOperationsSeq, @FM) + end + Lot_Operation_Services('AddOperationToLot', LotId, 'RTF_START', CurrSeq + 1, UserId) + If Error_Services('NoError') then + Lot_Operation_Services('AddOperationToLot', LotId, 'RTF_ASSIGN_REASON', CurrSeq + 2, UserId) + end else + ErrorMessage = Error_Services('GetMessage') + end + If Error_Services('NoError') then + Lot_Operation_Services('AddOperationToLot', LotId, 'RTF_ASSIGN_OPERATIONS', CurrSeq + 3, UserId) + end else + ErrorMessage = Error_Services('GetMessage') + end + If Error_Services('NoError') then + Lot_Operation_Services('AddOperationToLot', LotId, 'RTF_INIT_BIN_TO_BIN', CurrSeq + 4, UserId) + end else + ErrorMessage = Error_Services('GetMessage') + end + If Error_Services('NoError') then + Lot_Operation_Services('AddOperationToLot', LotId, 'RTF_DISPO', CurrSeq + 5, UserId) + end else + ErrorMessage = Error_Services('GetMessage') + end + If Error_Services('NoError') then + Lot_Operation_Services('AddOperationToLot', LotId, 'RTF_FINAL_BIN_TO_BIN', CurrSeq + 6, UserId) + end else + ErrorMessage = Error_Services('GetMessage') + end + If Error_Services('NoError') then + Lot_Operation_Services('AddOperationToLot', LotId, 'RTF_CLOSE', CurrSeq + 7, UserId) + end else + ErrorMessage = Error_Services('GetMessage') + end + + If ErrorMessage NE '' then + Error_Services('Add', ErrorMessage) + end + +end service + + Service GetReturnToFabResultOptions() + ErrorMessage = '' RTFResultOptions = '' RTFResultOptionKeys = '' table = "RETURN_TO_FAB_RESULT_OPTION" - Open "DICT ":table To @DICT Else - ErrorMessage = 'Error opening RETURN_TO_FAB_RESULT_OPTION dictionary' - End - If ErrorMessage EQ '' then + open "DICT ":table To @DICT then srch_strng = "ACTIVE":@VM:True$:@FM option = "" flag = "" @@ -144,12 +230,15 @@ Service GetReturnToFabResultOptions() ResultDesc = Database_Services('ReadDataColumn', table, RTFOptionID, RETURN_TO_FAB_RESULT_OPTION_RESULT$, True$, 0, False$) RTFResultOptions<2, rPos> = ResultDesc Next RTFReasonID + end else + ErrorMessage = 'Error opening RETURN_TO_FAB_RESULT_OPTION dictionary' end + If ErrorMessage EQ '' then Response = RTFResultOptions end else LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM; LogData<2> = '' LogData<3> = '' LogData<4> = '' @@ -157,9 +246,11 @@ Service GetReturnToFabResultOptions() Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMessage) end + end service -Service ConvertReturnToFabRecordToJSON(RTFId) +Service ConvertReturnToFabRecordToJSON(RTFId, UserId) + ErrorMessage = '' JsonString = '' If RowExists('RETURN_TO_FAB_LOTS', RTFId) then @@ -169,8 +260,19 @@ Service ConvertReturnToFabRecordToJSON(RTFId) If Error_Services('NoError') AND RTFRecord NE '' then If SRP_JSON(objRTF, 'New', 'Object') then SRP_JSON(objRTF, 'SetValue', 'ReturnToFabLotsId', RTFId) - SRP_JSON(objRTF, 'SetValue', 'CassId', RTFRecord) - SRP_JSON(objRTF, 'SetValue', 'LotType', RTFRecord) + CassId = RTFRecord + CassType = RTFRecord + SRP_JSON(objRTF, 'SetValue', 'CassId', CassId) + SRP_JSON(objRTF, 'SetValue', 'LotType', CassType) + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', CassId, CassType) + LotJsonString = Lot_Services('ConvertLotRecordToJson', NGLotId, '', UserId) + If SRP_Json(objLot, 'Parse', LotJsonString) EQ '' then + If SRP_Json(objLotSub, 'PARSE', SRP_Json(objLot, 'GetValue', 'Lot')) EQ '' then + SRP_Json(objRTF, 'Set', 'AssociatedLot' ,objLotSub) + SRP_Json(objLotSub, 'Release') + end + SRP_Json(objLot, 'Release') + end SRP_JSON(objRTF, 'SetValue', 'RequestorUserId', RTFRecord) SRP_JSON(objRTF, 'SetValue', 'StartDtm', OConv(RTFRecord, 'DT')) SRP_JSON(objRTF, 'SetValue', 'MHInitUserId', RTFRecord) @@ -227,6 +329,7 @@ Service ConvertReturnToFabRecordToJSON(RTFId) end else ErrorMessage = 'Error Converting RTF record to JSON. RTFId not found in database.' end + If ErrorMessage NE '' then LogData = '' LogData<1> = LoggingDTM;//Defined at entry of subroutine @@ -237,10 +340,13 @@ Service ConvertReturnToFabRecordToJSON(RTFId) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMessage) end + Response = JsonString + end service Service CreateReturnToFabReportJson(ShowOpenReport) + ErrorMessage = '' JsonString = '' objJSON = '' @@ -257,20 +363,41 @@ Service CreateReturnToFabReportJson(ShowOpenReport) If Error_Services('NoError') and RTFRecord NE '' then hRTFJsonSingle = '' if SRP_Json(hRTFJsonSingle, 'New', 'Object') then + SRP_JSON(hRTFJsonSingle, 'SetValue', 'ReturnToFabLotsId', RTFId) - SRP_JSON(hRTFJsonSingle, 'SetValue', 'CassId', RTFRecord) - SRP_JSON(hRTFJsonSingle, 'SetValue', 'LotType', RTFRecord) + CassId = RTFRecord + SRP_JSON(hRTFJsonSingle, 'SetValue', 'CassId', CassId) + CassType = RTFRecord + SRP_JSON(hRTFJsonSingle, 'SetValue', 'LotType', CassType) + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', CassId, CassType) + LotJsonString = Lot_Services('ConvertLotRecordToJson', NGLotId, '', UserId, False$) + If SRP_Json(objLot, 'Parse', LotJsonString) EQ '' then + If SRP_Json(objLotSub, 'PARSE', SRP_Json(objLot, 'GetValue', 'Lot')) EQ '' then + SRP_Json(hRTFJsonSingle, 'Set', 'AssociatedLot' ,objLotSub) + SRP_Json(objLotSub, 'Release') + end + SRP_Json(objLot, 'Release') + end SRP_JSON(hRTFJsonSingle, 'SetValue', 'RequestorUserId', RTFRecord) - SRP_JSON(hRTFJsonSingle, 'SetValue', 'StartDtm', OConv(RTFRecord, 'DT')) + StartDtm = Date_Services('ConvertDateTimeToISO8601', RTFRecord) + If StartDtm NE '' then + SRP_JSON(hRTFJsonSingle, 'SetValue', 'StartDtm', StartDtm) + end if RTFRecord NE '' then EvaluationDescription = Database_Services('ReadDataColumn', 'RETURN_TO_FAB_RESULT_OPTION', RTFRecord, RETURN_TO_FAB_RESULT_OPTION_RESULT$, True$, 0, False$) end else EvaluationDescription = '' end SRP_JSON(hRTFJsonSingle, 'SetValue', 'EvalDesc', EvaluationDescription) - SRP_JSON(hRTFJsonSingle, 'SetValue', 'FinalCompleteDtm', OConv(RTFRecord, 'DT')) + FinalCompleteDtm = Date_Services('ConvertDateTimeToISO8601', RTFRecord) + If FinalCompleteDtm NE '' then + SRP_JSON(hRTFJsonSingle, 'SetValue', 'FinalCompleteDtm', FinalCompleteDtm) + end SRP_JSON(hRTFJsonSingle, 'SetValue', 'Completed', RTFRecord, 'Boolean') - SRP_JSON(hRTFJsonSingle, 'SetValue', 'CompletedDtm', OConv(RTFRecord,'DT')) + CompletedDtm = Date_Services('ConvertDateTimeToISO8601',RTFRecord) + If CompletedDtm NE '' then + SRP_JSON(hRTFJsonSingle, 'SetValue', 'CompletedDtm', CompletedDtm) + end CurrStepId = Return_To_Fab_Services('GetRTFCurrStep', RTFId) SRP_Json(hRTFJsonSingle, 'SetValue', 'CurrStepId', CurrStepId, 'Number') SRP_Json(objReturnToFabReport, 'Add', hRTFJsonSingle) @@ -288,9 +415,10 @@ Service CreateReturnToFabReportJson(ShowOpenReport) end else ErrorMessage = 'Error creating root JSON object.' end + If ErrorMessage NE '' then LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = '' LogData<4> = '' @@ -298,26 +426,29 @@ Service CreateReturnToFabReportJson(ShowOpenReport) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMessage) end + Response = JsonString + end service Service GetReturnToFabRecordIdByCassId(CassId) + ErrorMessage = '' RTFRecords = '' If CassId NE '' then table = "RETURN_TO_FAB_LOTS" - Open "DICT ":table To @DICT Else - ErrorMessage = 'Error opening RETURN_TO_FAB_LOTS dictionary' - End - If ErrorMessage EQ '' then + open "DICT ":table To @DICT then srch_strng = "CASS_ID":@VM:CassId:@FM option = "" flag = "" Btree.Extract(srch_strng, table, @DICT, RTFRecords, option, flag) + end else + ErrorMessage = 'Error opening RETURN_TO_FAB_LOTS dictionary' end end else ErrorMessage = 'Error getting return to fab record by cass. ID. Cassette ID was null' end + If ErrorMessage EQ '' then Response = RTFRecords end else @@ -330,16 +461,15 @@ Service GetReturnToFabRecordIdByCassId(CassId) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMessage) end + End Service Service GetAllReturnToFabRecords(ShowOnlyOpen) + ErrorMessage = '' RTFRecords = '' table = "RETURN_TO_FAB_LOTS" - Open "DICT ":table To @DICT Else - ErrorMessage = 'Error opening RETURN_TO_FAB_LOTS dictionary' - End - If ErrorMessage EQ '' then + open "DICT ":table To @DICT then srch_strng = "CASS_ID":@VM:"#NULL":@FM if ShowOnlyOpen then srch_strng := "COMPLETED":@VM:"#1":@FM @@ -347,12 +477,15 @@ Service GetAllReturnToFabRecords(ShowOnlyOpen) option = "" flag = "" Btree.Extract(srch_strng, table, @DICT, RTFRecords, option, flag) + end else + ErrorMessage = 'Error opening RETURN_TO_FAB_LOTS dictionary' end + If ErrorMessage EQ '' then Response = RTFRecords end else LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = '' LogData<4> = '' @@ -360,21 +493,22 @@ Service GetAllReturnToFabRecords(ShowOnlyOpen) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMessage) end + end service Service GetOpenReturnToFabRecordIdByCassId(CassId) + ErrorMessage = '' OpenRTFRecords = '' If CassId NE '' then table = "RETURN_TO_FAB_LOTS" - Open "DICT ":table To @DICT Else - ErrorMessage = 'Error opening RETURN_TO_FAB_LOTS dictionary' - End - If ErrorMessage EQ '' then + open "DICT ":table To hRDS then srch_strng = "CASS_ID":@VM:CassId:@FM:"COMPLETED":@VM:"#1":@FM option = "" flag = "" - Btree.Extract(srch_strng, table, @DICT, OpenRTFRecords, option, flag) + Btree.Extract(srch_strng, table, hRDS, OpenRTFRecords, option, flag) + end else + ErrorMessage = 'Error opening RETURN_TO_FAB_LOTS dictionary' end end else ErrorMessage = 'Error getting return to fab record by cass. ID. Cassette ID was null' @@ -391,15 +525,21 @@ Service GetOpenReturnToFabRecordIdByCassId(CassId) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMessage) end + End Service Service SetReasonForReturn(RTFId, UserId, Reason) + ErrorMessage = '' If RTFId NE '' then If RowExists('RETURN_TO_FAB_LOTS', RTFId) then - RTFCurrStep = Return_To_Fab_Services('GetRTFCurrStep', RTFId) - If RTFCurrStep LE 3 AND RTFCurrStep GE 1 then - RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) + RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) + LegacyLotId = RTFRecord + LegacyLotType = RTFRecord + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType) + CurrOperation = Lot_Services('GetLotCurrOperationName', NGLotId) + If CurrOperation EQ 'RTF_ASSIGN_REASON' then + RTFRecordComplete = RTFRecord If RTFRecordComplete NE True$ then If UserId NE '' then @@ -407,7 +547,17 @@ Service SetReasonForReturn(RTFId, UserId, Reason) If Reason NE '' then RTFRecord = Reason Database_Services('WriteDataRow', 'RETURN_TO_FAB_LOTS', RTFId, RTFRecord, True$, False$, False$) - If Error_Services('HasError') then + If Error_Services('NoError') then + Lot_Services('MoveInLot', NGLotId, UserId) + If Error_Services('NoError') then + Lot_Services('MoveOutLot', NGLotId, UserId) + If Error_Services('HasError') then + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = Error_Services('GetMessage') + end + end else ErrorMessage = Error_Services('GetMessage') end end else @@ -423,7 +573,7 @@ Service SetReasonForReturn(RTFId, UserId, Reason) ErrorMessage = 'Error setting return to fab reason. Return to fab record has already been completed.' end end else - ErrorMessage = 'Error setting Return To Fab reason. Form is currently at step ': RTFCurrStep :'.' + ErrorMessage = 'Error setting Return To Fab reason. Form is currently at step ': CurrOperation :'.' end end else ErrorMessage = 'Error setting return to fab reason. Return to fab record did not exists' @@ -431,9 +581,10 @@ Service SetReasonForReturn(RTFId, UserId, Reason) end else ErrorMessage = 'Error setting return to fab reason. Return to fab record id was null' end + if ErrorMessage EQ '' then LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = UserId LogData<4> = RTFId @@ -441,7 +592,7 @@ Service SetReasonForReturn(RTFId, UserId, Reason) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) end else LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = UserId LogData<4> = RTFId @@ -449,14 +600,93 @@ Service SetReasonForReturn(RTFId, UserId, Reason) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMessage) end + end service -Service SetBinToBin(RTFId, MHUserId) +Service StartAssignOperation(RTFId, UserId) + ErrorMessage = '' If RTFId NE '' then If RowExists('RETURN_TO_FAB_LOTS', RTFId) then - RTFCurrStep = Return_To_Fab_Services('GetRTFCurrStep', RTFId) - If RTFCurrStep EQ 3 then + RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) + LegacyLotId = RTFRecord + LegacyLotType = RTFRecord + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType) + CurrOperationName = Lot_Services('GetLotCurrOperationName', NGLotId) + If CurrOperationName EQ 'RTF_ASSIGN_OPERATIONS' then + IsLotMovedIn = Lot_Services('IsLotMovedIn', NGLotId) + If Not(IsLotMovedIn) then + //Moves the lot in if it already isn't + Lot_Services('MoveInLot', NGLotId, UserId) + If Error_Services('HasError') then + ErrorMessage = Error_Services('GetMessage') + end + end + end else + ErrorMessage = 'Lot is not currently at the Assign Operations, operation.' + end + end else + ErrorMessage = 'Return To Fab ID was not found' + end + end else + ErrorMessage = 'Return To Fab ID was null.' + end + If ErrorMessage NE '' then + Error_Services('Add', ErrorMessage) + end + +end service + +Service SetOpAssignComplete(RTFId, UserId) + + ErrorMessage = '' + If RTFId NE '' then + If RowExists('RETURN_TO_FAB_LOTS', RTFId) then + RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) + LegacyLotId = RTFRecord + LegacyLotType = RTFRecord + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType) + CurrOperationName = Lot_Services('GetLotCurrOperationName', NGLotId) + If CurrOperationName EQ 'RTF_ASSIGN_OPERATIONS' then + IsLotMovedIn = Lot_Services('IsLotMovedIn', NGLotId) + If Not(IsLotMovedIn) then + //Moves the lot in if it already isn't + Lot_Services('MoveInLot', NGLotId, UserId) + end + If Error_Services('NoError') then + Lot_Services('MoveOutLot', NGLotId, UserId) + If Error_Services('HasError') then + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = 'Lot is not currently at the Assign Operations, operation.' + end + end else + ErrorMessage = 'Return To Fab ID was not found' + end + end else + ErrorMessage = 'Return To Fab ID was null.' + end + If ErrorMessage NE '' then + Error_Services('Add', ErrorMessage) + end + +end service + +Service SetBinToBin(RTFId, MHUserId) + + ErrorMessage = '' + If RTFId NE '' then + If RowExists('RETURN_TO_FAB_LOTS', RTFId) then + RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) + LegacyLotId = RTFRecord + LegacyLotType = RTFRecord + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType) + CurrOperationName = Lot_Services('GetLotCurrOperationName', NGLotId) + If CurrOperationName EQ 'RTF_INIT_BIN_TO_BIN' then RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) RTFRecordComplete = RTFRecord If RTFRecordComplete NE True$ then @@ -467,24 +697,38 @@ Service SetBinToBin(RTFId, MHUserId) RTFRecord = Datetime() Database_Services('WriteDataRow', 'RETURN_TO_FAB_LOTS', RTFId, RTFRecord, True$, False$, False$) If Error_Services('NoError') then - //Send notification that a return to fab record was created. - CassId = RTFRecord - RTFOrigUser = RTFRecord - Message = 'Return to fab form updated for ' : CassId : ' by ' : MHUserId : '.' : CRLF$ - Message := 'Initial Bin to Bin has been marked as completed.' : CRLF$ - Message := 'Link to Return To Fab form: https://goto.infineon.com/oiwizard/ReturnToFab' - Recipients = XLATE('NOTIFICATION','SHIPPING',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_ENG',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_MANUF',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_GENERAL',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = RTFOrigUser - SentFrom = 'OI_ADMIN' - Subject = 'Return To Fab Form Updated' - SendToGroup = '' - AttachWindow = '' - AttachKey = '' - Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup - obj_Notes('Create',Parms) + IsLotMovedIn = Lot_Services('IsLotMovedIn', NGLotId) + If Not(IsLotMovedIn) then + //Moves the lot in if it already isn't + Lot_Services('MoveInLot', NGLotId, MHUserId) + end + If Error_Services('NoError') then + Lot_Services('MoveOutLot', NGLotId, MHUserId) + If Error_Services('NoError') then + //Send notification that a return to fab record was created. + CassId = RTFRecord + RTFOrigUser = RTFRecord + Message = 'Return to fab form updated for ' : CassId : ' by ' : MHUserId : '.' : CRLF$ + Message := 'Initial Bin to Bin has been marked as completed.' : CRLF$ + Message := 'Link to Return To Fab form: https://goto.infineon.com/oiwizard/ReturnToFab' + Recipients = XLATE('NOTIFICATION','SHIPPING',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_ENG',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_MANUF',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = RTFOrigUser + SentFrom = 'OI_ADMIN' + Subject = 'Return To Fab Form Updated' + SendToGroup = '' + AttachWindow = '' + AttachKey = '' + Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup + obj_Notes('Create',Parms) + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = Error_Services('GetMessage') + end + end else ErrorMessage = Error_Services('GetMessage') end @@ -501,7 +745,7 @@ Service SetBinToBin(RTFId, MHUserId) ErrorMessage = 'Error setting Initial SAP Bin-to-Bin. Return to fab record has already been completed.' end end else - ErrorMessage = 'Error setting Initial SAP Bin-to-Bin. Form is currently at step ': RTFCurrStep :'.' + ErrorMessage = 'Error setting Initial SAP Bin-to-Bin. Form is currently at step ': CurrOperationName :'.' end end else ErrorMessage = 'Error setting Initial SAP Bin-to-Bin. Return to fab record did not exists' @@ -509,9 +753,10 @@ Service SetBinToBin(RTFId, MHUserId) end else ErrorMessage = 'Error setting Initial SAP Bin-to-Bin. Return to fab record id was null' end + If ErrorMessage EQ '' then LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = MHUserId LogData<4> = RTFId @@ -519,7 +764,7 @@ Service SetBinToBin(RTFId, MHUserId) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) end else LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = MHUserId LogData<4> = RTFId @@ -527,60 +772,85 @@ Service SetBinToBin(RTFId, MHUserId) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMessage) end + end service Service SetRTFCompleted(RTFId, CompleteUserId) + ErrorMessage = '' If RTFId NE '' then If RowExists('RETURN_TO_FAB_LOTS', RTFId) then RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) - RTFRecordComplete = RTFRecord - If RTFRecordComplete NE True$ then - If CompleteUserId NE '' then - If RowExists('LSL_USERS', CompleteUserId) then - RTFRecord = True$ - RTFRecord = Datetime() - Database_Services('WriteDataRow', 'RETURN_TO_FAB_LOTS', RTFId, RTFRecord, True$, False$, False$) - If Error_Services('NoError') then - //Send notification that a return to fab record was created. - CassId = RTFRecord - RTFOrigUser = RTFRecord - Message = 'Return to fab form updated for ' : CassId : ' by ' : CompleteUserId : '.' : CRLF$ - Message := 'Return to fab marked as completed.' : CRLF$ - Message := 'Link to Return To Fab form: https://goto.infineon.com/oiwizard/ReturnToFab' - Recipients = XLATE('NOTIFICATION','SHIPPING',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_ENG',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_MANUF',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_GENERAL',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = RTFRecord - SentFrom = 'OI_ADMIN' - Subject = 'Return To Fab Form Completed' - SendToGroup = '' - AttachWindow = '' - AttachKey = '' - Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup - obj_Notes('Create',Parms) + LegacyLotId = RTFRecord + LegacyLotType = RTFRecord + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType) + CurrOperationName = Lot_Services('GetLotCurrOperationName', NGLotId) + If CurrOperationName EQ 'RTF_CLOSE' then + RTFRecordComplete = RTFRecord + If RTFRecordComplete NE True$ then + If CompleteUserId NE '' then + If RowExists('LSL_USERS', CompleteUserId) then + RTFRecord = True$ + RTFRecord = Datetime() + Database_Services('WriteDataRow', 'RETURN_TO_FAB_LOTS', RTFId, RTFRecord, True$, False$, False$) + If Error_Services('NoError') then + IsLotMovedIn = Lot_Services('IsLotMovedIn', NGLotId) + If Not(IsLotMovedIn) then + //Moves the lot in if it already isn't + Lot_Services('MoveInLot', NGLotId, CompleteUserId) + end + If Error_Services('NoError') then + Lot_Services('MoveOutLot', NGLotId, CompleteUserId) + If Error_Services('NoError') then + //Send notification that a return to fab record was created. + CassId = RTFRecord + RTFOrigUser = RTFRecord + Message = 'Return to fab form updated for ' : CassId : ' by ' : CompleteUserId : '.' : CRLF$ + Message := 'Return to fab marked as completed.' : CRLF$ + Message := 'Link to Return To Fab form: https://goto.infineon.com/oiwizard/ReturnToFab' + Recipients = XLATE('NOTIFICATION','SHIPPING',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_ENG',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_MANUF',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = RTFRecord + SentFrom = 'OI_ADMIN' + Subject = 'Return To Fab Form Completed' + SendToGroup = '' + AttachWindow = '' + AttachKey = '' + Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup + obj_Notes('Create',Parms) + end else + ErrorMessage = 'Error moving lot out.' + end + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = Error_Services('GetMessage') + end end else - ErrorMessage = Error_Services('GetMessage') + ErrorMessage = 'Error setting Return To Fab form as complete. User ID was not found in OpenInsight.' end end else - ErrorMessage = 'Error setting Return To Fab form as complete. User ID was not found in OpenInsight.' + ErrorMessage = 'Error setting Return To Fab form as complete. User ID was null.' end end else - ErrorMessage = 'Error setting Return To Fab form as complete. User ID was null.' + ErrorMessage = 'Error setting Return To Fab form as complete. Return to fab record has already been completed.' end end else - ErrorMessage = 'Error setting Return To Fab form as complete. Return to fab record has already been completed.' + ErrorMessage = 'Lot is not currently at the RTF Close operation.' end + end else ErrorMessage = 'Error setting Return To Fab form as complete. Return to fab record did not exists' end end else ErrorMessage = 'Error setting Return To Fab form as complete. Return to fab record id was null' end + If ErrorMessage EQ '' then LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = CompleteUserId LogData<4> = RTFId @@ -588,7 +858,7 @@ Service SetRTFCompleted(RTFId, CompleteUserId) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) end else LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = CompleteUserId LogData<4> = RTFId @@ -596,14 +866,19 @@ Service SetRTFCompleted(RTFId, CompleteUserId) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMessage) end + end service Service SetEvalInfo(RTFId, EvalUserId, ResultId) ErrorMessage = '' If RTFId NE '' then if RowExists('RETURN_TO_FAB_LOTS', RTFId) then - RTFCurrStep = Return_To_Fab_Services('GetRTFCurrStep', RTFId) - If RTFCurrStep EQ 4 OR RTFCurrStep EQ 5 then + RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) + LegacyLotId = RTFRecord + LegacyLotType = RTFRecord + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType) + CurrOperationName = Lot_Services('GetLotCurrOperationName', NGLotId) + If CurrOperationName EQ 'RTF_DISPO' then If EvalUserId NE '' then if RowExists('LSL_USERS', EvalUserId) then If ResultId NE '' then @@ -616,25 +891,38 @@ Service SetEvalInfo(RTFId, EvalUserId, ResultId) RTFRecord = Datetime() Database_Services('WriteDataRow', 'RETURN_TO_FAB_LOTS', RTFId, RTFRecord, True$, False$, False$) If Error_Services('NoError') then - ResultDescription = XLate('RETURN_TO_FAB_RESULT_OPTION', ResultId, RETURN_TO_FAB_RESULT_OPTION_RESULT$, 'X') - //Send notification that a return to fab record was created. - CassId = RTFRecord - RTFOrigUser = RTFRecord - Message = 'Return to fab form updated for ' : CassId : ' by ' : EvalUserId : '.' : CRLF$ - Message := 'Result has been set to ' : ResultDescription : '.' : CRLF$ - Message := 'Link to Return To Fab form: https://goto.infineon.com/oiwizard/ReturnToFab' - Recipients = XLATE('NOTIFICATION','SHIPPING',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_ENG',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_MANUF',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_GENERAL',NOTIFICATION_USER_ID$,'X') - Recipients<1, -1> = RTFRecord - SentFrom = 'OI_ADMIN' - Subject = 'Return To Fab Form Updated' - SendToGroup = '' - AttachWindow = '' - AttachKey = '' - Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup - obj_Notes('Create',Parms) + IsLotMovedIn = Lot_Services('IsLotMovedIn', NGLotId) + If Not(IsLotMovedIn) then + //Moves the lot in if it already isn't + Lot_Services('MoveInLot', NGLotId, EvalUserId) + end + If Error_Services('NoError') then + Lot_Services('MoveOutLot', NGLotId, EvalUserId) + If Error_Services('NoError') then + ResultDescription = XLate('RETURN_TO_FAB_RESULT_OPTION', ResultId, RETURN_TO_FAB_RESULT_OPTION_RESULT$, 'X') + //Send notification that a return to fab record was created. + CassId = RTFRecord + RTFOrigUser = RTFRecord + Message = 'Return to fab form updated for ' : CassId : ' by ' : EvalUserId : '.' : CRLF$ + Message := 'Result has been set to ' : ResultDescription : '.' : CRLF$ + Message := 'Link to Return To Fab form: https://goto.infineon.com/oiwizard/ReturnToFab' + Recipients = XLATE('NOTIFICATION','SHIPPING',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_ENG',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = XLATE('NOTIFICATION','RETURN_TO_FAB_MANUF',NOTIFICATION_USER_ID$,'X') + Recipients<1, -1> = RTFRecord + SentFrom = 'OI_ADMIN' + Subject = 'Return To Fab Form Updated' + SendToGroup = '' + AttachWindow = '' + AttachKey = '' + Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup + obj_Notes('Create',Parms) + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = 'Error moving lot out.' + end end else ErrorMessage = Error_Services('GetMessage') end @@ -656,7 +944,7 @@ Service SetEvalInfo(RTFId, EvalUserId, ResultId) ErrorMessage = 'Error setting Eval. info. Evaluation user id was null.' end end else - ErrorMessage = 'Error setting Eval. info. Form is currently at step ': RTFCurrStep :'.' + ErrorMessage = 'Error setting Eval. info. Form is currently at step ': CurrOperationName :'.' end end else ErrorMessage = 'Error setting Eval. info. Return to fab record was not found.' @@ -688,8 +976,12 @@ Service SetFinalBinToBin(RTFId, MHUserId) ErrorMessage = '' If RTFId NE '' then If RowExists('RETURN_TO_FAB_LOTS', RTFId) then - RTFCurrStep = Return_To_Fab_Services('GetRTFCurrStep', RTFId) - If RTFCurrStep EQ 5 then + RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) + LegacyLotId = RTFRecord + LegacyLotType = RTFRecord + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType) + CurrOperationName = Lot_Services('GetLotCurrOperationName', NGLotId) + If CurrOperationName EQ 'RTF_FINAL_BIN_TO_BIN' then RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) RTFRecordComplete = RTFRecord If RTFRecordComplete NE True$ then @@ -699,9 +991,20 @@ Service SetFinalBinToBin(RTFId, MHUserId) RTFRecord = MHUserId RTFRecord = Datetime() Database_Services('WriteDataRow', 'RETURN_TO_FAB_LOTS', RTFId, RTFRecord, True$, False$, False$) - If Error_Services('HasError') then + If Error_Services('NoError') then + IsLotMovedIn = Lot_Services('IsLotMovedIn', NGLotId) + If Not(IsLotMovedIn) then + //Moves the lot in if it already isn't + Lot_Services('MoveInLot', NGLotId, MHUserId) + end + If Error_Services('NoError') then + Lot_Services('MoveOutLot', NGLotId, MHUserId) + end else + ErrorMessage = 'Error moving out lot.' + end + end else ErrorMessage = Error_Services('GetMessage') - end + end end else ErrorMessage = 'Error setting Final SAP Bin-to-Bin. User does not have permissions to perform this function. User must be apart of OI Security Group "MATERIAL HANDLER"' end @@ -716,7 +1019,7 @@ Service SetFinalBinToBin(RTFId, MHUserId) ErrorMessage = 'Error setting Final SAP Bin-to-Bin. Return to fab record has already been completed.' end end else - ErrorMessage = 'Error setting Final SAP Bin-to-Bin. Form is currently at step ': RTFCurrStep :'.' + ErrorMessage = 'Error setting Final SAP Bin-to-Bin. Form is currently at step ': CurrOperationName :'.' end end else ErrorMessage = 'Error setting Final SAP Bin-to-Bin. Return to fab record did not exists' @@ -724,9 +1027,10 @@ Service SetFinalBinToBin(RTFId, MHUserId) end else ErrorMessage = 'Error setting Final SAP Bin-to-Bin. Return to fab record id was null' end + If ErrorMessage EQ '' then LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = MHUserId LogData<4> = RTFId @@ -734,17 +1038,19 @@ Service SetFinalBinToBin(RTFId, MHUserId) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) end else LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = MHUserId LogData<4> = RTFId LogData<5> = ErrorMessage Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMessage) - end + end + end service Service AddMiscNote(RTFId, Note, UserId) + ErrorMessage = '' If RTFId NE '' then If RowExists('RETURN_TO_FAB_LOTS', RTFId) then @@ -774,9 +1080,10 @@ Service AddMiscNote(RTFId, Note, UserId) end else ErrorMessage = 'Error adding note to RTF Record. Return to fab record id was null' end + If ErrorMessage EQ '' then LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = UserId LogData<4> = RTFId @@ -784,46 +1091,200 @@ Service AddMiscNote(RTFId, Note, UserId) Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) end else LogData = '' - LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<1> = LoggingDTM LogData<2> = '' LogData<3> = UserId LogData<4> = RTFId LogData<5> = ErrorMessage Logging_Services('AppendLog', objReturnToFabLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMessage) - end + end + end service Service GetRTFCurrStep(RTFId) CurrStep = 0 RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) If RTFRecord NE '' then - CurrStep = 1 - If RTFRecord NE '' then - //Skip 2 because step 2 is an adhoc step(printing a label) - CurrStep = 3 - If RTFRecord NE '' then + RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFId, True$, 0, False$) + LegacyLotId = RTFRecord + LegacyLotType = RTFRecord + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType) + CurrOperationName = Lot_Services('GetLotCurrOperationName', NGLotId) + + Begin Case + Case CurrOperationName EQ 'RTF_START' + CurrStep = 1 + Case CurrOperationName EQ 'RTF_ASSIGN_REASON' + CurrStep = 2 + Case CurrOperationName EQ 'RTF_ASSIGN_OPERATIONS' + CurrStep = 3 + Case CurrOperationName EQ 'RTF_INIT_BIN_TO_BIN' CurrStep = 4 - If RTFRecord NE '' AND RTFRecord NE 0 then - CurrStep = 5 - If RTFRecord NE '' then - CurrStep = 6 - end - end - end - end + Case CurrOperationName EQ 'RTF_DISPO' + CurrStep = 5 + Case CurrOperationName EQ 'RTF_FINAL_BIN_TO_BIN' + CurrStep = 6 + Case CurrOperationName EQ 'RTF_CLOSE' + CurrStep = 7 + Case Otherwise$ + CurrStep = 0 + End Case end Response = CurrStep end service Service OpenOIWizardReturnToFabInBrowser(RTFId) + Command = 'explorer https://goto.infineon.com/oiwizard/returntofab/' : RTFId SRP_Run_Command(Command) + end service +Service InitializeReturnToFabLotOperations(LotId) + + ErrorMessage = '' + OperationsToInitialize = '' + OperationsToInitialize<1, 1> = 'RTF_CLOSE' + For each Operation in OperationsToInitialize using @VM setting sequence + Lot_Services('AddLotOperationIntoSequence', LotId, Operation, sequence) + If Error_Services('HasError') then + ErrorMessage = Error_Services('GetMessage') + end + Until ErrorMessage NE '' + Next Operation + If ErrorMessage NE '' then + Error_Services('Add', 'Error in ' : Service : ' : ' : ErrorMessage) + end + +end service +Service PrescribeReturnToFabOperation(LegacyLotId, OperationId, PrescribedSequence, UserId) + + ErrorMessage = '' + //Check that the lot has a valid return to fab record. + ExistingReturnToFabRecord = Return_To_Fab_Services('GetOpenReturnToFabRecordIdByCassId', LegacyLotId) + If ExistingReturnToFabRecord then + ReturnToFabLotRec = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', ExistingReturnToFabRecord, True$, 0, False$) + LotType = ReturnToFabLotRec + NGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LotType) + If NGLotId NE '' then + If RowExists('OPERATION', OperationID) then + If PrescribedSequence NE '' then + CurrentPrescribedOperations = Lot_Services('GetLotOperationSequence', NGLotId) + CurrentOperation = Lot_Services('GetLotCurrOperationName', NGLotId) + Lot_Services('AddLotOperationIntoSequence', NGLotId, OperationId, PrescribedSequence) + If Error_Services('NoError') then + Lot_Services('CreateLotEvent', NGLotId, Datetime(), 'SYSTEM_COMMENT', 'Prescribed ' : OperationId : '.', '', UserId) + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = 'Prescribed Sequence was null.' + end + end else + ErrorMessage = 'Specified operation was not found.' + end + end else + ErrorMessage = LegacyLotId : ' not found in LOT table.' + end + end else + ErrorMessage = 'Lot ' : LegacyLotId : 'does not have an active return to fab record.' + end + + If ErrorMessage NE '' then + Error_Services('Add', 'Error in ' : service : ' : ' : ErrorMessage) + end + +end service +/* +Returns a @VM delimited list of RTF Operations available to be prescribed +*/ +Service GetRTFOperationIDs() + + ErrorMessage = '' + RTFOperationKeys = '' + + Open 'DICT.OPERATION' to DICT then + SearchString = 'OPERATION_CLASS':@VM:'RTF':@FM + SearchString := 'ACTIVE':@VM:True$:@FM + Option = '' + Flag = '' + Btree.Extract(SearchString, 'OPERATION', DICT, RTFOperationKeys, Option, Flag) + end else + ErrorMessage = 'Error opening OPERATION table dictionary.' + end + + If ErrorMessage EQ '' then + Response = RTFOperationKeys + end else + Error_Services('Add', 'Error in ' : Service : ' : ' ErrorMessage) + end + +end service - - - +Service MigrateLegacyRTFRecord(RTFRecordId) + + RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFRecordId, True$, 0, False$) + + //First create a lot record if none already exist + CassId = RTFRecord + CassType = RTFRecord + LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', CassId, CassType) + If LotId EQ '' then + LotId = Lot_Services('CreateNewLot', CassType, '', '', '', '', '', 'SYSTEM', '', CassId) + end + If LotId NE '' then + Return_To_Fab_Services('AddDefaultRTFOperations', LotId, 'SYSTEM') + If Error_Services('NoError') then + //Now get all the created lot Operation records + LotOperationIds = Lot_Services('GetLotOperationSequence', LotId) + //Loop through all the lot operation record and fill them out. + for each LotOperationId in LotOperationIds using @FM + LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$) + OperationId = LotOperationRec + Begin Case + Case OperationId EQ 'RTF_START' + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + Case OperationId EQ 'RTF_ASSIGN_REASON' + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + Case OperationId EQ 'RTF_ASSIGN_OPERATIONS' + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + Case OperationId EQ 'RTF_INIT_BIN_TO_BIN' + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + Case OperationId EQ 'RTF_DISPO' + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + Case OperationId EQ 'RTF_FINAL_BIN_TO_BIN' + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + Case OperationId EQ 'RTF_CLOSE' + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + LotOperationRec = RTFRecord + End Case + Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec) + Next LotOperationId + + end + end + +end service diff --git a/LSL2/STPROC/SCRUBBER_PM_API.txt b/LSL2/STPROC/SCRUBBER_PM_API.txt index 7fc4fbd..6b7ded6 100644 --- a/LSL2/STPROC/SCRUBBER_PM_API.txt +++ b/LSL2/STPROC/SCRUBBER_PM_API.txt @@ -1,131 +1,129 @@ -Function Scrubber_pm_API(@API) -/*********************************************************************************************************************** - - This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written - permission from SRP Computer Solutions, Inc. - - Name : Scrubber_pm_API - - Description : API logic for the Scrubber_pm resource. - - Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: - - HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) - APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). - FullEndpointURL - The URL submitted by the client, including query params. - FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. - EndpointSegment - The URL endpoint segment. - ParentURL - The URL path preceeding the current endpoint. - CurrentAPI - The name of this stored procedure. - - Parameters : - API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - - APIPattern must follow this structure Scrubber_pm[.ID.[]] - - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. - Examples: - - Scrubber_pm.POST - - Scrubber_pm.ID.PUT - - Scrubber_pm.ID.firstName.GET - Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API - services do not rely upon anything being returned in the response. This is what the - various services like SetResponseBody and SetResponseStatus services are for. A response - value is only helpful if the developers want to use it for debug purposes. - - History : (Date, Initials, Notes) - 06/05/24 xxx Original programmer. - -***********************************************************************************************************************/ - -#pragma precomp SRP_PreCompiler - -Declare Subroutine Pm_Services, Http_Services, Logging_Services -Declare function Error_Services, Logging_Services, Environment_Services, Datetime - -$insert APP_INSERTS -$insert API_SETUP -$insert HTTP_INSERTS - -LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Scrubbers\API' -LogDate = Oconv(Date(), 'D4/') -LogTime = Oconv(Time(), 'MTS') -LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Tool Log.csv' -Headers = 'Logging DTM' : @FM : 'ScrubberID' : @FM : 'Notes' : @FM : 'Message' -objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) -LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM - -GoToAPI else - // The specific resource endpoint doesn't have a API handler yet. - HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') -end - -Return Response OR '' - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Endpoint Handlers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -API scrubber_pm.POST - Body = HTTP_Services('GetHTTPPostString') - If Body NE '' then - // The POST string will have been encoded so use percent (URL) decoding. - PMJson = HTTP_Services('DecodePercentString', Body) - ParseResponse = SRP_JSON(objJson, 'PARSE', PMJson) - If (ParseResponse EQ '') then - EquipmentID = SRP_JSON(objJson, 'GetValue', 'EquipmentId') - User = SRP_JSON(objJson, 'GetValue', 'User') - end else - HTTP_Services('SetResponseStatus', 400, 'Unable to parse the JSON data from the request.') - end - end else - HTTP_Services('SetResponseStatus', 400, 'JSON object is missing in the body of the request.') - end - -end api - - -API scrubber_pm.HEAD -API scrubber_pm.GET - - HTTP_Resource_Services('LoremIpsum') - -end api - - -API scrubber_pm.ID.HEAD -API scrubber_pm.ID.GET - - ScrubberID = EndpointSegment - IF RowExists('TOOL', ScrubberID) then - Pm_Services('CompleteScrubberPM', ScrubberID) - If Error_Services('HasError') then - ErrMsg = Error_Services('GetMessage') - HTTP_Services('SetResponseStatus', 500, ErrMsg) - LogData = '' - LogData<1> = OConv(Datetime(), 'DT2/^H') - LogData<2> = ScrubberID - LogData<3> = 'Error' - LogData<4> = ErrMsg - Logging_Services('AppendLog', objLog, LogData, @RM, @FM) - end else - LogData = '' - LogData<1> = OConv(Datetime(), 'DT2/^H') - LogData<2> = ScrubberID - LogData<3> = 'Success' - LogData<4> = 'Scrubber PM Completion was successful' - Logging_Services('AppendLog', objLog, LogData, @RM, @FM) - end - end else - ErrMsg = 'Scrubber does not exist!' - HTTP_Services('SetResponseStatus', 500, ErrMsg) - LogData = '' - LogData<1> = OConv(Datetime(), 'DT2/^H') - LogData<2> = ScrubberID - LogData<3> = 'Error' - LogData<4> = ErrMsg - Logging_Services('AppendLog', objLog, LogData, @RM, @FM) - end -end api - - +Function Scrubber_pm_API(@API) +/*********************************************************************************************************************** + + This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written + permission from SRP Computer Solutions, Inc. + + Name : Scrubber_pm_API + + Description : API logic for the Scrubber_pm resource. + + Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: + + HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) + APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). + FullEndpointURL - The URL submitted by the client, including query params. + FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. + EndpointSegment - The URL endpoint segment. + ParentURL - The URL path preceeding the current endpoint. + CurrentAPI - The name of this stored procedure. + + Parameters : + API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: + - APIPattern must follow this structure Scrubber_pm[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Scrubber_pm.POST + - Scrubber_pm.ID.PUT + - Scrubber_pm.ID.firstName.GET + Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API + services do not rely upon anything being returned in the response. This is what the + various services like SetResponseBody and SetResponseStatus services are for. A response + value is only helpful if the developers want to use it for debug purposes. + + History : (Date, Initials, Notes) + 06/05/24 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +Declare Subroutine Pm_Services, Http_Services, Logging_Services +Declare function Error_Services, Logging_Services, Environment_Services, Datetime + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS + +LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Scrubbers\API' +LogDate = Oconv(Date(), 'D4/') +LogTime = Oconv(Time(), 'MTS') +LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Tool Log.csv' +Headers = 'Logging DTM' : @FM : 'ScrubberID' : @FM : 'Notes' : @FM : 'Message' +objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) +LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') +end + +Return Response OR '' + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Endpoint Handlers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +API scrubber_pm.POST + Body = HTTP_Services('GetHTTPPostString') + If Body NE '' then + // The POST string will have been encoded so use percent (URL) decoding. + PMJson = HTTP_Services('DecodePercentString', Body) + ParseResponse = SRP_JSON(objJson, 'PARSE', PMJson) + If (ParseResponse EQ '') then + EquipmentID = SRP_JSON(objJson, 'GetValue', 'EquipmentId') + User = SRP_JSON(objJson, 'GetValue', 'User') + end else + HTTP_Services('SetResponseStatus', 400, 'Unable to parse the JSON data from the request.') + end + end else + HTTP_Services('SetResponseStatus', 400, 'JSON object is missing in the body of the request.') + end + +end api + + +API scrubber_pm.HEAD +API scrubber_pm.GET + + HTTP_Resource_Services('LoremIpsum') + +end api + + +API scrubber_pm.ID.HEAD +API scrubber_pm.ID.GET + + ScrubberID = EndpointSegment + IF RowExists('TOOL', ScrubberID) then + Pm_Services('CompleteScrubberPM', ScrubberID) + If Error_Services('HasError') then + ErrMsg = Error_Services('GetMessage') + HTTP_Services('SetResponseStatus', 500, ErrMsg) + LogData = '' + LogData<1> = OConv(Datetime(), 'DT2/^H') + LogData<2> = ScrubberID + LogData<3> = 'Error' + LogData<4> = ErrMsg + Logging_Services('AppendLog', objLog, LogData, @RM, @FM) + end else + LogData = '' + LogData<1> = OConv(Datetime(), 'DT2/^H') + LogData<2> = ScrubberID + LogData<3> = 'Success' + LogData<4> = 'Scrubber PM Completion was successful' + Logging_Services('AppendLog', objLog, LogData, @RM, @FM) + end + end else + ErrMsg = 'Scrubber does not exist!' + HTTP_Services('SetResponseStatus', 500, ErrMsg) + LogData = '' + LogData<1> = OConv(Datetime(), 'DT2/^H') + LogData<2> = ScrubberID + LogData<3> = 'Error' + LogData<4> = ErrMsg + Logging_Services('AppendLog', objLog, LogData, @RM, @FM) + end +end api diff --git a/LSL2/STPROC/TEST_RUN_SERVICES.txt b/LSL2/STPROC/TEST_RUN_SERVICES.txt index 1b13628..389fb0e 100644 --- a/LSL2/STPROC/TEST_RUN_SERVICES.txt +++ b/LSL2/STPROC/TEST_RUN_SERVICES.txt @@ -830,8 +830,3 @@ end service - - - - - diff --git a/LSL2/STPROC/TOOL_SERVICES.txt b/LSL2/STPROC/TOOL_SERVICES.txt index 3f9859c..9b79f95 100644 --- a/LSL2/STPROC/TOOL_SERVICES.txt +++ b/LSL2/STPROC/TOOL_SERVICES.txt @@ -110,10 +110,10 @@ end service Service GetTools(ToolClass) - + Query = 'SELECT TOOL ' If ToolClass NE '' then - Query := 'WITH CLASS EQ ':ToolClass:' ' + Query := 'WITH CLASS EQ ': Quote(ToolClass) end Query := 'BY CLASS BY TOOL_ID' Set_Status(0) @@ -238,6 +238,33 @@ Service ChangeToolMode(ToolID, NewMode, NewReason, CurrUser, ForceModeChange) end service +Service GetNumPoints(ToolClass, ToolPattern) + + ErrorMsg = '' + NumPoints = '' + If ( (ToolClass NE '') and (ToolPattern NE '') ) then + If RowExists('TOOL_CLASS', ToolClass) then + ToolPatterns = Xlate('TOOL_CLASS', ToolClass, 'PATTERN', 'X') + Locate ToolPattern in ToolPatterns using @VM setting PatternPos then + NumPoints = Xlate('TOOL_CLASS', ToolClass, 'PATTERN_SIZE', 'X')<0, PatternPos> + end else + ErrorMsg = 'Error in ':Service:' service. ToolPattern "':ToolPattern:'" not found in TOOL_CLASS "':ToolClass:'".' + end + end else + ErrorMsg = 'Error in ':Service:' service. ToolClass "':ToolClass:'" does not exist.' + end + end else + ErrorMsg = 'Error in ':Service:' service. Null ToolClass or ToolPattern passed into service.' + end + + If ErrorMsg EQ '' then + Response = NumPoints + end else + Error_Services('Add', ErrorMsg) + end + +end service + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -329,3 +356,4 @@ return + diff --git a/LSL2/STPROC/WAFERCOUNTER_API.txt b/LSL2/STPROC/WAFERCOUNTER_API.txt index aa05c17..eeb836d 100644 --- a/LSL2/STPROC/WAFERCOUNTER_API.txt +++ b/LSL2/STPROC/WAFERCOUNTER_API.txt @@ -307,3 +307,72 @@ API wafercounter.completewafercount.POST HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) end api + + +API wafercounter.ID.HEAD +API wafercounter.ID.GET + + ErrorMessage = '' + ResponseCode = '' + WaferCounterId = EndPointSegment + CassId = '' + Body = '' + OIWizardID = '' + UserId = '' + Cookies = HTTP_Services('GetHTTPCookie') + For each Cookie in Cookies using ';' + Key = Field(Cookie, '=', 1) + If Key EQ 'sessionID' then + OIWizardID = Field(Cookie, '=', 2) + end + Next Cookie + ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) + CassBarcodeData = '' + UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X') + StatusCode = '' + Body = HTTP_Services('GetHTTPPostString', True$) + DecodedJSON = HTTP_Services('DecodePercentString', Body) + + //Log Entry into API - + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = UserId + LogData<3> = OIWizardId + LogData<4> = 'Getting Wafer counter record. Record Id: ' : WaferCounterId + Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) + + If WaferCounterId NE '' then + WaferCounterJson = Wafer_Counter_Services('ConvertWaferCounterRecToJson', WaferCounterId) + If Error_Services('NoError') then + HTTP_Services('SetResponseBody', WaferCounterJson) + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + end else + ErrorMessage = 'Null wafer counter passed to endpoint.' + end + + If ErrorMessage EQ '' then + //Log Success + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = UserId + LogData<3> = OIWizardId + LogData<4> = 'Wafer Counter record successfully returned. Wafer Counter Id: ' : WaferCounterId + Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) + end else + //Log Failure + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = UserId + LogData<3> = OIWizardId + LogData<4> = 'Error returning wafer counter record. Wafer Counter Id: ' : WaferCounterId : ' . Error Message: ' : ErrorMessage + Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) + end + + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api diff --git a/LSL2/STPROC/WAFER_COUNTER_SERVICES.txt b/LSL2/STPROC/WAFER_COUNTER_SERVICES.txt index 35a43a4..c7d6902 100644 --- a/LSL2/STPROC/WAFER_COUNTER_SERVICES.txt +++ b/LSL2/STPROC/WAFER_COUNTER_SERVICES.txt @@ -34,6 +34,8 @@ $Insert RLIST_EQUATES $Insert WAFER_COUNTER_EQUATES $Insert TOOL_EQUATES $Insert TOOL_LOG_EQUATES +$Insert LOT_OPERATION_EQUATES +$Insert LOT_EQUATES Equ Tab$ to \09\ Equ CRLF$ to \0D0A\ @@ -213,7 +215,7 @@ end service Service GetWaferCounterJSON(WaferSize, ToolLocation, CassID) - + If ( (WaferSize NE '') and (ToolLocation NE '') and (CassID NE '') ) then URL = 'https://oi-metrology-viewer-prod.mes.infineon.com:4438/api/v1/WaferCounter/{waferSize}/last-quantity-and-slot-map/?area={area}&text={cassID}' Swap '{waferSize}' with WaferSize in URL @@ -226,15 +228,15 @@ Service GetWaferCounterJSON(WaferSize, ToolLocation, CassID) If Error_Services('NoError') then StatusCode = Httpclient_Services('GetResponseStatusCode') If StatusCode NE 200 then - Begin Case - Case Response EQ '' - ErrorMsg = 'Unexpected server error.' - Case Response EQ 'No files!' - ErrorMsg = 'No data. Please re-seat cassette and try again.' - Case Otherwise$ - // Use message in response body to populate error services - ErrorMsg = Response - End Case + Begin Case + Case Response EQ '' + ErrorMsg = 'Unexpected server error.' + Case Response EQ 'No files!' + ErrorMsg = 'No data. Please re-seat cassette and try again.' + Case Otherwise$ + // Use message in response body to populate error services + ErrorMsg = Response + End Case Error_Services('Add', ErrorMsg) end end @@ -244,7 +246,7 @@ end service Service AddScan(LotID, ScanQty, ScanDtm, ScanTool, ScanUser, ScanLocation, WaferMap) - + KeyID = RTI_CreateGuid() Record = '' Record = LotID @@ -448,9 +450,9 @@ Service ProcessCass2DBarcode(BarcodeText) end If ErrorMessage EQ '' then - Response = CassId : @VM: ExpectedQty : @VM : CassType + Response = CassId : @VM: ExpectedQty : @VM : CassType end else - Error_Services('Add', ErrorMessage) + Error_Services('Add', ErrorMessage) end end service @@ -464,16 +466,16 @@ end service Service ProcessTool2DBarcode(BarcodeText, CassId, CassType, UserId) ErrorMessage = '' - + If BarcodeText NE '' then DelimCnt = DCount(BarcodeText, '|') If DelimCnt EQ 2 then WaferSize = Field(BarcodeText, '|', 1) Area = Field(BarcodeText, '|', 2) If Environment_Services('IsProd') then - WcJson = Wafer_Counter_Services('GetWaferCounterJSON', WaferSize, Area, CassID) + WcJson = Wafer_Counter_Services('GetWaferCounterJSON', WaferSize, Area, CassID) end else - WcJson = Wafer_Counter_Services('GetWaferCounterJSONTestData', WaferSize, Area, CassID) + WcJson = Wafer_Counter_Services('GetWaferCounterJSONTestData', WaferSize, Area, CassID) end If Error_Services('NoError') then @@ -504,13 +506,13 @@ Service ProcessTool2DBarcode(BarcodeText, CassId, CassType, UserId) ErrorMessage = 'Invalid tool scan.' end end else - ErrorMessage = 'Scan data was null.' + ErrorMessage = 'Scan data was null.' end If ErrorMessage EQ '' then Response = WaferCounterId end else - Error_Services('Add', ErrorMessage) + Error_Services('Add', ErrorMessage) end end service @@ -521,15 +523,15 @@ end service // Emulates GetWaferCounterJson service. //---------------------------------------------------------------------------------------------------------------------- Service GetWaferCounterJSONTestData(WaferSize, ToolLocation, CassID) - + If ( (WaferSize NE '') and (ToolLocation NE '') and (CassID NE '') ) then Response = '' objJson = '' If SRP_JSON(objJson, 'New', 'Object') then SRP_JSON(objJson, 'SetValue', 'dateTimeFormatted', Datetime(), 'String') SRP_JSON(objJson, 'SetValue', 'equipmentId', 'WC8INCH1', 'String') - SRP_JSON(objJson, 'SetValue', 'total', 24, 'Number') - SRP_JSON(objJson, 'SetValue', 'slotMap', '1111111110111111111111111', 'String') + SRP_JSON(objJson, 'SetValue', 'total', 25, 'Number') + SRP_JSON(objJson, 'SetValue', 'slotMap', '1111111111111111111111111', 'String') Response = SRP_Json(objJson, 'Stringify', 'Styled') SRP_JSON(objJSON, 'Release') end @@ -537,15 +539,15 @@ Service GetWaferCounterJSONTestData(WaferSize, ToolLocation, CassID) If Error_Services('NoError') then StatusCode = 200 If StatusCode NE 200 then - Begin Case - Case Response EQ '' - ErrorMsg = 'Unexpected server error.' - Case Response EQ 'No files!' - ErrorMsg = 'No data. Please re-seat cassette and try again.' - Case Otherwise$ - // Use message in response body to populate error services - ErrorMsg = Response - End Case + Begin Case + Case Response EQ '' + ErrorMsg = 'Unexpected server error.' + Case Response EQ 'No files!' + ErrorMsg = 'No data. Please re-seat cassette and try again.' + Case Otherwise$ + // Use message in response body to populate error services + ErrorMsg = Response + End Case Error_Services('Add', ErrorMsg) end end @@ -553,6 +555,181 @@ Service GetWaferCounterJSONTestData(WaferSize, ToolLocation, CassID) end service +Service ConvertWaferCounterRecToJson(WaferCounterId) + + ErrorMessage = '' + If WaferCounterId NE '' then + WaferCounterRec = Database_Services('ReadDataRow', 'WAFER_COUNTER', WaferCounterId, True$, 0, False$) + If Error_Services('NoError') then + //Fields within wafer counter rec + CassId = WaferCounterRec + swap '.' with '*' in CassId + WaferCount = WaferCounterRec + ScanDtm = WaferCounterRec + ToolID = WaferCounterRec + WaferMapData = WaferCounterRec + swap 1 with 1:@FM in WaferMapData + swap 0 with 0:@FM in WaferMapData + + ActualWaferArray = '' + for i = 25 to 1 step -1 + Slot = i + WaferPresent = WaferMapData + ActualWaferArray<-1, 1> = Slot : @VM : WaferPresent + Next i + //Fields calculated at runtime. + CassType = '' + WONo = '' + CassNo = '' + ExpectedQty = '' + Begin Case + Case RowExists('RDS', CassId) + CassType = 'RDS' + WONo = XLATE('RDS', CassId, 'WO', 'X') + CassNo = XLATE('RDS', CassId, 'CASS_NO', 'X') + ExpectedQty = Xlate('RDS', CassId, 'WFRS_OUT', 'X') + Case RowExists('WM_OUT', CassId) OR RowExists('WM_IN', CassId) + CassType = 'WM_OUT' + WONo = Field(CassId, '*', 1) + CassNo = Field(CassId, '*', 3) + ExpectedQty = Xlate('WM_OUT', CassId, 'WAFER_CNT', 'X') + End Case + WoMatKey = WONo : '*' : CassNo + + ExpectedWaferData = Wo_Mat_Services('GetWaferMap', WoMatKey) + ExpectedWaferArray = '' + for i = 25 to 1 step -1 + Slot = i + WaferPresent = ExpectedWaferData<1, i> + ExpectedWaferArray<-1, 1> = Slot : @VM : WaferPresent + Next i + + //Constructing the JSON Object + objJson = '' + If SRP_Json(objJson, 'New', 'Object') then + SRP_Json(objJson, 'SetValue', 'WaferCounterId', WaferCounterId, 'String') + SRP_Json(objJson, 'SetValue', 'CassId', CassId, 'String') + SRP_Json(objJson, 'SetValue', 'CassType', CassType, 'String') + SRP_Json(objJson, 'SetValue', 'ExpectedQty', ExpectedQty, 'Number') + SRP_Json(objJson, 'SetValue', 'ScanDtm', OConv(ScanDtm, 'DT4/'), 'String') + SRP_Json(objJson, 'SetValue', 'ToolId', ToolId, 'String') + SRP_Json(objJson, 'SetValue', 'WaferCount', WaferCount, 'Number') + + //Wafer Counter Slot Array + objWaferCounterSlotArray = '' + IF SRP_Json(objWaferCounterSlotArray, 'New', 'Array') then + For each Slot in ActualWaferArray using @FM + SlotNo = Slot<1, 1> + WaferPresent = Slot<1, 2> + //Create the individiual slot object + objSlot = '' + If SRP_Json(objSlot, 'New', 'Object') then + SRP_Json(objSlot, 'SetValue', 'SlotNo', SlotNo, 'Number') + SRP_Json(objSlot, 'SetValue', 'WaferPresent', WaferPresent, 'Boolean') + SRP_Json(objWaferCounterSlotArray, 'Add', objSlot) + SRP_Json(objSlot, 'Release') + end + Next Slot + SRP_Json(objJson, 'Set', 'WaferArray', objWaferCounterSlotArray) + SRP_Json(objWaferCounterSlotArray, 'Release') + end + + //OpenInsight Expected Slot Array + objOISlotArray = '' + IF SRP_Json(objOISlotArray, 'New', 'Array') then + For each Slot in ExpectedWaferArray using @FM + SlotNo = Slot<1, 1> + WaferPresent = Slot<1, 2> + //Create the individiual slot object + objSlot = '' + If SRP_Json(objSlot, 'New', 'Object') then + SRP_Json(objSlot, 'SetValue', 'SlotNo', SlotNo, 'Number') + SRP_Json(objSlot, 'SetValue', 'WaferPresent', WaferPresent, 'Boolean') + SRP_Json(objOISlotArray, 'Add', objSlot) + SRP_Json(objSlot, 'Release') + end + Next slot + SRP_Json(objJson, 'Set', 'ExpectedWaferArray', objOISlotArray) + SRP_Json(objWaferCounterSlotArray, 'Release') + + + end + Response = SRP_Json(objJson, 'Stringify', 'Styled') + SRP_Json(objJson, 'Release') + end else + ErrorMessage = 'Error initializing JSON object' + end + end else + ErrorMessage = 'Error reading wafer counter record. ' : Error_Services('GetMessage') + end + end else + ErrorMessage = 'Wafer counter id was null.' + end + + If ErrorMessage NE '' then + Error_Services('Add', ErrorMessage) + end + +end service + +Service AssociateWaferCounter(LotOperationId, WaferCounterId, UserId) + + ErrorMessage = '' + + If RowExists('LSL_USERS', UserId) then + If RowExists('LOT_OPERATION', LotOperationId) then + If RowExists('WAFER_COUNTER', WaferCounterId) then + WaferCounterRec = Database_Services('ReadDataRow', 'WAFER_COUNTER', WaferCounterId, True$, 0, False$) + If Error_Services('NoError') then + WaferCounterToolId = WaferCounterRec + ThisLotOpRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$) + If Error_Services('NoError') then + LotId = ThisLotOpRec + If RowExists('LOT', LotId) then + ThisWaferCountCassId = WaferCounterRec + ThisLotId = ThisLotOpRec + LegacyLotType = Xlate('LOT', ThisLotId, LOT_LEGACY_LOT_TYPE$, 'X') + LotIdToCompare = '' + If LegacyLotType NE '' then + LotIdToCompare = Xlate('LOT', ThisLotId, LOT_LEGACY_LOT_ID$, 'X') + end else + LotIdToCompare = ThisLotId + end + + If ThisWaferCountCassId EQ LotIdToCompare then + ThisLotOpRec = WaferCounterId + Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, ThisLotOpRec) + If Error_Services('NoError') then + Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'LOG_WAFER_COUNT', 'Wafer Count logged.', WaferCounterToolId, UserId) + end + end else + ErrorMessage = 'Lot IDs do not match!' + end + end else + ErrorMessage = 'Lot not found.' + end + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = 'Wafer counter record not found.' + end + end else + ErrorMessage = 'Lot Operation record not found.' + end + end else + ErrorMessage = 'User ID not found.' + end + + If ErrorMessage NE '' then + Error_Services('Add', ErrorMessage) + end + +end service + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -566,3 +743,5 @@ ClearCursors: return + + diff --git a/LSL2/STPROC/WO_API.txt b/LSL2/STPROC/WO_API.txt index 27a2098..139fe90 100644 --- a/LSL2/STPROC/WO_API.txt +++ b/LSL2/STPROC/WO_API.txt @@ -149,4 +149,3 @@ CreateHALItem: HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': Message) end return - diff --git a/LSL2/STPROC/WO_MAT_API.txt b/LSL2/STPROC/WO_MAT_API.txt index 6fc25cd..9921d35 100644 --- a/LSL2/STPROC/WO_MAT_API.txt +++ b/LSL2/STPROC/WO_MAT_API.txt @@ -120,4 +120,3 @@ CreateHalItem: LogData<5> = ResponseMessage Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM) return - diff --git a/LSL2/STPROCINS/CLEAN_EQUATES.txt b/LSL2/STPROCINS/CLEAN_EQUATES.txt new file mode 100644 index 0000000..e863294 --- /dev/null +++ b/LSL2/STPROCINS/CLEAN_EQUATES.txt @@ -0,0 +1,20 @@ +compile insert CLEAN_EQUATES +/*---------------------------------------- + Author : Table Create Insert Routine + Written : 17/06/2025 + Description : Insert for Table CLEAN +----------------------------------------*/ +#ifndef __CLEAN_EQUATES__ +#define __CLEAN_EQUATES__ + + equ CLEAN_LOT_ID$ to 1 + equ CLEAN_TOOL$ to 2 + equ CLEAN_RECIPE$ to 3 + equ CLEAN_COMPLETE_DTM$ to 4 + equ CLEAN_LOT_OPERATION_ID$ to 5 + equ CLEAN_CLEAN_START_DTM$ to 6 + equ CLEAN_CLEAN_START_USER_ID$ to 7 + equ CLEAN_CLEAN_STOP_DTM$ to 8 + equ CLEAN_CLEAN_STOP_USER_ID$ to 9 + +#endif diff --git a/LSL2/STPROCINS/LOT_EQUATES.txt b/LSL2/STPROCINS/LOT_EQUATES.txt index 5fb7210..0325734 100644 --- a/LSL2/STPROCINS/LOT_EQUATES.txt +++ b/LSL2/STPROCINS/LOT_EQUATES.txt @@ -28,6 +28,6 @@ compile insert LOT_EQUATES equ LOT_PROD_SPEC_ID$ to 19 equ LOT_EPI_PART_NO$ to 20 equ LOT_PROD_VER_NO$ to 21 - equ LOT_MET_TEST_IDS$ to 22 + equ LOT_MET_TEST_IDS$ to 22 #endif diff --git a/LSL2/STPROCINS/LOT_OPERATION_EQUATES.txt b/LSL2/STPROCINS/LOT_OPERATION_EQUATES.txt index 7f2ed8a..e59bb9d 100644 --- a/LSL2/STPROCINS/LOT_OPERATION_EQUATES.txt +++ b/LSL2/STPROCINS/LOT_OPERATION_EQUATES.txt @@ -23,13 +23,13 @@ compile insert LOT_OPERATION_EQUATES equ LOT_OPERATION_MET_TEST_ID$ to 14 equ LOT_OPERATION_CLEAN_ID$ to 15 equ LOT_OPERATION_PACKAGING_ID$ to 16 - equ LOT_OPERATION_WAFER_COUNTER_ID$ to 17 - equ LOT_OPERATION_OPERATION_TYPE$ to 18 - equ LOT_OPERATION_OPERATION_CLASS$ to 19 - equ LOT_OPERATION_MET_TEST_TYPE_REQUIRED$ to 20 - equ LOT_OPERATION_MET_TEST_REQUIRED$ to 21 - equ LOT_OPERATION_PACKAGING_REQUIRED$ to 22 - equ LOT_OPERATION_CLEAN_REQUIRED$ to 23 - equ LOT_OPERATION_WAFER_COUNTER_REQUIRED$ to 24 + equ LOT_OPERATION_WAFER_COUNTER_ID$ to 18 + equ LOT_OPERATION_OPERATION_TYPE$ to 19 + equ LOT_OPERATION_OPERATION_CLASS$ to 20 + equ LOT_OPERATION_MET_TEST_TYPE_REQUIRED$ to 21 + equ LOT_OPERATION_MET_TEST_REQUIRED$ to 22 + equ LOT_OPERATION_PACKAGING_REQUIRED$ to 23 + equ LOT_OPERATION_CLEAN_REQUIRED$ to 24 + equ LOT_OPERATION_WAFER_COUNTER_REQUIRED$ to 25 #endif diff --git a/LSL2/STPROCINS/METROLOGY_DATA_EXAMPLE_EQUATES.txt b/LSL2/STPROCINS/METROLOGY_DATA_EXAMPLE_EQUATES.txt deleted file mode 100644 index 74ce3da..0000000 --- a/LSL2/STPROCINS/METROLOGY_DATA_EXAMPLE_EQUATES.txt +++ /dev/null @@ -1,21 +0,0 @@ -compile insert METROLOGY_DATA_EXAMPLE_EQUATES -/*---------------------------------------- - Author : Table Create Insert Routine - Written : 07/04/2025 - Description : Insert for Table METROLOGY_DATA_EXAMPLE -----------------------------------------*/ -#ifndef __METROLOGY_DATA_EXAMPLE_EQUATES__ -#define __METROLOGY_DATA_EXAMPLE_EQUATES__ - - equ METROLOGY_DATA_EXAMPLE_INSPECTION_TYPE$ to 1 - equ METROLOGY_DATA_EXAMPLE_TOOL_ID$ to 2 - equ METROLOGY_DATA_EXAMPLE_DATA_ENTRY_DTM$ to 3 - equ METROLOGY_DATA_EXAMPLE_DATA_ENTRY_USER$ to 4 - equ METROLOGY_DATA_EXAMPLE_RAW_DATA_POINTS$ to 5 - equ METROLOGY_DATA_EXAMPLE_DATA_AVERAGE$ to 6 - equ METROLOGY_DATA_EXAMPLE_SPEC_LIMIT_UPPER$ to 7 - equ METROLOGY_DATA_EXAMPLE_IN_SPEC$ to 8 - equ METROLOGY_DATA_EXAMPLE_SPEC_LIMIT_LOWER$ to 9 - -#endif - diff --git a/LSL2/STPROCINS/MET_TEST_DATA_EQUATES.txt b/LSL2/STPROCINS/MET_TEST_DATA_EQUATES.txt index 9c43994..0806a09 100644 --- a/LSL2/STPROCINS/MET_TEST_DATA_EQUATES.txt +++ b/LSL2/STPROCINS/MET_TEST_DATA_EQUATES.txt @@ -1,7 +1,6 @@ compile insert MET_TEST_DATA_EQUATES /*---------------------------------------- Author : Table Create Insert Routine - Written : 16/06/2025 Description : Insert for Table MET_TEST_DATA ----------------------------------------*/ #ifndef __MET_TEST_DATA_EQUATES__ @@ -41,3 +40,4 @@ compile insert MET_TEST_DATA_EQUATES equ MET_TEST_DATA.PROPERTY_15_OUT_OF_SPEC$ to 32 #endif + diff --git a/LSL2/STPROCINS/MET_TEST_INSERTS.txt b/LSL2/STPROCINS/MET_TEST_INSERTS.txt new file mode 100644 index 0000000..e27acdb --- /dev/null +++ b/LSL2/STPROCINS/MET_TEST_INSERTS.txt @@ -0,0 +1,16 @@ +compile insert MET_TEST_INSERTS +/*---------------------------------------- + Author : Daniel Stieber + Written : 20/05/2025 + Description : Metadata Insert for + MET_TEST system. +----------------------------------------*/ +#ifndef __MET_TEST_INSERTS__ +#define __MET_TEST_INSERTS__ + + Declare subroutine Met_Test_Services + Declare function Met_Test_Services + + Equ NUM_PROPERTIES$ to 15 + +#endif diff --git a/LSL2/STPROCINS/PACKAGING_EQUATES.txt b/LSL2/STPROCINS/PACKAGING_EQUATES.txt new file mode 100644 index 0000000..8d55fda --- /dev/null +++ b/LSL2/STPROCINS/PACKAGING_EQUATES.txt @@ -0,0 +1,14 @@ +compile insert PACKAGING_EQUATES +/*---------------------------------------- + Author : Table Create Insert Routine + Written : 16/05/2025 + Description : Insert for Table PACKAGING +----------------------------------------*/ +#ifndef __PACKAGING_EQUATES__ +#define __PACKAGING_EQUATES__ + + equ PACKAGING_LOT_ID$ to 1 + equ PACKAGING_COMPLETE$ to 2 + equ PACKAGING_COMPLETE_DTM$ to 3 + +#endif diff --git a/LSL2/STPROCINS/PRODUCT_OPERATION_EQUATES.txt b/LSL2/STPROCINS/PRODUCT_OPERATION_EQUATES.txt index 03a44b5..ed99bbf 100644 --- a/LSL2/STPROCINS/PRODUCT_OPERATION_EQUATES.txt +++ b/LSL2/STPROCINS/PRODUCT_OPERATION_EQUATES.txt @@ -1,7 +1,7 @@ compile insert PRODUCT_OPERATION_EQUATES /*---------------------------------------- Author : Table Create Insert Routine - Written : 11/10/2024 + Written : 13/05/2025 Description : Insert for Table PRODUCT_OPERATION ----------------------------------------*/ #ifndef __PRODUCT_OPERATION_EQUATES__