4146 |
03 Oct 16 |
nicklas |
1 |
package net.sf.basedb.reggie.servlet; |
4146 |
03 Oct 16 |
nicklas |
2 |
|
4146 |
03 Oct 16 |
nicklas |
3 |
import java.io.IOException; |
4157 |
07 Oct 16 |
nicklas |
4 |
import java.io.PrintWriter; |
4165 |
21 Oct 16 |
nicklas |
5 |
import java.util.Date; |
4153 |
05 Oct 16 |
nicklas |
6 |
import java.util.HashSet; |
4153 |
05 Oct 16 |
nicklas |
7 |
import java.util.Iterator; |
4154 |
06 Oct 16 |
nicklas |
8 |
import java.util.List; |
4153 |
05 Oct 16 |
nicklas |
9 |
import java.util.Set; |
4146 |
03 Oct 16 |
nicklas |
10 |
|
4146 |
03 Oct 16 |
nicklas |
11 |
import javax.servlet.ServletException; |
4146 |
03 Oct 16 |
nicklas |
12 |
import javax.servlet.http.HttpServlet; |
4146 |
03 Oct 16 |
nicklas |
13 |
import javax.servlet.http.HttpServletRequest; |
4146 |
03 Oct 16 |
nicklas |
14 |
import javax.servlet.http.HttpServletResponse; |
4146 |
03 Oct 16 |
nicklas |
15 |
|
4146 |
03 Oct 16 |
nicklas |
16 |
import org.json.simple.JSONArray; |
4146 |
03 Oct 16 |
nicklas |
17 |
import org.json.simple.JSONObject; |
4146 |
03 Oct 16 |
nicklas |
18 |
|
6326 |
14 Jun 21 |
nicklas |
19 |
import net.sf.basedb.core.AnyToAny; |
4166 |
21 Oct 16 |
nicklas |
20 |
import net.sf.basedb.core.BioMaterial; |
4154 |
06 Oct 16 |
nicklas |
21 |
import net.sf.basedb.core.BioMaterialEvent; |
4154 |
06 Oct 16 |
nicklas |
22 |
import net.sf.basedb.core.BioPlate; |
4154 |
06 Oct 16 |
nicklas |
23 |
import net.sf.basedb.core.BioPlateType; |
4173 |
24 Oct 16 |
nicklas |
24 |
import net.sf.basedb.core.BioWell; |
4146 |
03 Oct 16 |
nicklas |
25 |
import net.sf.basedb.core.DbControl; |
4153 |
05 Oct 16 |
nicklas |
26 |
import net.sf.basedb.core.Extract; |
4893 |
09 Jul 18 |
nicklas |
27 |
import net.sf.basedb.core.Include; |
4153 |
05 Oct 16 |
nicklas |
28 |
import net.sf.basedb.core.Item; |
4153 |
05 Oct 16 |
nicklas |
29 |
import net.sf.basedb.core.ItemList; |
4153 |
05 Oct 16 |
nicklas |
30 |
import net.sf.basedb.core.ItemQuery; |
4153 |
05 Oct 16 |
nicklas |
31 |
import net.sf.basedb.core.ItemSubtype; |
4166 |
21 Oct 16 |
nicklas |
32 |
import net.sf.basedb.core.MeasuredBioMaterial; |
4154 |
06 Oct 16 |
nicklas |
33 |
import net.sf.basedb.core.PlateGeometry; |
4146 |
03 Oct 16 |
nicklas |
34 |
import net.sf.basedb.core.SessionControl; |
4154 |
06 Oct 16 |
nicklas |
35 |
import net.sf.basedb.core.Type; |
4157 |
07 Oct 16 |
nicklas |
36 |
import net.sf.basedb.core.query.Annotations; |
4154 |
06 Oct 16 |
nicklas |
37 |
import net.sf.basedb.core.query.Expressions; |
4154 |
06 Oct 16 |
nicklas |
38 |
import net.sf.basedb.core.query.Hql; |
4154 |
06 Oct 16 |
nicklas |
39 |
import net.sf.basedb.core.query.Orders; |
4154 |
06 Oct 16 |
nicklas |
40 |
import net.sf.basedb.core.query.Restrictions; |
4164 |
20 Oct 16 |
nicklas |
41 |
import net.sf.basedb.core.snapshot.SnapshotManager; |
4146 |
03 Oct 16 |
nicklas |
42 |
import net.sf.basedb.reggie.JsonUtil; |
4146 |
03 Oct 16 |
nicklas |
43 |
import net.sf.basedb.reggie.Reggie; |
4146 |
03 Oct 16 |
nicklas |
44 |
import net.sf.basedb.reggie.counter.CounterService; |
4153 |
05 Oct 16 |
nicklas |
45 |
import net.sf.basedb.reggie.dao.Annotationtype; |
4154 |
06 Oct 16 |
nicklas |
46 |
import net.sf.basedb.reggie.dao.BioplateType; |
4154 |
06 Oct 16 |
nicklas |
47 |
import net.sf.basedb.reggie.dao.Geometry; |
4893 |
09 Jul 18 |
nicklas |
48 |
import net.sf.basedb.reggie.dao.ReggieItem; |
4146 |
03 Oct 16 |
nicklas |
49 |
import net.sf.basedb.reggie.dao.ReggieRole; |
4153 |
05 Oct 16 |
nicklas |
50 |
import net.sf.basedb.reggie.dao.Subtype; |
4153 |
05 Oct 16 |
nicklas |
51 |
import net.sf.basedb.util.Values; |
4146 |
03 Oct 16 |
nicklas |
52 |
import net.sf.basedb.util.error.ThrowableUtil; |
5371 |
16 Apr 19 |
nicklas |
53 |
import net.sf.basedb.util.excel.XlsxTableWriter; |
5371 |
16 Apr 19 |
nicklas |
54 |
import net.sf.basedb.util.excel.XlsxToCsvUtil; |
4173 |
24 Oct 16 |
nicklas |
55 |
import net.sf.basedb.util.export.TableWriter; |
4146 |
03 Oct 16 |
nicklas |
56 |
|
4146 |
03 Oct 16 |
nicklas |
57 |
/** |
4146 |
03 Oct 16 |
nicklas |
Handles outtake of biomaterial for external parties. |
4146 |
03 Oct 16 |
nicklas |
59 |
|
4146 |
03 Oct 16 |
nicklas |
@author nicklas |
4146 |
03 Oct 16 |
nicklas |
@since 4.8 |
4146 |
03 Oct 16 |
nicklas |
62 |
*/ |
4146 |
03 Oct 16 |
nicklas |
63 |
public class OuttakeServlet |
4146 |
03 Oct 16 |
nicklas |
64 |
extends HttpServlet |
4146 |
03 Oct 16 |
nicklas |
65 |
{ |
4146 |
03 Oct 16 |
nicklas |
66 |
|
4146 |
03 Oct 16 |
nicklas |
67 |
private static final long serialVersionUID = -1308781977707573172L; |
4146 |
03 Oct 16 |
nicklas |
68 |
|
4146 |
03 Oct 16 |
nicklas |
69 |
public OuttakeServlet() |
4146 |
03 Oct 16 |
nicklas |
70 |
{} |
4146 |
03 Oct 16 |
nicklas |
71 |
|
4146 |
03 Oct 16 |
nicklas |
72 |
@SuppressWarnings("unchecked") |
4146 |
03 Oct 16 |
nicklas |
73 |
@Override |
4146 |
03 Oct 16 |
nicklas |
74 |
protected void doGet(HttpServletRequest req, HttpServletResponse resp) |
4146 |
03 Oct 16 |
nicklas |
75 |
throws ServletException, IOException |
4146 |
03 Oct 16 |
nicklas |
76 |
{ |
4146 |
03 Oct 16 |
nicklas |
77 |
String cmd = req.getParameter("cmd"); |
4146 |
03 Oct 16 |
nicklas |
78 |
JsonUtil.setJsonResponseHeaders(resp); |
4146 |
03 Oct 16 |
nicklas |
79 |
|
4146 |
03 Oct 16 |
nicklas |
80 |
JSONObject json = new JSONObject(); |
4146 |
03 Oct 16 |
nicklas |
81 |
json.put("status", "ok"); |
4146 |
03 Oct 16 |
nicklas |
82 |
|
4153 |
05 Oct 16 |
nicklas |
83 |
final SessionControl sc = Reggie.getSessionControl(req); |
4146 |
03 Oct 16 |
nicklas |
84 |
DbControl dc = null; |
4146 |
03 Oct 16 |
nicklas |
85 |
try |
4146 |
03 Oct 16 |
nicklas |
86 |
{ |
4146 |
03 Oct 16 |
nicklas |
87 |
if ("CheckSourceList".equals(cmd)) |
4146 |
03 Oct 16 |
nicklas |
88 |
{ |
6336 |
16 Jun 21 |
nicklas |
89 |
dc = sc.newDbControl(":Define outtake"); |
4146 |
03 Oct 16 |
nicklas |
90 |
|
4153 |
05 Oct 16 |
nicklas |
91 |
int listId = Values.getInt(req.getParameter("listId")); |
6326 |
14 Jun 21 |
nicklas |
92 |
ItemSubtype outtakeType = Subtype.getByCName(req.getParameter("outtakeType")).get(dc); |
4153 |
05 Oct 16 |
nicklas |
93 |
|
4153 |
05 Oct 16 |
nicklas |
94 |
ItemList list = ItemList.getById(dc, listId); |
4153 |
05 Oct 16 |
nicklas |
95 |
Item memberType = list.getMemberType(); |
4153 |
05 Oct 16 |
nicklas |
96 |
ItemSubtype memberSubtype = list.getItemSubtype(); |
4153 |
05 Oct 16 |
nicklas |
97 |
|
4153 |
05 Oct 16 |
nicklas |
98 |
JSONObject jsonList = new JSONObject(); |
4153 |
05 Oct 16 |
nicklas |
99 |
jsonList.put("id", list.getId()); |
4153 |
05 Oct 16 |
nicklas |
100 |
jsonList.put("name", list.getName()); |
4153 |
05 Oct 16 |
nicklas |
101 |
jsonList.put("itemType", memberType.name()); |
4153 |
05 Oct 16 |
nicklas |
102 |
jsonList.put("size", list.getSize()); |
4153 |
05 Oct 16 |
nicklas |
103 |
|
4153 |
05 Oct 16 |
nicklas |
104 |
if (memberType == Item.EXTRACT) |
4153 |
05 Oct 16 |
nicklas |
105 |
{ |
4994 |
02 Oct 18 |
nicklas |
106 |
int numDoNotUse = 0; |
6326 |
14 Jun 21 |
nicklas |
107 |
int numIncorrectSubtype = 0; |
6183 |
26 Mar 21 |
nicklas |
108 |
ItemQuery<Extract> memberQuery = list.getMembers(); |
4153 |
05 Oct 16 |
nicklas |
109 |
memberQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT); |
4153 |
05 Oct 16 |
nicklas |
110 |
|
4153 |
05 Oct 16 |
nicklas |
111 |
MinMax remainingQuantity = new MinMax(); |
6220 |
20 Apr 21 |
nicklas |
112 |
MinMax conc = new MinMax(); |
4153 |
05 Oct 16 |
nicklas |
113 |
|
4153 |
05 Oct 16 |
nicklas |
114 |
Iterator<Extract> it = memberQuery.iterate(dc); |
4153 |
05 Oct 16 |
nicklas |
115 |
while (it.hasNext()) |
4153 |
05 Oct 16 |
nicklas |
116 |
{ |
4153 |
05 Oct 16 |
nicklas |
117 |
Extract e = it.next(); |
4153 |
05 Oct 16 |
nicklas |
118 |
remainingQuantity.add(e.getRemainingQuantity()); |
6220 |
20 Apr 21 |
nicklas |
119 |
Float c = (Float)Annotationtype.ND_CONC.getAnnotationValue(dc, e); |
6220 |
20 Apr 21 |
nicklas |
120 |
if (c == null) c = (Float)Annotationtype.QUBIT_CONC.getAnnotationValue(dc, e); |
6220 |
20 Apr 21 |
nicklas |
121 |
conc.add(c); |
4153 |
05 Oct 16 |
nicklas |
122 |
|
6326 |
14 Jun 21 |
nicklas |
123 |
ItemSubtype subtype = e.getItemSubtype(); |
6326 |
14 Jun 21 |
nicklas |
124 |
if (!outtakeType.equals(subtype)) |
6326 |
14 Jun 21 |
nicklas |
125 |
{ |
6326 |
14 Jun 21 |
nicklas |
126 |
numIncorrectSubtype++; |
6326 |
14 Jun 21 |
nicklas |
127 |
} |
4994 |
02 Oct 18 |
nicklas |
128 |
|
4994 |
02 Oct 18 |
nicklas |
129 |
if (Annotationtype.DO_NOT_USE.getAnnotationValue(dc, e) != null) |
4994 |
02 Oct 18 |
nicklas |
130 |
{ |
4994 |
02 Oct 18 |
nicklas |
131 |
numDoNotUse++; |
4994 |
02 Oct 18 |
nicklas |
132 |
} |
4153 |
05 Oct 16 |
nicklas |
133 |
} |
4153 |
05 Oct 16 |
nicklas |
134 |
|
4153 |
05 Oct 16 |
nicklas |
135 |
jsonList.put("remainingQuantity", remainingQuantity.asJSONObject()); |
6220 |
20 Apr 21 |
nicklas |
136 |
jsonList.put("conc", conc.asJSONObject()); |
4994 |
02 Oct 18 |
nicklas |
137 |
jsonList.put("numDoNotUse", numDoNotUse); |
6326 |
14 Jun 21 |
nicklas |
138 |
jsonList.put("numIncorrectSubtype", numIncorrectSubtype); |
4153 |
05 Oct 16 |
nicklas |
139 |
} |
4153 |
05 Oct 16 |
nicklas |
140 |
|
6326 |
14 Jun 21 |
nicklas |
141 |
if (memberSubtype != null) |
4153 |
05 Oct 16 |
nicklas |
142 |
{ |
4153 |
05 Oct 16 |
nicklas |
143 |
jsonList.put("subtype", Subtype.get(memberSubtype).asJSONObject(dc)); |
4153 |
05 Oct 16 |
nicklas |
144 |
} |
4153 |
05 Oct 16 |
nicklas |
145 |
|
4153 |
05 Oct 16 |
nicklas |
146 |
json.put("list", jsonList); |
4146 |
03 Oct 16 |
nicklas |
147 |
} |
4157 |
07 Oct 16 |
nicklas |
148 |
else if ("GetOuttakeWorklists".equals(cmd)) |
4157 |
07 Oct 16 |
nicklas |
149 |
{ |
6336 |
16 Jun 21 |
nicklas |
150 |
dc = sc.newDbControl("Register outtake"); |
4157 |
07 Oct 16 |
nicklas |
151 |
|
4157 |
07 Oct 16 |
nicklas |
152 |
ItemQuery<ItemList> query = ItemList.getQuery(); |
4157 |
07 Oct 16 |
nicklas |
153 |
query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT); |
4157 |
07 Oct 16 |
nicklas |
154 |
query.restrict(Restrictions.eq(Hql.property("externalId"), Expressions.string(Reggie.OUTTAKE_ALIQUOTS_LIST_ID))); |
4168 |
21 Oct 16 |
nicklas |
155 |
if (Values.getBoolean(req.getParameter("forDelivery"))) |
4157 |
07 Oct 16 |
nicklas |
156 |
{ |
4179 |
27 Oct 16 |
nicklas |
// OuttakeResult == Successful |
4179 |
27 Oct 16 |
nicklas |
158 |
query.join(Annotations.innerJoin(null, Annotationtype.OUTTAKE_RESULT.load(dc), "ors")); |
4179 |
27 Oct 16 |
nicklas |
159 |
query.restrict(Restrictions.eq(Hql.alias("ors"), Expressions.string("Successful"))); |
4179 |
27 Oct 16 |
nicklas |
160 |
|
4168 |
21 Oct 16 |
nicklas |
// CompletedDate != null AND DeliveredDate == null |
4168 |
21 Oct 16 |
nicklas |
162 |
query.join(Annotations.innerJoin(null, Annotationtype.OUTTAKE_COMPLETED_DATE.load(dc), "ocd")); |
4168 |
21 Oct 16 |
nicklas |
163 |
query.join(Annotations.leftJoin(null, Annotationtype.OUTTAKE_DELIVERED_DATE.load(dc), "odd")); |
4168 |
21 Oct 16 |
nicklas |
164 |
query.restrict(Restrictions.eq(Hql.alias("odd"), null)); |
4168 |
21 Oct 16 |
nicklas |
165 |
} |
4168 |
21 Oct 16 |
nicklas |
166 |
else |
4168 |
21 Oct 16 |
nicklas |
167 |
{ |
4168 |
21 Oct 16 |
nicklas |
// CompletedDate == null |
4157 |
07 Oct 16 |
nicklas |
169 |
query.join(Annotations.leftJoin(null, Annotationtype.OUTTAKE_COMPLETED_DATE.load(dc), "cd")); |
4157 |
07 Oct 16 |
nicklas |
170 |
query.restrict(Restrictions.eq(Hql.alias("cd"), null)); |
4157 |
07 Oct 16 |
nicklas |
171 |
} |
4157 |
07 Oct 16 |
nicklas |
172 |
query.order(Orders.asc(Hql.property("name"))); |
4157 |
07 Oct 16 |
nicklas |
173 |
|
4157 |
07 Oct 16 |
nicklas |
174 |
List<ItemList> result = query.list(dc); |
4157 |
07 Oct 16 |
nicklas |
175 |
JSONArray jsonLists = new JSONArray(); |
4157 |
07 Oct 16 |
nicklas |
176 |
for (ItemList list: result) |
4157 |
07 Oct 16 |
nicklas |
177 |
{ |
4157 |
07 Oct 16 |
nicklas |
178 |
JSONObject jsonList = new JSONObject(); |
4157 |
07 Oct 16 |
nicklas |
179 |
|
4157 |
07 Oct 16 |
nicklas |
180 |
jsonList.put("id", list.getId()); |
4157 |
07 Oct 16 |
nicklas |
181 |
jsonList.put("name", list.getName()); |
4179 |
27 Oct 16 |
nicklas |
182 |
jsonList.put("itemType", list.getMemberType().name()); |
4157 |
07 Oct 16 |
nicklas |
183 |
jsonList.put("size", list.getSize()); |
4157 |
07 Oct 16 |
nicklas |
184 |
jsonList.put("comments", list.getDescription()); |
6326 |
14 Jun 21 |
nicklas |
185 |
jsonList.put("parentType", Annotationtype.OUTTAKE_PARENT_TYPE.getAnnotationValue(dc, list)); |
4157 |
07 Oct 16 |
nicklas |
186 |
jsonLists.add(jsonList); |
4157 |
07 Oct 16 |
nicklas |
187 |
} |
4157 |
07 Oct 16 |
nicklas |
188 |
json.put("workLists", jsonLists); |
4157 |
07 Oct 16 |
nicklas |
189 |
} |
4157 |
07 Oct 16 |
nicklas |
190 |
else if ("DownloadLabels".equals(cmd)) |
4157 |
07 Oct 16 |
nicklas |
191 |
{ |
4157 |
07 Oct 16 |
nicklas |
192 |
json = null; // No JSON output |
4157 |
07 Oct 16 |
nicklas |
193 |
|
4157 |
07 Oct 16 |
nicklas |
194 |
int workListId = Values.getInt(req.getParameter("workListId")); |
4166 |
21 Oct 16 |
nicklas |
195 |
boolean useExternalId = Values.getBoolean(req.getParameter("useExternalId")); |
5310 |
15 Feb 19 |
nicklas |
196 |
String format = Values.getString(req.getParameter("format"), "csv"); |
4146 |
03 Oct 16 |
nicklas |
197 |
|
6336 |
16 Jun 21 |
nicklas |
198 |
dc = sc.newDbControl(":Labels for outtake"); |
4157 |
07 Oct 16 |
nicklas |
199 |
|
4157 |
07 Oct 16 |
nicklas |
200 |
ItemList workList = ItemList.getById(dc, workListId); |
4157 |
07 Oct 16 |
nicklas |
201 |
|
6183 |
26 Mar 21 |
nicklas |
202 |
ItemQuery<Extract> memberQuery = workList.getMembers(); |
4157 |
07 Oct 16 |
nicklas |
203 |
memberQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT); |
4157 |
07 Oct 16 |
nicklas |
// Sort by bioplate position |
4157 |
07 Oct 16 |
nicklas |
205 |
memberQuery.join(Hql.leftJoin("bioWell", "bw")); |
4157 |
07 Oct 16 |
nicklas |
206 |
memberQuery.join(Hql.leftJoin("bw", "bioPlate", "bp", null, false)); |
4157 |
07 Oct 16 |
nicklas |
207 |
memberQuery.order(Orders.asc(Hql.property("bp", "name"))); |
4157 |
07 Oct 16 |
nicklas |
208 |
memberQuery.order(Orders.asc(Hql.property("bw", "row"))); |
4157 |
07 Oct 16 |
nicklas |
209 |
memberQuery.order(Orders.asc(Hql.property("bw", "column"))); |
5310 |
15 Feb 19 |
nicklas |
210 |
String filename = Reggie.makeSafeFileName(workList.getName())+"-labels"; |
5310 |
15 Feb 19 |
nicklas |
211 |
|
5310 |
15 Feb 19 |
nicklas |
212 |
TableWriter tw = null; |
5310 |
15 Feb 19 |
nicklas |
213 |
XlsxTableWriter xls = null; |
5310 |
15 Feb 19 |
nicklas |
214 |
if ("xlsx".equals(format)) |
5310 |
15 Feb 19 |
nicklas |
215 |
{ |
5310 |
15 Feb 19 |
nicklas |
216 |
resp.setHeader("Content-Disposition", "attachment; filename="+filename+".xlsx"); |
5371 |
16 Apr 19 |
nicklas |
217 |
resp.setContentType(XlsxToCsvUtil.XLSX_MIME_TYPE); |
5310 |
15 Feb 19 |
nicklas |
218 |
xls = new XlsxTableWriter("Labels"); |
5310 |
15 Feb 19 |
nicklas |
219 |
tw = xls; |
5310 |
15 Feb 19 |
nicklas |
220 |
} |
5310 |
15 Feb 19 |
nicklas |
221 |
else |
5310 |
15 Feb 19 |
nicklas |
222 |
{ |
5310 |
15 Feb 19 |
nicklas |
223 |
resp.setHeader("Content-Disposition", "attachment; filename="+filename+".csv"); |
5310 |
15 Feb 19 |
nicklas |
224 |
resp.setContentType("text/plain"); |
5310 |
15 Feb 19 |
nicklas |
225 |
resp.setCharacterEncoding("UTF-8"); |
5310 |
15 Feb 19 |
nicklas |
226 |
tw = new TableWriter(resp.getWriter()); |
5310 |
15 Feb 19 |
nicklas |
// The LABEL header is only required in the CSV format |
5310 |
15 Feb 19 |
nicklas |
228 |
tw.tablePrintData("LABEL"); |
5310 |
15 Feb 19 |
nicklas |
229 |
} |
4157 |
07 Oct 16 |
nicklas |
230 |
|
4157 |
07 Oct 16 |
nicklas |
231 |
|
4157 |
07 Oct 16 |
nicklas |
232 |
Iterator<Extract> it = memberQuery.iterate(dc); |
4157 |
07 Oct 16 |
nicklas |
233 |
while (it.hasNext()) |
4157 |
07 Oct 16 |
nicklas |
234 |
{ |
4157 |
07 Oct 16 |
nicklas |
235 |
Extract aliquot = it.next(); |
4166 |
21 Oct 16 |
nicklas |
236 |
String name = aliquot.getName(); |
4168 |
21 Oct 16 |
nicklas |
237 |
if (useExternalId && aliquot.getExternalId() != null) |
4166 |
21 Oct 16 |
nicklas |
238 |
{ |
4168 |
21 Oct 16 |
nicklas |
239 |
name = aliquot.getExternalId(); |
4166 |
21 Oct 16 |
nicklas |
240 |
} |
5310 |
15 Feb 19 |
nicklas |
241 |
tw.tablePrintData(name); |
4157 |
07 Oct 16 |
nicklas |
242 |
} |
4157 |
07 Oct 16 |
nicklas |
243 |
|
5310 |
15 Feb 19 |
nicklas |
244 |
if (xls != null) |
5310 |
15 Feb 19 |
nicklas |
245 |
{ |
5310 |
15 Feb 19 |
nicklas |
246 |
xls.getSheet().setColumnWidth(0, 18*256); |
5310 |
15 Feb 19 |
nicklas |
247 |
xls.saveTo(resp.getOutputStream()); |
5310 |
15 Feb 19 |
nicklas |
248 |
xls.close(); |
5310 |
15 Feb 19 |
nicklas |
249 |
} |
5310 |
15 Feb 19 |
nicklas |
250 |
tw.flush(); |
4157 |
07 Oct 16 |
nicklas |
251 |
|
4157 |
07 Oct 16 |
nicklas |
252 |
} |
4164 |
20 Oct 16 |
nicklas |
253 |
else if ("GetOuttakeInfo".equals(cmd)) |
4164 |
20 Oct 16 |
nicklas |
254 |
{ |
4164 |
20 Oct 16 |
nicklas |
255 |
int workListId = Values.getInt(req.getParameter("workListId")); |
4166 |
21 Oct 16 |
nicklas |
256 |
boolean useExternalId = Values.getBoolean(req.getParameter("useExternalId")); |
4157 |
07 Oct 16 |
nicklas |
257 |
|
6336 |
16 Jun 21 |
nicklas |
258 |
dc = sc.newDbControl(":Lab protocol for outtake"); |
4164 |
20 Oct 16 |
nicklas |
259 |
SnapshotManager manager = new SnapshotManager(); |
4164 |
20 Oct 16 |
nicklas |
260 |
|
4164 |
20 Oct 16 |
nicklas |
261 |
ItemList list = ItemList.getById(dc, workListId); |
4164 |
20 Oct 16 |
nicklas |
262 |
JSONObject jsonList = new JSONObject(); |
4164 |
20 Oct 16 |
nicklas |
263 |
jsonList.put("id", list.getId()); |
4164 |
20 Oct 16 |
nicklas |
264 |
jsonList.put("name", list.getName()); |
4164 |
20 Oct 16 |
nicklas |
265 |
jsonList.put("size", list.getSize()); |
4164 |
20 Oct 16 |
nicklas |
266 |
jsonList.put("comments", list.getDescription()); |
4165 |
21 Oct 16 |
nicklas |
267 |
|
4165 |
21 Oct 16 |
nicklas |
268 |
Float targetAmount = (Float)Annotationtype.OUTTAKE_TARGET_AMOUNT.getAnnotationValue(dc, manager, list); |
4165 |
21 Oct 16 |
nicklas |
269 |
Float targetVolume = (Float)Annotationtype.OUTTAKE_TARGET_VOLUME.getAnnotationValue(dc, manager, list); |
4165 |
21 Oct 16 |
nicklas |
270 |
|
4168 |
21 Oct 16 |
nicklas |
271 |
jsonList.put("TargetAmount", targetAmount); |
4168 |
21 Oct 16 |
nicklas |
272 |
jsonList.put("TargetVolume", targetVolume); |
6326 |
14 Jun 21 |
nicklas |
273 |
jsonList.put("parentType", Annotationtype.OUTTAKE_PARENT_TYPE.getAnnotationValue(dc, manager, list)); |
4164 |
20 Oct 16 |
nicklas |
274 |
|
6183 |
26 Mar 21 |
nicklas |
275 |
ItemQuery<Extract> memberQuery = list.getMembers(); |
4164 |
20 Oct 16 |
nicklas |
276 |
memberQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT); |
4164 |
20 Oct 16 |
nicklas |
// Sort by bioplate position |
4164 |
20 Oct 16 |
nicklas |
278 |
memberQuery.join(Hql.leftJoin("bioWell", "bw")); |
4164 |
20 Oct 16 |
nicklas |
279 |
memberQuery.join(Hql.leftJoin("bw", "bioPlate", "bp", null, false)); |
4164 |
20 Oct 16 |
nicklas |
280 |
memberQuery.order(Orders.asc(Hql.property("bp", "name"))); |
4164 |
20 Oct 16 |
nicklas |
281 |
memberQuery.order(Orders.asc(Hql.property("bw", "row"))); |
4164 |
20 Oct 16 |
nicklas |
282 |
memberQuery.order(Orders.asc(Hql.property("bw", "column"))); |
4164 |
20 Oct 16 |
nicklas |
283 |
|
4164 |
20 Oct 16 |
nicklas |
284 |
JSONArray jsonAliquots = new JSONArray(); |
4164 |
20 Oct 16 |
nicklas |
285 |
Iterator<Extract> it = memberQuery.iterate(dc); |
4164 |
20 Oct 16 |
nicklas |
286 |
while (it.hasNext()) |
4164 |
20 Oct 16 |
nicklas |
287 |
{ |
4164 |
20 Oct 16 |
nicklas |
288 |
Extract aliquot = it.next(); |
4164 |
20 Oct 16 |
nicklas |
289 |
Extract parent = (Extract)aliquot.getParent(); |
4164 |
20 Oct 16 |
nicklas |
290 |
|
4164 |
20 Oct 16 |
nicklas |
291 |
JSONObject jsonA = new JSONObject(); |
4164 |
20 Oct 16 |
nicklas |
292 |
jsonA.put("id", aliquot.getId()); |
4164 |
20 Oct 16 |
nicklas |
293 |
jsonA.put("name", aliquot.getName()); |
4166 |
21 Oct 16 |
nicklas |
294 |
if (useExternalId) |
4166 |
21 Oct 16 |
nicklas |
295 |
{ |
4168 |
21 Oct 16 |
nicklas |
296 |
jsonA.put("externalId", aliquot.getExternalId()); |
4166 |
21 Oct 16 |
nicklas |
297 |
} |
4168 |
21 Oct 16 |
nicklas |
298 |
jsonA.put("bioWell", JsonUtil.getBioWellAsJSON(aliquot.getBioWell(), true)); |
4168 |
21 Oct 16 |
nicklas |
299 |
|
4165 |
21 Oct 16 |
nicklas |
300 |
Float remain = parent.getRemainingQuantity(); |
6220 |
20 Apr 21 |
nicklas |
301 |
Float conc = (Float)Annotationtype.ND_CONC.getAnnotationValue(dc, parent); |
6220 |
20 Apr 21 |
nicklas |
302 |
if (conc == null) conc = (Float)Annotationtype.QUBIT_CONC.getAnnotationValue(dc, parent); |
4165 |
21 Oct 16 |
nicklas |
303 |
|
6326 |
14 Jun 21 |
nicklas |
304 |
if (targetAmount != null && targetVolume != null) |
4165 |
21 Oct 16 |
nicklas |
305 |
{ |
6326 |
14 Jun 21 |
nicklas |
// Aliquots should be normalized |
6326 |
14 Jun 21 |
nicklas |
307 |
if (remain != null && conc != null) |
6326 |
14 Jun 21 |
nicklas |
308 |
{ |
6326 |
14 Jun 21 |
nicklas |
309 |
Dilution d = new Dilution(targetAmount, targetVolume, conc, remain); |
6326 |
14 Jun 21 |
nicklas |
310 |
jsonA.put("dilution", d.asJSONObject()); |
6326 |
14 Jun 21 |
nicklas |
311 |
} |
4165 |
21 Oct 16 |
nicklas |
312 |
} |
6326 |
14 Jun 21 |
nicklas |
313 |
else if (targetVolume != null) |
6326 |
14 Jun 21 |
nicklas |
314 |
{ |
6326 |
14 Jun 21 |
nicklas |
315 |
if (remain != null) |
6326 |
14 Jun 21 |
nicklas |
316 |
{ |
6326 |
14 Jun 21 |
nicklas |
// A specific volume is needed (remaining quantity is expcted to be µl) |
6326 |
14 Jun 21 |
nicklas |
318 |
Dilution d = new Dilution(targetVolume, remain); |
6326 |
14 Jun 21 |
nicklas |
319 |
jsonA.put("dilution", d.asJSONObject()); |
6326 |
14 Jun 21 |
nicklas |
320 |
} |
6326 |
14 Jun 21 |
nicklas |
321 |
} |
4165 |
21 Oct 16 |
nicklas |
322 |
|
4164 |
20 Oct 16 |
nicklas |
323 |
JSONObject jsonP = new JSONObject(); |
4164 |
20 Oct 16 |
nicklas |
324 |
jsonP.put("id", parent.getId()); |
4164 |
20 Oct 16 |
nicklas |
325 |
jsonP.put("name", parent.getName()); |
6730 |
05 May 22 |
nicklas |
326 |
jsonP.put("label", Annotationtype.TUBE_LABEL.getAnnotationValue(dc, parent)); |
4164 |
20 Oct 16 |
nicklas |
327 |
jsonP.put("bioWell", JsonUtil.getBioWellAsJSON(parent.getBioWell(), true)); |
6220 |
20 Apr 21 |
nicklas |
328 |
jsonP.put("conc", conc); |
4166 |
21 Oct 16 |
nicklas |
329 |
jsonP.put("remainingQuantity", remain); |
4164 |
20 Oct 16 |
nicklas |
330 |
|
4164 |
20 Oct 16 |
nicklas |
331 |
jsonA.put("parent", jsonP); |
4164 |
20 Oct 16 |
nicklas |
332 |
jsonAliquots.add(jsonA); |
4164 |
20 Oct 16 |
nicklas |
333 |
} |
4164 |
20 Oct 16 |
nicklas |
334 |
|
4164 |
20 Oct 16 |
nicklas |
335 |
json.put("list", jsonList); |
4164 |
20 Oct 16 |
nicklas |
336 |
json.put("aliquots", jsonAliquots); |
4164 |
20 Oct 16 |
nicklas |
337 |
} |
4173 |
24 Oct 16 |
nicklas |
338 |
else if ("DownloadDeliveryFile".equals(cmd)) |
4173 |
24 Oct 16 |
nicklas |
339 |
{ |
4173 |
24 Oct 16 |
nicklas |
340 |
json = null; // No JSON output |
4173 |
24 Oct 16 |
nicklas |
341 |
|
4173 |
24 Oct 16 |
nicklas |
342 |
int workListId = Values.getInt(req.getParameter("workListId")); |
4173 |
24 Oct 16 |
nicklas |
343 |
boolean useExternalId = Values.getBoolean(req.getParameter("useExternalId")); |
4164 |
20 Oct 16 |
nicklas |
344 |
|
6336 |
16 Jun 21 |
nicklas |
345 |
dc = sc.newDbControl(":Export outtake delivery data"); |
4173 |
24 Oct 16 |
nicklas |
346 |
|
4173 |
24 Oct 16 |
nicklas |
347 |
ItemList workList = ItemList.getById(dc, workListId); |
6326 |
14 Jun 21 |
nicklas |
348 |
Float targetAmount = (Float)Annotationtype.OUTTAKE_TARGET_AMOUNT.getAnnotationValue(dc, workList); |
6326 |
14 Jun 21 |
nicklas |
349 |
Float targetVolume = (Float)Annotationtype.OUTTAKE_TARGET_VOLUME.getAnnotationValue(dc, workList); |
6326 |
14 Jun 21 |
nicklas |
350 |
|
6183 |
26 Mar 21 |
nicklas |
351 |
ItemQuery<Extract> memberQuery = workList.getMembers(); |
4173 |
24 Oct 16 |
nicklas |
352 |
memberQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT); |
4173 |
24 Oct 16 |
nicklas |
// Sort by bioplate position |
4173 |
24 Oct 16 |
nicklas |
354 |
memberQuery.join(Hql.leftJoin("bioWell", "bw")); |
4173 |
24 Oct 16 |
nicklas |
355 |
memberQuery.join(Hql.leftJoin("bw", "bioPlate", "bp", null, false)); |
4173 |
24 Oct 16 |
nicklas |
356 |
memberQuery.order(Orders.asc(Hql.property("bp", "name"))); |
4173 |
24 Oct 16 |
nicklas |
357 |
memberQuery.order(Orders.asc(Hql.property("bw", "row"))); |
4173 |
24 Oct 16 |
nicklas |
358 |
memberQuery.order(Orders.asc(Hql.property("bw", "column"))); |
4173 |
24 Oct 16 |
nicklas |
359 |
String filename = Reggie.makeSafeFileName(workList.getName()); |
4173 |
24 Oct 16 |
nicklas |
360 |
|
4173 |
24 Oct 16 |
nicklas |
361 |
resp.setHeader("Content-Disposition", "attachment; filename="+filename+".txt"); |
4173 |
24 Oct 16 |
nicklas |
362 |
resp.setContentType("text/plain"); |
4173 |
24 Oct 16 |
nicklas |
363 |
resp.setCharacterEncoding("UTF-8"); |
4173 |
24 Oct 16 |
nicklas |
364 |
|
4173 |
24 Oct 16 |
nicklas |
365 |
PrintWriter out = resp.getWriter(); |
4173 |
24 Oct 16 |
nicklas |
366 |
|
4173 |
24 Oct 16 |
nicklas |
367 |
TableWriter tw = new TableWriter(out); |
6326 |
14 Jun 21 |
nicklas |
368 |
Object[] data = null; |
6326 |
14 Jun 21 |
nicklas |
369 |
if (targetAmount != null && targetVolume != null) |
6326 |
14 Jun 21 |
nicklas |
370 |
{ |
6326 |
14 Jun 21 |
nicklas |
371 |
tw.tablePrintData("Name", "Box", "Position", "Quantity (µg)", "Concentration (ng/µl)"); |
6326 |
14 Jun 21 |
nicklas |
372 |
data = new Object[5]; |
6326 |
14 Jun 21 |
nicklas |
373 |
} |
6326 |
14 Jun 21 |
nicklas |
374 |
else |
6326 |
14 Jun 21 |
nicklas |
375 |
{ |
6326 |
14 Jun 21 |
nicklas |
376 |
tw.tablePrintData("Name", "Box", "Position", "Quantity (µl)"); |
6326 |
14 Jun 21 |
nicklas |
377 |
data = new Object[4]; |
6326 |
14 Jun 21 |
nicklas |
378 |
} |
4173 |
24 Oct 16 |
nicklas |
379 |
|
4173 |
24 Oct 16 |
nicklas |
380 |
Iterator<Extract> it = memberQuery.iterate(dc); |
4173 |
24 Oct 16 |
nicklas |
381 |
while (it.hasNext()) |
4173 |
24 Oct 16 |
nicklas |
382 |
{ |
4173 |
24 Oct 16 |
nicklas |
383 |
Extract aliquot = it.next(); |
4173 |
24 Oct 16 |
nicklas |
384 |
BioWell well = aliquot.getBioWell(); |
4173 |
24 Oct 16 |
nicklas |
385 |
String name = aliquot.getName(); |
4173 |
24 Oct 16 |
nicklas |
386 |
if (useExternalId && aliquot.getExternalId() != null) |
4173 |
24 Oct 16 |
nicklas |
387 |
{ |
4173 |
24 Oct 16 |
nicklas |
388 |
name = aliquot.getExternalId(); |
4173 |
24 Oct 16 |
nicklas |
389 |
} |
4173 |
24 Oct 16 |
nicklas |
390 |
data[0] = name; |
4173 |
24 Oct 16 |
nicklas |
391 |
data[1] = well.getPlate().getName(); |
4173 |
24 Oct 16 |
nicklas |
392 |
data[2] = well.getCoordinate(); |
4173 |
24 Oct 16 |
nicklas |
393 |
data[3] = Values.formatNumber(aliquot.getRemainingQuantity(), 1); |
6326 |
14 Jun 21 |
nicklas |
394 |
if (data.length > 4) |
6326 |
14 Jun 21 |
nicklas |
395 |
{ |
6326 |
14 Jun 21 |
nicklas |
396 |
data[4] = Values.formatNumber((Float)Annotationtype.DILUTION_CONC.getAnnotationValue(dc, aliquot), 1); |
6326 |
14 Jun 21 |
nicklas |
397 |
} |
4173 |
24 Oct 16 |
nicklas |
398 |
tw.tablePrintData(data); |
4173 |
24 Oct 16 |
nicklas |
399 |
} |
4173 |
24 Oct 16 |
nicklas |
400 |
|
4173 |
24 Oct 16 |
nicklas |
401 |
tw.flush(); |
4173 |
24 Oct 16 |
nicklas |
402 |
out.flush(); |
4173 |
24 Oct 16 |
nicklas |
403 |
out.close(); |
4173 |
24 Oct 16 |
nicklas |
404 |
} |
4173 |
24 Oct 16 |
nicklas |
405 |
|
4146 |
03 Oct 16 |
nicklas |
406 |
} |
4146 |
03 Oct 16 |
nicklas |
407 |
catch (Throwable t) |
4146 |
03 Oct 16 |
nicklas |
408 |
{ |
4146 |
03 Oct 16 |
nicklas |
409 |
t.printStackTrace(); |
4157 |
07 Oct 16 |
nicklas |
410 |
if (json != null) |
4157 |
07 Oct 16 |
nicklas |
411 |
{ |
4157 |
07 Oct 16 |
nicklas |
412 |
json.clear(); |
4157 |
07 Oct 16 |
nicklas |
413 |
json.put("status", "error"); |
4157 |
07 Oct 16 |
nicklas |
414 |
json.put("message", t.getMessage()); |
4157 |
07 Oct 16 |
nicklas |
415 |
json.put("stacktrace", ThrowableUtil.stackTraceToString(t)); |
4157 |
07 Oct 16 |
nicklas |
416 |
} |
4157 |
07 Oct 16 |
nicklas |
417 |
else |
4157 |
07 Oct 16 |
nicklas |
418 |
{ |
4157 |
07 Oct 16 |
nicklas |
419 |
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, t.getMessage()); |
4157 |
07 Oct 16 |
nicklas |
420 |
} |
4146 |
03 Oct 16 |
nicklas |
421 |
} |
4146 |
03 Oct 16 |
nicklas |
422 |
finally |
4146 |
03 Oct 16 |
nicklas |
423 |
{ |
4146 |
03 Oct 16 |
nicklas |
424 |
if (dc != null) dc.close(); |
5310 |
15 Feb 19 |
nicklas |
425 |
if (json != null) |
5310 |
15 Feb 19 |
nicklas |
426 |
{ |
5310 |
15 Feb 19 |
nicklas |
427 |
json.writeJSONString(resp.getWriter()); |
5310 |
15 Feb 19 |
nicklas |
428 |
} |
4146 |
03 Oct 16 |
nicklas |
429 |
} |
4146 |
03 Oct 16 |
nicklas |
430 |
} |
4146 |
03 Oct 16 |
nicklas |
431 |
|
4146 |
03 Oct 16 |
nicklas |
432 |
@SuppressWarnings("unchecked") |
4146 |
03 Oct 16 |
nicklas |
433 |
@Override |
4146 |
03 Oct 16 |
nicklas |
434 |
protected void doPost(HttpServletRequest req, HttpServletResponse resp) |
4146 |
03 Oct 16 |
nicklas |
435 |
throws ServletException, IOException |
4146 |
03 Oct 16 |
nicklas |
436 |
{ |
4146 |
03 Oct 16 |
nicklas |
437 |
String cmd = req.getParameter("cmd"); |
4146 |
03 Oct 16 |
nicklas |
438 |
JsonUtil.setJsonResponseHeaders(resp); |
4146 |
03 Oct 16 |
nicklas |
439 |
|
4146 |
03 Oct 16 |
nicklas |
440 |
JSONObject json = new JSONObject(); |
4146 |
03 Oct 16 |
nicklas |
441 |
JSONArray jsonMessages = new JSONArray(); |
4146 |
03 Oct 16 |
nicklas |
442 |
json.put("status", "ok"); |
4146 |
03 Oct 16 |
nicklas |
443 |
|
4146 |
03 Oct 16 |
nicklas |
444 |
final SessionControl sc = Reggie.getSessionControl(req); |
4146 |
03 Oct 16 |
nicklas |
445 |
DbControl dc = null; |
4146 |
03 Oct 16 |
nicklas |
446 |
|
4146 |
03 Oct 16 |
nicklas |
447 |
try |
4146 |
03 Oct 16 |
nicklas |
448 |
{ |
4146 |
03 Oct 16 |
nicklas |
449 |
if ("DefineOuttake".equals(cmd)) |
4146 |
03 Oct 16 |
nicklas |
450 |
{ |
6336 |
16 Jun 21 |
nicklas |
451 |
dc = sc.newDbControl(":Define outtake wizard"); |
4146 |
03 Oct 16 |
nicklas |
452 |
|
4146 |
03 Oct 16 |
nicklas |
453 |
ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.PREP_CURATOR, ReggieRole.ADMINISTRATOR); |
4146 |
03 Oct 16 |
nicklas |
454 |
|
4146 |
03 Oct 16 |
nicklas |
455 |
JSONObject jsonReq = JsonUtil.parseRequest(req); |
4154 |
06 Oct 16 |
nicklas |
456 |
|
4154 |
06 Oct 16 |
nicklas |
457 |
Number sourceListId = (Number)jsonReq.get("sourceList"); |
4154 |
06 Oct 16 |
nicklas |
458 |
ItemList sourceList = ItemList.getById(dc, sourceListId.intValue()); |
4154 |
06 Oct 16 |
nicklas |
459 |
String comments = (String)jsonReq.get("comments"); |
4154 |
06 Oct 16 |
nicklas |
460 |
|
6326 |
14 Jun 21 |
nicklas |
461 |
Number targetAmount = (Number)jsonReq.get("targetAmount"); |
6326 |
14 Jun 21 |
nicklas |
462 |
Number targetVolume = (Number)jsonReq.get("targetVolume"); |
6326 |
14 Jun 21 |
nicklas |
463 |
ItemSubtype outtakeType = Subtype.getByCName((String)jsonReq.get("outtakeType")).get(dc); |
4154 |
06 Oct 16 |
nicklas |
464 |
|
4154 |
06 Oct 16 |
nicklas |
465 |
ItemList aliquotList = ItemList.getNew(dc, sourceList.getMemberType()); |
4154 |
06 Oct 16 |
nicklas |
466 |
aliquotList.setName((String)jsonReq.get("outtakeName")); |
4154 |
06 Oct 16 |
nicklas |
467 |
aliquotList.setDescription(comments); |
4154 |
06 Oct 16 |
nicklas |
468 |
aliquotList.setExternalId(Reggie.OUTTAKE_ALIQUOTS_LIST_ID); |
4154 |
06 Oct 16 |
nicklas |
469 |
dc.saveItem(aliquotList); |
4154 |
06 Oct 16 |
nicklas |
470 |
|
6326 |
14 Jun 21 |
nicklas |
471 |
AnyToAny sourceLink = AnyToAny.getNew(dc, aliquotList, sourceList, "Source list", false); |
6326 |
14 Jun 21 |
nicklas |
472 |
sourceLink.setDescription("This is the source list that contain parent items for the aliquots in this list"); |
6326 |
14 Jun 21 |
nicklas |
473 |
dc.saveItem(sourceLink); |
6326 |
14 Jun 21 |
nicklas |
474 |
|
4154 |
06 Oct 16 |
nicklas |
475 |
Annotationtype.OUTTAKE_TARGET_AMOUNT.setAnnotationValue(dc, aliquotList, targetAmount); |
4154 |
06 Oct 16 |
nicklas |
476 |
Annotationtype.OUTTAKE_TARGET_VOLUME.setAnnotationValue(dc, aliquotList, targetVolume); |
6326 |
14 Jun 21 |
nicklas |
477 |
Annotationtype.OUTTAKE_PARENT_TYPE.setAnnotationValue(dc, aliquotList, outtakeType.getName()); |
4154 |
06 Oct 16 |
nicklas |
478 |
|
4893 |
09 Jul 18 |
nicklas |
// Query for finding existing child aliquots |
4154 |
06 Oct 16 |
nicklas |
480 |
ItemQuery<Extract> aliquotQuery = Extract.getQuery(); |
4154 |
06 Oct 16 |
nicklas |
481 |
aliquotQuery.join(Hql.innerJoin("creationEvent", Item.BIOMATERIALEVENT.getAlias())); |
4154 |
06 Oct 16 |
nicklas |
482 |
aliquotQuery.join(Hql.innerJoin(Item.BIOMATERIALEVENT.getAlias(), "sources", "src")); |
4154 |
06 Oct 16 |
nicklas |
483 |
aliquotQuery.restrict(Restrictions.eq(Hql.index("src", null), Hql.entityParameter("parent", Item.EXTRACT))); |
4154 |
06 Oct 16 |
nicklas |
484 |
aliquotQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.parameter("name"))); |
4154 |
06 Oct 16 |
nicklas |
485 |
|
4154 |
06 Oct 16 |
nicklas |
// Load items in the source list |
6183 |
26 Mar 21 |
nicklas |
487 |
ItemQuery<Extract> memberQuery = sourceList.getMembers(); |
4154 |
06 Oct 16 |
nicklas |
488 |
memberQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT); |
4154 |
06 Oct 16 |
nicklas |
// Sort by bioplate position |
4154 |
06 Oct 16 |
nicklas |
490 |
memberQuery.join(Hql.leftJoin("bioWell", "bw")); |
4154 |
06 Oct 16 |
nicklas |
491 |
memberQuery.join(Hql.leftJoin("bw", "bioPlate", "bp", null, false)); |
4154 |
06 Oct 16 |
nicklas |
492 |
memberQuery.order(Orders.asc(Hql.property("bp", "name"))); |
4154 |
06 Oct 16 |
nicklas |
493 |
memberQuery.order(Orders.asc(Hql.property("bw", "row"))); |
4154 |
06 Oct 16 |
nicklas |
494 |
memberQuery.order(Orders.asc(Hql.property("bw", "column"))); |
4154 |
06 Oct 16 |
nicklas |
495 |
|
4154 |
06 Oct 16 |
nicklas |
// Prepare storage boxes |
4154 |
06 Oct 16 |
nicklas |
497 |
PlateGeometry geometry = Geometry.NINE_BY_NINE.load(dc); |
4154 |
06 Oct 16 |
nicklas |
//PlateGeometry geometry = Geometry.THREE_BY_TWO.load(dc); |
4154 |
06 Oct 16 |
nicklas |
499 |
BioPlateType storageType = BioplateType.STORAGE_BOX.load(dc); |
4154 |
06 Oct 16 |
nicklas |
500 |
BioPlate aliquotBox = null; |
4154 |
06 Oct 16 |
nicklas |
501 |
int row = 0; |
4154 |
06 Oct 16 |
nicklas |
502 |
int column = 0; |
4154 |
06 Oct 16 |
nicklas |
503 |
|
4893 |
09 Jul 18 |
nicklas |
// Storage box name parameters for outtakes |
4154 |
06 Oct 16 |
nicklas |
505 |
String boxPrefix = "ScanB-Outtake"; |
4893 |
09 Jul 18 |
nicklas |
506 |
int numDigitsInBoxName = 3; |
4154 |
06 Oct 16 |
nicklas |
507 |
|
4154 |
06 Oct 16 |
nicklas |
508 |
Iterator<Extract> it = memberQuery.iterate(dc); |
4154 |
06 Oct 16 |
nicklas |
509 |
while (it.hasNext()) |
4154 |
06 Oct 16 |
nicklas |
510 |
{ |
4154 |
06 Oct 16 |
nicklas |
511 |
Extract parent = it.next(); |
4154 |
06 Oct 16 |
nicklas |
512 |
Extract aliquot = Extract.getNew(dc); |
4154 |
06 Oct 16 |
nicklas |
513 |
|
4893 |
09 Jul 18 |
nicklas |
// Check existing aliquots and generate new name for this aliquot |
4154 |
06 Oct 16 |
nicklas |
515 |
aliquotQuery.setEntityParameter("parent", parent); |
4893 |
09 Jul 18 |
nicklas |
516 |
aliquotQuery.setParameter("name", parent.getName()+".a%", Type.STRING); |
4893 |
09 Jul 18 |
nicklas |
517 |
String aliquotName = ReggieItem.getNextChildItemName(dc, parent.getName(), aliquotQuery, "a", true); |
4893 |
09 Jul 18 |
nicklas |
518 |
aliquot.setName(aliquotName); |
4154 |
06 Oct 16 |
nicklas |
519 |
aliquot.setDescription(comments); |
4146 |
03 Oct 16 |
nicklas |
520 |
|
4154 |
06 Oct 16 |
nicklas |
// Link to parent item |
4154 |
06 Oct 16 |
nicklas |
522 |
BioMaterialEvent creationEvent = aliquot.getCreationEvent(); |
4154 |
06 Oct 16 |
nicklas |
523 |
creationEvent.setSource(parent); |
4154 |
06 Oct 16 |
nicklas |
524 |
|
4168 |
21 Oct 16 |
nicklas |
// Find parent item (=Specimen) with External ID and copy it to the aliquot |
4168 |
21 Oct 16 |
nicklas |
526 |
BioMaterial specimen = findParentWithExternalId(parent); |
4168 |
21 Oct 16 |
nicklas |
527 |
if (specimen != null) |
4168 |
21 Oct 16 |
nicklas |
528 |
{ |
4168 |
21 Oct 16 |
nicklas |
529 |
aliquot.setExternalId(aliquot.getName().replace(specimen.getName(), specimen.getExternalId())); |
4168 |
21 Oct 16 |
nicklas |
530 |
} |
4168 |
21 Oct 16 |
nicklas |
531 |
|
4154 |
06 Oct 16 |
nicklas |
// Place in storage box |
4154 |
06 Oct 16 |
nicklas |
533 |
if (aliquotBox == null) |
4154 |
06 Oct 16 |
nicklas |
534 |
{ |
4893 |
09 Jul 18 |
nicklas |
535 |
ItemQuery<BioPlate> boxQuery = BioPlate.getQuery(); |
4893 |
09 Jul 18 |
nicklas |
536 |
boxQuery.include(Include.ALL); |
4893 |
09 Jul 18 |
nicklas |
537 |
String boxName = ReggieItem.getNextItemName(dc, boxQuery, boxPrefix, numDigitsInBoxName, true); |
4154 |
06 Oct 16 |
nicklas |
538 |
aliquotBox = BioPlate.getNew(dc, geometry, storageType); |
4893 |
09 Jul 18 |
nicklas |
539 |
aliquotBox.setName(boxName); |
4154 |
06 Oct 16 |
nicklas |
540 |
aliquotBox.setDescription(comments); |
4154 |
06 Oct 16 |
nicklas |
541 |
dc.saveItem(aliquotBox); |
4154 |
06 Oct 16 |
nicklas |
542 |
} |
4154 |
06 Oct 16 |
nicklas |
543 |
aliquot.setBioWell(aliquotBox.getBioWell(row, column)); |
4154 |
06 Oct 16 |
nicklas |
//jsonMessages.add("Created: " + aliquot.getName() + "; " +aliquotBox + aliquot.getBioWell().getCoordinate()); |
4154 |
06 Oct 16 |
nicklas |
545 |
|
4154 |
06 Oct 16 |
nicklas |
// Move to the next position/box |
4154 |
06 Oct 16 |
nicklas |
547 |
column++; |
4154 |
06 Oct 16 |
nicklas |
548 |
if (column >= geometry.getColumns()) |
4154 |
06 Oct 16 |
nicklas |
549 |
{ |
4154 |
06 Oct 16 |
nicklas |
550 |
row++; |
4154 |
06 Oct 16 |
nicklas |
551 |
column = 0; |
4154 |
06 Oct 16 |
nicklas |
552 |
if (row >= geometry.getRows()) |
4154 |
06 Oct 16 |
nicklas |
553 |
{ |
4154 |
06 Oct 16 |
nicklas |
554 |
row = 0; |
4154 |
06 Oct 16 |
nicklas |
555 |
aliquotBox = null; |
4154 |
06 Oct 16 |
nicklas |
556 |
} |
4154 |
06 Oct 16 |
nicklas |
557 |
} |
4154 |
06 Oct 16 |
nicklas |
558 |
|
4154 |
06 Oct 16 |
nicklas |
559 |
dc.saveItem(aliquot); |
4154 |
06 Oct 16 |
nicklas |
560 |
aliquotList.add(aliquot); |
4154 |
06 Oct 16 |
nicklas |
561 |
} |
4154 |
06 Oct 16 |
nicklas |
562 |
|
4154 |
06 Oct 16 |
nicklas |
// Protect the list from changes |
4154 |
06 Oct 16 |
nicklas |
564 |
aliquotList.setDisableManualMembers(true); |
4154 |
06 Oct 16 |
nicklas |
565 |
aliquotList.setDisableSyncFilters(true); |
4154 |
06 Oct 16 |
nicklas |
566 |
|
4146 |
03 Oct 16 |
nicklas |
567 |
dc.commit(); |
4154 |
06 Oct 16 |
nicklas |
568 |
jsonMessages.add("Created " + aliquotList.getSize() + " outtake aliquots in list: " + aliquotList.getName()); |
4154 |
06 Oct 16 |
nicklas |
569 |
} |
4165 |
21 Oct 16 |
nicklas |
570 |
else if ("RegisterOuttakeComplete".equals(cmd)) |
4165 |
21 Oct 16 |
nicklas |
571 |
{ |
6336 |
16 Jun 21 |
nicklas |
572 |
dc = sc.newDbControl(":Register outtake"); |
4165 |
21 Oct 16 |
nicklas |
573 |
|
4173 |
24 Oct 16 |
nicklas |
574 |
ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.SAMPLE_PREP, ReggieRole.ADMINISTRATOR); |
4165 |
21 Oct 16 |
nicklas |
575 |
|
4165 |
21 Oct 16 |
nicklas |
576 |
JSONObject jsonReq = JsonUtil.parseRequest(req); |
4165 |
21 Oct 16 |
nicklas |
577 |
|
4165 |
21 Oct 16 |
nicklas |
578 |
Number workListId = (Number)jsonReq.get("workList"); |
4165 |
21 Oct 16 |
nicklas |
579 |
String comments = (String)jsonReq.get("comments"); |
4165 |
21 Oct 16 |
nicklas |
580 |
Date completedDate = Reggie.CONVERTER_STRING_TO_DATE.convert((String)jsonReq.get("completedDate")); |
4179 |
27 Oct 16 |
nicklas |
581 |
boolean failed = Boolean.TRUE.equals(jsonReq.get("failed")); |
4165 |
21 Oct 16 |
nicklas |
582 |
|
4165 |
21 Oct 16 |
nicklas |
583 |
ItemList workList = ItemList.getById(dc, workListId.intValue()); |
4165 |
21 Oct 16 |
nicklas |
584 |
workList.setDescription(comments); |
4165 |
21 Oct 16 |
nicklas |
585 |
Annotationtype.OUTTAKE_COMPLETED_DATE.setAnnotationValue(dc, workList, completedDate); |
4179 |
27 Oct 16 |
nicklas |
586 |
Annotationtype.OUTTAKE_RESULT.setAnnotationValue(dc, workList, failed ? "Failed" : "Successful"); |
4165 |
21 Oct 16 |
nicklas |
587 |
|
4179 |
27 Oct 16 |
nicklas |
588 |
boolean sampleConsumed = failed ? Boolean.TRUE.equals(jsonReq.get("sampleConsumed")) : true; |
4179 |
27 Oct 16 |
nicklas |
589 |
JSONArray jsonExcept = (JSONArray)jsonReq.get("except"); |
4179 |
27 Oct 16 |
nicklas |
590 |
Set<Integer> except = new HashSet<>(); |
4179 |
27 Oct 16 |
nicklas |
591 |
if (jsonExcept != null) |
4179 |
27 Oct 16 |
nicklas |
592 |
{ |
4179 |
27 Oct 16 |
nicklas |
593 |
for (Object o : jsonExcept) |
4179 |
27 Oct 16 |
nicklas |
594 |
{ |
4179 |
27 Oct 16 |
nicklas |
595 |
except.add(((Number)o).intValue()); |
4179 |
27 Oct 16 |
nicklas |
596 |
} |
4179 |
27 Oct 16 |
nicklas |
597 |
} |
4165 |
21 Oct 16 |
nicklas |
598 |
|
6183 |
26 Mar 21 |
nicklas |
599 |
ItemQuery<Extract> memberQuery = workList.getMembers(); |
4165 |
21 Oct 16 |
nicklas |
600 |
memberQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT); |
4165 |
21 Oct 16 |
nicklas |
// Sort by bioplate position |
4165 |
21 Oct 16 |
nicklas |
602 |
memberQuery.join(Hql.leftJoin("bioWell", "bw")); |
4165 |
21 Oct 16 |
nicklas |
603 |
memberQuery.join(Hql.leftJoin("bw", "bioPlate", "bp", null, false)); |
4165 |
21 Oct 16 |
nicklas |
604 |
memberQuery.order(Orders.asc(Hql.property("bp", "name"))); |
4165 |
21 Oct 16 |
nicklas |
605 |
memberQuery.order(Orders.asc(Hql.property("bw", "row"))); |
4165 |
21 Oct 16 |
nicklas |
606 |
memberQuery.order(Orders.asc(Hql.property("bw", "column"))); |
4165 |
21 Oct 16 |
nicklas |
607 |
|
4165 |
21 Oct 16 |
nicklas |
608 |
Float targetAmount = (Float)Annotationtype.OUTTAKE_TARGET_AMOUNT.getAnnotationValue(dc, workList); |
4165 |
21 Oct 16 |
nicklas |
609 |
Float targetVolume = (Float)Annotationtype.OUTTAKE_TARGET_VOLUME.getAnnotationValue(dc, workList); |
4165 |
21 Oct 16 |
nicklas |
610 |
|
4165 |
21 Oct 16 |
nicklas |
611 |
JSONArray jsonAliquots = new JSONArray(); |
4165 |
21 Oct 16 |
nicklas |
612 |
Iterator<Extract> it = memberQuery.iterate(dc); |
4179 |
27 Oct 16 |
nicklas |
613 |
int numExceptions = 0; |
4165 |
21 Oct 16 |
nicklas |
614 |
while (it.hasNext()) |
4165 |
21 Oct 16 |
nicklas |
615 |
{ |
4165 |
21 Oct 16 |
nicklas |
616 |
Extract aliquot = it.next(); |
4165 |
21 Oct 16 |
nicklas |
617 |
Extract parent = (Extract)aliquot.getParent(); |
4165 |
21 Oct 16 |
nicklas |
618 |
BioMaterialEvent creationEvent = aliquot.getCreationEvent(); |
4165 |
21 Oct 16 |
nicklas |
619 |
creationEvent.setEventDate(completedDate); |
4165 |
21 Oct 16 |
nicklas |
620 |
|
4165 |
21 Oct 16 |
nicklas |
621 |
Float remain = parent.getRemainingQuantity(); |
6220 |
20 Apr 21 |
nicklas |
622 |
Float conc = (Float)Annotationtype.ND_CONC.getAnnotationValue(dc, parent); |
6220 |
20 Apr 21 |
nicklas |
623 |
if (conc == null) conc = (Float)Annotationtype.QUBIT_CONC.getAnnotationValue(dc, parent); |
4165 |
21 Oct 16 |
nicklas |
624 |
|
6326 |
14 Jun 21 |
nicklas |
625 |
if (targetAmount != null && targetVolume != null) |
4165 |
21 Oct 16 |
nicklas |
626 |
{ |
6326 |
14 Jun 21 |
nicklas |
627 |
if (remain != null && conc != null) |
4179 |
27 Oct 16 |
nicklas |
628 |
{ |
6326 |
14 Jun 21 |
nicklas |
629 |
boolean isException = except.contains(aliquot.getId()); |
6326 |
14 Jun 21 |
nicklas |
630 |
if (isException) numExceptions++; |
6326 |
14 Jun 21 |
nicklas |
631 |
|
6326 |
14 Jun 21 |
nicklas |
632 |
if (sampleConsumed != isException) |
6326 |
14 Jun 21 |
nicklas |
633 |
{ |
6326 |
14 Jun 21 |
nicklas |
634 |
Dilution d = new Dilution(targetAmount, targetVolume, conc, remain); |
6326 |
14 Jun 21 |
nicklas |
635 |
creationEvent.getEventSource(parent).setUsedQuantity(d.amount); |
6326 |
14 Jun 21 |
nicklas |
636 |
aliquot.setOriginalQuantity(d.amount); |
6326 |
14 Jun 21 |
nicklas |
637 |
Annotationtype.DILUTION_CONC.setAnnotationValue(dc, aliquot, d.getDilutedConc()); |
6326 |
14 Jun 21 |
nicklas |
//jsonMessages.add(aliquot.getId() + ":" + aliquot.getName() + ": " + ndConc + "--" + d.getDilutedConc() + ":"+isException); |
6326 |
14 Jun 21 |
nicklas |
639 |
} |
6326 |
14 Jun 21 |
nicklas |
640 |
else |
6326 |
14 Jun 21 |
nicklas |
641 |
{ |
6326 |
14 Jun 21 |
nicklas |
// jsonMessages.add(aliquot.getId() + ":" + aliquot.getName() + " not consumed: " + isException); |
6326 |
14 Jun 21 |
nicklas |
643 |
} |
4179 |
27 Oct 16 |
nicklas |
644 |
} |
6326 |
14 Jun 21 |
nicklas |
645 |
} |
6326 |
14 Jun 21 |
nicklas |
646 |
else if (targetVolume != null) |
6326 |
14 Jun 21 |
nicklas |
647 |
{ |
6326 |
14 Jun 21 |
nicklas |
648 |
if (remain != null) |
4179 |
27 Oct 16 |
nicklas |
649 |
{ |
6326 |
14 Jun 21 |
nicklas |
650 |
boolean isException = except.contains(aliquot.getId()); |
6326 |
14 Jun 21 |
nicklas |
651 |
if (isException) numExceptions++; |
6326 |
14 Jun 21 |
nicklas |
652 |
if (sampleConsumed != isException) |
6326 |
14 Jun 21 |
nicklas |
653 |
{ |
6326 |
14 Jun 21 |
nicklas |
654 |
Dilution d = new Dilution(targetVolume, remain); |
6326 |
14 Jun 21 |
nicklas |
655 |
creationEvent.getEventSource(parent).setUsedQuantity(d.volume); |
6326 |
14 Jun 21 |
nicklas |
656 |
aliquot.setOriginalQuantity(d.volume); |
6326 |
14 Jun 21 |
nicklas |
//jsonMessages.add(aliquot.getId() + ":" + aliquot.getName() + ": " + d.volume + ":"+isException); |
6326 |
14 Jun 21 |
nicklas |
658 |
} |
6326 |
14 Jun 21 |
nicklas |
659 |
else |
6326 |
14 Jun 21 |
nicklas |
660 |
{ |
6326 |
14 Jun 21 |
nicklas |
//jsonMessages.add(aliquot.getId() + ":" + aliquot.getName() + " not consumed: " + isException); |
6326 |
14 Jun 21 |
nicklas |
662 |
} |
4179 |
27 Oct 16 |
nicklas |
663 |
} |
4165 |
21 Oct 16 |
nicklas |
664 |
} |
4165 |
21 Oct 16 |
nicklas |
665 |
} |
4165 |
21 Oct 16 |
nicklas |
666 |
|
4179 |
27 Oct 16 |
nicklas |
667 |
if (failed) |
4179 |
27 Oct 16 |
nicklas |
668 |
{ |
4179 |
27 Oct 16 |
nicklas |
669 |
jsonMessages.add(workList.getName() + " registered as failed"); |
4179 |
27 Oct 16 |
nicklas |
670 |
String msg = sampleConsumed ? "All samples consumed" : "No samples consumed"; |
4179 |
27 Oct 16 |
nicklas |
671 |
if (numExceptions > 0) |
4179 |
27 Oct 16 |
nicklas |
672 |
{ |
4179 |
27 Oct 16 |
nicklas |
673 |
msg += " except " + numExceptions; |
4179 |
27 Oct 16 |
nicklas |
674 |
} |
4179 |
27 Oct 16 |
nicklas |
675 |
jsonMessages.add(msg); |
4179 |
27 Oct 16 |
nicklas |
676 |
} |
4179 |
27 Oct 16 |
nicklas |
677 |
else |
4179 |
27 Oct 16 |
nicklas |
678 |
{ |
4179 |
27 Oct 16 |
nicklas |
679 |
jsonMessages.add(workList.getName() + " registered as completed"); |
4179 |
27 Oct 16 |
nicklas |
680 |
} |
4165 |
21 Oct 16 |
nicklas |
681 |
dc.commit(); |
4165 |
21 Oct 16 |
nicklas |
682 |
} |
4173 |
24 Oct 16 |
nicklas |
683 |
else if ("RegisterOuttakeDelivered".equals(cmd)) |
4173 |
24 Oct 16 |
nicklas |
684 |
{ |
6336 |
16 Jun 21 |
nicklas |
685 |
dc = sc.newDbControl(":Export outtake delivery data"); |
4173 |
24 Oct 16 |
nicklas |
686 |
|
4173 |
24 Oct 16 |
nicklas |
687 |
ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.PREP_CURATOR, ReggieRole.ADMINISTRATOR); |
4173 |
24 Oct 16 |
nicklas |
688 |
|
4173 |
24 Oct 16 |
nicklas |
689 |
JSONObject jsonReq = JsonUtil.parseRequest(req); |
4173 |
24 Oct 16 |
nicklas |
690 |
|
4173 |
24 Oct 16 |
nicklas |
691 |
Number workListId = (Number)jsonReq.get("workList"); |
4173 |
24 Oct 16 |
nicklas |
692 |
String comments = (String)jsonReq.get("comments"); |
4173 |
24 Oct 16 |
nicklas |
693 |
Date deliveredDate = Reggie.CONVERTER_STRING_TO_DATE.convert((String)jsonReq.get("deliveredDate")); |
4173 |
24 Oct 16 |
nicklas |
694 |
|
4173 |
24 Oct 16 |
nicklas |
695 |
ItemList workList = ItemList.getById(dc, workListId.intValue()); |
4173 |
24 Oct 16 |
nicklas |
696 |
workList.setDescription(comments); |
4173 |
24 Oct 16 |
nicklas |
697 |
Annotationtype.OUTTAKE_DELIVERED_DATE.setAnnotationValue(dc, workList, deliveredDate); |
4173 |
24 Oct 16 |
nicklas |
698 |
|
4173 |
24 Oct 16 |
nicklas |
699 |
jsonMessages.add(workList.getName() + " registered as delivered"); |
4173 |
24 Oct 16 |
nicklas |
700 |
dc.commit(); |
4173 |
24 Oct 16 |
nicklas |
701 |
} |
4146 |
03 Oct 16 |
nicklas |
702 |
json.put("messages", jsonMessages); |
4146 |
03 Oct 16 |
nicklas |
703 |
CounterService.getInstance().setForceCount(); |
4146 |
03 Oct 16 |
nicklas |
704 |
} |
4146 |
03 Oct 16 |
nicklas |
705 |
catch (Throwable t) |
4146 |
03 Oct 16 |
nicklas |
706 |
{ |
4146 |
03 Oct 16 |
nicklas |
707 |
t.printStackTrace(); |
4146 |
03 Oct 16 |
nicklas |
708 |
json.clear(); |
4146 |
03 Oct 16 |
nicklas |
709 |
json.put("status", "error"); |
4146 |
03 Oct 16 |
nicklas |
710 |
json.put("message", t.getMessage()); |
4146 |
03 Oct 16 |
nicklas |
711 |
json.put("stacktrace", ThrowableUtil.stackTraceToString(t)); |
4146 |
03 Oct 16 |
nicklas |
712 |
} |
4146 |
03 Oct 16 |
nicklas |
713 |
finally |
4146 |
03 Oct 16 |
nicklas |
714 |
{ |
4146 |
03 Oct 16 |
nicklas |
715 |
if (dc != null) dc.close(); |
4146 |
03 Oct 16 |
nicklas |
716 |
json.writeJSONString(resp.getWriter()); |
4146 |
03 Oct 16 |
nicklas |
717 |
} |
4146 |
03 Oct 16 |
nicklas |
718 |
} |
4146 |
03 Oct 16 |
nicklas |
719 |
|
4166 |
21 Oct 16 |
nicklas |
720 |
|
4166 |
21 Oct 16 |
nicklas |
721 |
private BioMaterial findParentWithExternalId(MeasuredBioMaterial item) |
4166 |
21 Oct 16 |
nicklas |
722 |
{ |
4166 |
21 Oct 16 |
nicklas |
723 |
BioMaterial parent = item; |
4166 |
21 Oct 16 |
nicklas |
724 |
while (parent != null && parent.getExternalId() == null) |
4166 |
21 Oct 16 |
nicklas |
725 |
{ |
4166 |
21 Oct 16 |
nicklas |
726 |
parent = item.getParent(); |
4166 |
21 Oct 16 |
nicklas |
727 |
if (parent instanceof MeasuredBioMaterial) |
4166 |
21 Oct 16 |
nicklas |
728 |
{ |
4166 |
21 Oct 16 |
nicklas |
729 |
item = (MeasuredBioMaterial)parent; |
4166 |
21 Oct 16 |
nicklas |
730 |
} |
4166 |
21 Oct 16 |
nicklas |
731 |
else |
4166 |
21 Oct 16 |
nicklas |
732 |
{ |
4166 |
21 Oct 16 |
nicklas |
733 |
item = null; |
4166 |
21 Oct 16 |
nicklas |
734 |
} |
4166 |
21 Oct 16 |
nicklas |
735 |
} |
4166 |
21 Oct 16 |
nicklas |
736 |
|
4166 |
21 Oct 16 |
nicklas |
737 |
return parent; |
4166 |
21 Oct 16 |
nicklas |
738 |
} |
4166 |
21 Oct 16 |
nicklas |
739 |
|
4153 |
05 Oct 16 |
nicklas |
740 |
/** |
4153 |
05 Oct 16 |
nicklas |
Helper class for keeping track of min and max of a collection of values. |
4153 |
05 Oct 16 |
nicklas |
Also keep counters for total number of values and null values. |
4153 |
05 Oct 16 |
nicklas |
743 |
*/ |
4153 |
05 Oct 16 |
nicklas |
744 |
static class MinMax |
4153 |
05 Oct 16 |
nicklas |
745 |
{ |
4153 |
05 Oct 16 |
nicklas |
746 |
private Float min; |
4153 |
05 Oct 16 |
nicklas |
747 |
private Float max; |
4153 |
05 Oct 16 |
nicklas |
748 |
private int nulls; |
4153 |
05 Oct 16 |
nicklas |
749 |
private int values; |
4153 |
05 Oct 16 |
nicklas |
750 |
|
4153 |
05 Oct 16 |
nicklas |
751 |
MinMax() |
4153 |
05 Oct 16 |
nicklas |
752 |
{} |
4153 |
05 Oct 16 |
nicklas |
753 |
|
4153 |
05 Oct 16 |
nicklas |
754 |
/** |
4153 |
05 Oct 16 |
nicklas |
Add a value. |
4153 |
05 Oct 16 |
nicklas |
756 |
*/ |
4153 |
05 Oct 16 |
nicklas |
757 |
void add(Float value) |
4153 |
05 Oct 16 |
nicklas |
758 |
{ |
4153 |
05 Oct 16 |
nicklas |
759 |
values++; |
4153 |
05 Oct 16 |
nicklas |
760 |
if (value == null) |
4153 |
05 Oct 16 |
nicklas |
761 |
{ |
4153 |
05 Oct 16 |
nicklas |
762 |
nulls++; |
4153 |
05 Oct 16 |
nicklas |
763 |
return; |
4153 |
05 Oct 16 |
nicklas |
764 |
} |
4153 |
05 Oct 16 |
nicklas |
765 |
if (min == null || value < min) min = value; |
4153 |
05 Oct 16 |
nicklas |
766 |
if (max == null || value > max) max = value; |
4153 |
05 Oct 16 |
nicklas |
767 |
} |
4153 |
05 Oct 16 |
nicklas |
768 |
|
4153 |
05 Oct 16 |
nicklas |
769 |
/** |
4153 |
05 Oct 16 |
nicklas |
The min value. |
4153 |
05 Oct 16 |
nicklas |
771 |
*/ |
4153 |
05 Oct 16 |
nicklas |
772 |
Float getMin() |
4153 |
05 Oct 16 |
nicklas |
773 |
{ |
4153 |
05 Oct 16 |
nicklas |
774 |
return min; |
4153 |
05 Oct 16 |
nicklas |
775 |
} |
4153 |
05 Oct 16 |
nicklas |
776 |
|
4153 |
05 Oct 16 |
nicklas |
777 |
/** |
4153 |
05 Oct 16 |
nicklas |
The max value. |
4153 |
05 Oct 16 |
nicklas |
779 |
*/ |
4153 |
05 Oct 16 |
nicklas |
780 |
Float getMax() |
4153 |
05 Oct 16 |
nicklas |
781 |
{ |
4153 |
05 Oct 16 |
nicklas |
782 |
return max; |
4153 |
05 Oct 16 |
nicklas |
783 |
} |
4153 |
05 Oct 16 |
nicklas |
784 |
|
4153 |
05 Oct 16 |
nicklas |
785 |
/** |
4153 |
05 Oct 16 |
nicklas |
Total number of values. |
4153 |
05 Oct 16 |
nicklas |
787 |
*/ |
4153 |
05 Oct 16 |
nicklas |
788 |
int getValues() |
4153 |
05 Oct 16 |
nicklas |
789 |
{ |
4153 |
05 Oct 16 |
nicklas |
790 |
return values; |
4153 |
05 Oct 16 |
nicklas |
791 |
} |
4153 |
05 Oct 16 |
nicklas |
792 |
|
4153 |
05 Oct 16 |
nicklas |
793 |
/** |
4153 |
05 Oct 16 |
nicklas |
Number of null values. |
4153 |
05 Oct 16 |
nicklas |
795 |
*/ |
4153 |
05 Oct 16 |
nicklas |
796 |
int getNulls() |
4153 |
05 Oct 16 |
nicklas |
797 |
{ |
4153 |
05 Oct 16 |
nicklas |
798 |
return nulls; |
4153 |
05 Oct 16 |
nicklas |
799 |
} |
4153 |
05 Oct 16 |
nicklas |
800 |
|
4153 |
05 Oct 16 |
nicklas |
801 |
JSONObject asJSONObject() |
4153 |
05 Oct 16 |
nicklas |
802 |
{ |
4153 |
05 Oct 16 |
nicklas |
803 |
JSONObject json = new JSONObject(); |
4153 |
05 Oct 16 |
nicklas |
804 |
json.put("min", min); |
4153 |
05 Oct 16 |
nicklas |
805 |
json.put("max", max); |
4153 |
05 Oct 16 |
nicklas |
806 |
json.put("values", values); |
4153 |
05 Oct 16 |
nicklas |
807 |
json.put("nulls", nulls); |
4153 |
05 Oct 16 |
nicklas |
808 |
return json; |
4153 |
05 Oct 16 |
nicklas |
809 |
} |
4153 |
05 Oct 16 |
nicklas |
810 |
|
4153 |
05 Oct 16 |
nicklas |
811 |
} |
4165 |
21 Oct 16 |
nicklas |
812 |
|
4165 |
21 Oct 16 |
nicklas |
813 |
/** |
4165 |
21 Oct 16 |
nicklas |
Calculates dilution information for an extract with known |
4165 |
21 Oct 16 |
nicklas |
remaining quantity and concentration given a target amount and |
4165 |
21 Oct 16 |
nicklas |
volume. |
4165 |
21 Oct 16 |
nicklas |
817 |
*/ |
4165 |
21 Oct 16 |
nicklas |
818 |
static class Dilution |
4165 |
21 Oct 16 |
nicklas |
819 |
{ |
4165 |
21 Oct 16 |
nicklas |
820 |
|
4165 |
21 Oct 16 |
nicklas |
821 |
final float remainingQuantity; |
4165 |
21 Oct 16 |
nicklas |
822 |
final float conc; |
4165 |
21 Oct 16 |
nicklas |
823 |
|
4165 |
21 Oct 16 |
nicklas |
// Results |
4165 |
21 Oct 16 |
nicklas |
825 |
float amount; |
4165 |
21 Oct 16 |
nicklas |
826 |
float volume; |
4165 |
21 Oct 16 |
nicklas |
827 |
float water; |
4165 |
21 Oct 16 |
nicklas |
828 |
float dilutedConc; |
4165 |
21 Oct 16 |
nicklas |
829 |
|
4165 |
21 Oct 16 |
nicklas |
830 |
/** |
6326 |
14 Jun 21 |
nicklas |
Use a fixed target volume. If remaining quantity is lower |
6326 |
14 Jun 21 |
nicklas |
we can't take more of course. |
6326 |
14 Jun 21 |
nicklas |
@since 4.31.3 |
6326 |
14 Jun 21 |
nicklas |
834 |
*/ |
6326 |
14 Jun 21 |
nicklas |
835 |
Dilution(float targetVolume, float remainingQuantity) |
6326 |
14 Jun 21 |
nicklas |
836 |
{ |
6326 |
14 Jun 21 |
nicklas |
837 |
this.remainingQuantity = remainingQuantity; |
6326 |
14 Jun 21 |
nicklas |
838 |
this.conc = Float.NaN; |
6326 |
14 Jun 21 |
nicklas |
839 |
|
6326 |
14 Jun 21 |
nicklas |
840 |
this.volume = Math.min(targetVolume, remainingQuantity); |
6326 |
14 Jun 21 |
nicklas |
841 |
this.water = Float.NaN; |
6326 |
14 Jun 21 |
nicklas |
842 |
this.amount = Float.NaN; |
6326 |
14 Jun 21 |
nicklas |
843 |
} |
6326 |
14 Jun 21 |
nicklas |
844 |
|
6326 |
14 Jun 21 |
nicklas |
845 |
/** |
4165 |
21 Oct 16 |
nicklas |
Create a new dilution calculation. |
4165 |
21 Oct 16 |
nicklas |
@param targetAmount The target amount (µg) |
4165 |
21 Oct 16 |
nicklas |
@param targetVolume The target volume (µl) |
4165 |
21 Oct 16 |
nicklas |
@param conc The concentration of the extract (ng/µl) |
4165 |
21 Oct 16 |
nicklas |
@param remainingQuantity The remaining quantity of the extract (µg) |
4165 |
21 Oct 16 |
nicklas |
851 |
*/ |
4165 |
21 Oct 16 |
nicklas |
852 |
Dilution(float targetAmount, float targetVolume, float conc, float remainingQuantity) |
4165 |
21 Oct 16 |
nicklas |
853 |
{ |
4165 |
21 Oct 16 |
nicklas |
854 |
this.remainingQuantity = remainingQuantity; |
4165 |
21 Oct 16 |
nicklas |
855 |
this.conc = conc; |
4165 |
21 Oct 16 |
nicklas |
856 |
|
4165 |
21 Oct 16 |
nicklas |
857 |
float targetConc = targetAmount / targetVolume; |
4165 |
21 Oct 16 |
nicklas |
858 |
|
4165 |
21 Oct 16 |
nicklas |
// Take targetAmount, but not more than what is remaining |
4165 |
21 Oct 16 |
nicklas |
860 |
amount = targetAmount; |
4165 |
21 Oct 16 |
nicklas |
861 |
if (remainingQuantity < amount) |
4165 |
21 Oct 16 |
nicklas |
862 |
{ |
4165 |
21 Oct 16 |
nicklas |
863 |
amount = remainingQuantity; |
4165 |
21 Oct 16 |
nicklas |
// Adjust target volume to keep target concentration the same |
4165 |
21 Oct 16 |
nicklas |
865 |
targetVolume = amount / targetConc; |
4165 |
21 Oct 16 |
nicklas |
866 |
} |
4165 |
21 Oct 16 |
nicklas |
867 |
|
4165 |
21 Oct 16 |
nicklas |
// Calculate volume rounded up to one decimal place |
4165 |
21 Oct 16 |
nicklas |
869 |
volume = (float)Math.ceil(10000 * (amount / conc)) / 10; |
4165 |
21 Oct 16 |
nicklas |
870 |
|
4165 |
21 Oct 16 |
nicklas |
871 |
if (volume < 1f) |
4165 |
21 Oct 16 |
nicklas |
872 |
{ |
4165 |
21 Oct 16 |
nicklas |
// Do not take less than 1µl |
4165 |
21 Oct 16 |
nicklas |
874 |
volume = 1f; |
4165 |
21 Oct 16 |
nicklas |
875 |
amount = volume * conc / 1000; |
4165 |
21 Oct 16 |
nicklas |
// Adjust target volume to keep concentration the same |
4165 |
21 Oct 16 |
nicklas |
877 |
targetVolume = amount / targetConc; |
4165 |
21 Oct 16 |
nicklas |
878 |
} |
4165 |
21 Oct 16 |
nicklas |
879 |
|
4165 |
21 Oct 16 |
nicklas |
// May be negative, but then we don't dilute at all |
4165 |
21 Oct 16 |
nicklas |
881 |
water = targetVolume - volume; |
4165 |
21 Oct 16 |
nicklas |
882 |
} |
4165 |
21 Oct 16 |
nicklas |
883 |
|
4165 |
21 Oct 16 |
nicklas |
884 |
/** |
4165 |
21 Oct 16 |
nicklas |
Expected concentration after dilution. Negative water volume |
4165 |
21 Oct 16 |
nicklas |
means that no dilution is done. |
4165 |
21 Oct 16 |
nicklas |
887 |
*/ |
4165 |
21 Oct 16 |
nicklas |
888 |
float getDilutedConc() |
4165 |
21 Oct 16 |
nicklas |
889 |
{ |
4165 |
21 Oct 16 |
nicklas |
890 |
return water <= 0 ? conc : 1000 * amount / (volume + water); |
4165 |
21 Oct 16 |
nicklas |
891 |
} |
4165 |
21 Oct 16 |
nicklas |
892 |
|
4165 |
21 Oct 16 |
nicklas |
893 |
JSONObject asJSONObject() |
4165 |
21 Oct 16 |
nicklas |
894 |
{ |
4165 |
21 Oct 16 |
nicklas |
895 |
JSONObject json = new JSONObject(); |
4165 |
21 Oct 16 |
nicklas |
896 |
json.put("amount", amount); |
4165 |
21 Oct 16 |
nicklas |
897 |
json.put("volume", volume); |
4165 |
21 Oct 16 |
nicklas |
898 |
json.put("water", water); |
4165 |
21 Oct 16 |
nicklas |
899 |
return json; |
4165 |
21 Oct 16 |
nicklas |
900 |
} |
4165 |
21 Oct 16 |
nicklas |
901 |
} |
4146 |
03 Oct 16 |
nicklas |
902 |
} |