From c4dce99f4b842c50b7f437c770085d149d23e982 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 5 Mar 2015 15:09:04 +0530 Subject: [PATCH] [fixes] pos #2830, #2795 --- attributions.md | 7 + erpnext/accounts/doctype/sales_invoice/pos.py | 4 - .../doctype/sales_invoice/sales_invoice.js | 3 +- .../doctype/sales_invoice/sales_invoice.json | 22 +- erpnext/accounts/page/pos/pos.js | 13 +- erpnext/accounts/page/pos/pos_page.html | 15 ++ erpnext/public/images/pos.svg | 4 + erpnext/public/js/pos/pos.js | 209 +++++++++--------- 8 files changed, 143 insertions(+), 134 deletions(-) create mode 100644 attributions.md create mode 100644 erpnext/accounts/page/pos/pos_page.html create mode 100644 erpnext/public/images/pos.svg diff --git a/attributions.md b/attributions.md new file mode 100644 index 0000000000..9cd6eb8f8f --- /dev/null +++ b/attributions.md @@ -0,0 +1,7 @@ +## ERPNext includes these public works + +For Frappe Framework, please see attributions.md at https://github.com/frappe/frappe/ + +#### Images + +POS Icon: https://thenounproject.com/icon/41958 by hunotika diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index 6b0d933e28..7227f742b4 100644 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -41,7 +41,3 @@ def get_items(price_list, sales_or_purchase, item=None): item_det.item_code=i.name where %s""" % ('%(price_list)s', condition), args, as_dict=1) - -@frappe.whitelist() -def get_mode_of_payment(): - return sorted([d.name for d in frappe.get_list("Mode of Payment")]) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 482f5df421..a289d0e876 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -9,6 +9,7 @@ cur_frm.pformat.print_heading = 'Invoice'; frappe.provide("erpnext.accounts"); erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.extend({ onload: function() { + var me = this; this._super(); if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) { @@ -22,7 +23,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte this.frm.set_value("is_pos", 1); this.is_pos(function() { if (cint(frappe.defaults.get_user_defaults("fs_pos_view"))===1) - cur_frm.cscript.toggle_pos(true); + erpnext.pos.toggle(me.frm); }); } } diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 45afb0b324..9029c48a89 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -103,16 +103,6 @@ "permlevel": 0, "read_only": 0 }, - { - "fieldname": "is_pos", - "fieldtype": "Check", - "label": "Is POS", - "oldfieldname": "is_pos", - "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 1, - "read_only": 0 - }, { "fieldname": "company", "fieldtype": "Link", @@ -168,6 +158,16 @@ "reqd": 1, "search_index": 0 }, + { + "fieldname": "is_pos", + "fieldtype": "Check", + "label": "Is POS", + "oldfieldname": "is_pos", + "oldfieldtype": "Check", + "permlevel": 0, + "print_hide": 1, + "read_only": 0 + }, { "fieldname": "shipping_address_name", "fieldtype": "Link", @@ -1244,7 +1244,7 @@ "icon": "icon-file-text", "idx": 1, "is_submittable": 1, - "modified": "2015-03-04 16:08:58.641155", + "modified": "2015-03-05 01:42:46.778216", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index c3b3c03c22..1bc5681231 100644 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -1,18 +1,11 @@ frappe.pages['pos'].on_page_load = function(wrapper) { var page = frappe.ui.make_app_page({ parent: wrapper, - title: __('Start POS'), + title: __('Start Point-of-Sale (POS)'), single_column: true }); - page.main.html('
\ -

' + __("Select type of transaction") + '

\ -

\ -

' - + '
' - + __("Make new POS Setting") + '

\ -

\ -
'); + page.main.html(frappe.render_template("pos_page", {})); var pos_type = frappe.ui.form.make_control({ parent: page.main.find(".select-type"), @@ -34,6 +27,8 @@ frappe.pages['pos'].on_page_load = function(wrapper) { pos_type.refresh(); + pos_type.set_input("Sales Invoice"); + page.main.find(".btn-primary").on("click", function() { erpnext.open_as_pos = true; new_doc(pos_type.get_value()); diff --git a/erpnext/accounts/page/pos/pos_page.html b/erpnext/accounts/page/pos/pos_page.html new file mode 100644 index 0000000000..98cce009ad --- /dev/null +++ b/erpnext/accounts/page/pos/pos_page.html @@ -0,0 +1,15 @@ +
+ +

{%= __("Select type of transaction") %}

+

+ +

+

+ +

+

+ + {%= __("Make new POS Setting") %} +

+
diff --git a/erpnext/public/images/pos.svg b/erpnext/public/images/pos.svg new file mode 100644 index 0000000000..3d12d9cb86 --- /dev/null +++ b/erpnext/public/images/pos.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/erpnext/public/js/pos/pos.js b/erpnext/public/js/pos/pos.js index 91193a28e5..282d9b9d7e 100644 --- a/erpnext/public/js/pos/pos.js +++ b/erpnext/public/js/pos/pos.js @@ -335,19 +335,15 @@ erpnext.pos.PointOfSale = Class.extend({ if (!this.frm.doc.is_pos) { this.frm.set_value("is_pos", 1); } - this.frm.page.clear_actions(); this.frm.page.set_primary_action(__("Pay"), function() { me.make_payment(); }); - this.frm.toolbar.current_status = null; } else if (this.frm.doc.docstatus===1) { - this.frm.page.clear_actions(); this.frm.page.set_primary_action(__("New"), function() { me.frm.pos_active = false; erpnext.open_as_pos = true; new_doc(me.frm.doctype); }); - this.frm.toolbar.current_status = null; } }, refresh_delete_btn: function() { @@ -382,6 +378,18 @@ erpnext.pos.PointOfSale = Class.extend({ this.frm.script_manager.trigger("calculate_taxes_and_totals"); this.refresh(); }, + with_modes_of_payment: function(callback) { + var me = this; + if(me.modes_of_payment) { + callback(); + } else { + me.modes_of_payment = []; + $.ajax("/api/resource/Mode of Payment").success(function(data) { + $.each(data.data, function(i, d) { me.modes_of_payment.push(d.name); }); + callback(); + }); + } + }, make_payment: function() { var me = this; var no_of_items = this.frm.doc.items.length; @@ -389,95 +397,92 @@ erpnext.pos.PointOfSale = Class.extend({ if (no_of_items == 0) msgprint(__("Payment cannot be made for empty cart")); else { - frappe.call({ - method: 'erpnext.accounts.doctype.sales_invoice.pos.get_mode_of_payment', - callback: function(r) { - if(!r.message) { - msgprint(__("Please add to Modes of Payment from Setup.")) - return; + + this.with_modes_of_payment(function() { + // prefer cash payment! + var default_mode = me.modes_of_payment.indexOf(__("Cash"))!==-1 ? __("Cash") : undefined; + + // show payment wizard + var dialog = new frappe.ui.Dialog({ + width: 400, + title: 'Payment', + fields: [ + {fieldtype:'Currency', + fieldname:'total_amount', label: __('Total Amount'), read_only:1, + "default": me.frm.doc.grand_total, read_only: 1}, + {fieldtype:'Select', fieldname:'mode_of_payment', + label: __('Mode of Payment'), + options: me.modes_of_payment.join('\n'), reqd: 1, + "default": default_mode}, + {fieldtype:'Currency', fieldname:'paid_amount', label:__('Amount Paid'), + reqd:1, "default": me.frm.doc.grand_total, hidden: 1, change: function() { + var values = dialog.get_values(); + dialog.set_value("change", Math.round(values.paid_amount - values.total_amount)); + dialog.get_input("change").trigger("change"); + + }}, + {fieldtype:'Currency', fieldname:'change', label: __('Change'), + "default": 0.0, hidden: 1, change: function() { + var values = dialog.get_values(); + var write_off_amount = (flt(values.paid_amount) - flt(values.change)) - values.total_amount; + dialog.get_field("write_off_amount").toggle(write_off_amount); + dialog.set_value("write_off_amount", write_off_amount); + } + }, + {fieldtype:'Currency', fieldname:'write_off_amount', + label: __('Write Off'), default: 0.0, hidden: 1}, + ] + }); + me.dialog = dialog; + dialog.show(); + + // make read only + dialog.get_input("total_amount").prop("disabled", true); + dialog.get_input("write_off_amount").prop("disabled", true); + + // toggle amount paid and change + dialog.get_input("mode_of_payment").on("change", function() { + var is_cash = dialog.get_value("mode_of_payment") === __("Cash"); + dialog.get_field("paid_amount").toggle(is_cash); + dialog.get_field("change").toggle(is_cash); + + if (is_cash && !dialog.get_value("change")) { + // set to nearest 5 + var paid_amount = 5 * Math.ceil(dialog.get_value("total_amount") / 5); + dialog.set_value("paid_amount", paid_amount); + dialog.get_input("paid_amount").trigger("change"); } + }).trigger("change"); - var modes_of_payment = r.message; - - // prefer cash payment! - var default_mode = modes_of_payment.indexOf(__("Cash"))!==-1 ? __("Cash") : undefined; - - // show payment wizard - var dialog = new frappe.ui.Dialog({ - width: 400, - title: 'Payment', - fields: [ - {fieldtype:'Currency', fieldname:'total_amount', label: __('Total Amount'), read_only:1, - options:"currency", default:me.frm.doc.grand_total, read_only: 1}, - {fieldtype:'Select', fieldname:'mode_of_payment', label: __('Mode of Payment'), - options:modes_of_payment.join('\n'), reqd: 1, default: default_mode}, - {fieldtype:'Currency', fieldname:'paid_amount', label:__('Amount Paid'), reqd:1, - options: "currency", - default:me.frm.doc.grand_total, hidden: 1}, - {fieldtype:'Currency', fieldname:'change', label: __('Change'), options: "currency", - default: 0.0, hidden: 1}, - {fieldtype:'Currency', fieldname:'write_off_amount', label: __('Write Off'), options: "currency", - default: 0.0, hidden: 1}, - {fieldtype:'Button', fieldname:'pay', label:'Pay'} - ] - }); - dialog.show(); - - // make read only - dialog.get_input("total_amount").prop("disabled", true); - dialog.get_input("write_off_amount").prop("disabled", true); - - dialog.get_input("paid_amount").on("change", function() { - var values = dialog.get_values(); - dialog.set_value("change", Math.round(values.paid_amount - values.total_amount)); - dialog.get_input("change").trigger("change"); - }); - - dialog.get_input("change").on("change", function() { - var values = dialog.get_values(); - var write_off_amount = (flt(values.paid_amount) - flt(values.change)) - values.total_amount; - dialog.set_value("write_off_amount", write_off_amount); - dialog.fields_dict.write_off_amount.$wrapper.toggleClass("hide", !!!write_off_amount); - }); - - // toggle amount paid and change - dialog.get_input("mode_of_payment").on("change", function() { - var is_cash = dialog.get_value("mode_of_payment") === __("Cash"); - dialog.fields_dict.paid_amount.$wrapper.toggleClass("hide", !is_cash); - dialog.fields_dict.change.$wrapper.toggleClass("hide", !is_cash); - - if (is_cash && !dialog.get_value("change")) { - // set to nearest 5 - var paid_amount = 5 * Math.ceil(dialog.get_value("total_amount") / 5); - dialog.set_value("paid_amount", paid_amount); - dialog.get_input("paid_amount").trigger("change"); - } - }).trigger("change"); - - dialog.fields_dict.pay.input.onclick = function() { - var values = dialog.get_values(); - var is_cash = values.mode_of_payment === __("Cash"); - if (!is_cash) { - values.write_off_amount = values.change = 0.0; - values.paid_amount = values.total_amount; - } - me.frm.set_value("mode_of_payment", values.mode_of_payment); - - var paid_amount = flt((flt(values.paid_amount) - flt(values.change)) / me.frm.doc.conversion_rate, precision("paid_amount")); - me.frm.set_value("paid_amount", paid_amount); - - // specifying writeoff amount here itself, so as to avoid recursion issue - me.frm.set_value("write_off_amount", me.frm.doc.base_grand_total - paid_amount); - me.frm.set_value("outstanding_amount", 0); - - me.frm.savesubmit(this); - dialog.hide(); - me.refresh(); - }; - } + me.set_pay_button(dialog); }); } }, + set_pay_button: function(dialog) { + var me = this; + dialog.set_primary_action(__("Pay"), function() { + var values = dialog.get_values(); + console.log(values); + var is_cash = values.mode_of_payment === __("Cash"); + if (!is_cash) { + values.write_off_amount = values.change = 0.0; + values.paid_amount = values.total_amount; + } + me.frm.set_value("mode_of_payment", values.mode_of_payment); + + var paid_amount = flt((flt(values.paid_amount) - flt(values.change)) / me.frm.doc.conversion_rate, precision("paid_amount")); + me.frm.set_value("paid_amount", paid_amount); + + // specifying writeoff amount here itself, so as to avoid recursion issue + me.frm.set_value("write_off_amount", me.frm.doc.base_grand_total - paid_amount); + me.frm.set_value("outstanding_amount", 0); + + me.frm.savesubmit(this); + dialog.hide(); + me.refresh(); + }) + + } }); erpnext.pos.make_pos_btn = function(frm) { @@ -486,28 +491,13 @@ erpnext.pos.make_pos_btn = function(frm) { return; } - if(frm.doc.docstatus <= 1) { - if(!frm.pos_active) { - var btn_label = __("POS View"), - icon = "icon-th"; - } else { - var btn_label = __("Form View"), - icon = "icon-file-text"; - } + if(!frm.pos_btn) { + frm.pos_btn = frm.page.add_action_icon("icon-th", function() { + erpnext.pos.toggle(frm) }); + } - if(erpnext.open_as_pos) { - erpnext.pos.toggle(frm, true); - erpnext.open_as_pos = false; - } - - frm.$pos_btn && frm.$pos_btn.remove(); - - frm.$pos_btn = frm.page.add_menu_item(btn_label, function() { - erpnext.pos.toggle(frm); - }); - } else { - // hack: will avoid calling refresh from refresh - setTimeout(function() { erpnext.pos.toggle(frm, false); }, 100); + if(erpnext.open_as_pos && !frm.pos_active) { + erpnext.pos.toggle(frm); } } @@ -534,6 +524,7 @@ erpnext.pos.toggle = function(frm, show) { frm.page.set_view(frm.pos_active ? "main" : "pos"); frm.pos_active = !frm.pos_active; + frm.toolbar.current_status = null; frm.refresh(); // refresh