Added print, make new invoice from POS functionality
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js
index 90ccbfb..dc2b265 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.js
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.js
@@ -33,14 +33,12 @@
this.prepare_menu();
this.set_online_status();
},
- () => this.make_sales_invoice_frm(),
() => this.setup_pos_profile(),
() => {
- this.make_cart();
this.make_items();
this.bind_events();
- this.disable_text_box_and_button();
- }
+ },
+ () => this.make_new_invoice(),
]);
}
@@ -96,7 +94,19 @@
}
disable_text_box_and_button() {
- $(this.wrapper).find('input, button').prop("disabled", !(this.frm.doc.docstatus===0));
+ let disabled = this.frm.doc.docstatus == 1 ? true: false;
+ let pointer_events = this.frm.doc.docstatus == 1 ? "none":"inherit";
+
+ $(this.wrapper).find('input, button', 'select').prop("disabled", disabled);
+ $(this.wrapper).find(".number-pad-container").toggleClass("hide", disabled);
+
+ $(this.wrapper).find('.cart-container').css('pointer-events', pointer_events);
+ $(this.wrapper).find('.item-container').css('pointer-events', pointer_events);
+
+ this.page.clear_actions();
+ if(this.frm.doc.docstatus === 1) {
+ this.set_primary_action()
+ }
}
make_items() {
@@ -110,6 +120,9 @@
}
this.update_item_in_cart(item_code, 'qty', '+1');
this.cart && this.cart.unselect_all();
+ },
+ update_cart: (item, field, value) => {
+ this.update_item_in_cart(item, field, value)
}
}
});
@@ -125,11 +138,18 @@
value = item[field] + flt(value);
}
+ if (field === 'serial_no') {
+ value = item.serial_no + '\n' + value;
+ }
+
this.update_item_in_frm(item, field, value)
.then(() => {
// update cart
this.cart.add_item(item);
- });
+ })
+ .then(() => {
+ this.show_taxes_and_totals();
+ })
// if (barcode) {
// const value = barcode['serial_no'] ?
@@ -148,6 +168,7 @@
.then(() => {
// update cart
this.cart.add_item(item);
+ this.show_taxes_and_totals();
});
}
@@ -161,7 +182,49 @@
}
make_payment_modal() {
- this.payment = new Payment(this.frm);
+ this.payment = new Payment({
+ frm: this.frm,
+ events: {
+ submit_form: () => {
+ this.submit_sales_invoice()
+ }
+ }
+ });
+ }
+
+ submit_sales_invoice() {
+ var me = this;
+ this.frm.savesubmit();
+ // frappe.confirm(__("Permanently Submit {0}?", [this.frm.doc.name]), function() {
+// return frappe.call({
+// method: 'erpnext.selling.page.point_of_sale.point_of_sale.submit_invoice',
+// freeze: true,
+// args: {
+// doc: me.frm.doc
+// }
+// }).then(r => {
+// if(r.message) {
+// me.frm.doc = r.message;
+// me.frm.meta.default_print_format = 'POS Invoice';
+// frappe.show_alert({
+// indicator: 'green',
+// message: __(`Sales invoice ${r.message.name} created succesfully`)
+// });
+//
+// me.frm.msgbox = frappe.msgprint(
+// `<a class="btn btn-primary" onclick="cur_frm.print_preview.printit(true)" style="margin-right: 5px;">
+// ${__('Print')}</a>
+// <a class="btn btn-default new_doc">
+// ${__('New')}</a>`
+// );
+// $(me.frm.msgbox.wrapper).find('.new_doc').click(function() {
+// me.frm.msgbox.hide()
+// me.make_new_invoice()
+// })
+// me.disable_text_box_and_button();
+// }
+// });
+// })
}
bind_events() {
@@ -179,15 +242,26 @@
});
}
+ make_new_invoice() {
+ return frappe.run_serially([
+ () => this.make_sales_invoice_frm(),
+ () => {
+ this.make_cart();
+ this.disable_text_box_and_button();
+ }
+ ]);
+ }
+
make_sales_invoice_frm() {
- const dt = 'Sales Invoice';
+ this.dt = 'Sales Invoice';
return new Promise(resolve => {
- frappe.model.with_doctype(dt, () => {
+ frappe.model.with_doctype(this.dt, () => {
const page = $('<div>');
- const frm = new _f.Frm(dt, page, false);
- const name = frappe.model.make_new_doc_and_get_name(dt, true);
+ const frm = new _f.Frm(this.dt, page, false);
+ const name = frappe.model.make_new_doc_and_get_name(this.dt, true);
frm.refresh(name);
frm.doc.items = [];
+ this.doc = frm.doc;
this.frm = frm;
this.frm.set_value('is_pos', 1);
resolve();
@@ -196,6 +270,7 @@
}
prepare_menu() {
+ var me = this;
this.page.clear_menu();
// for mobile
@@ -203,12 +278,8 @@
//
}).addClass('visible-xs');
- this.page.add_menu_item(__("New Sales Invoice"), function () {
- //
- });
-
- this.page.add_menu_item(__("Sync Master Data"), function () {
- //
+ this.page.add_menu_item(__("Email"), function () {
+ me.frm.email_doc();
});
this.page.add_menu_item(__("Sync Offline Invoices"), function () {
@@ -219,6 +290,39 @@
frappe.set_route('List', 'POS Profile');
});
}
+
+ set_primary_action() {
+ var me = this;
+ this.page.set_secondary_action(__("Print"), function () {
+ me.frm.print_preview.printit(true)
+ })
+
+ this.page.set_primary_action(__("New"), function () {
+ me.make_new_invoice()
+ })
+ }
+
+ show_taxes_and_totals() {
+ let tax_template = '';
+ let currency = this.frm.doc.currency;
+ const taxes_wrapper = $(this.wrapper).find('.taxes');
+
+ this.frm.refresh_field('taxes')
+ $(this.wrapper).find('.net_total').html(format_currency(this.frm.doc.net_total, this.currency))
+ console.log(this.frm.doc.taxes[0].tax_amount)
+ $.each(this.frm.doc.taxes, function(index, data) {
+ console.log(data.tax_amount)
+ tax_template += `
+ <div class="list-item" style="padding-right: 0;">
+ <div >${data.description}</div>
+ <div class="text-right bold">${fmt_money(data.tax_amount, currency)}</div>
+ </div>`
+ })
+
+ taxes_wrapper.empty()
+ console.log(tax_template)
+ taxes_wrapper.html(tax_template)
+ }
}
class POSCart {
@@ -237,36 +341,39 @@
}
make_dom() {
+ $(this.wrapper).find('.pos-cart').empty()
this.wrapper.append(`
- <div class="customer-field">
- </div>
- <div class="cart-wrapper">
- <div class="list-item-table">
- <div class="list-item list-item--head">
- <div class="list-item__content list-item__content--flex-2 text-muted">${__('Item Name')}</div>
- <div class="list-item__content text-muted text-right">${__('Quantity')}</div>
- <div class="list-item__content text-muted text-right">${__('Discount')}</div>
- <div class="list-item__content text-muted text-right">${__('Rate')}</div>
+ <div class="pos-cart">
+ <div class="customer-field">
+ </div>
+ <div class="cart-wrapper">
+ <div class="list-item-table">
+ <div class="list-item list-item--head">
+ <div class="list-item__content list-item__content--flex-2 text-muted">${__('Item Name')}</div>
+ <div class="list-item__content text-muted text-right">${__('Quantity')}</div>
+ <div class="list-item__content text-muted text-right">${__('Discount')}</div>
+ <div class="list-item__content text-muted text-right">${__('Rate')}</div>
+ </div>
+ <div class="cart-items">
+ <div class="empty-state">
+ <span>No Items added to cart</span>
+ </div>
+ </div>
</div>
- <div class="cart-items">
- <div class="empty-state">
- <span>No Items added to cart</span>
+ <div class="taxes-and-totals">
+ <div class="list-item">
+ <div class="list-item__content list-item__content--flex-2 text-muted">${__('Net Total')}</div>
+ <div class="list-item__content net_total">0.00</div>
+ </div>
+ <div class="list-item">
+ <div class="list-item__content list-item__content--flex-2 text-muted">${__('Taxes')}</div>
+ <div class="list-item__content taxes">0.00</div>
</div>
</div>
</div>
- <div class="taxes-and-totals">
- <div class="list-item">
- <div class="list-item__content list-item__content--flex-2 text-muted">${__('Net Total')}</div>
- <div class="list-item__content">0.00</div>
- </div>
- <div class="list-item">
- <div class="list-item__content list-item__content--flex-2 text-muted">${__('Taxes')}</div>
- <div class="list-item__content">0.00</div>
- </div>
+ <div class="number-pad-container">
</div>
</div>
- <div class="number-pad-container">
- </div>
`);
this.$cart_items = this.wrapper.find('.cart-items');
}
@@ -304,7 +411,7 @@
wrapper: this.wrapper.find('.number-pad-container'),
onclick: (btn_value) => {
// on click
- if (!this.selected_item) {
+ if (!this.selected_item && btn_value !== 'Pay') {
frappe.show_alert({
indicator: 'red',
message: __('Please select an item in the cart')
@@ -502,6 +609,7 @@
this.wrapper = wrapper;
this.pos_profile = pos_profile;
this.items = {};
+ this.events = events;
this.currency = this.pos_profile.currency ||
frappe.defaults.get_default('currency');
@@ -509,12 +617,11 @@
this.make_fields();
this.init_clusterize();
- this.bind_events(events);
+ this.bind_events();
// bootstrap with 20 items
this.get_items()
.then((items, serial_no) => {
- console.log(serial_no);
this.items = items;
})
.then(() => this.render_items());
@@ -621,14 +728,19 @@
this.get_items({search_value: search_term})
.then((items) => {
this.render_items(items);
+ if(this.serial_no) {
+ this.events.update_cart(items[0].item_code,
+ 'serial_no', this.serial_no)
+ }
});
}
- bind_events(events) {
+ bind_events() {
+ var me = this;
this.wrapper.on('click', '.pos-item-wrapper', function(e) {
const $item = $(this);
const item_code = $item.attr('data-item-code');
- events.item_click.apply(null, [item_code]);
+ me.events.item_click.apply(null, [item_code]);
});
}
@@ -691,7 +803,8 @@
}).then(r => {
const { items, serial_no } = r.message;
- res(items, serial_no);
+ this.serial_no = serial_no || "";
+ res(items);
});
});
}
@@ -796,8 +909,9 @@
}
class Payment {
- constructor(frm) {
+ constructor({frm, events}) {
this.frm = frm;
+ this.events = events;
this.make();
this.set_primary_action();
// this.show_outstanding_amount()
@@ -837,9 +951,9 @@
var me = this;
this.dialog.set_primary_action(__("Submit"), function() {
- this.frm.doc.savesubmit()
- this.dialog.hide()
- });
+ me.dialog.hide()
+ me.events.submit_form()
+ })
}
get_fields() {
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index e6cfc71..73546a0 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -50,4 +50,17 @@
'serial_no': serial_no
})
- return res
\ No newline at end of file
+ return res
+
+@frappe.whitelist()
+def submit_invoice(doc):
+ if isinstance(doc, basestring):
+ args = json.loads(doc)
+
+ doc = frappe.new_doc('Sales Invoice')
+ doc.update(args)
+ doc.run_method("set_missing_values")
+ doc.run_method("calculate_taxes_and_totals")
+ doc.submit()
+
+ return doc