Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

13 роки тому
13 роки тому
13 роки тому
12 роки тому
13 роки тому
11 роки тому
12 роки тому
11 роки тому
12 роки тому
13 роки тому
13 роки тому
12 роки тому
13 роки тому
12 роки тому
13 роки тому
12 роки тому
12 роки тому
13 роки тому
12 роки тому
13 роки тому
12 роки тому
13 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
13 роки тому
13 роки тому
13 роки тому
13 роки тому
12 роки тому
12 роки тому
13 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
11 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. // MIT License. See license.txt
  3. /* Form page structure
  4. + this.parent (either FormContainer or Dialog)
  5. + this.wrapper
  6. + this.toolbar
  7. + this.form_wrapper
  8. + this.head
  9. + this.body
  10. + this.layout
  11. + this.sidebar
  12. + this.footer
  13. */
  14. wn.provide('_f');
  15. wn.provide('wn.ui.form');
  16. wn.ui.form.Controller = Class.extend({
  17. init: function(opts) {
  18. $.extend(this, opts);
  19. this.setup && this.setup();
  20. }
  21. });
  22. _f.frms = {};
  23. _f.Frm = function(doctype, parent, in_form) {
  24. this.docname = '';
  25. this.doctype = doctype;
  26. this.display = 0;
  27. this.refresh_if_stale_for = 120;
  28. var me = this;
  29. this.opendocs = {};
  30. this.sections = [];
  31. this.grids = [];
  32. this.cscript = new wn.ui.form.Controller({frm:this});
  33. this.pformat = {};
  34. this.fetch_dict = {};
  35. this.parent = parent;
  36. this.tinymce_id_list = [];
  37. this.setup_meta(doctype);
  38. // show in form instead of in dialog, when called using url (router.js)
  39. this.in_form = in_form ? true : false;
  40. // notify on rename
  41. var me = this;
  42. $(document).on('rename', function(event, dt, old_name, new_name) {
  43. if(dt==me.doctype)
  44. me.rename_notify(dt, old_name, new_name)
  45. });
  46. }
  47. _f.Frm.prototype.check_doctype_conflict = function(docname) {
  48. var me = this;
  49. if(this.doctype=='DocType' && docname=='DocType') {
  50. msgprint('Allowing DocType, DocType. Be careful!')
  51. } else if(this.doctype=='DocType') {
  52. if (wn.views.formview[docname] || wn.pages['List/'+docname]) {
  53. msgprint("Cannot open DocType when its instance is open")
  54. throw 'doctype open conflict'
  55. }
  56. } else {
  57. if (wn.views.formview.DocType && wn.views.formview.DocType.frm.opendocs[this.doctype]) {
  58. msgprint("Cannot open instance when its DocType is open")
  59. throw 'doctype open conflict'
  60. }
  61. }
  62. }
  63. _f.Frm.prototype.setup = function() {
  64. var me = this;
  65. this.fields = [];
  66. this.fields_dict = {};
  67. this.state_fieldname = wn.workflow.get_state_fieldname(this.doctype);
  68. // wrapper
  69. this.wrapper = this.parent;
  70. wn.ui.make_app_page({
  71. parent: this.wrapper,
  72. single_column: true
  73. });
  74. this.appframe = this.wrapper.appframe;
  75. this.layout_main = $(this.wrapper)
  76. .find(".layout-main")
  77. .css({"padding-bottom": "0px"})
  78. .get(0);
  79. this.toolbar = new wn.ui.form.Toolbar({
  80. frm: this,
  81. appframe: this.appframe
  82. });
  83. this.frm_head = this.toolbar;
  84. // print layout
  85. this.setup_print_layout();
  86. // 2 column layout
  87. this.setup_std_layout();
  88. // client script must be called after "setup" - there are no fields_dict attached to the frm otherwise
  89. this.script_manager = new wn.ui.form.ScriptManager({
  90. frm: this
  91. });
  92. this.script_manager.setup();
  93. this.watch_model_updates();
  94. this.footer = new wn.ui.form.Footer({
  95. frm: this,
  96. parent: $(this.wrapper).find(".appframe-footer")
  97. })
  98. this.setup_done = true;
  99. }
  100. _f.Frm.prototype.setup_print_layout = function() {
  101. this.print_wrapper = $('<div>\
  102. <div class="print-toolbar row" style="background-color: #eee; \
  103. padding-top: 5px; padding-bottom: 5px; margin-top: -15px; \
  104. margin-bottom: 15px; padding-left: 15px; position:relative;">\
  105. <i class="text-muted icon-print" style="position: absolute; top: 13px; left: 10px; "></i>\
  106. <div class="col-xs-3">\
  107. <select class="print-preview-select form-control"></select></div>\
  108. <div class="col-xs-3" style="padding-top: 7px;">\
  109. <input type="checkbox" class="print-letterhead" checked/> Letterhead</div>\
  110. <div class="col-xs-6 text-right" style="padding-top: 7px;">\
  111. <a style="margin-right: 7px;" class="print-print">Print</a>\
  112. <a class="close">×</a>\
  113. </div>\
  114. </div>\
  115. <div class="print-preview">\
  116. </div>\
  117. </div>')
  118. .appendTo(this.layout_main)
  119. .toggle(false);
  120. var me = this;
  121. this.print_wrapper.find(".close").click(function() {
  122. me.hide_print();
  123. });
  124. this.print_formats = wn.meta.get_print_formats(this.meta.name);
  125. this.print_letterhead = this.print_wrapper
  126. .find(".print-letterhead")
  127. .on("change", function() { me.print_sel.trigger("change"); });
  128. this.print_sel = this.print_wrapper
  129. .find(".print-preview-select")
  130. .on("change", function() {
  131. _p.build(me.print_sel.val(), function(html) {
  132. me.print_wrapper.find(".print-preview").html(html);
  133. }, !me.print_letterhead.is(":checked"), true, true);
  134. })
  135. this.print_wrapper.find(".print-print").click(function() {
  136. _p.build(
  137. me.print_sel.val(), // fmtname
  138. _p.go, // onload
  139. !me.print_letterhead.is(":checked") // no_letterhead
  140. );
  141. })
  142. }
  143. _f.Frm.prototype.print_doc = function() {
  144. if(this.print_wrapper.is(":visible")) {
  145. this.hide_print();
  146. return;
  147. }
  148. if(!wn.model.can_print(this.doc.doctype, cur_frm)) {
  149. msgprint(wn._("You are not allowed to Print this document."));
  150. return;
  151. }
  152. if(this.doc.docstatus==2) {
  153. msgprint(wn._("Cannot Print Cancelled Documents."));
  154. return;
  155. }
  156. this.print_wrapper.toggle(true);
  157. this.print_sel
  158. .empty().add_options(this.print_formats)
  159. .trigger("change");
  160. this.form_wrapper.toggle(false);
  161. }
  162. _f.Frm.prototype.hide_print = function() {
  163. if(this.setup_done) {
  164. this.print_wrapper.toggle(false);
  165. this.form_wrapper.toggle(true);
  166. }
  167. }
  168. _f.Frm.prototype.watch_model_updates = function() {
  169. // watch model updates
  170. var me = this;
  171. // on main doc
  172. wn.model.on(me.doctype, "*", function(fieldname, value, doc) {
  173. // set input
  174. if(doc.name===me.docname) {
  175. me.dirty();
  176. me.fields_dict[fieldname]
  177. && me.fields_dict[fieldname].refresh(fieldname);
  178. me.refresh_dependency();
  179. me.script_manager.trigger(fieldname, doc.doctype, doc.name);
  180. }
  181. })
  182. // on table fields
  183. $.each(wn.model.get("DocField", {fieldtype:"Table", parent: me.doctype}), function(i, df) {
  184. wn.model.on(df.options, "*", function(fieldname, value, doc) {
  185. if(doc.parent===me.docname && doc.parentfield===df.fieldname) {
  186. me.dirty();
  187. me.fields_dict[df.fieldname].grid.set_value(fieldname, value, doc);
  188. me.script_manager.trigger(fieldname, doc.doctype, doc.name);
  189. }
  190. })
  191. })
  192. }
  193. _f.Frm.prototype.onhide = function() {
  194. if(_f.cur_grid_cell) _f.cur_grid_cell.grid.cell_deselect();
  195. }
  196. _f.Frm.prototype.setup_std_layout = function() {
  197. this.form_wrapper = $('<div></div>').appendTo(this.layout_main);
  198. this.body_header = $("<div>").appendTo(this.form_wrapper);
  199. this.body = $("<div>").appendTo(this.form_wrapper);
  200. // only tray
  201. this.meta.section_style='Simple'; // always simple!
  202. // layout
  203. this.layout = new wn.ui.form.Layout({
  204. parent: this.body,
  205. doctype: this.doctype,
  206. frm: this,
  207. });
  208. this.layout.make();
  209. this.fields_dict = this.layout.fields_dict;
  210. this.fields = this.layout.fields_list;
  211. this.dashboard = new wn.ui.form.Dashboard({
  212. frm: this,
  213. });
  214. // state
  215. this.states = new wn.ui.form.States({
  216. frm: this
  217. });
  218. }
  219. // email the form
  220. _f.Frm.prototype.email_doc = function(message) {
  221. new wn.views.CommunicationComposer({
  222. doc: this.doc,
  223. subject: wn._(this.meta.name) + ': ' + this.docname,
  224. recipients: this.doc.email || this.doc.email_id || this.doc.contact_email,
  225. attach_document_print: true,
  226. message: message,
  227. real_name: this.doc.real_name || this.doc.contact_display || this.doc.contact_name
  228. });
  229. }
  230. // rename the form
  231. _f.Frm.prototype.rename_doc = function() {
  232. wn.model.rename_doc(this.doctype, this.docname);
  233. }
  234. // notify this form of renamed records
  235. _f.Frm.prototype.rename_notify = function(dt, old, name) {
  236. // from form
  237. if(this.meta.istable)
  238. return;
  239. if(this.docname == old)
  240. this.docname = name;
  241. else
  242. return;
  243. // cleanup
  244. if(this && this.opendocs[old]) {
  245. // delete docfield copy
  246. wn.meta.docfield_copy[dt][name] = wn.meta.docfield_copy[dt][old];
  247. delete wn.meta.docfield_copy[dt][old];
  248. }
  249. delete this.opendocs[old];
  250. this.opendocs[name] = true;
  251. if(this.meta.in_dialog || !this.in_form) {
  252. return;
  253. }
  254. wn.re_route[window.location.hash] = '#Form/' + encodeURIComponent(this.doctype) + '/' + encodeURIComponent(name);
  255. wn.set_route('Form', this.doctype, name);
  256. }
  257. // SETUP
  258. _f.Frm.prototype.setup_meta = function(doctype) {
  259. this.meta = wn.model.get_doc('DocType',this.doctype);
  260. this.perm = wn.perm.get_perm(this.doctype); // for create
  261. if(this.meta.istable) { this.meta.in_dialog = 1 }
  262. }
  263. _f.Frm.prototype.defocus_rest = function() {
  264. // deselect others
  265. if(_f.cur_grid_cell) _f.cur_grid_cell.grid.cell_deselect();
  266. }
  267. _f.Frm.prototype.refresh_header = function() {
  268. // set title
  269. // main title
  270. if(!this.meta.in_dialog || this.in_form) {
  271. set_title(this.meta.issingle ? this.doctype : this.docname);
  272. }
  273. if(wn.ui.toolbar.recent)
  274. wn.ui.toolbar.recent.add(this.doctype, this.docname, 1);
  275. // show / hide buttons
  276. if(this.frm_head) {
  277. this.frm_head.refresh();
  278. }
  279. }
  280. _f.Frm.prototype.check_doc_perm = function() {
  281. // get perm
  282. var dt = this.parent_doctype?this.parent_doctype : this.doctype;
  283. var dn = this.parent_docname?this.parent_docname : this.docname;
  284. this.perm = wn.perm.get_perm(dt, dn);
  285. if(!this.perm[0].read) {
  286. return 0;
  287. }
  288. return 1
  289. }
  290. _f.Frm.prototype.refresh = function(docname) {
  291. // record switch
  292. if(docname) {
  293. if(this.docname != docname && (!this.meta.in_dialog || this.in_form) &&
  294. !this.meta.istable) {
  295. scroll(0, 0);
  296. this.hide_print();
  297. }
  298. this.docname = docname;
  299. }
  300. cur_frm = this;
  301. if(this.docname) { // document to show
  302. // check permissions
  303. if(!this.check_doc_perm()) return;
  304. // read only (workflow)
  305. this.read_only = wn.workflow.is_read_only(this.doctype, this.docname);
  306. // set the doc
  307. this.doc = wn.model.get_doc(this.doctype, this.docname);
  308. // check if doctype is already open
  309. if (!this.opendocs[this.docname]) {
  310. this.check_doctype_conflict(this.docname);
  311. } else {
  312. if(this.doc && (!this.doc.__unsaved) && this.doc.__last_sync_on &&
  313. (new Date() - this.doc.__last_sync_on) > (this.refresh_if_stale_for * 1000)) {
  314. this.reload_doc();
  315. return;
  316. }
  317. }
  318. // do setup
  319. if(!this.setup_done) this.setup();
  320. // load the record for the first time, if not loaded (call 'onload')
  321. cur_frm.cscript.is_onload = false;
  322. if(!this.opendocs[this.docname]) {
  323. cur_frm.cscript.is_onload = true;
  324. this.setnewdoc();
  325. } else {
  326. this.render_form();
  327. }
  328. }
  329. }
  330. _f.Frm.prototype.render_form = function() {
  331. if(!this.meta.istable) {
  332. // header
  333. this.refresh_header();
  334. // call trigger
  335. this.script_manager.trigger("refresh");
  336. // trigger global trigger
  337. // to use this
  338. $(document).trigger('form_refresh');
  339. // fields
  340. this.refresh_fields();
  341. // call onload post render for callbacks to be fired
  342. if(this.cscript.is_onload) {
  343. this.script_manager.trigger("onload_post_render");
  344. }
  345. // focus on first input
  346. if(this.doc.docstatus==0) {
  347. var first = this.form_wrapper.find('.form-layout-row :input:first');
  348. if(!in_list(["Date", "Datetime"], first.attr("data-fieldtype"))) {
  349. first.focus();
  350. }
  351. }
  352. } else {
  353. this.refresh_header();
  354. }
  355. $(cur_frm.wrapper).trigger('render_complete');
  356. }
  357. _f.Frm.prototype.refresh_field = function(fname) {
  358. cur_frm.fields_dict[fname] && cur_frm.fields_dict[fname].refresh
  359. && cur_frm.fields_dict[fname].refresh();
  360. }
  361. _f.Frm.prototype.refresh_fields = function() {
  362. this.layout.refresh(this.doc);
  363. this.layout.primary_button = $(this.wrapper).find(".btn-primary");
  364. // cleanup activities after refresh
  365. this.cleanup_refresh(this);
  366. // dependent fields
  367. this.refresh_dependency();
  368. }
  369. _f.Frm.prototype.cleanup_refresh = function() {
  370. var me = this;
  371. if(me.fields_dict['amended_from']) {
  372. if (me.doc.amended_from) {
  373. unhide_field('amended_from');
  374. if (me.fields_dict['amendment_date']) unhide_field('amendment_date');
  375. } else {
  376. hide_field('amended_from');
  377. if (me.fields_dict['amendment_date']) hide_field('amendment_date');
  378. }
  379. }
  380. if(me.fields_dict['trash_reason']) {
  381. if(me.doc.trash_reason && me.doc.docstatus == 2) {
  382. unhide_field('trash_reason');
  383. } else {
  384. hide_field('trash_reason');
  385. }
  386. }
  387. if(me.meta.autoname && me.meta.autoname.substr(0,6)=='field:' && !me.doc.__islocal) {
  388. var fn = me.meta.autoname.substr(6);
  389. cur_frm.toggle_display(fn, false);
  390. }
  391. if(me.meta.autoname=="naming_series:" && !me.doc.__islocal) {
  392. cur_frm.toggle_display("naming_series", false);
  393. }
  394. }
  395. // Resolve "depends_on" and show / hide accordingly
  396. _f.Frm.prototype.refresh_dependency = function() {
  397. var me = this;
  398. var doc = locals[this.doctype][this.docname];
  399. // build dependants' dictionary
  400. var has_dep = false;
  401. for(fkey in me.fields) {
  402. var f = me.fields[fkey];
  403. f.dependencies_clear = true;
  404. if(f.df.depends_on) {
  405. has_dep = true;
  406. }
  407. }
  408. if(!has_dep)return;
  409. // show / hide based on values
  410. for(var i=me.fields.length-1;i>=0;i--) {
  411. var f = me.fields[i];
  412. f.guardian_has_value = true;
  413. if(f.df.depends_on) {
  414. // evaluate guardian
  415. var v = doc[f.df.depends_on];
  416. if(f.df.depends_on.substr(0,5)=='eval:') {
  417. f.guardian_has_value = eval(f.df.depends_on.substr(5));
  418. } else if(f.df.depends_on.substr(0,3)=='fn:') {
  419. f.guardian_has_value = me.script_manager.trigger(f.df.depends_on.substr(3), me.doctype, me.docname);
  420. } else {
  421. if(!v) {
  422. f.guardian_has_value = false;
  423. }
  424. }
  425. // show / hide
  426. if(f.guardian_has_value) {
  427. if(f.df.hidden_due_to_dependency) {
  428. f.df.hidden_due_to_dependency = false;
  429. f.refresh();
  430. }
  431. } else {
  432. if(!f.df.hidden_due_to_dependency) {
  433. f.df.hidden_due_to_dependency = true;
  434. f.refresh();
  435. }
  436. }
  437. }
  438. }
  439. this.layout.refresh_section_count();
  440. }
  441. _f.Frm.prototype.setnewdoc = function() {
  442. // moved this call to refresh function
  443. // this.check_doctype_conflict(docname);
  444. var me = this;
  445. this.script_manager.trigger("before_load", this.doctype, this.docname, function() {
  446. me.script_manager.trigger("onload");
  447. me.opendocs[me.docname] = true;
  448. me.render_form();
  449. })
  450. }
  451. _f.Frm.prototype.runscript = function(scriptname, callingfield, onrefresh) {
  452. var me = this;
  453. if(this.docname) {
  454. // make doc list
  455. var doclist = wn.model.compress(make_doclist(this.doctype, this.docname));
  456. // send to run
  457. if(callingfield)
  458. $(callingfield.input).set_working();
  459. return $c('runserverobj', {'docs':doclist, 'method':scriptname },
  460. function(r, rtxt) {
  461. // run refresh
  462. if(onrefresh)
  463. onrefresh(r,rtxt);
  464. // fields
  465. me.refresh_fields();
  466. // enable button
  467. if(callingfield)
  468. $(callingfield.input).done_working();
  469. }
  470. );
  471. }
  472. }
  473. _f.Frm.prototype.copy_doc = function(onload, from_amend) {
  474. if(!this.perm[0].create) {
  475. msgprint('You are not allowed to create '+this.meta.name);
  476. return;
  477. }
  478. var dn = this.docname;
  479. // copy parent
  480. var newdoc = wn.model.copy_doc(this.doctype, dn, from_amend);
  481. // copy chidren
  482. var dl = make_doclist(this.doctype, dn);
  483. // table fields dict - for no_copy check
  484. var tf_dict = {};
  485. for(var d in dl) {
  486. d1 = dl[d];
  487. // get tabel field
  488. if(d1.parentfield && !tf_dict[d1.parentfield]) {
  489. tf_dict[d1.parentfield] = wn.meta.get_docfield(d1.parenttype, d1.parentfield);
  490. }
  491. if(d1.parent==dn && cint(tf_dict[d1.parentfield].no_copy)!=1) {
  492. var ch = wn.model.copy_doc(d1.doctype, d1.name, from_amend);
  493. ch.parent = newdoc.name;
  494. ch.docstatus = 0;
  495. ch.owner = user;
  496. ch.creation = '';
  497. ch.modified_by = user;
  498. ch.modified = '';
  499. }
  500. }
  501. newdoc.__islocal = 1;
  502. newdoc.docstatus = 0;
  503. newdoc.owner = user;
  504. newdoc.creation = '';
  505. newdoc.modified_by = user;
  506. newdoc.modified = '';
  507. if(onload)onload(newdoc);
  508. loaddoc(newdoc.doctype, newdoc.name);
  509. }
  510. _f.Frm.prototype.reload_doc = function() {
  511. this.check_doctype_conflict(this.docname);
  512. var me = this;
  513. var onsave = function(r, rtxt) {
  514. me.refresh();
  515. }
  516. if(!me.doc.__islocal) {
  517. wn.model.remove_from_locals(me.doctype, me.docname);
  518. wn.model.with_doc(me.doctype, me.docname, function() {
  519. me.refresh();
  520. })
  521. }
  522. }
  523. var validated;
  524. _f.Frm.prototype.save = function(save_action, callback, btn, on_error) {
  525. $(document.activeElement).blur();
  526. // let any pending js process finish
  527. setTimeout(100, this._save(save_action, callback, btn, on_error));
  528. }
  529. _f.Frm.prototype._save = function(save_action, callback, btn, on_error) {
  530. var me = this;
  531. if((!this.meta.in_dialog || this.in_form) && !this.meta.istable)
  532. scroll(0, 0);
  533. // validate
  534. if(save_action!="Cancel") {
  535. validated = true;
  536. this.script_manager.trigger("validate");
  537. if(!validated) {
  538. if(on_error)
  539. on_error();
  540. return;
  541. }
  542. }
  543. var doclist = new wn.model.DocList(this.doctype, this.docname);
  544. doclist.save(save_action || "Save", function(r) {
  545. if(!r.exc) {
  546. me.refresh();
  547. } else {
  548. if(on_error)
  549. on_error();
  550. }
  551. callback && callback(r);
  552. if(wn._from_link) {
  553. if(me.doctype===wn._from_link.df.options) {
  554. wn._from_link.parse_validate_and_set_in_model(me.docname);
  555. wn.set_route("Form", wn._from_link.frm.doctype, wn._from_link.frm.docname);
  556. setTimeout(function() { scroll(0, wn._from_link_scrollY); }, 100);
  557. }
  558. wn._from_link = null;
  559. }
  560. }, btn);
  561. }
  562. _f.Frm.prototype.savesubmit = function(btn, on_error) {
  563. var me = this;
  564. wn.confirm("Permanently Submit "+this.docname+"?", function() {
  565. validated = true;
  566. me.script_manager.trigger("before_submit");
  567. if(!validated) {
  568. if(on_error)
  569. on_error();
  570. return;
  571. }
  572. me.save('Submit', function(r) {
  573. if(!r.exc) {
  574. me.script_manager.trigger("on_submit");
  575. }
  576. }, btn, on_error);
  577. });
  578. }
  579. _f.Frm.prototype.savecancel = function(btn, on_error) {
  580. var me = this;
  581. wn.confirm("Permanently Cancel "+this.docname+"?", function() {
  582. validated = true;
  583. me.script_manager.trigger("before_cancel");
  584. if(!validated) {
  585. if(on_error)
  586. on_error();
  587. return;
  588. }
  589. var doclist = new wn.model.DocList(me.doctype, me.docname);
  590. doclist.cancel(function(r) {
  591. if(!r.exc) {
  592. me.refresh();
  593. me.script_manager.trigger("after_cancel");
  594. }
  595. }, btn, on_error);
  596. });
  597. }
  598. // delete the record
  599. _f.Frm.prototype.savetrash = function() {
  600. wn.model.delete_doc(this.doctype, this.docname, function(r) {
  601. window.history.back();
  602. })
  603. }
  604. _f.Frm.prototype.amend_doc = function() {
  605. if(!this.fields_dict['amended_from']) {
  606. alert('"amended_from" field must be present to do an amendment.');
  607. return;
  608. }
  609. var me = this;
  610. var fn = function(newdoc) {
  611. newdoc.amended_from = me.docname;
  612. if(me.fields_dict && me.fields_dict['amendment_date'])
  613. newdoc.amendment_date = dateutil.obj_to_str(new Date());
  614. }
  615. this.copy_doc(fn, 1);
  616. }
  617. _f.Frm.prototype.disable_save = function() {
  618. // IMPORTANT: this function should be called in refresh event
  619. this.save_disabled = true;
  620. this.appframe.set_title_right("", null);
  621. }
  622. _f.Frm.prototype.save_or_update = function() {
  623. if(this.save_disabled) return;
  624. if(this.doc.docstatus===0) {
  625. this.save();
  626. } else if(this.doc.docstatus===1 && this.doc.__unsaved) {
  627. this.save("Update");
  628. }
  629. }
  630. _f.get_value = function(dt, dn, fn) {
  631. if(locals[dt] && locals[dt][dn])
  632. return locals[dt][dn][fn];
  633. }
  634. _f.Frm.prototype.dirty = function() {
  635. this.doc.__unsaved = 1;
  636. $(this.wrapper).trigger('dirty')
  637. }
  638. _f.Frm.prototype.get_docinfo = function() {
  639. return wn.model.docinfo[this.doctype][this.docname];
  640. }
  641. _f.Frm.prototype.get_perm = function(permlevel, access_type) {
  642. return this.perm[permlevel] ? this.perm[permlevel][access_type] : null;
  643. }
  644. _f.Frm.prototype.set_intro = function(txt) {
  645. wn.utils.set_intro(this, this.body, txt);
  646. }
  647. _f.Frm.prototype.set_footnote = function(txt) {
  648. wn.utils.set_footnote(this, this.body, txt);
  649. }
  650. _f.Frm.prototype.add_custom_button = function(label, fn, icon) {
  651. return this.appframe.add_primary_action(label, fn, icon || "icon-arrow-right");
  652. }
  653. _f.Frm.prototype.clear_custom_buttons = function() {
  654. this.toolbar.refresh()
  655. }
  656. _f.Frm.prototype.add_fetch = function(link_field, src_field, tar_field) {
  657. if(!this.fetch_dict[link_field]) {
  658. this.fetch_dict[link_field] = {'columns':[], 'fields':[]}
  659. }
  660. this.fetch_dict[link_field].columns.push(src_field);
  661. this.fetch_dict[link_field].fields.push(tar_field);
  662. }
  663. _f.Frm.prototype.set_print_heading = function(txt) {
  664. this.pformat[cur_frm.docname] = txt;
  665. }