diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.js b/erpnext/accounts/doctype/pos_profile/pos_profile.js
index da49036973..8de8e351bc 100755
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.js
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.js
@@ -3,11 +3,11 @@
frappe.ui.form.on("POS Profile", "onload", function(frm) {
frm.set_query("selling_price_list", function() {
- return { filter: { selling: 1 } };
+ return { filters: { selling: 1 } };
});
frm.set_query("print_format", function() {
- return { filter: { doc_type: "Sales Invoice" } };
+ return { filters: { doc_type: "Sales Invoice", print_format_type: "Js"} };
});
erpnext.queries.setup_queries(frm, "Warehouse", function() {
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index 0cf17da1c9..9bea107423 100644
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -14,14 +14,16 @@ def get_pos_data():
doc = frappe.new_doc('Sales Invoice')
doc.update_stock = 1;
doc.is_pos = 1;
- pos_profile = get_pos_profile(doc.company)
+ pos_profile = get_pos_profile(doc.company) or {}
- if not pos_profile:
- frappe.throw(_("Create pos profile first"))
+ if pos_profile.get('name'):
+ pos_profile = frappe.get_doc('POS Profile', pos_profile.get('name'))
+ else:
+ frappe.msgprint(_("Warning Message: Create pos profile"))
- pos_profile = frappe.get_doc('POS Profile', pos_profile.name)
update_pos_profile_data(doc, pos_profile)
update_multi_mode_option(doc, pos_profile)
+ print_template = frappe.db.get_value('Print Format', pos_profile.get('print_format'), 'html') or ''
return {
'doc': doc,
@@ -29,7 +31,7 @@ def get_pos_data():
'customers': get_customers(pos_profile),
'pricing_rules': get_pricing_rules(doc),
'mode_of_payment': get_mode_of_payment(doc),
- 'print_template': frappe.db.get_value('Print Format', pos_profile.print_format, 'html') or '',
+ 'print_template': print_template,
'meta': {
'invoice': frappe.get_meta('Sales Invoice'),
'items': frappe.get_meta('Sales Invoice Item'),
@@ -40,21 +42,21 @@ def get_pos_data():
def update_pos_profile_data(doc, pos_profile):
company_data = frappe.db.get_value('Company', doc.company, '*', as_dict=1)
- doc.taxes_and_charges = pos_profile.taxes_and_charges
+ doc.taxes_and_charges = pos_profile.get('taxes_and_charges')
if doc.taxes_and_charges:
update_tax_table(doc)
- doc.currency = pos_profile.currency or company_data.default_currency
+ doc.currency = pos_profile.get('currency') or company_data.default_currency
doc.conversion_rate = 1.0
if doc.currency != company_data.default_currency:
doc.conversion_rate = get_exchange_rate(doc.currency, company_data.default_currency)
- doc.selling_price_list = pos_profile.selling_price_list or frappe.db.get_value('Selling Settings', None, 'selling_price_list')
- doc.naming_series = pos_profile.naming_series or 'SINV-'
- doc.letter_head = pos_profile.letter_head or company_data.default_letter_head
- doc.ignore_pricing_rule = pos_profile.ignore_pricing_rule
- doc.apply_discount_on = pos_profile.apply_discount_on
- doc.customer_group = pos_profile.customer_group or get_root('Customer Group')
- doc.territory = pos_profile.territory or get_root('Territory')
+ doc.selling_price_list = pos_profile.get('selling_price_list') or frappe.db.get_value('Selling Settings', None, 'selling_price_list')
+ doc.naming_series = pos_profile.get('naming_series') or 'SINV-'
+ doc.letter_head = pos_profile.get('letter_head') or company_data.default_letter_head
+ doc.ignore_pricing_rule = pos_profile.get('ignore_pricing_rule') or 0
+ doc.apply_discount_on = pos_profile.get('apply_discount_on') or ''
+ doc.customer_group = pos_profile.get('customer_group') or get_root('Customer Group')
+ doc.territory = pos_profile.get('territory') or get_root('Territory')
def get_root(table):
root = frappe.db.sql(""" select name from `tab%(table)s` having
@@ -64,6 +66,9 @@ def get_root(table):
def update_multi_mode_option(doc, pos_profile):
from frappe.model import default_fields
+
+ if not pos_profile:
+ return
for payment_mode in pos_profile.payments:
payment_mode = payment_mode.as_dict()
@@ -89,10 +94,10 @@ def get_items(doc, pos_profile):
item.price_list_rate = frappe.db.get_value('Item Price', {'item_code': item.name,
'price_list': doc.selling_price_list}, 'price_list_rate') or 0
- item.default_warehouse = pos_profile.warehouse or item.default_warehouse or None
- item.expense_account = pos_profile.expense_account or item.expense_account
- item.income_account = pos_profile.income_account or item_doc.income_account
- item.cost_center = pos_profile.cost_center or item_doc.selling_cost_center
+ item.default_warehouse = pos_profile.get('warehouse') or item.default_warehouse or None
+ item.expense_account = pos_profile.get('expense_account') or item.expense_account
+ item.income_account = pos_profile.get('income_account') or item_doc.income_account
+ item.cost_center = pos_profile.get('cost_center') or item_doc.selling_cost_center
item.actual_qty = frappe.db.get_value('Bin', {'item_code': item.name,
'warehouse': item.default_warehouse}, 'actual_qty') or 0
item.serial_nos = frappe.db.sql_list("""select name from `tabSerial No` where warehouse= %(warehouse)s
@@ -103,7 +108,7 @@ def get_items(doc, pos_profile):
def get_customers(pos_profile):
filters = {'disabled': 0}
- if pos_profile.customer:
+ if pos_profile.get('customer'):
filters.update({'name': pos_profile.customer})
return frappe.get_all("Customer", fields=["*"], filters = filters)
@@ -133,13 +138,13 @@ def make_invoice(doc_list):
si_doc = frappe.new_doc('Sales Invoice')
si_doc.offline_pos_name = name
si_doc.update(doc)
- submit_invoice(si_doc)
+ submit_invoice(si_doc, name)
name_list.append(name)
return name_list
def validate_customer(doc):
- if not frappe.db.get_value('Customer', doc.get('customer')):
+ if not frappe.db.exists('Customer', doc.get('customer')):
customer_doc = frappe.new_doc('Customer')
customer_doc.customer_name = doc.get('customer')
customer_doc.customer_type = 'Company'
@@ -165,20 +170,21 @@ def validate_item(doc):
item_doc.save(ignore_permissions=True)
frappe.db.commit()
-def submit_invoice(si_doc):
+def submit_invoice(si_doc, name):
try:
si_doc.insert()
si_doc.submit()
except Exception, e:
if frappe.message_log: frappe.message_log.pop()
frappe.db.rollback()
- save_invoice(e, si_doc)
+ save_invoice(e, si_doc, name)
-def save_invoice(e, si_doc):
- si_doc.docstatus = 0
- si_doc.name = ''
- si_doc.save(ignore_permissions=True)
- make_scheduler_log(e, si_doc.name)
+def save_invoice(e, si_doc, name):
+ if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name, 'docstatus': 1}):
+ si_doc.docstatus = 0
+ si_doc.name = ''
+ si_doc.save(ignore_permissions=True)
+ make_scheduler_log(e, si_doc.name)
def make_scheduler_log(e, sales_invoice):
scheduler_log = frappe.new_doc('Scheduler Log')
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index 04dd5804d2..2162563f22 100644
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -7,21 +7,35 @@ frappe.pages['pos'].on_page_load = function(wrapper) {
title: 'Point of Sale',
single_column: true
});
-
- wrapper = $(wrapper).find('.page-content')
- new erpnext.pos.PointOfSale(page, wrapper)
+
+ wrapper.pos = new erpnext.pos.PointOfSale(wrapper)
}
+frappe.pages['pos'].refresh = function(wrapper) {
+ wrapper.pos.on_refresh_page()
+}
+
+
erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
- init: function(page, wrapper){
- this.page = page;
- this.wrapper = wrapper;
+ init: function(wrapper){
+ this.load = true;
+ this.page = wrapper.page;
+ this.wrapper = $(wrapper).find('.page-content');
this.set_indicator();
this.onload();
this.make_menu_list();
this.set_interval_for_si_sync();
this.si_docs = this.get_doc_from_localstorage();
},
+
+ on_refresh_page: function() {
+ var me = this;
+ if(this.load){
+ this.load = false;
+ }else{
+ this.create_new();
+ }
+ },
check_internet_connection: function(){
var me = this;
@@ -48,7 +62,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
onload: function(){
var me = this;
-
this.get_data_from_server(function(){
me.create_new();
});
@@ -64,7 +77,11 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
});
this.page.add_menu_item(__("Sync Master Data"), function(){
- me.get_data_from_server()
+ me.get_data_from_server(function(){
+ me.load_data()
+ me.make_customer()
+ me.make_item_list()
+ })
});
this.page.add_menu_item(__("New Sales Invoice"), function() {
@@ -83,7 +100,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.list_dialog.show();
this.list_body = this.list_dialog.body;
$(this.list_body).append('
\
-
Customer
\
+
Sr
\
+
Customer
\
Grand Total
\
Status
\
')
@@ -91,9 +109,10 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
$.each(this.si_docs, function(index, data){
for(key in data) {
$(frappe.render_template("pos_invoice_list", {
+ sr: index + 1,
name: key,
customer: data[key].customer,
- grand_total: data[key].grand_total,
+ grand_total: format_currency(data[key].grand_total, me.frm.doc.currency),
status: (data[key].docstatus == 1) ? 'Submitted' : 'Draft'
})).appendTo($(me.list_body));
}
@@ -104,12 +123,21 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
doc_data = me.get_invoice_doc(me.si_docs)
if(doc_data){
me.frm.doc = doc_data[0][me.name];
+ me.set_missing_values();
me.refresh();
me.disable_input_field();
me.list_dialog.hide();
}
})
},
+
+ set_missing_values: function(){
+ var me = this;
+ doc = JSON.parse(localStorage.getItem('doc'))
+ if(this.frm.doc.payments.length == 0){
+ this.frm.doc.payments = doc.payments;
+ }
+ },
get_invoice_doc: function(si_docs){
var me = this;
@@ -127,6 +155,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
frappe.call({
method: "erpnext.accounts.doctype.sales_invoice.pos.get_pos_data",
freeze: true,
+ freeze_message: __("Master data syncing, it might take some time"),
callback: function(r){
window.items = r.message.items;
window.customers = r.message.customers;
@@ -142,8 +171,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
},
create_new: function(){
- this.frm = {}
var me = this;
+ this.frm = {}
this.name = '';
this.frm.doc = JSON.parse(localStorage.getItem('doc'))
this.load_data();
@@ -555,11 +584,9 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
me.create_invoice();
me.make_payment();
});
- }else if(this.frm.doc.docstatus == 0){
+ }else if(this.frm.doc.docstatus == 0 && this.name){
this.page.set_primary_action(__("Submit"), function() {
- frappe.confirm(__("Do you really want to submit the invoice?"), function () {
- me.write_off_amount()
- })
+ me.write_off_amount()
})
}else if(this.frm.doc.docstatus == 1){
this.page.set_primary_action(__("Print"), function() {
@@ -571,6 +598,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
}, 1000)
});
})
+ }else {
+ this.page.clear_primary_action()
}
},
@@ -582,27 +611,36 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
dialog = new frappe.ui.Dialog({
title: 'Write Off Amount',
fields: [
- {fieldtype: "Currency", fieldname: "write_off_amount", label: __("Amount"), reqd: 1},
+ {fieldtype: "Check", fieldname: "write_off_amount", label: __("Write of Outstanding Amount")},
]
- });
+ });
- dialog.show();
+ dialog.show();
- dialog.fields_dict.write_off_amount.$input.change(function(){
- value = dialog.get_values()
- })
-
- dialog.set_primary_action(__("Submit"), function(){
- me.frm.doc.write_off_amount = value.write_off_amount;
- me.calculate_outstanding_amount();
- dialog.hide();
- me.change_status();
- })
+ dialog.fields_dict.write_off_amount.$input.change(function(){
+ write_off_amount = dialog.get_values().write_off_amount
+ me.frm.doc.write_off_outstanding_amount_automatically = write_off_amount;
+ me.frm.doc.base_write_off_amount = (write_off_amount==1) ? flt(me.frm.doc.grand_total - me.frm.doc.paid_amount, precision("outstanding_amount")) : 0;
+ me.frm.doc.write_off_amount = flt(me.frm.doc.base_write_off_amount * me.frm.doc.conversion_rate, precision("write_off_amount"))
+ me.calculate_outstanding_amount();
+ })
+
+ dialog.set_primary_action(__("Submit"), function(){
+ dialog.hide()
+ me.submit_invoice()
+ })
}else{
- me.change_status();
+ this.submit_invoice()
}
},
+ submit_invoice: function(){
+ var me = this;
+ frappe.confirm(__("Do you really want to submit the invoice?"), function () {
+ me.change_status();
+ })
+ },
+
change_status: function(){
if(this.frm.doc.docstatus == 0){
this.frm.doc.docstatus = 1;
@@ -662,14 +700,18 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
},
get_doc_from_localstorage: function(){
- return JSON.parse(localStorage.getItem('sales_invoice_doc')) || [];
+ try{
+ return JSON.parse(localStorage.getItem('sales_invoice_doc')) || [];
+ }catch(e){
+ return []
+ }
},
set_interval_for_si_sync: function(){
var me = this;
setInterval(function(){
me.sync_sales_invoice()
- }, 6000)
+ }, 60000)
},
sync_sales_invoice: function(){
@@ -711,14 +753,16 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
remove_doc_from_localstorage: function(){
var me = this;
this.si_docs = this.get_doc_from_localstorage();
+ this.new_si_docs = []
if(this.removed_items){
$.each(this.si_docs, function(index, data){
for(key in data){
- if(in_list(me.removed_items, key)){
- me.si_docs.splice(index)
+ if(!in_list(me.removed_items, key)){
+ me.new_si_docs.push(data)
}
}
})
+ this.si_docs = this.new_si_docs;
this.update_localstorage();
}
},
diff --git a/erpnext/accounts/print_format/point_of_sale/__init__.py b/erpnext/accounts/print_format/point_of_sale/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/print_format/point_of_sale/point_of_sale.json b/erpnext/accounts/print_format/point_of_sale/point_of_sale.json
new file mode 100644
index 0000000000..7641924f02
--- /dev/null
+++ b/erpnext/accounts/print_format/point_of_sale/point_of_sale.json
@@ -0,0 +1,18 @@
+{
+ "creation": "2016-05-05 17:16:18.564460",
+ "custom_format": 1,
+ "disabled": 0,
+ "doc_type": "Sales Invoice",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "html": "\n\n\n\t{{ company }}
\n\t{{ __(\"Invoice\") }}
\n
\n\n\t{{ __(\"Date\") }}: {{ posting_date }}
\n
\n\n
\n\n\t\n\t\t\n\t\t\t{{ __(\"Item\") }} | \n\t\t\t{{ __(\"Qty\") }} | \n\t\t\t{{ __(\"Amount\") }} | \n\t\t
\n\t\n\t\n\t\t{% for item in items %}\n\t\t\n\t\t\t\n\t\t\t\t{{ item.item_name }}\n\t\t\t | \n\t\t\t{{ item.qty }} @ {{ format_currency(item.rate, currency) }} | \n\t\t\t{{ format_currency(item.amount, currency) }} | \n\t\t
\n\t\t{% endfor %}\n\t\n
\n\n\n\t\n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Net Total\") }}\n\t\t\t | \n\t\t\t\n\t\t\t\t{{ format_currency(total, currency) }}\n\t\t\t | \n\t\t
\n\t\t{% for row in taxes %}\n\t\t{% if not row.included_in_print_rate %}\n\t\t\n\t\t\t\n\t\t\t\t{{ row.description }}\n\t\t\t | \n\t\t\t\n\t\t\t\t{{ format_currency(row.tax_amount, currency) }}\n\t\t\t | \n\t\t
\n\t\t{% endif %}\n\t\t{% endfor %}\n\t\t{% if discount_amount %}\n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Discount\") }}\n\t\t\t | \n\t\t\t\n\t\t\t\t{{ format_currency(discount_amount, currency) }}\n\t\t\t | \n\t\t
\n\t\t{% endif %}\n\t\t\n\t\t\t\n\t\t\t\t{{ __(\"Grand Total\") }}\n\t\t\t | \n\t\t\t\n\t\t\t\t{{ format_currency(grand_total, currency) }}\n\t\t\t | \n\t\t
\n\t\n
\n\n\n
\n{{ __(\"Thank you, please visit again.\") }}
",
+ "idx": 0,
+ "modified": "2016-05-11 15:04:24.359583",
+ "modified_by": "Administrator",
+ "name": "Point of Sale",
+ "owner": "Administrator",
+ "print_format_builder": 0,
+ "print_format_type": "Js",
+ "standard": "Yes"
+}
\ No newline at end of file
diff --git a/erpnext/config/desktop.py b/erpnext/config/desktop.py
index 68bf7681e3..9944db9882 100644
--- a/erpnext/config/desktop.py
+++ b/erpnext/config/desktop.py
@@ -131,8 +131,7 @@ def get_data():
"icon": "octicon octicon-credit-card",
"type": "page",
"link": "pos",
- "label": _("POS"),
- "hidden": 1
+ "label": _("POS")
},
{
"module_name": "Projects",
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index 03c381a85e..340ebdb5e5 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -15,15 +15,13 @@
"public/js/templates/address_list.html",
"public/js/templates/contact_list.html",
"public/js/controllers/stock_controller.js",
- "public/js/controllers/payments.js",
+ "public/js/payment/payments.js",
"public/js/controllers/taxes_and_totals.js",
"public/js/controllers/transaction.js",
"public/js/pos/pos.html",
"public/js/pos/pos_bill_item.html",
"public/js/pos/pos_item.html",
"public/js/pos/pos_tax_row.html",
- "public/js/pos/pos_print.html",
- "public/js/pos/pos.js",
"public/js/pos/pos_invoice_list.html",
"public/js/payment/pos_payment.html",
"public/js/payment/payment_details.html",
diff --git a/erpnext/public/css/erpnext.css b/erpnext/public/css/erpnext.css
index 6777e1e4d7..346cfa0c62 100644
--- a/erpnext/public/css/erpnext.css
+++ b/erpnext/public/css/erpnext.css
@@ -124,3 +124,55 @@
.dashboard-list-item:last-child {
border-bottom: none;
}
+
+.payment-toolbar {
+ margin-left: 35px;
+}
+
+.payment-mode {
+ cursor: pointer;
+ font-family: sans-serif;
+ font-size: 15px;
+}
+
+.pos-payment-row .col-xs-6 {
+ padding :10px;
+}
+
+.pos-payment-row {
+ border-bottom:1px solid #d1d8dd;
+ margin: 2px 0px 5px 0px;
+}
+
+.pos-payment-row:hover, .pos-keyboard-key:hover{
+ background-color: #FAFBFC;
+ cursor: pointer;
+}
+
+.pos-keyboard-key, .delete-btn {
+ border: 1px solid #d1d8dd;
+ height:85px;
+ width:85px;
+ margin:10px 10px;
+ font-size:24px;
+ font-weight:200;
+ background-color: #FDFDFD;
+ border-color: #e8e8e8;
+}
+
+.amount {
+ margin-top: 5px;
+}
+
+.amount-label {
+ font-size: 16px;
+}
+
+.selected-payment-mode {
+ background-color: #FAFBFC;
+ cursor: pointer;
+}
+
+.pos-invoice-list {
+ padding: 15px 10px;
+}
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index c6224668bc..af651c9b85 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -165,7 +165,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
erpnext.hide_company();
this.show_item_wise_taxes();
this.set_dynamic_labels();
- // erpnext.pos.make_pos_btn(this.frm);
this.setup_sms();
this.make_show_payments_btn();
},
diff --git a/erpnext/public/js/controllers/payments.js b/erpnext/public/js/payment/payments.js
similarity index 93%
rename from erpnext/public/js/controllers/payments.js
rename to erpnext/public/js/payment/payments.js
index 7ac2b7baea..f5527b1d04 100644
--- a/erpnext/public/js/controllers/payments.js
+++ b/erpnext/public/js/payment/payments.js
@@ -20,10 +20,8 @@ erpnext.payments = erpnext.stock.StockController.extend({
var me = this;
this.dialog.set_primary_action(__("Submit"), function() {
- frappe.confirm(__("Do you really want to submit the invoice?"), function () {
- me.write_off_amount();
- me.dialog.hide();
- })
+ me.dialog.hide()
+ me.write_off_amount()
})
},
@@ -35,13 +33,6 @@ erpnext.payments = erpnext.stock.StockController.extend({
this.bind_keyboard_event()
},
- pay_amount: function(){
- var me = this;
- this.make_multimode_payment();
- this.calculate_outstanding_amount()
- this.show_payment_details();
- },
-
make_multimode_payment: function(){
var me = this;
@@ -91,12 +82,12 @@ erpnext.payments = erpnext.stock.StockController.extend({
me.payment_val = flt(me.frm.doc.outstanding_amount)
me.selected_mode.val(format_number(me.payment_val, 2));
me.update_paid_amount()
- me.bind_amount_change_event();
}else if(flt(me.selected_mode.val()) > 0){
//If user click on existing row which has value
me.payment_val = flt(me.selected_mode.val());
}
me.selected_mode.select()
+ me.bind_amount_change_event();
})
},
diff --git a/erpnext/public/js/payment/pos_payment.html b/erpnext/public/js/payment/pos_payment.html
index e93644dc28..223850c504 100644
--- a/erpnext/public/js/payment/pos_payment.html
+++ b/erpnext/public/js/payment/pos_payment.html
@@ -31,7 +31,7 @@
{% } %}
-
+
diff --git a/erpnext/public/js/pos/pos.js b/erpnext/public/js/pos/pos.js
deleted file mode 100644
index 60801e628a..0000000000
--- a/erpnext/public/js/pos/pos.js
+++ /dev/null
@@ -1,583 +0,0 @@
-// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-// License: GNU General Public License v3. See license.txt
-
-frappe.provide("erpnext.pos");
-
-erpnext.pos.PointOfSale = Class.extend({
- init: function(wrapper, frm) {
- this.wrapper = wrapper;
- this.frm = frm;
- this.wrapper.html(frappe.render_template("pos", {currency: this.frm.currency}));
-
- this.check_transaction_type();
- this.make();
-
- var me = this;
- $(this.frm.wrapper).on("refresh-fields", function() {
- me.refresh();
- });
-
- this.wrapper.find('input.discount-percentage').on("change", function() {
- frappe.model.set_value(me.frm.doctype, me.frm.docname,
- "additional_discount_percentage", flt(this.value));
- });
-
- this.wrapper.find('input.discount-amount').on("change", function() {
- frappe.model.set_value(me.frm.doctype, me.frm.docname, "discount_amount", flt(this.value));
- });
- },
- check_transaction_type: function() {
- var me = this;
-
- // Check whether the transaction is "Sales" or "Purchase"
- if (frappe.meta.has_field(cur_frm.doc.doctype, "customer")) {
- this.set_transaction_defaults("Customer");
- }
- else if (frappe.meta.has_field(cur_frm.doc.doctype, "supplier")) {
- this.set_transaction_defaults("Supplier");
- }
- },
- set_transaction_defaults: function(party) {
- var me = this;
- this.party = party;
- this.price_list = (party == "Customer" ?
- this.frm.doc.selling_price_list : this.frm.doc.buying_price_list);
- this.price_list_field = (party == "Customer" ? "selling_price_list" : "buying_price_list");
- this.sales_or_purchase = (party == "Customer" ? "Sales" : "Purchase");
- },
- make: function() {
- this.make_party();
- this.make_search();
- this.make_item_list();
- },
- make_party: function() {
- var me = this;
- this.party_field = frappe.ui.form.make_control({
- df: {
- "fieldtype": "Link",
- "options": this.party,
- "label": this.party,
- "fieldname": this.party.toLowerCase(),
- "placeholder": this.party
- },
- parent: this.wrapper.find(".party-area"),
- frm: this.frm,
- doctype: this.frm.doctype,
- docname: this.frm.docname,
- only_input: true,
- });
- this.party_field.make_input();
- this.party_field.$input.on("change", function() {
- if(!me.party_field.autocomplete_open)
- frappe.model.set_value(me.frm.doctype, me.frm.docname,
- me.party.toLowerCase(), this.value);
- });
- },
- make_search: function() {
- var me = this;
- this.search = frappe.ui.form.make_control({
- df: {
- "fieldtype": "Data",
- "label": "Item",
- "fieldname": "pos_item",
- "placeholder": "Search Item"
- },
- parent: this.wrapper.find(".search-area"),
- only_input: true,
- });
- this.search.make_input();
- this.search.$input.on("keyup", function() {
- if(!me.search.autocomplete_open)
- if(me.item_timeout)
- clearTimeout(me.item_timeout);
- me.item_timeout = setTimeout(function() { me.make_item_list(); }, 1000);
- });
- },
- make_item_list: function() {
- var me = this;
- if(!this.price_list) {
- msgprint(__("Price List not found or disabled"));
- return;
- }
-
- me.item_timeout = null;
- frappe.call({
- method: 'erpnext.accounts.doctype.sales_invoice.pos.get_items',
- args: {
- sales_or_purchase: this.sales_or_purchase,
- price_list: this.price_list,
- item: this.search.$input.val()
- },
- callback: function(r) {
- var $wrap = me.wrapper.find(".item-list");
- me.wrapper.find(".item-list").empty();
- if (r.message) {
- if (r.message.length === 1) {
- var item = r.message[0];
- if (item.serial_no) {
- me.add_to_cart(item.item_code, item.serial_no);
- me.search.$input.val("");
- return;
-
- } else if (item.barcode) {
- me.add_to_cart(item.item_code);
- me.search.$input.val("");
- return;
- }
- }
-
- $.each(r.message, function(index, obj) {
- $(frappe.render_template("pos_item", {
- item_code: obj.name,
- item_price: format_currency(obj.price_list_rate, obj.currency),
- item_name: obj.name===obj.item_name ? "" : obj.item_name,
- item_image: obj.image ? "url('" + obj.image + "')" : null,
- color: frappe.get_palette(obj.item_name),
- abbr: frappe.get_abbr(obj.item_name)
- })).tooltip().appendTo($wrap);
- });
- }
-
- // if form is local then allow this function
- $(me.wrapper).find("div.pos-item").on("click", function() {
- if(me.frm.doc.docstatus==0) {
- me.add_to_cart($(this).attr("data-item-code"));
- }
- });
- }
- });
- },
- add_to_cart: function(item_code, serial_no) {
- var me = this;
- var caught = false;
-
- if(!me.frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" &&
- me.frm.doc.quotation_to == "Customer")
- || me.frm.doctype != "Quotation")) {
- msgprint(__("Please select {0} first.", [me.party]));
- return;
- }
-
- // get no_of_items
- var no_of_items = me.wrapper.find(".pos-bill-item").length;
-
- // check whether the item is already added
- if (no_of_items != 0) {
- $.each(this.frm.doc["items"] || [], function(i, d) {
- if (d.item_code == item_code) {
- caught = true;
- if (serial_no)
- frappe.model.set_value(d.doctype, d.name, "serial_no", d.serial_no + '\n' + serial_no);
- else
- frappe.model.set_value(d.doctype, d.name, "qty", d.qty + 1);
- }
- });
- }
-
- // if item not found then add new item
- if (!caught)
- this.add_new_item_to_grid(item_code, serial_no);
-
- this.refresh();
- this.refresh_search_box();
- },
- add_new_item_to_grid: function(item_code, serial_no) {
- var me = this;
-
- var child = frappe.model.add_child(me.frm.doc, this.frm.doctype + " Item", "items");
- child.item_code = item_code;
- child.qty = 1;
-
- if (serial_no)
- child.serial_no = serial_no;
-
- this.frm.script_manager.trigger("item_code", child.doctype, child.name);
- frappe.after_ajax(function() {
- me.frm.script_manager.trigger("qty", child.doctype, child.name);
- })
- },
- refresh_search_box: function() {
- var me = this;
-
- // Clear Item Box and remake item list
- if (this.search.$input.val()) {
- this.search.set_input("");
- this.make_item_list();
- }
- },
- update_qty: function(item_code, qty) {
- var me = this;
- $.each(this.frm.doc["items"] || [], function(i, d) {
- if (d.item_code == item_code) {
- if (qty == 0) {
- frappe.model.clear_doc(d.doctype, d.name);
- me.refresh_grid();
- } else {
- frappe.model.set_value(d.doctype, d.name, "qty", qty);
- }
- }
- });
- this.refresh();
- },
- refresh: function() {
- var me = this;
-
- this.refresh_item_list();
- this.refresh_fields();
-
- // if form is local then only run all these functions
- if (this.frm.doc.docstatus===0) {
- this.call_when_local();
- }
-
- this.disable_text_box_and_button();
- this.set_primary_action();
-
- // If quotation to is not Customer then remove party
- if (this.frm.doctype == "Quotation" && this.frm.doc.quotation_to!="Customer") {
- this.party_field.$input.prop("disabled", true);
- }
- },
- refresh_fields: function() {
- this.party_field.set_input(this.frm.doc[this.party.toLowerCase()]);
- this.party_field.frm = this.frm;
- this.party_field.doctype = this.frm.doctype;
- this.party_field.docname = this.frm.docname;
-
- this.wrapper.find('input.discount-percentage').val(this.frm.doc.additional_discount_percentage);
- this.wrapper.find('input.discount-amount').val(this.frm.doc.discount_amount);
-
- this.show_items_in_item_cart();
- this.show_taxes();
- this.set_totals();
- },
- refresh_item_list: function() {
- var me = this;
- // refresh item list on change of price list
- if (this.frm.doc[this.price_list_field] != this.price_list) {
- this.price_list = this.frm.doc[this.price_list_field];
- this.make_item_list();
- }
- },
- show_items_in_item_cart: function() {
- var me = this;
- var $items = this.wrapper.find(".items").empty();
-
- $.each(this.frm.doc.items|| [], function(i, d) {
- $(frappe.render_template("pos_bill_item", {
- item_code: d.item_code,
- item_name: (d.item_name===d.item_code || !d.item_name) ? "" : ("
" + d.item_name),
- qty: d.qty,
- actual_qty: d.actual_qty,
- projected_qty: d.projected_qty,
- rate: format_currency(d.rate, me.frm.doc.currency),
- amount: format_currency(d.amount, me.frm.doc.currency)
- })).appendTo($items);
- });
-
- this.wrapper.find("input.pos-item-qty").on("focus", function() {
- $(this).select();
- });
- },
- show_taxes: function() {
- var me = this;
- var taxes = this.frm.doc["taxes"] || [];
- $(this.wrapper)
- .find(".tax-area").toggleClass("hide", (taxes && taxes.length) ? false : true)
- .find(".tax-table").empty();
-
- $.each(taxes, function(i, d) {
- if (d.tax_amount) {
- $(frappe.render_template("pos_tax_row", {
- description: d.description,
- tax_amount: format_currency(flt(d.tax_amount)/flt(me.frm.doc.conversion_rate),
- me.frm.doc.currency)
- })).appendTo(me.wrapper.find(".tax-table"));
- }
- });
- },
- set_totals: function() {
- var me = this;
- this.wrapper.find(".net-total").text(format_currency(me.frm.doc["net_total"], me.frm.doc.currency));
- this.wrapper.find(".grand-total").text(format_currency(me.frm.doc.grand_total, me.frm.doc.currency));
- },
- call_when_local: function() {
- var me = this;
-
- // append quantity to the respective item after change from input box
- $(this.wrapper).find("input.pos-item-qty").on("change", function() {
- var item_code = $(this).parents(".pos-bill-item").attr("data-item-code");
- me.update_qty(item_code, $(this).val());
- });
-
- // increase/decrease qty on plus/minus button
- $(this.wrapper).find(".pos-qty-btn").on("click", function() {
- var $item = $(this).parents(".pos-bill-item:first");
- me.increase_decrease_qty($item, $(this).attr("data-action"));
- });
-
- this.focus();
- },
- focus: function() {
- if(this.frm.doc[this.party.toLowerCase()]) {
- this.search.$input.focus();
- } else {
- if(!(this.frm.doctype == "Quotation" && this.frm.doc.quotation_to!="Customer"))
- this.party_field.$input.focus();
- }
- },
- increase_decrease_qty: function($item, operation) {
- var item_code = $item.attr("data-item-code");
- var item_qty = cint($item.find("input.pos-item-qty").val());
-
- if (operation == "increase-qty")
- this.update_qty(item_code, item_qty + 1);
- else if (operation == "decrease-qty" && item_qty != 0)
- this.update_qty(item_code, item_qty - 1);
- },
- disable_text_box_and_button: function() {
- var me = this;
- // if form is submitted & cancelled then disable all input box & buttons
- $(this.wrapper)
- .find(".pos-qty-btn")
- .toggle(this.frm.doc.docstatus===0);
-
- $(this.wrapper).find('input, button').prop("disabled", !(this.frm.doc.docstatus===0));
-
- this.wrapper.find(".pos-item-area").toggleClass("hide", me.frm.doc.docstatus!==0);
-
- },
- set_primary_action: function() {
- var me = this;
- if (this.frm.page.current_view_name==="main") return;
-
- if (this.frm.doctype == "Sales Invoice" && this.frm.doc.docstatus===0) {
- if (!this.frm.doc.is_pos) {
- this.frm.set_value("is_pos", 1);
- }
- this.frm.page.set_primary_action(__("Pay"), function() {
- me.make_payment();
- });
- } else if (this.frm.doc.docstatus===1) {
- this.frm.page.set_primary_action(__("New"), function() {
- erpnext.open_as_pos = true;
- new_doc(me.frm.doctype);
- });
- }
- },
- refresh_delete_btn: function() {
- $(this.wrapper).find(".remove-items").toggle($(".item-cart .warning").length ? true : false);
- },
- remove_selected_items: function() {
- var me = this;
- var selected_items = [];
- var no_of_items = $(this.wrapper).find("#cart tbody tr").length;
- for(var x=0; x<=no_of_items - 1; x++) {
- var row = $(this.wrapper).find("#cart tbody tr:eq(" + x + ")");
- if(row.attr("data-selected") == "true") {
- selected_items.push(row.attr("id"));
- }
- }
-
- var child = this.frm.doc["items"] || [];
-
- $.each(child, function(i, d) {
- for (var i in selected_items) {
- if (d.item_code == selected_items[i]) {
- frappe.model.clear_doc(d.doctype, d.name);
- }
- }
- });
-
- this.refresh_grid();
- },
- refresh_grid: function() {
- this.frm.dirty();
- this.frm.fields_dict["items"].grid.refresh();
- 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;
-
- if (no_of_items == 0)
- msgprint(__("Payment cannot be made for empty cart"));
- else {
-
- this.with_modes_of_payment(function() {
- // prefer cash payment!
- var default_mode = me.frm.doc.mode_of_payment ? me.frm.doc.mode_of_payment :
- 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'),
- "default": me.frm.doc.grand_total},
- {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,
- change: function() {
- var values = dialog.get_values();
-
- var actual_change = flt(values.paid_amount - values.total_amount,
- precision("paid_amount"));
-
- if (actual_change > 0) {
- var rounded_change =
- round_based_on_smallest_currency_fraction(actual_change,
- me.frm.doc.currency, precision("paid_amount"));
- } else {
- var rounded_change = 0;
- }
-
- dialog.set_value("change", rounded_change);
- 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
- dialog.set_value("paid_amount", dialog.get_value("total_amount"));
- dialog.get_input("paid_amount").trigger("change");
- } else if (!is_cash) {
- dialog.set_value("paid_amount", dialog.get_value("total_amount"));
- dialog.set_value("change", 0);
- }
- }).trigger("change");
-
- me.set_pay_button(dialog);
- });
- }
- },
- set_pay_button: function(dialog) {
- var me = this;
- dialog.set_primary_action(__("Pay"), 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)), 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.grand_total - paid_amount);
- me.frm.set_value("outstanding_amount", 0);
-
- me.frm.savesubmit(this);
- dialog.hide();
- })
-
- }
-});
-
-erpnext.pos.make_pos_btn = function(frm) {
- frm.page.add_menu_item(__("{0} View", [frm.page.current_view_name === "pos" ? "Form" : "Point-of-Sale"]), function() {
- erpnext.pos.toggle(frm);
- });
-
- if(frm.pos_btn) return;
-
- // Show POS button only if it is enabled from features setup
- if (cint(sys_defaults.fs_pos_view)!==1 || frm.doctype==="Material Request") {
- return;
- }
-
- if(!frm.pos_btn) {
- frm.pos_btn = frm.page.add_action_icon("icon-th", function() {
- erpnext.pos.toggle(frm);
- });
- }
-
- if(erpnext.open_as_pos && frm.page.current_view_name !== "pos") {
- erpnext.pos.toggle(frm, true);
- }
-}
-
-erpnext.pos.toggle = function(frm, show) {
- // Check whether it is Selling or Buying cycle
- var price_list = frappe.meta.has_field(cur_frm.doc.doctype, "selling_price_list") ?
- frm.doc.selling_price_list : frm.doc.buying_price_list;
-
- if(show!==undefined) {
- if((show===true && frm.page.current_view_name === "pos")
- || (show===false && frm.page.current_view_name === "main")) {
- return;
- }
- }
-
- if(frm.page.current_view_name!=="pos") {
- // before switching, ask for pos name
- if(!price_list) {
- frappe.throw(__("Please select Price List"));
- }
-
- if(!frm.doc.company) {
- frappe.throw(__("Please select Company"));
- }
- }
-
- // make pos
- if(!frm.pos) {
- var wrapper = frm.page.add_view("pos", "");
- frm.pos = new erpnext.pos.PointOfSale(wrapper, frm);
- }
-
- // toggle view
- frm.page.set_view(frm.page.current_view_name==="pos" ? "main" : "pos");
-
- frm.toolbar.current_status = null;
- frm.refresh();
-
- // refresh
- if(frm.page.current_view_name==="pos") {
- frm.pos.refresh();
- }
-}
diff --git a/erpnext/public/js/pos/pos_invoice_list.html b/erpnext/public/js/pos/pos_invoice_list.html
index 463b3e7e5f..8d2644ce27 100644
--- a/erpnext/public/js/pos/pos_invoice_list.html
+++ b/erpnext/public/js/pos/pos_invoice_list.html
@@ -1,5 +1,6 @@
-
{%= customer %}
+
{%= sr %}
+
{%= customer %}
{%= grand_total %}
{%= status %}
diff --git a/erpnext/public/js/pos/pos_print.html b/erpnext/public/js/pos/pos_print.html
deleted file mode 100644
index d31a88568f..0000000000
--- a/erpnext/public/js/pos/pos_print.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
- {{ company }}
-
-
- {{currency}}
-
-{% for item in items %}
-
{{item.item_code}}
-{% endfor %}
\ No newline at end of file