Proyecto en colaboración con OPASO

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. /* Authors : Carlos C. Corrada-Bravo
  2. David J. Ortiz-Rivera
  3. Organization : Centro de Desarrollo y Consultoria Computacional
  4. Project : OPASO Material Registry
  5. File : laboratory.js
  6. Description : Generate and display laboratory inventory */
  7. /* save inventory data globaly */
  8. var controlTimeout,control,total,r,next,transaction,row,form,admin
  9. var active = false;
  10. var sort_key = "mat_name";
  11. let lab_id = get_arg("lab_id");
  12. /* set listeners when document is ready */
  13. $(document).ready(function(){
  14. link_gen();
  15. laboratory();
  16. });
  17. function display_form(type,transaction){
  18. let f = `.${type}-form`;
  19. let s = `#${type}-submit`;
  20. $(".form-shader").addClass("fade-in")
  21. $(f).addClass("c-form");
  22. $(f).addClass("slide-down");
  23. $(s).attr("value",transaction);
  24. }
  25. /* hide_form() - hide form */
  26. function hide_form(){
  27. $(".c-form").removeClass("slide-down");
  28. setTimeout(function(){
  29. $(".form-shader").removeClass("fade-in");
  30. },250);
  31. }
  32. /* main_transaction() - handle main transactions */
  33. function main_transaction(){
  34. /* extract args */
  35. let s = `#${r}`;
  36. let amount = parseFloat($("#transaction").val());
  37. var uom = $(s).find("td[value=uom]").text();
  38. var mat_id = $(s).find("td[value=mat_name]").attr("mat_id");
  39. var man_id = $(s).find("td[value=man_name]").attr("man_id");
  40. let capacity = parseFloat($(s).find("td[value=capacity]").text());
  41. /* calculate material left */
  42. if(transaction === "add"){
  43. total += amount;
  44. }
  45. else{
  46. total -= amount;
  47. }
  48. /* query server */
  49. hide_form();
  50. $.post("/scripts/opaso",{query: 9,lab_id: lab_id,mat_id: mat_id,man_id: man_id,capacity: capacity,transaction: transaction,total: total,amount: amount,uom: uom},function(data){
  51. // console.log(data);
  52. /* extract response */
  53. let response = JSON.parse(data);
  54. let status = response["status"];
  55. /* handle by status */
  56. switch(status){
  57. case "success": /* on success, update total/quantity */
  58. if(total < 1){
  59. $(s).remove();
  60. $(".table-total").text($(".inventory-body tr").length);
  61. }
  62. /* update quantity */
  63. else{
  64. $("#total").val(total);
  65. $("#transaction").val(0);
  66. let containers = total/capacity;
  67. $(s).find("td[value=quantity]").text(Math.ceil(containers));
  68. $(s).find("td[value=total]").text(total);
  69. }
  70. set_alert(status,"Transaction complete");
  71. break;
  72. case "expired": /* on expired, redirect to index */
  73. window.location.href = "/?error=session_expired";
  74. break;
  75. default: /* on error, display message */
  76. set_alert(status,response["message"]);
  77. break;
  78. }
  79. });
  80. }
  81. /* add_material() - add material to inventory */
  82. function add_material(){
  83. /* generate material entries */
  84. row = {};
  85. form = {};
  86. row[next] = {};
  87. /* populate entries */
  88. $(".material-input").each(function(){
  89. /* extract field name */
  90. var field = $(this).attr("name");
  91. /* generate inventory row */
  92. switch(field){
  93. case "quantity":
  94. /* calculate total */
  95. row[next][field] = $(this).val();
  96. let mtotal = parseFloat(form["capacity"]) * parseFloat($(this).val());
  97. form["total"] = mtotal;
  98. row[next]["total"] = mtotal;
  99. break;
  100. case "mat_name":
  101. case "man_name":
  102. case "capacity":
  103. case "uom":
  104. case "location":
  105. row[next][field] = $(this).val();
  106. break;
  107. }
  108. /* set field entry */
  109. form[field] = $(this).val();
  110. });
  111. /* query server */
  112. hide_form();
  113. $.post("/scripts/opaso",{query: 10,lab_id: lab_id,data: JSON.stringify(form)},function(data){
  114. // console.log(data);
  115. /* extract response */
  116. let response = JSON.parse(data);
  117. let status = response["status"];
  118. /* handle by status */
  119. switch(status){
  120. case "expired": /* on expired, redirect to index */
  121. window.location.href = "/?error=session_expired";
  122. break;
  123. case "success": /* on success, update inventory */
  124. // console.log(row);
  125. /* extract args */
  126. let mat_id = response["mat_id"];
  127. let man_id = response["man_id"];
  128. let s_uom = form["uom"].toLowerCase();
  129. let s_total = parseFloat(form["total"]);
  130. let s_capacity = parseFloat(form["capacity"]);
  131. let s_man_name = form["man_name"].toLowerCase();
  132. /* verify if material exists */
  133. var flag = true;
  134. let s = `td[mat_id=${mat_id}]`;
  135. $(s).each(function(){
  136. /* extract args */
  137. var capacity = parseFloat($(this).parent().find("td[value=capacity]").text());
  138. var man_name = $(this).parent().find("td[value=man_name]").text().toLowerCase();
  139. var uom = $(this).parent().find("td[value=uom]").text().toLowerCase();
  140. /* update quantities */
  141. if((capacity === s_capacity) && (man_name === s_man_name) && (uom === s_uom)){
  142. var ntotal = parseFloat($(this).parent().find("td[value=total]").text()) + s_total;
  143. var containers = ntotal/capacity;
  144. $(this).parent().find("td[value=total]").text(ntotal);
  145. $(this).parent().find("td[value=quantity]").text(Math.ceil(containers));
  146. flag = false;
  147. }
  148. });
  149. /* generate table row */
  150. if(flag){
  151. let tr = element_gen("tr",{class: "entry-row",id: next});
  152. for(var r in row){
  153. for(var field in row[r]){
  154. /* identify material */
  155. if(field === "mat_name"){
  156. var attributes = {class: "entry-cell",mat_id: mat_id,text: row[r][field],value: field};
  157. }
  158. /* identify material */
  159. else if(field === "man_name"){
  160. if(!row[r][field]){
  161. row[r][field] = "-";
  162. }
  163. var attributes = {class: "entry-cell",man_id: man_id,text: row[r][field],value: field};
  164. }
  165. else{
  166. if(!row[r][field]){
  167. row[r][field] = "-";
  168. }
  169. var attributes = {class: "entry-cell",text: row[r][field],value: field};
  170. }
  171. var td = element_gen("td",attributes);
  172. tr.append(td);
  173. }
  174. let actions = {add:{class: "t-icon material-icons",icon: "add"},use: {class: "t-icon material-icons",icon: "remove"},offer: {class: "t-icon material-icons",icon: "redeem"},discard: {class: "t-icon material-icons",icon: "delete"}};
  175. var td = element_gen("td",{class: "actions-cell"});
  176. for(var action in actions){
  177. var icon = element_gen("i",{class: actions[action]["class"],text: actions[action]["icon"]});
  178. var button = element_gen("button",{class: "button action",id: action,title: action,childs: {icon}});
  179. td.append(button);
  180. }
  181. }
  182. /* append */
  183. tr.append(td);
  184. $(".inventory-body").append(tr);
  185. /* sort table */
  186. next += 1;
  187. full_sort(next,sort_key);
  188. $(".table-total").text(`Total: ${next}`);
  189. }
  190. default: /* on success/error, display message */
  191. set_alert(status,response["message"]);
  192. break;
  193. }
  194. });
  195. }
  196. /* transaction - handle material transactions */
  197. function transaction(){
  198. /* extract args */
  199. transaction = $(this).attr("id");
  200. r = $(this).parent().parent().attr("id");
  201. let s = `#${r}`;
  202. total = parseFloat($(s).find("td[value=total]").text());
  203. uom = $(s).find("td[value=uom]").text();
  204. let header = `${transaction} material (${uom})`;
  205. $(".main-header").text(header);
  206. /* hide total capacity */
  207. if(transaction === "add"){
  208. $(".total").hide();
  209. }
  210. /* set total quantity */
  211. else{
  212. $("#total").val(total);
  213. $(".total").show();
  214. }
  215. $("#transaction").val(0);
  216. $(".transaction-label").text(transaction);
  217. display_form("main",transaction);
  218. }
  219. /* fetch_material() - fetch material data */
  220. function fetch_material(){
  221. /* extract key */
  222. let mat_name = $(this).text();
  223. let mat_id = $(this).attr("mat_id");
  224. let uom = $(this).parent().find("td[value=uom]").text();
  225. let man_id = $(this).parent().find("td[value=man_name]").attr("man_id");
  226. let capacity = $(this).parent().find("td[value=capacity]").text();
  227. $.post("/scripts/opaso",{query: 12,lab_id: lab_id,mat_id: mat_id,man_id: man_id,capacity: capacity,uom: uom},function(data){
  228. // console.log(data);
  229. /* extract response */
  230. let response = JSON.parse(data);
  231. let status = response["status"];
  232. /* handle by status */
  233. switch(status){
  234. case "success": /* on success, generate material data */
  235. let material = response["material"];
  236. $("h5[value=mat_name]").text(mat_name);
  237. var href = `/materials?mat_id=${mat_id}`;
  238. $(".material-link").attr("href",href);
  239. for(var a in material){
  240. let s = `span[value=${a}]`;
  241. if(a === "sds" && material[a]){
  242. var icon = element_gen("i",{class: "fas fa-link"});
  243. var link = element_gen("a",{href: decodeURIComponent(material[a]),target: "_blank",rel: "noopener noreferrer",childs: {icon}});
  244. $(s).html(link);
  245. }
  246. else{
  247. /* correct null values */
  248. if(!material[a]){
  249. material[a] = "-";
  250. }
  251. $(s).text(material[a]);
  252. }
  253. }
  254. $(".material-data-shader").addClass("slide-right");
  255. break;
  256. case "expired": /* on expired, redirect to index */
  257. window.location.href = "/?error=session_expired";
  258. break;
  259. default: /* on error, display message */
  260. set_alert(status,response["message"]);
  261. break;
  262. }
  263. });
  264. }
  265. /* set_listeners() - listen for events */
  266. function set_listeners(){
  267. /* sort table */
  268. $(".sort").click(function(){
  269. sort_key = $(this).attr("value");
  270. if(sort_key === "mat_name"){
  271. $(".sort-material").show();
  272. $(".sort-alt").hide();
  273. }
  274. else{
  275. $(".sort-alt").show();
  276. $(".sort-material").hide();
  277. }
  278. full_sort(next,sort_key);
  279. });
  280. /* add/use material */
  281. $("tbody").on("click",".action",transaction);
  282. /* add material to inventory */
  283. $(".add-material").click(function(){
  284. display_form("add","add-material");
  285. });
  286. /* handle popover */
  287. $("tbody td[value=mat_name]").click(fetch_material);
  288. /* handle form submit */
  289. $(".submit").click(function(){
  290. /* add material */
  291. transaction = $(this).attr("value");
  292. if(transaction === "add-material"){
  293. /* verify null fields */
  294. var valid = true;
  295. $(".material-input").each(function(){
  296. var field = $(this).attr("name");
  297. /* highlight */
  298. if(!$(this).val()){
  299. valid = false;
  300. $(this).addClass("invalid");
  301. }
  302. /* unhighlight */
  303. else{
  304. $(this).removeClass("invalid");
  305. }
  306. });
  307. /* valid form */
  308. if(valid){
  309. set_confirm("Do you wish to add entry to inventory?",transaction);
  310. }
  311. /* invalid form */
  312. else{
  313. set_alert("warning","All fields required");
  314. }
  315. }
  316. /* main transactions */
  317. else{
  318. /* validate amount */
  319. let amount = parseFloat($("#transaction").val());
  320. if((transaction === "add" || amount <= total) && amount > 0){
  321. /* generate message */
  322. let s = `#${r}`;
  323. let uom = $(s).find("td[value=uom]").text();
  324. let material = $(s).find("td[value=mat_name]").text();
  325. let verb = transaction.charAt(0).toUpperCase() + transaction.slice(1);
  326. let message = `${verb} ${amount}${uom} of ${material}. Is this correct?`;
  327. /* configure alert */
  328. set_confirm(message,transaction);
  329. }
  330. /* amount not valid */
  331. else{
  332. set_alert("error","Please correct transaction amount");
  333. }
  334. }
  335. });
  336. /* handle query submit */
  337. $("#yes").click(function(){
  338. transaction = $(this).attr("value");
  339. /* add material */
  340. if(transaction === "add-material"){
  341. add_material();
  342. }
  343. /* main transactions */
  344. else{
  345. main_transaction(transaction);
  346. }
  347. hide_confirm();
  348. });
  349. /* handle query cancel */
  350. $(".hide-confirm").click(function(element){
  351. /* prevent child propagation */
  352. if(element.target === element.currentTarget){
  353. hide_confirm();
  354. }
  355. });
  356. /* close form */
  357. $(".close-form").click(function(element){
  358. if(element.target === element.currentTarget){
  359. hide_form();
  360. }
  361. });
  362. /* hide material data */
  363. $(".hide-material-data").click(function(element){
  364. if(element.target === element.currentTarget){
  365. $(".material-data-shader").removeClass("slide-right");
  366. }
  367. });
  368. /* download file */
  369. $(".download-option").click(function(){
  370. /* extract args */
  371. $("html").addClass("wait");
  372. let download_type = $(this).attr("value");
  373. /* generate file */
  374. $.post("/scripts/opaso",{query: 24,download_type: download_type,lab_id: get_arg("lab_id")},function(data){
  375. // console.log(data);
  376. /* extract response */
  377. let response = JSON.parse(data);
  378. let status = response["status"];
  379. /* handle by status */
  380. switch(status){
  381. case "success": /* on success, generate table */
  382. var link=element_gen("a",{href: response["url"],download: response["file_name"]});
  383. link.click();
  384. break;
  385. case "expired": /* on expired, redirect to index */
  386. window.location.href = "/?error=session_expired";
  387. break;
  388. default: /* on error, display message */
  389. set_alert(status,response["message"]);
  390. break;
  391. }
  392. $("html").removeClass("wait");
  393. });
  394. });
  395. }
  396. /* table_gen(data: dictionary) - generate table body */
  397. function table_gen(data){
  398. for(var d in data){
  399. /* generate table row */
  400. let tr = element_gen("tr",{class: "entry-row",id: d});
  401. let fields = data[d];
  402. for(var field in fields){
  403. /* identify material */
  404. if(field === "material"){
  405. var attributes = {class: "entry-cell",mat_id: fields[field]["mat_id"],text: fields[field]["mat_name"],value: "mat_name"};
  406. }
  407. /* identify material */
  408. else if(field === "manufacturer"){
  409. if(!fields[field]["man_name"]){
  410. fields[field]["man_name"] = "-";
  411. }
  412. var attributes = {class: "entry-cell",man_id: fields[field]["man_id"],text: fields[field]["man_name"],value: "man_name"};
  413. }
  414. else{
  415. /* correct null entries */
  416. if(!fields[field]){
  417. fields[field] = "-";
  418. }
  419. var attributes = {class: "entry-cell",text: fields[field],value: field};
  420. }
  421. /* generate cell */
  422. var td = element_gen("td",attributes);
  423. tr.append(td);
  424. }
  425. let actions = {add:{class: "t-icon material-icons",icon: "add"},use: {class: "t-icon material-icons",icon: "remove"},offer: {class: "t-icon material-icons",icon: "redeem"},discard: {class: "t-icon material-icons",icon: "delete"}};
  426. var td = element_gen("td",{class: "actions-cell"});
  427. for(var action in actions){
  428. var icon = element_gen("i",{class: actions[action]["class"],text: actions[action]["icon"]});
  429. var button = element_gen("button",{class: "button action",id: action,title: action,childs: {icon}});
  430. td.append(button);
  431. }
  432. /* append */
  433. tr.append(td);
  434. $(".inventory-body").append(tr);
  435. }
  436. $(".processing").hide();
  437. setTimeout(function(){
  438. $(".main-wrapper").show();
  439. },250);
  440. }
  441. /* laboratory() - fetch lab inventory */
  442. function laboratory(){
  443. /* avoid null queries */
  444. if(is_valid(lab_id)){
  445. $.post("/scripts/opaso",{query: 3,lab_id: lab_id},function(data){
  446. // console.log(data);
  447. /* extract response */
  448. let response = JSON.parse(data)
  449. let status = response["status"];
  450. /* handle by status */
  451. switch(status){
  452. case "success": /* on success, generate inventory */
  453. let inventory = response["lab"]["inventory"];
  454. let personnel = response["lab"]["personnel"];
  455. /* generate personnel table */
  456. for(var p in personnel){
  457. var name = element_gen("td",{class: "entry-cell person-name",text: personnel[p]["person_name"]});
  458. var access_level = element_gen("td",{class: "entry-cell access-level",text: personnel[p]["access_level"]});
  459. var person = element_gen("tr",{class: "personnel-row",childs:{name,access_level}});
  460. $(".personnel-body").append(person);
  461. }
  462. table_gen(inventory);
  463. set_listeners();
  464. next = Object.keys(inventory).length;
  465. $(".table-total").text(`Total: ${next}`);
  466. break;
  467. case "expired": /* on expired, redirect to index */
  468. window.location.href = "/?error=session_expired";
  469. break;
  470. default: /* on error, display message */
  471. /* display alert */
  472. set_alert(status,response["message"]);
  473. break;
  474. }
  475. });
  476. }
  477. /* missing arg */
  478. else{
  479. set_alert(status,"One or more arguments are missing");
  480. }
  481. }