You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

308 line
9.7 KiB

  1. // Healthcare
  2. frappe.ui.form.on('Sales Invoice', {
  3. refresh(frm) {
  4. if (frm.doc.docstatus === 0 && !frm.doc.is_return) {
  5. frm.add_custom_button(__('Healthcare Services'), function() {
  6. get_healthcare_services_to_invoice(frm);
  7. },__('Get Items From'));
  8. frm.add_custom_button(__('Prescriptions'), function() {
  9. get_drugs_to_invoice(frm);
  10. },__('Get Items From'));
  11. }
  12. },
  13. patient(frm) {
  14. if (frm.doc.patient) {
  15. frappe.db.get_value("Patient", frm.doc.patient, "customer")
  16. .then(r => {
  17. if (!r.exc && r.message.customer) {
  18. frm.set_value("customer", r.message.customer);
  19. } else {
  20. frappe.show_alert({
  21. indicator: "warning",
  22. message: __("Patient <b>{0}</b> is not linked to a Customer",
  23. [`<a class='bold' href='/app/patient/${frm.doc.patient}'>${frm.doc.patient}</a>`]
  24. ),
  25. });
  26. frm.set_value("customer", "");
  27. }
  28. frm.set_df_property("customer", "read_only", frm.doc.customer ? 1 : 0);
  29. })
  30. } else {
  31. frm.set_value("customer", "");
  32. frm.set_df_property("customer", "read_only", 0);
  33. }
  34. }
  35. });
  36. var get_healthcare_services_to_invoice = function(frm) {
  37. var me = this;
  38. let selected_patient = '';
  39. var dialog = new frappe.ui.Dialog({
  40. title: __("Get Items from Healthcare Services"),
  41. fields:[
  42. {
  43. fieldtype: 'Link',
  44. options: 'Patient',
  45. label: 'Patient',
  46. fieldname: "patient",
  47. reqd: true
  48. },
  49. { fieldtype: 'Section Break' },
  50. { fieldtype: 'HTML', fieldname: 'results_area' }
  51. ]
  52. });
  53. var $wrapper;
  54. var $results;
  55. var $placeholder;
  56. dialog.set_values({
  57. 'patient': frm.doc.patient
  58. });
  59. dialog.fields_dict["patient"].df.onchange = () => {
  60. var patient = dialog.fields_dict.patient.input.value;
  61. if(patient && patient!=selected_patient){
  62. selected_patient = patient;
  63. var method = "healthcare.healthcare.utils.get_healthcare_services_to_invoice";
  64. var args = {patient: patient, company: frm.doc.company};
  65. var columns = (["service", "reference_name", "reference_type"]);
  66. get_healthcare_items(frm, true, $results, $placeholder, method, args, columns);
  67. }
  68. else if(!patient){
  69. selected_patient = '';
  70. $results.empty();
  71. $results.append($placeholder);
  72. }
  73. }
  74. $wrapper = dialog.fields_dict.results_area.$wrapper.append(`<div class="results"
  75. style="border: 1px solid #d1d8dd; border-radius: 3px; height: 300px; overflow: auto;"></div>`);
  76. $results = $wrapper.find('.results');
  77. $placeholder = $(`<div class="multiselect-empty-state">
  78. <span class="text-center" style="margin-top: -40px;">
  79. <i class="fa fa-2x fa-heartbeat text-extra-muted"></i>
  80. <p class="text-extra-muted">No billable Healthcare Services found</p>
  81. </span>
  82. </div>`);
  83. $results.on('click', '.list-item--head :checkbox', (e) => {
  84. $results.find('.list-item-container .list-row-check')
  85. .prop("checked", ($(e.target).is(':checked')));
  86. });
  87. set_primary_action(frm, dialog, $results, true);
  88. dialog.show();
  89. };
  90. var get_healthcare_items = function(frm, invoice_healthcare_services, $results, $placeholder, method, args, columns) {
  91. var me = this;
  92. $results.empty();
  93. frappe.call({
  94. method: method,
  95. args: args,
  96. callback: function(data) {
  97. if(data.message){
  98. $results.append(make_list_row(columns, invoice_healthcare_services));
  99. for(let i=0; i<data.message.length; i++){
  100. $results.append(make_list_row(columns, invoice_healthcare_services, data.message[i]));
  101. }
  102. }else {
  103. $results.append($placeholder);
  104. }
  105. }
  106. });
  107. }
  108. var make_list_row= function(columns, invoice_healthcare_services, result={}) {
  109. var me = this;
  110. // Make a head row by default (if result not passed)
  111. let head = Object.keys(result).length === 0;
  112. let contents = ``;
  113. columns.forEach(function(column) {
  114. contents += `<div class="list-item__content ellipsis">
  115. ${
  116. head ? `<span class="ellipsis">${__(frappe.model.unscrub(column))}</span>`
  117. :(column !== "name" ? `<span class="ellipsis">${__(result[column])}</span>`
  118. : `<a class="list-id ellipsis">
  119. ${__(result[column])}</a>`)
  120. }
  121. </div>`;
  122. })
  123. let $row = $(`<div class="list-item">
  124. <div class="list-item__content" style="flex: 0 0 10px;">
  125. <input type="checkbox" class="list-row-check" ${result.checked ? 'checked' : ''}>
  126. </div>
  127. ${contents}
  128. </div>`);
  129. $row = list_row_data_items(head, $row, result, invoice_healthcare_services);
  130. return $row;
  131. };
  132. var set_primary_action= function(frm, dialog, $results, invoice_healthcare_services) {
  133. var me = this;
  134. dialog.set_primary_action(__('Add'), function() {
  135. let checked_values = get_checked_values($results);
  136. if(checked_values.length > 0){
  137. if(invoice_healthcare_services) {
  138. frm.set_value("patient", dialog.fields_dict.patient.input.value);
  139. }
  140. add_to_item_line(frm, checked_values, invoice_healthcare_services);
  141. dialog.hide();
  142. }
  143. else{
  144. if(invoice_healthcare_services){
  145. frappe.msgprint(__("Please select Healthcare Service"));
  146. }
  147. else{
  148. frappe.msgprint(__("Please select Drug"));
  149. }
  150. }
  151. });
  152. };
  153. var get_checked_values= function($results) {
  154. return $results.find('.list-item-container').map(function() {
  155. let checked_values = {};
  156. if ($(this).find('.list-row-check:checkbox:checked').length > 0 ) {
  157. checked_values['dn'] = $(this).attr('data-dn');
  158. checked_values['dt'] = $(this).attr('data-dt');
  159. checked_values['item'] = $(this).attr('data-item');
  160. if($(this).attr('data-rate') != 'undefined'){
  161. checked_values['rate'] = $(this).attr('data-rate');
  162. }
  163. else{
  164. checked_values['rate'] = false;
  165. }
  166. if($(this).attr('data-income-account') != 'undefined'){
  167. checked_values['income_account'] = $(this).attr('data-income-account');
  168. }
  169. else{
  170. checked_values['income_account'] = false;
  171. }
  172. if($(this).attr('data-qty') != 'undefined'){
  173. checked_values['qty'] = $(this).attr('data-qty');
  174. }
  175. else{
  176. checked_values['qty'] = false;
  177. }
  178. if($(this).attr('data-description') != 'undefined'){
  179. checked_values['description'] = $(this).attr('data-description');
  180. }
  181. else{
  182. checked_values['description'] = false;
  183. }
  184. return checked_values;
  185. }
  186. }).get();
  187. };
  188. var get_drugs_to_invoice = function(frm) {
  189. var me = this;
  190. let selected_encounter = '';
  191. var dialog = new frappe.ui.Dialog({
  192. title: __("Get Items from Prescriptions"),
  193. fields:[
  194. { fieldtype: 'Link', options: 'Patient', label: 'Patient', fieldname: "patient", reqd: true },
  195. { fieldtype: 'Link', options: 'Patient Encounter', label: 'Patient Encounter', fieldname: "encounter", reqd: true,
  196. description:'Quantity will be calculated only for items which has "Nos" as UoM. You may change as required for each invoice item.',
  197. get_query: function(doc) {
  198. return {
  199. filters: {
  200. patient: dialog.get_value("patient"),
  201. company: frm.doc.company,
  202. docstatus: 1
  203. }
  204. };
  205. }
  206. },
  207. { fieldtype: 'Section Break' },
  208. { fieldtype: 'HTML', fieldname: 'results_area' }
  209. ]
  210. });
  211. var $wrapper;
  212. var $results;
  213. var $placeholder;
  214. dialog.set_values({
  215. 'patient': frm.doc.patient,
  216. 'encounter': ""
  217. });
  218. dialog.fields_dict["encounter"].df.onchange = () => {
  219. var encounter = dialog.fields_dict.encounter.input.value;
  220. if(encounter && encounter!=selected_encounter){
  221. selected_encounter = encounter;
  222. var method = "healthcare.healthcare.utils.get_drugs_to_invoice";
  223. var args = {encounter: encounter};
  224. var columns = (["drug_code", "quantity", "description"]);
  225. get_healthcare_items(frm, false, $results, $placeholder, method, args, columns);
  226. }
  227. else if(!encounter){
  228. selected_encounter = '';
  229. $results.empty();
  230. $results.append($placeholder);
  231. }
  232. }
  233. $wrapper = dialog.fields_dict.results_area.$wrapper.append(`<div class="results"
  234. style="border: 1px solid #d1d8dd; border-radius: 3px; height: 300px; overflow: auto;"></div>`);
  235. $results = $wrapper.find('.results');
  236. $placeholder = $(`<div class="multiselect-empty-state">
  237. <span class="text-center" style="margin-top: -40px;">
  238. <i class="fa fa-2x fa-heartbeat text-extra-muted"></i>
  239. <p class="text-extra-muted">No Drug Prescription found</p>
  240. </span>
  241. </div>`);
  242. $results.on('click', '.list-item--head :checkbox', (e) => {
  243. $results.find('.list-item-container .list-row-check')
  244. .prop("checked", ($(e.target).is(':checked')));
  245. });
  246. set_primary_action(frm, dialog, $results, false);
  247. dialog.show();
  248. };
  249. var list_row_data_items = function(head, $row, result, invoice_healthcare_services) {
  250. if(invoice_healthcare_services){
  251. head ? $row.addClass('list-item--head')
  252. : $row = $(`<div class="list-item-container"
  253. data-dn= "${result.reference_name}" data-dt= "${result.reference_type}" data-item= "${result.service}"
  254. data-rate = ${result.rate}
  255. data-income-account = "${result.income_account}"
  256. data-qty = ${result.qty}
  257. data-description = "${result.description}">
  258. </div>`).append($row);
  259. }
  260. else{
  261. head ? $row.addClass('list-item--head')
  262. : $row = $(`<div class="list-item-container"
  263. data-item= "${result.drug_code}"
  264. data-qty = ${result.quantity}
  265. data-description = "${result.description}">
  266. </div>`).append($row);
  267. }
  268. return $row
  269. };
  270. var add_to_item_line = function(frm, checked_values, invoice_healthcare_services){
  271. if(invoice_healthcare_services){
  272. frappe.call({
  273. doc: frm.doc,
  274. method: "set_healthcare_services",
  275. args:{
  276. checked_values: checked_values
  277. },
  278. callback: function() {
  279. frm.trigger("validate");
  280. frm.refresh_fields();
  281. }
  282. });
  283. }
  284. else{
  285. for(let i=0; i<checked_values.length; i++){
  286. var si_item = frappe.model.add_child(frm.doc, 'Sales Invoice Item', 'items');
  287. frappe.model.set_value(si_item.doctype, si_item.name, 'item_code', checked_values[i]['item']);
  288. frappe.model.set_value(si_item.doctype, si_item.name, 'qty', 1);
  289. if(checked_values[i]['qty'] > 1){
  290. frappe.model.set_value(si_item.doctype, si_item.name, 'qty', parseFloat(checked_values[i]['qty']));
  291. }
  292. }
  293. frm.refresh_fields();
  294. }
  295. };